diff -u -r1.43 operations_posix_windows.cpp --- boost/libs/filesystem/src/operations_posix_windows.cpp 5 Dec 2004 22:45:44 -0000 1.43 +++ boost/libs/filesystem/src/operations_posix_windows.cpp 12 Dec 2004 21:12:20 -0000 @@ -69,11 +69,59 @@ // in 64-bit off_t's (and thus st_size) on 32-bit systems that support // the Large File Support (LFS) interface, such as Linux, Solaris, and IRIX. + // This may be necessary to get readdir_r. +# ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 199506L +# endif + # include # include "dirent.h" # include "unistd.h" # include "fcntl.h" # include "utime.h" + +# include +# include + + // There is no easy way to detect the availability of readdir_r + // with the preprocessor, but we can detect it by overload + // resolution. + + // If readdir_r is available we will include a buffer pointer in + // the handle, using the handle type std::pair; + // otherwise we will use DIR *. This means we can overload the + // implementation on the handle type rather than using a template. + + // We overload readdir_r with a function that returns a type + // convertible to int so that the readdir_r-based implementation + // will be well-formed even if it is not usable (and therefore not + // used). + + namespace + { + struct readdir_handle_helper : std::pair + { + operator int() { return first; } + }; + } + + static inline readdir_handle_helper readdir_r( DIR *, ... ) + { + assert( !"readdir_r not available but used anyway" ); + return readdir_handle_helper(); + } + + namespace + { + typedef boost::mpl::if_c< + sizeof( ::readdir_r( (DIR *) 0, (struct dirent *) 0, + (struct dirent **) 0) ) + == sizeof( int ), + std::pair, + DIR *>::type + readdir_handle_type; + } + # endif #include // even on Windows some functions use stat() @@ -90,34 +138,61 @@ { #ifdef BOOST_POSIX -# define BOOST_HANDLE DIR * -# define BOOST_INVALID_HANDLE_VALUE 0 +# define BOOST_HANDLE readdir_handle_type +# define BOOST_INVALID_HANDLE_VALUE readdir_handle_type() # define BOOST_SYSTEM_DIRECTORY_TYPE struct dirent * inline const char * find_first_file( const char * dir, - BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & ) + DIR * & handle, BOOST_SYSTEM_DIRECTORY_TYPE & ) // Returns: 0 if error, otherwise name { const char * dummy_first_name = "."; - return ( (handle = ::opendir( dir )) - == BOOST_INVALID_HANDLE_VALUE ) ? 0 : dummy_first_name; + return ( (handle = ::opendir( dir )) == 0 ) ? 0 : dummy_first_name; } - inline void find_close( BOOST_HANDLE handle ) + inline const char * find_first_file( const char * dir, + std::pair & handle, BOOST_SYSTEM_DIRECTORY_TYPE & ) + // Returns: 0 if error, otherwise name { - assert( handle != BOOST_INVALID_HANDLE_VALUE ); + if ( (handle.first = ::opendir( dir )) == 0 ) + return 0; + + // The required buffer size is the size that struct dirent would + // have were its d_name array to be long enough - which it might + // not be. + const std::size_t buf_len = sizeof( struct dirent ) + - sizeof( ( (struct dirent *) 0 )->d_name ) + + ::pathconf( dir, _PC_NAME_MAX ) + 1; + + if ( (handle.second = new char[buf_len]) == 0) + { + ::closedir( handle.first ); + handle.first = 0; + return 0; + } + + const char * dummy_first_name = "."; + return dummy_first_name; + } + + inline void find_close( DIR * handle ) + { + assert( handle != 0 ); ::closedir( handle ); } + inline void find_close( std::pair handle ) + { + assert( handle.first != 0 && handle.second != 0 ); + ::closedir( handle.first ); + delete[] handle.second; + } + inline const char * find_next_file( - BOOST_HANDLE handle, const fs::path & ph, BOOST_SYSTEM_DIRECTORY_TYPE & ) + DIR * handle, const fs::path & ph, BOOST_SYSTEM_DIRECTORY_TYPE & ) // Returns: if EOF 0, otherwise name // Throws: if system reports error { - -// TODO: use readdir_r() if available, so code is multi-thread safe. -// Fly-in-ointment: not all platforms support readdir_r(). - struct dirent * dp; errno = 0; if ( (dp = ::readdir( handle )) == 0 ) @@ -133,6 +208,24 @@ } return dp->d_name; } + + inline const char * find_next_file( + std::pair handle, const fs::path & ph, + BOOST_SYSTEM_DIRECTORY_TYPE & ) + // Returns: if EOF 0, otherwise name + // Throws: if system reports error + { + struct dirent * dp; + if ( int error = ::readdir_r( + handle.first, (struct dirent *) handle.second, &dp ) ) + { + boost::throw_exception( + fs::filesystem_error( + "boost::filesystem::directory_iterator::operator++", + ph, error ) ); + } + return ( dp == 0 ) ? 0 : dp->d_name; + } #else // BOOST_WINDOWS # define BOOST_HANDLE HANDLE