// directory_posix_windows.cpp ---------------------------------------------// // Copyright © 2002 Beman Dawes // Copyright © 2001 Dietmar Kühl // Use, modification, and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy // at http://www.boost.org/LICENSE_1_0.txt) // See library home page at http://www.boost.org/libs/filesystem //----------------------------------------------------------------------------// // The point of this implementation is to prove the interface. There is no // claim the implementation is efficient, follows good coding practice, etc. //----------------------------------------------------------------------------// // define BOOST_FILESYSTEM_SOURCE so that knows // the library is being built (possibly exporting rather than importing code) #define BOOST_FILESYSTEM_SOURCE #define _FILE_OFFSET_BITS 64 // at worst, these defines may have no effect, #define __USE_FILE_OFFSET64 // but that is harmless on Windows and on POSIX // 64-bit systems or on 32-bit systems which don't have files larger // than can be represented by a traditional POSIX/UNIX off_t type. // OTOH, defining them should kick in 64-bit off_t's (and thus // st_size) on 32-bit systems that provide the Large File // Support (LFS) interface, such as Linux, Solaris, and IRIX. // The defines are given before any headers are included to // ensure that they are available to all included headers. // That is required at least on Solaris, and possibly on other // systems as well. #include #include #include #include #include #include namespace fs = boost::filesystem; // BOOST_POSIX or BOOST_WINDOWS specify which API to use. # if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX ) # if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) # define BOOST_WINDOWS # else # define BOOST_POSIX # endif # endif # if defined(BOOST_WINDOWS) # include "windows.h" # if defined(__BORLANDC__) || defined(__MWERKS__) # if defined(__BORLANDC__) using std::time_t; # endif # include "utime.h" # else # include "sys/utime.h" # endif // For Windows, the xxxA form of various function names is used to avoid // inadvertently getting wide forms of the functions. (The undecorated // forms are actually macros, so can misfire if the user has various // other macros defined. There was a bug report of this happening.) # else // BOOST_POSIX # include # include "dirent.h" # include "unistd.h" # include "fcntl.h" # include "utime.h" # endif #include // even on Windows some functions use stat() #include #include #include // for remove, rename #include #include //#include // for debugging only; comment out when not in use #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::strcmp; using ::remove; using ::rename; } #endif #include // must be the last header // helpers -----------------------------------------------------------------// namespace { #ifdef BOOST_POSIX # define BOOST_HANDLE DIR * # define BOOST_INVALID_HANDLE_VALUE 0 # define BOOST_SYSTEM_DIRECTORY_TYPE struct dirent inline const char * find_first_file( const char * dir, BOOST_HANDLE & 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; } inline void find_close( BOOST_HANDLE handle ) { assert( handle != BOOST_INVALID_HANDLE_VALUE ); ::closedir( handle ); } // warning: the only dirent member updated is d_name inline int readdir_r_simulator( DIR * dirp, struct dirent * entry, struct dirent ** result ) // *result set to 0 on end of directory { # if defined(_POSIX_THREAD_SAFE_FUNCTIONS) \ && defined(_SC_THREAD_SAFE_FUNCTIONS) \ && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0) \ && ( !defined(__HP_aCC) || ( defined(__HP_aCC) && defined(_REENTRANT) ) ) if ( ::sysconf( _SC_THREAD_SAFE_FUNCTIONS ) >= 0 ) { return ::readdir_r( dirp, entry, result ); } # endif struct dirent * p; errno = 0; *result = 0; if ( (p = ::readdir( dirp )) == 0 ) return errno; // POSIX specs require entry->d_name be large enough: std::strcpy( entry->d_name, p->d_name ); *result = entry; return 0; } inline const char * find_next_file( BOOST_HANDLE handle, const fs::path & ph, BOOST_SYSTEM_DIRECTORY_TYPE & entry ) // Returns: if EOF 0, otherwise name // Throws: if system reports error { struct dirent * result; int return_code; if ( (return_code = ::readdir_r_simulator( handle, &entry, &result )) != 0 ) { boost::throw_exception( fs::filesystem_error( "boost::filesystem::directory_iterator::operator++", ph, return_code ) ); } return result ? entry.d_name : 0; } #else // BOOST_WINDOWS # define BOOST_HANDLE HANDLE # define BOOST_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE # define BOOST_SYSTEM_DIRECTORY_TYPE WIN32_FIND_DATAA inline const char * find_first_file( const char * dir, BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & data ) // Returns: 0 if error, otherwise name // Note: an empty root directory has no "." or ".." entries, so this causes // a ERROR_FILE_NOT_FOUND error which we do not considered an error. Instead, // the handle is set to BOOST_INVALID_HANDLE_VALUE and a non-zero is returned. { // use a form of search Sebastian Martel reports will work with Win98 std::string dirpath( dir ); dirpath += (dirpath.empty() || (dirpath[dirpath.size()-1] != '\\' && dirpath[dirpath.size()-1] != '/')) ? "\\*" : "*"; return ( (handle = ::FindFirstFileA( dirpath.c_str(), &data )) == BOOST_INVALID_HANDLE_VALUE && ::GetLastError() != ERROR_FILE_NOT_FOUND) ? 0 : data.cFileName; } inline void find_close( BOOST_HANDLE handle ) { assert( handle != BOOST_INVALID_HANDLE_VALUE ); ::FindClose( handle ); } inline const char * find_next_file( BOOST_HANDLE handle, const fs::path & ph, BOOST_SYSTEM_DIRECTORY_TYPE & data ) // Returns: 0 if EOF, otherwise name // Throws: if system reports error { if ( ::FindNextFileA( handle, &data ) == 0 ) { if ( ::GetLastError() != ERROR_NO_MORE_FILES ) { boost::throw_exception( fs::filesystem_error( "boost::filesystem::directory_iterator::operator++", ph.branch_path(), fs::detail::system_error_code() ) ); } else { return 0; } // end reached } return data.cFileName; } #endif fs::directory_iterator end_itr; bool is_empty_directory( const fs::path & dir_path ) { return fs::directory_iterator(dir_path) == end_itr; } unsigned long remove_all_aux( const fs::path & ph ) { unsigned long count = 1; if ( !fs::symbolic_link_exists( ph ) // don't recurse symbolic links && fs::is_directory( ph ) ) { for ( fs::directory_iterator itr( ph ); itr != end_itr; ++itr ) { count += remove_all_aux( *itr ); } } fs::remove( ph ); return count; } } // unnamed namespace namespace boost { namespace filesystem { namespace detail { std::size_t path_max() { #ifdef PATH_MAX static std::size_t max = PATH_MAX; #else static std::size_t max = 0; #endif if(max == 0) { long tmp = ::pathconf("/", _PC_NAME_MAX); if(tmp <= 0) { max = 4096; } else { max = static_cast(tmp+1); } } return max; } // dir_itr_imp -------------------------------------------------------------// class dir_itr_imp { public: path entry_path; BOOST_HANDLE handle; BOOST_SYSTEM_DIRECTORY_TYPE* dynamic_entry; dir_itr_imp() : dynamic_entry(0) { dirent de; dynamic_entry = (BOOST_SYSTEM_DIRECTORY_TYPE*) (new char[(sizeof(dirent)-sizeof(de.d_name))+path_max()+1]); } ~dir_itr_imp() { if ( handle != BOOST_INVALID_HANDLE_VALUE ) find_close( handle ); delete [] dynamic_entry; } }; // dot_or_dot_dot ----------------------------------------------------------// inline bool dot_or_dot_dot( const char * name ) { # if !BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT(0x0564) ) return std::strcmp( name, "." ) == 0 || std::strcmp( name, ".." ) == 0; # else // Borland workaround for failure of intrinsics to be placed in // namespace std with certain combinations of compiler options. // To ensure test coverage, the workaround is applied to all // configurations, regardless of option settings. return name[0]=='.' && (name[1]=='\0' || (name[1]=='.' && name[2]=='\0')); # endif } // directory_iterator implementation ---------------------------------------// BOOST_FILESYSTEM_DECL void dir_itr_init( dir_itr_imp_ptr & m_imp, const path & dir_path ) { m_imp.reset( new dir_itr_imp ); const char * name = 0; // initialization quiets compiler warnings if ( dir_path.empty() ) m_imp->handle = BOOST_INVALID_HANDLE_VALUE; else { name = find_first_file( dir_path.native_directory_string().c_str(), m_imp->handle, *(m_imp->dynamic_entry)); // sets handle if ( m_imp->handle == BOOST_INVALID_HANDLE_VALUE && name ) // eof { m_imp.reset(); // make end iterator return; } } if ( m_imp->handle != BOOST_INVALID_HANDLE_VALUE ) { m_imp->entry_path = dir_path; // append name, except ignore "." or ".." if ( !dot_or_dot_dot( name ) ) { m_imp->entry_path.m_path_append( name, no_check ); } else { m_imp->entry_path.m_path_append( "dummy", no_check ); dir_itr_increment( m_imp ); } } else { boost::throw_exception( filesystem_error( "boost::filesystem::directory_iterator constructor", dir_path, fs::detail::system_error_code() ) ); } } BOOST_FILESYSTEM_DECL path & dir_itr_dereference( const dir_itr_imp_ptr & m_imp ) { assert( m_imp.get() ); // fails if dereference end iterator return m_imp->entry_path; } BOOST_FILESYSTEM_DECL void dir_itr_increment( dir_itr_imp_ptr & m_imp ) { assert( m_imp.get() ); // fails on increment end iterator assert( m_imp->handle != BOOST_INVALID_HANDLE_VALUE ); // reality check const char * name; while ( (name = find_next_file( m_imp->handle, m_imp->entry_path, *(m_imp->dynamic_entry))) != 0 ) { // append name, except ignore "." or ".." if ( !dot_or_dot_dot( name ) ) { m_imp->entry_path.m_replace_leaf( name ); return; } } m_imp.reset(); // make base() the end iterator } } // namespace detail // free functions ----------------------------------------------------------// BOOST_FILESYSTEM_DECL bool exists( const path & ph ) { # ifdef BOOST_POSIX struct stat path_stat; if(::stat( ph.string().c_str(), &path_stat ) != 0) { if((errno == ENOENT) || (errno == ENOTDIR)) return false; // stat failed because the path does not exist // for any other error we assume the file does exist and fall through, // this may not be the best policy though... (JM 20040330) } return true; # else if(::GetFileAttributesA( ph.string().c_str() ) == 0xFFFFFFFF) { UINT err = ::GetLastError(); if((err == ERROR_FILE_NOT_FOUND) || (err == ERROR_INVALID_PARAMETER) || (err == ERROR_NOT_READY) || (err == ERROR_PATH_NOT_FOUND) || (err == ERROR_INVALID_NAME) || (err == ERROR_BAD_NETPATH )) return false; // GetFileAttributes failed because the path does not exist // for any other error we assume the file does exist and fall through, // this may not be the best policy though... (JM 20040330) return true; } return true; # endif } BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() { # ifdef BOOST_POSIX struct stat lcl_stat; return sizeof( lcl_stat.st_size ) > 4; # else return true; # endif } // suggested by Walter Landry BOOST_FILESYSTEM_DECL bool symbolic_link_exists( const path & ph ) { # ifdef BOOST_POSIX struct stat path_stat; return ::lstat( ph.native_file_string().c_str(), &path_stat ) == 0 && S_ISLNK( path_stat.st_mode ); # else return false; // Windows has no O/S concept of symbolic links // (.lnk files are an application feature, not // a Windows operating system feature) # endif } BOOST_FILESYSTEM_DECL bool is_directory( const path & ph ) { # ifdef BOOST_POSIX struct stat path_stat; if ( ::stat( ph.native_directory_string().c_str(), &path_stat ) != 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::is_directory", ph, fs::detail::system_error_code() ) ); return S_ISDIR( path_stat.st_mode ); # else DWORD attributes = ::GetFileAttributesA( ph.native_directory_string().c_str() ); if ( attributes == 0xFFFFFFFF ) boost::throw_exception( filesystem_error( "boost::filesystem::is_directory", ph, fs::detail::system_error_code() ) ); return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; # endif } BOOST_FILESYSTEM_DECL bool _is_empty( const path & ph ) { # ifdef BOOST_POSIX struct stat path_stat; if ( ::stat( ph.string().c_str(), &path_stat ) != 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::is_empty", ph, fs::detail::system_error_code() ) ); return S_ISDIR( path_stat.st_mode ) ? is_empty_directory( ph ) : path_stat.st_size == 0; # else WIN32_FILE_ATTRIBUTE_DATA fad; if ( !::GetFileAttributesExA( ph.string().c_str(), ::GetFileExInfoStandard, &fad ) ) boost::throw_exception( filesystem_error( "boost::filesystem::is_empty", ph, fs::detail::system_error_code() ) ); return ( fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ? is_empty_directory( ph ) :( !fad.nFileSizeHigh && !fad.nFileSizeLow ); # endif } # ifdef BOOST_WINDOWS // Thanks to Jeremy Maitin-Shepard for much help and for permission to // base the implementation on portions of his file-equivalence-win32.cpp // experimental code. struct handle_wrapper { BOOST_HANDLE handle; handle_wrapper( BOOST_HANDLE h ) : handle(h) {} ~handle_wrapper() { if ( handle != BOOST_INVALID_HANDLE_VALUE ) ::CloseHandle(handle); } }; # endif BOOST_FILESYSTEM_DECL bool equivalent( const path & ph1, const path & ph2 ) { # ifdef BOOST_POSIX struct stat s1; int s1_result = ::stat( ph1.string().c_str(), &s1 ); // save error code in case we have to throw int error1 = (s1_result != 0 ? fs::detail::system_error_code() : 0); struct stat s2; int s2_result = ::stat( ph2.string().c_str(), &s2 ); if ( s1_result != 0 || s2_result != 0 ) { if ( s1_result == 0 || s2_result == 0 ) return false; assert( s1_result != 0 && s2_result != 0 ); boost::throw_exception( filesystem_error( "boost::filesystem::equivalent", ph1, error1 ) ); } // at this point, both stats are known to be valid return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino // According to the POSIX stat specs, "The st_ino and st_dev fields // taken together uniquely identify the file within the system." // Just to be sure, size and mod time are also checked. && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; # else // Note well: Physical location on external media is part of the // equivalence criteria. If there are no open handles, physical location // can change due to defragmentation or other relocations. Thus handles // must be held open until location information for both paths has // been retrieved. handle_wrapper p1( ::CreateFileA( ph1.string().c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ) ); int error1; // save error code in case we have to throw if ( p1.handle == BOOST_INVALID_HANDLE_VALUE ) error1 = fs::detail::system_error_code(); handle_wrapper p2( ::CreateFileA( ph2.string().c_str(), 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ) ); if ( p1.handle == BOOST_INVALID_HANDLE_VALUE || p2.handle == BOOST_INVALID_HANDLE_VALUE ) { if ( p1.handle != BOOST_INVALID_HANDLE_VALUE || p2.handle != BOOST_INVALID_HANDLE_VALUE ) return false; assert( p1.handle == BOOST_INVALID_HANDLE_VALUE && p2.handle == BOOST_INVALID_HANDLE_VALUE ); boost::throw_exception( filesystem_error( "boost::filesystem::equivalent", ph1, error1 ) ); } // at this point, both handles are known to be valid BY_HANDLE_FILE_INFORMATION info1, info2; if ( !::GetFileInformationByHandle( p1.handle, &info1 ) ) boost::throw_exception( filesystem_error( "boost::filesystem::equivalent", ph1, fs::detail::system_error_code() ) ); if ( !::GetFileInformationByHandle( p2.handle, &info2 ) ) boost::throw_exception( filesystem_error( "boost::filesystem::equivalent", ph2, fs::detail::system_error_code() ) ); // In theory, volume serial numbers are sufficient to distinguish between // devices, but in practice VSN's are sometimes duplicated, so last write // time and file size are also checked. return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && info1.nFileIndexHigh == info2.nFileIndexHigh && info1.nFileIndexLow == info2.nFileIndexLow && info1.nFileSizeHigh == info2.nFileSizeHigh && info1.nFileSizeLow == info2.nFileSizeLow && info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; # endif } BOOST_FILESYSTEM_DECL boost::intmax_t file_size( const path & ph ) { # ifdef BOOST_POSIX struct stat path_stat; if ( ::stat( ph.string().c_str(), &path_stat ) != 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::file_size", ph, fs::detail::system_error_code() ) ); if ( S_ISDIR( path_stat.st_mode ) ) boost::throw_exception( filesystem_error( "boost::filesystem::file_size", ph, "invalid: is a directory", is_directory_error ) ); return static_cast(path_stat.st_size); # else // by now, intmax_t is 64-bits on all Windows compilers WIN32_FILE_ATTRIBUTE_DATA fad; if ( !::GetFileAttributesExA( ph.string().c_str(), ::GetFileExInfoStandard, &fad ) ) boost::throw_exception( filesystem_error( "boost::filesystem::file_size", ph, fs::detail::system_error_code() ) ); if ( (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=0 ) boost::throw_exception( filesystem_error( "boost::filesystem::file_size", ph, "invalid: is a directory", is_directory_error ) ); return (static_cast(fad.nFileSizeHigh) << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow; # endif } BOOST_FILESYSTEM_DECL std::time_t last_write_time( const path & ph ) { // Works for both Windows and POSIX struct stat path_stat; if ( ::stat( ph.string().c_str(), &path_stat ) != 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::last_write_time", ph, fs::detail::system_error_code() ) ); return path_stat.st_mtime; } BOOST_FILESYSTEM_DECL void last_write_time( const path & ph, const std::time_t new_time ) { // Works for both Windows and POSIX struct stat path_stat; if ( ::stat( ph.string().c_str(), &path_stat ) != 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::last_write_time", ph, fs::detail::system_error_code() ) ); ::utimbuf buf; buf.actime = path_stat.st_atime; // utime() updates access time too:-( buf.modtime = new_time; if ( ::utime( ph.string().c_str(), &buf ) != 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::last_write_time", ph, fs::detail::system_error_code() ) ); } BOOST_FILESYSTEM_DECL bool create_directory( const path & dir_path ) { # ifdef BOOST_POSIX if ( ::mkdir( dir_path.native_directory_string().c_str(), S_IRWXU|S_IRWXG|S_IRWXO ) == 0 ) return true; if ( errno != EEXIST ) # else if ( ::CreateDirectoryA( dir_path.native_directory_string().c_str(), 0 ) ) return true; if ( ::GetLastError() != ERROR_ALREADY_EXISTS ) # endif boost::throw_exception( filesystem_error( "boost::filesystem::create_directory", dir_path, fs::detail::system_error_code() ) ); if ( !is_directory( dir_path ) ) boost::throw_exception( filesystem_error( "boost::filesystem::create_directory", dir_path, "path exists and is not a directory", not_directory_error ) ); return false; } BOOST_FILESYSTEM_DECL bool remove( const path & ph ) { if ( exists( ph ) # ifdef BOOST_POSIX || symbolic_link_exists( ph ) ) // handle dangling symbolic links { # if defined(__QNXNTO__) || (defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))) // Some Metrowerks C library versions fail on directories because of a // known Metrowerks coding error in ::remove. Workaround is to call // rmdir() or unlink() as indicated. // Same bug reported for QNX; same fix. if ( (is_directory( ph ) ? ::rmdir( ph.string().c_str() ) : ::unlink( ph.string().c_str() )) != 0 ) # else // note that the POSIX behavior for symbolic links is what we want; // the link rather than what it points to is deleted if ( std::remove( ph.string().c_str() ) != 0 ) # endif { int error = fs::detail::system_error_code(); // POSIX says "If the directory is not an empty directory, rmdir() // shall fail and set errno to EEXIST or ENOTEMPTY." // Linux uses ENOTEMPTY, Solaris uses EEXIST. if ( error == EEXIST ) error = ENOTEMPTY; boost::throw_exception( filesystem_error( "boost::filesystem::remove", ph, error ) ); } # else ) { if ( is_directory( ph ) ) { if ( !::RemoveDirectoryA( ph.string().c_str() ) ) boost::throw_exception( filesystem_error( "boost::filesystem::remove", ph, fs::detail::system_error_code() ) ); } else { if ( !::DeleteFileA( ph.string().c_str() ) ) boost::throw_exception( filesystem_error( "boost::filesystem::remove", ph, fs::detail::system_error_code() ) ); } # endif return true; } return false; } BOOST_FILESYSTEM_DECL unsigned long remove_all( const path & ph ) { return exists( ph )|| symbolic_link_exists( ph ) ? remove_all_aux( ph ) : 0; } BOOST_FILESYSTEM_DECL void rename( const path & old_path, const path & new_path ) { # ifdef BOOST_POSIX if ( exists( new_path ) // POSIX is too permissive so must check || std::rename( old_path.string().c_str(), new_path.string().c_str() ) != 0 ) # else if ( !::MoveFileA( old_path.string().c_str(), new_path.string().c_str() ) ) # endif boost::throw_exception( filesystem_error( "boost::filesystem::rename", old_path, new_path, fs::detail::system_error_code() ) ); } #ifdef BOOST_POSIX namespace detail { void throw_copy_file_error( const path & from_file_ph, const path & to_file_ph ) { boost::throw_exception( fs::filesystem_error( "boost::filesystem::copy_file", from_file_ph, to_file_ph, system_error_code() ) ); } } #endif BOOST_FILESYSTEM_DECL void copy_file( const path & from_file_ph, const path & to_file_ph ) { # ifdef BOOST_POSIX const std::size_t buf_sz = 32768; boost::scoped_array buf( new char [buf_sz] ); int infile=0, outfile=0; // init quiets compiler warning struct stat from_stat; if ( ::stat( from_file_ph.string().c_str(), &from_stat ) != 0 || (infile = ::open( from_file_ph.string().c_str(), O_RDONLY )) < 0 || (outfile = ::open( to_file_ph.string().c_str(), O_WRONLY | O_CREAT | O_EXCL, from_stat.st_mode )) < 0 ) { if ( infile >= 0 ) ::close( infile ); detail::throw_copy_file_error( from_file_ph, to_file_ph ); } ssize_t sz, sz_read=1, sz_write; while ( sz_read > 0 && (sz_read = ::read( infile, buf.get(), buf_sz )) > 0 ) { // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), // Marc Rochkind, Addison-Wesley, 2004, page 94 sz_write = 0; do { if ( (sz = ::write( outfile, buf.get(), sz_read - sz_write )) < 0 ) { sz_read = sz; // cause read loop termination break; // and error to be thrown after closes } sz_write += sz; } while ( sz_write < sz_read ); } if ( ::close( infile) < 0 ) sz_read = -1; if ( ::close( outfile) < 0 ) sz_read = -1; if ( sz_read < 0 ) detail::throw_copy_file_error( from_file_ph, to_file_ph ); # else if ( !::CopyFileA( from_file_ph.string().c_str(), to_file_ph.string().c_str(), /*fail_if_exists=*/true ) ) boost::throw_exception( fs::filesystem_error( "boost::filesystem::copy_file", from_file_ph, to_file_ph, detail::system_error_code() ) ); # endif } BOOST_FILESYSTEM_DECL path current_path() { # ifdef BOOST_POSIX for ( long path_max = 32;; path_max *=2 ) // loop 'til buffer large enough { boost::scoped_array buf( new char[static_cast(path_max)] ); if ( ::getcwd( buf.get(), static_cast(path_max) ) == 0 ) { if ( errno != ERANGE // there is a bug in some versions of the Metrowerks C lib on the Mac: wrong errno set #if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && errno != 0 #endif ) boost::throw_exception( filesystem_error( "boost::filesystem::current_path", path(), fs::detail::system_error_code() ) ); } else return path( buf.get(), native ); } BOOST_UNREACHABLE_RETURN(0) # else DWORD sz; if ( (sz = ::GetCurrentDirectoryA( 0, static_cast(0) )) == 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::current_path", "size is 0" ) ); boost::scoped_array buf( new char[sz] ); if ( ::GetCurrentDirectoryA( sz, buf.get() ) == 0 ) boost::throw_exception( filesystem_error( "boost::filesystem::current_path", path(), fs::detail::system_error_code() ) ); return path( buf.get(), native ); # endif } BOOST_FILESYSTEM_DECL const path & initial_path() { static path init_path; if ( init_path.empty() ) init_path = current_path(); return init_path; } BOOST_FILESYSTEM_DECL path system_complete( const path & ph ) { # ifdef BOOST_WINDOWS if ( ph.empty() ) return ph; char buf[MAX_PATH]; char * pfn; std::size_t len = ::GetFullPathNameA( ph.string().c_str(), sizeof(buf) , buf, &pfn ); if ( !len ) { boost::throw_exception( filesystem_error( "boost::filesystem::system_complete", ph, "size is 0" ) ); } buf[len] = '\0'; return path( buf, native ); # else return (ph.empty() || ph.is_complete()) ? ph : current_path() / ph; # endif } BOOST_FILESYSTEM_DECL path complete( const path & ph, const path & base ) { assert( base.is_complete() && (ph.is_complete() || !ph.has_root_name()) ); // precondition # ifdef BOOST_WINDOWS if (ph.empty() || ph.is_complete()) return ph; if ( !ph.has_root_name() ) return ph.has_root_directory() ? path( base.root_name(), native ) / ph : base / ph; return base / ph; # else return (ph.empty() || ph.is_complete()) ? ph : base / ph; # endif } } // namespace filesystem } // namespace boost