1 // directory_posix_windows.cpp ---------------------------------------------//
3 // Copyright © 2002 Beman Dawes
4 // Copyright © 2001 Dietmar Kühl
5 // Use, modification, and distribution is subject to the Boost Software
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
7 // at http://www.boost.org/LICENSE_1_0.txt)
9 // See library home page at http://www.boost.org/libs/filesystem
11 //----------------------------------------------------------------------------//
14 // The point of this implementation is to prove the interface. There is no
15 // claim the implementation is efficient, follows good coding practice, etc.
18 //----------------------------------------------------------------------------//
20 // define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows
21 // the library is being built (possibly exporting rather than importing code)
22 #define BOOST_FILESYSTEM_SOURCE
24 #define _FILE_OFFSET_BITS 64 // at worst, these defines may have no effect,
25 #define __USE_FILE_OFFSET64 // but that is harmless on Windows and on POSIX
26 // 64-bit systems or on 32-bit systems which don't have files larger
27 // than can be represented by a traditional POSIX/UNIX off_t type.
28 // OTOH, defining them should kick in 64-bit off_t's (and thus
29 // st_size) on 32-bit systems that provide the Large File
30 // Support (LFS) interface, such as Linux, Solaris, and IRIX.
31 // The defines are given before any headers are included to
32 // ensure that they are available to all included headers.
33 // That is required at least on Solaris, and possibly on other
36 #include <boost/filesystem/config.hpp>
37 #include <boost/filesystem/operations.hpp>
38 #include <boost/filesystem/exception.hpp>
39 #include <boost/scoped_array.hpp>
40 #include <boost/throw_exception.hpp>
41 #include <boost/detail/workaround.hpp>
43 namespace fs = boost::filesystem;
45 // BOOST_POSIX or BOOST_WINDOWS specify which API to use.
46 # if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX )
47 # if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
48 # define BOOST_WINDOWS
54 # if defined(BOOST_WINDOWS)
56 # if defined(__BORLANDC__) || defined(__MWERKS__)
57 # if defined(__BORLANDC__)
62 # include "sys/utime.h"
65 // For Windows, the xxxA form of various function names is used to avoid
66 // inadvertently getting wide forms of the functions. (The undecorated
67 // forms are actually macros, so can misfire if the user has various
68 // other macros defined. There was a bug report of this happening.)
71 # include <sys/types.h>
78 #include <sys/stat.h> // even on Windows some functions use stat()
81 #include <cstdio> // for remove, rename
84 //#include <iostream> // for debugging only; comment out when not in use
86 #ifdef BOOST_NO_STDC_NAMESPACE
87 namespace std { using ::strcmp; using ::remove; using ::rename; }
90 #include <boost/config/abi_prefix.hpp> // must be the last header
92 // helpers -----------------------------------------------------------------//
98 # define BOOST_HANDLE DIR *
99 # define BOOST_INVALID_HANDLE_VALUE 0
100 # define BOOST_SYSTEM_DIRECTORY_TYPE struct dirent
102 inline const char * find_first_file( const char * dir,
103 BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & )
104 // Returns: 0 if error, otherwise name
106 const char * dummy_first_name = ".";
107 return ( (handle = ::opendir( dir ))
108 == BOOST_INVALID_HANDLE_VALUE ) ? 0 : dummy_first_name;
111 inline void find_close( BOOST_HANDLE handle )
113 assert( handle != BOOST_INVALID_HANDLE_VALUE );
114 ::closedir( handle );
117 // warning: the only dirent member updated is d_name
118 inline int readdir_r_simulator( DIR * dirp, struct dirent * entry,
119 struct dirent ** result ) // *result set to 0 on end of directory
121 # if defined(_POSIX_THREAD_SAFE_FUNCTIONS) \
122 && defined(_SC_THREAD_SAFE_FUNCTIONS) \
123 && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0) \
124 && ( !defined(__HP_aCC) || ( defined(__HP_aCC) && defined(_REENTRANT) ) )
125 if ( ::sysconf( _SC_THREAD_SAFE_FUNCTIONS ) >= 0 )
126 { return ::readdir_r( dirp, entry, result ); }
132 if ( (p = ::readdir( dirp )) == 0 )
134 // POSIX specs require entry->d_name be large enough:
135 std::strcpy( entry->d_name, p->d_name );
140 inline const char * find_next_file( BOOST_HANDLE handle,
141 const fs::path & ph, BOOST_SYSTEM_DIRECTORY_TYPE & entry )
142 // Returns: if EOF 0, otherwise name
143 // Throws: if system reports error
145 struct dirent * result;
147 if ( (return_code = ::readdir_r_simulator( handle, &entry, &result )) != 0 )
149 boost::throw_exception(
150 fs::filesystem_error(
151 "boost::filesystem::directory_iterator::operator++",
154 return result ? entry.d_name : 0;
156 #else // BOOST_WINDOWS
158 # define BOOST_HANDLE HANDLE
159 # define BOOST_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE
160 # define BOOST_SYSTEM_DIRECTORY_TYPE WIN32_FIND_DATAA
162 inline const char * find_first_file( const char * dir,
163 BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & data )
164 // Returns: 0 if error, otherwise name
165 // Note: an empty root directory has no "." or ".." entries, so this causes
166 // a ERROR_FILE_NOT_FOUND error which we do not considered an error. Instead,
167 // the handle is set to BOOST_INVALID_HANDLE_VALUE and a non-zero is returned.
169 // use a form of search Sebastian Martel reports will work with Win98
170 std::string dirpath( dir );
171 dirpath += (dirpath.empty()
172 || (dirpath[dirpath.size()-1] != '\\'
173 && dirpath[dirpath.size()-1] != '/')) ? "\\*" : "*";
175 return ( (handle = ::FindFirstFileA( dirpath.c_str(), &data ))
176 == BOOST_INVALID_HANDLE_VALUE
177 && ::GetLastError() != ERROR_FILE_NOT_FOUND) ? 0 : data.cFileName;
180 inline void find_close( BOOST_HANDLE handle )
182 assert( handle != BOOST_INVALID_HANDLE_VALUE );
183 ::FindClose( handle );
186 inline const char * find_next_file(
187 BOOST_HANDLE handle, const fs::path & ph,
188 BOOST_SYSTEM_DIRECTORY_TYPE & data )
189 // Returns: 0 if EOF, otherwise name
190 // Throws: if system reports error
192 if ( ::FindNextFileA( handle, &data ) == 0 )
194 if ( ::GetLastError() != ERROR_NO_MORE_FILES )
196 boost::throw_exception( fs::filesystem_error(
197 "boost::filesystem::directory_iterator::operator++",
198 ph.branch_path(), fs::detail::system_error_code() ) );
200 else { return 0; } // end reached
202 return data.cFileName;
208 fs::directory_iterator end_itr;
210 bool is_empty_directory( const fs::path & dir_path )
212 return fs::directory_iterator(dir_path) == end_itr;
215 unsigned long remove_all_aux( const fs::path & ph )
217 unsigned long count = 1;
218 if ( !fs::symbolic_link_exists( ph ) // don't recurse symbolic links
219 && fs::is_directory( ph ) )
221 for ( fs::directory_iterator itr( ph );
222 itr != end_itr; ++itr )
224 count += remove_all_aux( *itr );
231 } // unnamed namespace
240 // dir_itr_imp -------------------------------------------------------------//
250 if ( handle != BOOST_INVALID_HANDLE_VALUE ) find_close( handle );
254 // dot_or_dot_dot ----------------------------------------------------------//
256 inline bool dot_or_dot_dot( const char * name )
258 # if !BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT(0x0564) )
259 return std::strcmp( name, "." ) == 0
260 || std::strcmp( name, ".." ) == 0;
262 // Borland workaround for failure of intrinsics to be placed in
263 // namespace std with certain combinations of compiler options.
264 // To ensure test coverage, the workaround is applied to all
265 // configurations, regardless of option settings.
267 && (name[1]=='\0' || (name[1]=='.' && name[2]=='\0'));
271 // directory_iterator implementation ---------------------------------------//
273 BOOST_FILESYSTEM_DECL void dir_itr_init( dir_itr_imp_ptr & m_imp,
274 const path & dir_path )
276 m_imp.reset( new dir_itr_imp );
277 BOOST_SYSTEM_DIRECTORY_TYPE scratch;
278 const char * name = 0; // initialization quiets compiler warnings
279 if ( dir_path.empty() )
280 m_imp->handle = BOOST_INVALID_HANDLE_VALUE;
283 name = find_first_file( dir_path.native_directory_string().c_str(),
284 m_imp->handle, scratch ); // sets handle
285 if ( m_imp->handle == BOOST_INVALID_HANDLE_VALUE
288 m_imp.reset(); // make end iterator
292 if ( m_imp->handle != BOOST_INVALID_HANDLE_VALUE )
294 m_imp->entry_path = dir_path;
295 // append name, except ignore "." or ".."
296 if ( !dot_or_dot_dot( name ) )
298 m_imp->entry_path.m_path_append( name, no_check );
302 m_imp->entry_path.m_path_append( "dummy", no_check );
303 dir_itr_increment( m_imp );
308 boost::throw_exception( filesystem_error(
309 "boost::filesystem::directory_iterator constructor",
310 dir_path, fs::detail::system_error_code() ) );
314 BOOST_FILESYSTEM_DECL path & dir_itr_dereference(
315 const dir_itr_imp_ptr & m_imp )
317 assert( m_imp.get() ); // fails if dereference end iterator
318 return m_imp->entry_path;
321 BOOST_FILESYSTEM_DECL void dir_itr_increment( dir_itr_imp_ptr & m_imp )
323 assert( m_imp.get() ); // fails on increment end iterator
324 assert( m_imp->handle != BOOST_INVALID_HANDLE_VALUE ); // reality check
326 BOOST_SYSTEM_DIRECTORY_TYPE scratch;
329 while ( (name = find_next_file( m_imp->handle,
330 m_imp->entry_path, scratch )) != 0 )
332 // append name, except ignore "." or ".."
333 if ( !dot_or_dot_dot( name ) )
335 m_imp->entry_path.m_replace_leaf( name );
339 m_imp.reset(); // make base() the end iterator
341 } // namespace detail
343 // free functions ----------------------------------------------------------//
345 BOOST_FILESYSTEM_DECL bool exists( const path & ph )
348 struct stat path_stat;
349 if(::stat( ph.string().c_str(), &path_stat ) != 0)
351 if((errno == ENOENT) || (errno == ENOTDIR))
352 return false; // stat failed because the path does not exist
353 // for any other error we assume the file does exist and fall through,
354 // this may not be the best policy though... (JM 20040330)
358 if(::GetFileAttributesA( ph.string().c_str() ) == 0xFFFFFFFF)
360 UINT err = ::GetLastError();
361 if((err == ERROR_FILE_NOT_FOUND)
362 || (err == ERROR_INVALID_PARAMETER)
363 || (err == ERROR_NOT_READY)
364 || (err == ERROR_PATH_NOT_FOUND)
365 || (err == ERROR_INVALID_NAME)
366 || (err == ERROR_BAD_NETPATH ))
367 return false; // GetFileAttributes failed because the path does not exist
368 // for any other error we assume the file does exist and fall through,
369 // this may not be the best policy though... (JM 20040330)
376 BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
379 struct stat lcl_stat;
380 return sizeof( lcl_stat.st_size ) > 4;
386 // suggested by Walter Landry
387 BOOST_FILESYSTEM_DECL bool symbolic_link_exists( const path & ph )
390 struct stat path_stat;
391 return ::lstat( ph.native_file_string().c_str(), &path_stat ) == 0
392 && S_ISLNK( path_stat.st_mode );
394 return false; // Windows has no O/S concept of symbolic links
395 // (.lnk files are an application feature, not
396 // a Windows operating system feature)
400 BOOST_FILESYSTEM_DECL bool is_directory( const path & ph )
403 struct stat path_stat;
404 if ( ::stat( ph.native_directory_string().c_str(), &path_stat ) != 0 )
405 boost::throw_exception( filesystem_error(
406 "boost::filesystem::is_directory",
407 ph, fs::detail::system_error_code() ) );
408 return S_ISDIR( path_stat.st_mode );
410 DWORD attributes = ::GetFileAttributesA( ph.native_directory_string().c_str() );
411 if ( attributes == 0xFFFFFFFF )
412 boost::throw_exception( filesystem_error(
413 "boost::filesystem::is_directory",
414 ph, fs::detail::system_error_code() ) );
415 return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
419 BOOST_FILESYSTEM_DECL bool _is_empty( const path & ph )
422 struct stat path_stat;
423 if ( ::stat( ph.string().c_str(), &path_stat ) != 0 )
424 boost::throw_exception( filesystem_error(
425 "boost::filesystem::is_empty",
426 ph, fs::detail::system_error_code() ) );
428 return S_ISDIR( path_stat.st_mode )
429 ? is_empty_directory( ph )
430 : path_stat.st_size == 0;
432 WIN32_FILE_ATTRIBUTE_DATA fad;
433 if ( !::GetFileAttributesExA( ph.string().c_str(),
434 ::GetFileExInfoStandard, &fad ) )
435 boost::throw_exception( filesystem_error(
436 "boost::filesystem::is_empty",
437 ph, fs::detail::system_error_code() ) );
439 return ( fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
440 ? is_empty_directory( ph )
441 :( !fad.nFileSizeHigh && !fad.nFileSizeLow );
445 # ifdef BOOST_WINDOWS
446 // Thanks to Jeremy Maitin-Shepard for much help and for permission to
447 // base the implementation on portions of his file-equivalence-win32.cpp
448 // experimental code.
449 struct handle_wrapper
452 handle_wrapper( BOOST_HANDLE h )
456 if ( handle != BOOST_INVALID_HANDLE_VALUE )
457 ::CloseHandle(handle);
462 BOOST_FILESYSTEM_DECL bool equivalent( const path & ph1, const path & ph2 )
466 int s1_result = ::stat( ph1.string().c_str(), &s1 );
467 // save error code in case we have to throw
468 int error1 = (s1_result != 0 ? fs::detail::system_error_code() : 0);
470 int s2_result = ::stat( ph2.string().c_str(), &s2 );
474 if ( s1_result == 0 || s2_result == 0 ) return false;
475 assert( s1_result != 0 && s2_result != 0 );
476 boost::throw_exception( filesystem_error(
477 "boost::filesystem::equivalent",
480 // at this point, both stats are known to be valid
481 return s1.st_dev == s2.st_dev
482 && s1.st_ino == s2.st_ino
483 // According to the POSIX stat specs, "The st_ino and st_dev fields
484 // taken together uniquely identify the file within the system."
485 // Just to be sure, size and mod time are also checked.
486 && s1.st_size == s2.st_size
487 && s1.st_mtime == s2.st_mtime;
489 // Note well: Physical location on external media is part of the
490 // equivalence criteria. If there are no open handles, physical location
491 // can change due to defragmentation or other relocations. Thus handles
492 // must be held open until location information for both paths has
496 ph1.string().c_str(),
498 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
501 FILE_FLAG_BACKUP_SEMANTICS,
503 int error1; // save error code in case we have to throw
504 if ( p1.handle == BOOST_INVALID_HANDLE_VALUE )
505 error1 = fs::detail::system_error_code();
508 ph2.string().c_str(),
510 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
513 FILE_FLAG_BACKUP_SEMANTICS,
515 if ( p1.handle == BOOST_INVALID_HANDLE_VALUE
516 || p2.handle == BOOST_INVALID_HANDLE_VALUE )
518 if ( p1.handle != BOOST_INVALID_HANDLE_VALUE
519 || p2.handle != BOOST_INVALID_HANDLE_VALUE ) return false;
520 assert( p1.handle == BOOST_INVALID_HANDLE_VALUE
521 && p2.handle == BOOST_INVALID_HANDLE_VALUE );
522 boost::throw_exception( filesystem_error(
523 "boost::filesystem::equivalent",
526 // at this point, both handles are known to be valid
527 BY_HANDLE_FILE_INFORMATION info1, info2;
528 if ( !::GetFileInformationByHandle( p1.handle, &info1 ) )
529 boost::throw_exception( filesystem_error(
530 "boost::filesystem::equivalent",
531 ph1, fs::detail::system_error_code() ) );
532 if ( !::GetFileInformationByHandle( p2.handle, &info2 ) )
533 boost::throw_exception( filesystem_error(
534 "boost::filesystem::equivalent",
535 ph2, fs::detail::system_error_code() ) );
536 // In theory, volume serial numbers are sufficient to distinguish between
537 // devices, but in practice VSN's are sometimes duplicated, so last write
538 // time and file size are also checked.
539 return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
540 && info1.nFileIndexHigh == info2.nFileIndexHigh
541 && info1.nFileIndexLow == info2.nFileIndexLow
542 && info1.nFileSizeHigh == info2.nFileSizeHigh
543 && info1.nFileSizeLow == info2.nFileSizeLow
544 && info1.ftLastWriteTime.dwLowDateTime
545 == info2.ftLastWriteTime.dwLowDateTime
546 && info1.ftLastWriteTime.dwHighDateTime
547 == info2.ftLastWriteTime.dwHighDateTime;
552 BOOST_FILESYSTEM_DECL boost::intmax_t file_size( const path & ph )
555 struct stat path_stat;
556 if ( ::stat( ph.string().c_str(), &path_stat ) != 0 )
557 boost::throw_exception( filesystem_error(
558 "boost::filesystem::file_size",
559 ph, fs::detail::system_error_code() ) );
560 if ( S_ISDIR( path_stat.st_mode ) )
561 boost::throw_exception( filesystem_error(
562 "boost::filesystem::file_size",
563 ph, "invalid: is a directory",
564 is_directory_error ) );
565 return static_cast<boost::intmax_t>(path_stat.st_size);
567 // by now, intmax_t is 64-bits on all Windows compilers
568 WIN32_FILE_ATTRIBUTE_DATA fad;
569 if ( !::GetFileAttributesExA( ph.string().c_str(),
570 ::GetFileExInfoStandard, &fad ) )
571 boost::throw_exception( filesystem_error(
572 "boost::filesystem::file_size",
573 ph, fs::detail::system_error_code() ) );
574 if ( (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=0 )
575 boost::throw_exception( filesystem_error(
576 "boost::filesystem::file_size",
577 ph, "invalid: is a directory",
578 is_directory_error ) );
579 return (static_cast<boost::intmax_t>(fad.nFileSizeHigh)
580 << (sizeof(fad.nFileSizeLow)*8))
585 BOOST_FILESYSTEM_DECL std::time_t last_write_time( const path & ph )
587 // Works for both Windows and POSIX
588 struct stat path_stat;
589 if ( ::stat( ph.string().c_str(), &path_stat ) != 0 )
590 boost::throw_exception( filesystem_error(
591 "boost::filesystem::last_write_time",
592 ph, fs::detail::system_error_code() ) );
593 return path_stat.st_mtime;
596 BOOST_FILESYSTEM_DECL void last_write_time( const path & ph, const std::time_t new_time )
598 // Works for both Windows and POSIX
599 struct stat path_stat;
600 if ( ::stat( ph.string().c_str(), &path_stat ) != 0 )
601 boost::throw_exception( filesystem_error(
602 "boost::filesystem::last_write_time",
603 ph, fs::detail::system_error_code() ) );
605 buf.actime = path_stat.st_atime; // utime() updates access time too:-(
606 buf.modtime = new_time;
607 if ( ::utime( ph.string().c_str(), &buf ) != 0 )
608 boost::throw_exception( filesystem_error(
609 "boost::filesystem::last_write_time",
610 ph, fs::detail::system_error_code() ) );
613 BOOST_FILESYSTEM_DECL bool create_directory( const path & dir_path )
616 if ( ::mkdir( dir_path.native_directory_string().c_str(),
617 S_IRWXU|S_IRWXG|S_IRWXO ) == 0 ) return true;
618 if ( errno != EEXIST )
620 if ( ::CreateDirectoryA( dir_path.native_directory_string().c_str(), 0 ) )
622 if ( ::GetLastError() != ERROR_ALREADY_EXISTS )
624 boost::throw_exception( filesystem_error(
625 "boost::filesystem::create_directory",
626 dir_path, fs::detail::system_error_code() ) );
627 if ( !is_directory( dir_path ) )
628 boost::throw_exception( filesystem_error(
629 "boost::filesystem::create_directory",
630 dir_path, "path exists and is not a directory", not_directory_error ) );
634 BOOST_FILESYSTEM_DECL bool remove( const path & ph )
638 || symbolic_link_exists( ph ) ) // handle dangling symbolic links
640 # if defined(__QNXNTO__) || (defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)))
641 // Some Metrowerks C library versions fail on directories because of a
642 // known Metrowerks coding error in ::remove. Workaround is to call
643 // rmdir() or unlink() as indicated.
644 // Same bug reported for QNX; same fix.
645 if ( (is_directory( ph )
646 ? ::rmdir( ph.string().c_str() )
647 : ::unlink( ph.string().c_str() )) != 0 )
649 // note that the POSIX behavior for symbolic links is what we want;
650 // the link rather than what it points to is deleted
651 if ( std::remove( ph.string().c_str() ) != 0 )
655 int error = fs::detail::system_error_code();
656 // POSIX says "If the directory is not an empty directory, rmdir()
657 // shall fail and set errno to EEXIST or ENOTEMPTY."
658 // Linux uses ENOTEMPTY, Solaris uses EEXIST.
659 if ( error == EEXIST ) error = ENOTEMPTY;
660 boost::throw_exception( filesystem_error(
661 "boost::filesystem::remove", ph, error ) );
666 if ( is_directory( ph ) )
668 if ( !::RemoveDirectoryA( ph.string().c_str() ) )
669 boost::throw_exception( filesystem_error(
670 "boost::filesystem::remove",
671 ph, fs::detail::system_error_code() ) );
675 if ( !::DeleteFileA( ph.string().c_str() ) )
676 boost::throw_exception( filesystem_error(
677 "boost::filesystem::remove",
678 ph, fs::detail::system_error_code() ) );
686 BOOST_FILESYSTEM_DECL unsigned long remove_all( const path & ph )
688 return exists( ph )|| symbolic_link_exists( ph )
689 ? remove_all_aux( ph ) : 0;
692 BOOST_FILESYSTEM_DECL void rename( const path & old_path,
693 const path & new_path )
696 if ( exists( new_path ) // POSIX is too permissive so must check
697 || std::rename( old_path.string().c_str(), new_path.string().c_str() ) != 0 )
699 if ( !::MoveFileA( old_path.string().c_str(), new_path.string().c_str() ) )
701 boost::throw_exception( filesystem_error(
702 "boost::filesystem::rename",
703 old_path, new_path, fs::detail::system_error_code() ) );
709 void throw_copy_file_error( const path & from_file_ph,
710 const path & to_file_ph )
712 boost::throw_exception( fs::filesystem_error(
713 "boost::filesystem::copy_file",
714 from_file_ph, to_file_ph, system_error_code() ) );
719 BOOST_FILESYSTEM_DECL void copy_file( const path & from_file_ph,
720 const path & to_file_ph )
723 const std::size_t buf_sz = 32768;
724 boost::scoped_array<char> buf( new char [buf_sz] );
725 int infile=0, outfile=0; // init quiets compiler warning
726 struct stat from_stat;
728 if ( ::stat( from_file_ph.string().c_str(), &from_stat ) != 0
729 || (infile = ::open( from_file_ph.string().c_str(),
731 || (outfile = ::open( to_file_ph.string().c_str(),
732 O_WRONLY | O_CREAT | O_EXCL,
733 from_stat.st_mode )) < 0 )
735 if ( infile >= 0 ) ::close( infile );
736 detail::throw_copy_file_error( from_file_ph, to_file_ph );
739 ssize_t sz, sz_read=1, sz_write;
741 && (sz_read = ::read( infile, buf.get(), buf_sz )) > 0 )
743 // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
744 // Marc Rochkind, Addison-Wesley, 2004, page 94
748 if ( (sz = ::write( outfile, buf.get(), sz_read - sz_write )) < 0 )
750 sz_read = sz; // cause read loop termination
751 break; // and error to be thrown after closes
754 } while ( sz_write < sz_read );
757 if ( ::close( infile) < 0 ) sz_read = -1;
758 if ( ::close( outfile) < 0 ) sz_read = -1;
761 detail::throw_copy_file_error( from_file_ph, to_file_ph );
763 if ( !::CopyFileA( from_file_ph.string().c_str(),
764 to_file_ph.string().c_str(), /*fail_if_exists=*/true ) )
765 boost::throw_exception( fs::filesystem_error(
766 "boost::filesystem::copy_file",
767 from_file_ph, to_file_ph, detail::system_error_code() ) );
771 BOOST_FILESYSTEM_DECL path current_path()
774 for ( long path_max = 32;; path_max *=2 ) // loop 'til buffer large enough
776 boost::scoped_array<char>
777 buf( new char[static_cast<std::size_t>(path_max)] );
778 if ( ::getcwd( buf.get(), static_cast<std::size_t>(path_max) ) == 0 )
781 // there is a bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
782 #if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
786 boost::throw_exception(
787 filesystem_error( "boost::filesystem::current_path", path(),
788 fs::detail::system_error_code() ) );
790 else return path( buf.get(), native );
792 BOOST_UNREACHABLE_RETURN(0)
795 if ( (sz = ::GetCurrentDirectoryA( 0, static_cast<char*>(0) )) == 0 )
796 boost::throw_exception(
797 filesystem_error( "boost::filesystem::current_path",
799 boost::scoped_array<char> buf( new char[sz] );
800 if ( ::GetCurrentDirectoryA( sz, buf.get() ) == 0 )
801 boost::throw_exception(
802 filesystem_error( "boost::filesystem::current_path", path(),
803 fs::detail::system_error_code() ) );
804 return path( buf.get(), native );
808 BOOST_FILESYSTEM_DECL const path & initial_path()
810 static path init_path;
811 if ( init_path.empty() ) init_path = current_path();
815 BOOST_FILESYSTEM_DECL path system_complete( const path & ph )
817 # ifdef BOOST_WINDOWS
818 if ( ph.empty() ) return ph;
821 std::size_t len = ::GetFullPathNameA( ph.string().c_str(),
822 sizeof(buf) , buf, &pfn );
824 { boost::throw_exception(
825 filesystem_error( "boost::filesystem::system_complete",
826 ph, "size is 0" ) ); }
828 return path( buf, native );
830 return (ph.empty() || ph.is_complete())
831 ? ph : current_path() / ph;
835 BOOST_FILESYSTEM_DECL path complete( const path & ph, const path & base )
837 assert( base.is_complete()
838 && (ph.is_complete() || !ph.has_root_name()) ); // precondition
839 # ifdef BOOST_WINDOWS
840 if (ph.empty() || ph.is_complete()) return ph;
841 if ( !ph.has_root_name() )
842 return ph.has_root_directory()
843 ? path( base.root_name(), native ) / ph
847 return (ph.empty() || ph.is_complete()) ? ph : base / ph;
850 } // namespace filesystem