]> git.lyx.org Git - lyx.git/blob - boost/libs/filesystem/src/operations_posix_windows.cpp
Remove the SConscript files in boost.
[lyx.git] / boost / libs / filesystem / src / operations_posix_windows.cpp
1 //  directory_posix_windows.cpp  ---------------------------------------------//
2
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)
8
9 //  See library home page at http://www.boost.org/libs/filesystem
10
11 //----------------------------------------------------------------------------//
12
13
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.
16
17
18 //----------------------------------------------------------------------------// 
19
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 
23
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
34       // systems as well.
35
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>
42
43 namespace fs = boost::filesystem;
44
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
49 #   else
50 #     define BOOST_POSIX
51 #   endif
52 # endif
53
54 # if defined(BOOST_WINDOWS)
55 #   include "windows.h"
56 #   if defined(__BORLANDC__) || defined(__MWERKS__)
57 #     if defined(__BORLANDC__)
58         using std::time_t;
59 #     endif
60 #     include "utime.h"
61 #   else
62 #     include "sys/utime.h"
63 #   endif
64
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.)
69
70 # else // BOOST_POSIX
71 #   include <sys/types.h>
72 #   include "dirent.h"
73 #   include "unistd.h"
74 #   include "fcntl.h"
75 #   include "utime.h"
76 # endif
77
78 #include <sys/stat.h>  // even on Windows some functions use stat()
79 #include <string>
80 #include <cstring>
81 #include <cstdio>      // for remove, rename
82 #include <cerrno>
83 #include <cassert>
84 //#include <iostream>    // for debugging only; comment out when not in use
85
86 #ifdef BOOST_NO_STDC_NAMESPACE
87 namespace std { using ::strcmp; using ::remove; using ::rename; }
88 #endif
89
90 #include <boost/config/abi_prefix.hpp> // must be the last header
91
92 //  helpers  -----------------------------------------------------------------//
93
94 namespace
95 {
96 #ifdef BOOST_POSIX
97
98 # define BOOST_HANDLE DIR *
99 # define BOOST_INVALID_HANDLE_VALUE 0
100 # define BOOST_SYSTEM_DIRECTORY_TYPE struct dirent
101
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
105   {
106     const char * dummy_first_name = ".";
107     return ( (handle = ::opendir( dir ))
108       == BOOST_INVALID_HANDLE_VALUE ) ? 0 : dummy_first_name;
109   }  
110
111   inline void find_close( BOOST_HANDLE handle )
112   {
113     assert( handle != BOOST_INVALID_HANDLE_VALUE );
114     ::closedir( handle );
115   }
116
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
120     {
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 ); }
127 #     endif
128
129       struct dirent * p;
130       errno = 0;
131       *result = 0;
132       if ( (p = ::readdir( dirp )) == 0 )
133         return errno;
134       // POSIX specs require entry->d_name be large enough:
135       std::strcpy( entry->d_name, p->d_name );
136       *result = entry;
137       return 0;
138     }
139
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
144   {
145     struct dirent * result;
146     int return_code;
147     if ( (return_code = ::readdir_r_simulator( handle, &entry, &result )) != 0 )
148     {
149       boost::throw_exception(
150         fs::filesystem_error(
151           "boost::filesystem::directory_iterator::operator++",
152           ph, return_code ) );
153     }
154     return result ? entry.d_name : 0;
155   }
156 #else // BOOST_WINDOWS
157
158 # define BOOST_HANDLE HANDLE
159 # define BOOST_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE
160 # define BOOST_SYSTEM_DIRECTORY_TYPE WIN32_FIND_DATAA
161
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.
168   {
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] != '/')) ? "\\*" : "*";
174
175     return ( (handle = ::FindFirstFileA( dirpath.c_str(), &data ))
176       == BOOST_INVALID_HANDLE_VALUE
177       && ::GetLastError() != ERROR_FILE_NOT_FOUND) ? 0 : data.cFileName;
178   }  
179
180   inline void find_close( BOOST_HANDLE handle )
181   {
182     assert( handle != BOOST_INVALID_HANDLE_VALUE );
183     ::FindClose( handle );
184   }
185
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
191   {
192     if ( ::FindNextFileA( handle, &data ) == 0 )
193     {
194       if ( ::GetLastError() != ERROR_NO_MORE_FILES )
195       {
196         boost::throw_exception( fs::filesystem_error(
197           "boost::filesystem::directory_iterator::operator++",
198           ph.branch_path(), fs::detail::system_error_code() ) );
199       }
200       else { return 0; } // end reached
201      }
202     return data.cFileName;
203   }
204
205 #endif
206
207   
208   fs::directory_iterator end_itr;
209
210   bool is_empty_directory( const fs::path & dir_path )
211   {
212     return fs::directory_iterator(dir_path) == end_itr;
213   }
214
215   unsigned long remove_all_aux( const fs::path & ph )
216   {
217     unsigned long count = 1;
218     if ( !fs::symbolic_link_exists( ph ) // don't recurse symbolic links
219       && fs::is_directory( ph ) )
220     {
221       for ( fs::directory_iterator itr( ph );
222             itr != end_itr; ++itr )
223       {
224         count += remove_all_aux( *itr );
225       }
226     }
227     fs::remove( ph );
228     return count;
229   }
230
231 } // unnamed namespace
232
233 namespace boost
234 {
235   namespace filesystem
236   {
237     namespace detail
238     {
239
240 //  dir_itr_imp  -------------------------------------------------------------// 
241
242       class dir_itr_imp
243       {
244       public:
245         path              entry_path;
246         BOOST_HANDLE      handle;
247
248         ~dir_itr_imp()
249         {
250           if ( handle != BOOST_INVALID_HANDLE_VALUE ) find_close( handle );
251         }
252       };
253
254 //  dot_or_dot_dot  ----------------------------------------------------------//
255
256       inline bool dot_or_dot_dot( const char * name )
257       {
258 # if !BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT(0x0564) )
259         return std::strcmp( name, "." ) == 0
260             || std::strcmp( name, ".." ) == 0;
261 # else
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.
266         return name[0]=='.'
267           && (name[1]=='\0' || (name[1]=='.' && name[2]=='\0'));
268 # endif
269       }
270
271 //  directory_iterator implementation  ---------------------------------------//
272
273       BOOST_FILESYSTEM_DECL void dir_itr_init( dir_itr_imp_ptr & m_imp,
274                                                const path & dir_path )
275       {
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;
281         else
282         {
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
286             && name ) // eof
287           {
288             m_imp.reset(); // make end iterator
289             return;
290           }
291         }
292         if ( m_imp->handle != BOOST_INVALID_HANDLE_VALUE )
293         {
294           m_imp->entry_path = dir_path;
295           // append name, except ignore "." or ".."
296           if ( !dot_or_dot_dot( name ) )
297           { 
298             m_imp->entry_path.m_path_append( name, no_check );
299           }
300           else
301           {
302             m_imp->entry_path.m_path_append( "dummy", no_check );
303             dir_itr_increment( m_imp );
304           }
305         }
306         else
307         {
308           boost::throw_exception( filesystem_error(  
309             "boost::filesystem::directory_iterator constructor",
310             dir_path, fs::detail::system_error_code() ) );
311         }  
312       }
313
314       BOOST_FILESYSTEM_DECL path & dir_itr_dereference(
315         const dir_itr_imp_ptr & m_imp )
316       {
317         assert( m_imp.get() ); // fails if dereference end iterator
318         return m_imp->entry_path;
319       }
320
321       BOOST_FILESYSTEM_DECL void dir_itr_increment( dir_itr_imp_ptr & m_imp )
322       {
323         assert( m_imp.get() ); // fails on increment end iterator
324         assert( m_imp->handle != BOOST_INVALID_HANDLE_VALUE ); // reality check
325
326         BOOST_SYSTEM_DIRECTORY_TYPE scratch;
327         const char * name;
328
329         while ( (name = find_next_file( m_imp->handle,
330           m_imp->entry_path, scratch )) != 0 )
331         {
332           // append name, except ignore "." or ".."
333           if ( !dot_or_dot_dot( name ) )
334           {
335             m_imp->entry_path.m_replace_leaf( name );
336             return;
337           }
338         }
339         m_imp.reset(); // make base() the end iterator
340       }
341     } // namespace detail
342
343 //  free functions  ----------------------------------------------------------//
344
345     BOOST_FILESYSTEM_DECL bool exists( const path & ph )
346     {
347 #   ifdef BOOST_POSIX
348       struct stat path_stat;
349       if(::stat( ph.string().c_str(), &path_stat ) != 0)
350       {
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)
355       }
356       return true;
357 #   else
358       if(::GetFileAttributesA( ph.string().c_str() ) == 0xFFFFFFFF)
359       {
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)
370          return true;
371       }
372       return true;
373 #   endif
374     }
375
376     BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
377     {
378 #   ifdef BOOST_POSIX
379       struct stat lcl_stat;
380       return sizeof( lcl_stat.st_size ) > 4;
381 #   else
382       return true;
383 #   endif
384     }
385
386     // suggested by Walter Landry
387     BOOST_FILESYSTEM_DECL bool symbolic_link_exists( const path & ph )
388     {
389 #   ifdef BOOST_POSIX
390       struct stat path_stat;
391       return ::lstat( ph.native_file_string().c_str(), &path_stat ) == 0
392         && S_ISLNK( path_stat.st_mode );
393 #   else
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)
397 #   endif
398     }
399
400     BOOST_FILESYSTEM_DECL bool is_directory( const path & ph )
401     {
402 #   ifdef BOOST_POSIX
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 );
409 #   else
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;
416 #   endif
417     }
418
419     BOOST_FILESYSTEM_DECL bool _is_empty( const path & ph )
420     {
421 #   ifdef BOOST_POSIX
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() ) );
427       
428       return S_ISDIR( path_stat.st_mode )
429         ? is_empty_directory( ph )
430         : path_stat.st_size == 0;
431 #   else
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() ) );
438       
439       return ( fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
440         ? is_empty_directory( ph )
441         :( !fad.nFileSizeHigh && !fad.nFileSizeLow );
442 #   endif
443     }
444
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
450     {
451       BOOST_HANDLE handle;
452       handle_wrapper( BOOST_HANDLE h )
453         : handle(h) {}
454       ~handle_wrapper()
455       {
456         if ( handle != BOOST_INVALID_HANDLE_VALUE )
457           ::CloseHandle(handle);
458       }
459     };
460 # endif
461
462     BOOST_FILESYSTEM_DECL bool equivalent( const path & ph1, const path & ph2 )
463     {
464 #   ifdef BOOST_POSIX
465       struct stat s1;
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);
469       struct stat s2;
470       int s2_result = ::stat( ph2.string().c_str(), &s2 );
471       if ( s1_result != 0
472         || s2_result != 0 )
473       {
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",
478           ph1, error1 ) );
479       }
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;
488 #   else
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
493       // been retrieved.
494       handle_wrapper p1(
495         ::CreateFileA(
496             ph1.string().c_str(),
497             0,
498             FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
499             0,
500             OPEN_EXISTING,
501             FILE_FLAG_BACKUP_SEMANTICS,
502             0 ) );
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();
506       handle_wrapper p2(
507         ::CreateFileA(
508             ph2.string().c_str(),
509             0,
510             FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
511             0,
512             OPEN_EXISTING,
513             FILE_FLAG_BACKUP_SEMANTICS,
514             0 ) );
515       if ( p1.handle == BOOST_INVALID_HANDLE_VALUE
516         || p2.handle == BOOST_INVALID_HANDLE_VALUE )
517       {
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",
524           ph1, error1 ) );
525       }
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;
548 #   endif
549     }
550
551
552     BOOST_FILESYSTEM_DECL boost::intmax_t file_size( const path & ph )
553     {
554 #   ifdef BOOST_POSIX
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);
566 #   else
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))
581         + fad.nFileSizeLow;
582 #   endif
583     }
584
585     BOOST_FILESYSTEM_DECL std::time_t last_write_time( const path & ph )
586     {
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;
594     }
595
596     BOOST_FILESYSTEM_DECL void last_write_time( const path & ph, const std::time_t new_time )
597     {
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() ) );
604       ::utimbuf buf;
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() ) );
611     }
612
613     BOOST_FILESYSTEM_DECL bool create_directory( const path & dir_path )
614     {
615 #   ifdef BOOST_POSIX
616       if ( ::mkdir( dir_path.native_directory_string().c_str(),
617         S_IRWXU|S_IRWXG|S_IRWXO ) == 0 ) return true;
618       if ( errno != EEXIST ) 
619 #   else
620       if ( ::CreateDirectoryA( dir_path.native_directory_string().c_str(), 0 ) )
621         return true;
622       if ( ::GetLastError() != ERROR_ALREADY_EXISTS )
623 #   endif
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 ) );
631       return false;
632     }
633
634     BOOST_FILESYSTEM_DECL bool remove( const path & ph )
635     {
636       if ( exists( ph )
637 #   ifdef BOOST_POSIX
638         || symbolic_link_exists( ph ) ) // handle dangling symbolic links
639       {
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 )
648 #     else
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 )
652 #     endif
653
654         {
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 ) );
662         }
663 #   else
664       )
665       {
666         if ( is_directory( ph ) )
667         {
668           if ( !::RemoveDirectoryA( ph.string().c_str() ) )
669             boost::throw_exception( filesystem_error(
670               "boost::filesystem::remove",
671               ph, fs::detail::system_error_code() ) );
672         }
673         else
674         {
675           if ( !::DeleteFileA( ph.string().c_str() ) )
676             boost::throw_exception( filesystem_error(
677               "boost::filesystem::remove",
678               ph, fs::detail::system_error_code() ) );
679         }
680 #   endif
681         return true;
682       }
683       return false;
684     }
685
686     BOOST_FILESYSTEM_DECL unsigned long remove_all( const path & ph )
687     {
688       return exists( ph )|| symbolic_link_exists( ph )
689         ? remove_all_aux( ph ) : 0;
690     }
691
692     BOOST_FILESYSTEM_DECL void rename( const path & old_path,
693                  const path & new_path )
694     {
695 #   ifdef BOOST_POSIX
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 )
698 #   else
699       if ( !::MoveFileA( old_path.string().c_str(), new_path.string().c_str() ) )
700 #   endif
701         boost::throw_exception( filesystem_error(
702           "boost::filesystem::rename",
703           old_path, new_path, fs::detail::system_error_code() ) );
704     }
705
706 #ifdef BOOST_POSIX
707     namespace detail
708     {
709       void throw_copy_file_error( const path & from_file_ph,
710                     const path & to_file_ph )
711       {
712         boost::throw_exception( fs::filesystem_error(
713           "boost::filesystem::copy_file",
714           from_file_ph, to_file_ph, system_error_code() ) );
715       }
716     }
717 #endif
718
719     BOOST_FILESYSTEM_DECL void copy_file( const path & from_file_ph,
720                     const path & to_file_ph )
721     {
722 #   ifdef BOOST_POSIX
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;
727
728       if ( ::stat( from_file_ph.string().c_str(), &from_stat ) != 0
729         || (infile = ::open( from_file_ph.string().c_str(),
730                              O_RDONLY )) < 0
731         || (outfile = ::open( to_file_ph.string().c_str(),
732                               O_WRONLY | O_CREAT | O_EXCL,
733                               from_stat.st_mode )) < 0 )
734       {
735         if ( infile >= 0 ) ::close( infile );
736         detail::throw_copy_file_error( from_file_ph, to_file_ph );
737       }
738
739       ssize_t sz, sz_read=1, sz_write;
740       while ( sz_read > 0
741         && (sz_read = ::read( infile, buf.get(), buf_sz )) > 0 )
742       {
743         // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
744         // Marc Rochkind, Addison-Wesley, 2004, page 94
745         sz_write = 0;
746         do
747         {
748           if ( (sz = ::write( outfile, buf.get(), sz_read - sz_write )) < 0 )
749           { 
750             sz_read = sz; // cause read loop termination
751             break;        //  and error to be thrown after closes
752           }
753           sz_write += sz;
754         } while ( sz_write < sz_read );
755       }
756
757       if ( ::close( infile) < 0 ) sz_read = -1;
758       if ( ::close( outfile) < 0 ) sz_read = -1;
759
760       if ( sz_read < 0 )
761         detail::throw_copy_file_error( from_file_ph, to_file_ph );
762 #   else
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() ) );
768 #   endif
769     }
770
771     BOOST_FILESYSTEM_DECL path current_path()
772     {
773 #   ifdef BOOST_POSIX
774       for ( long path_max = 32;; path_max *=2 ) // loop 'til buffer large enough
775       {
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 )
779         {
780           if ( errno != ERANGE
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__))
783             && errno != 0
784 #endif
785             )
786             boost::throw_exception(
787               filesystem_error( "boost::filesystem::current_path", path(),
788                 fs::detail::system_error_code() ) );
789         }
790         else return path( buf.get(), native );
791       }
792       BOOST_UNREACHABLE_RETURN(0)
793 #   else
794       DWORD sz;
795       if ( (sz = ::GetCurrentDirectoryA( 0, static_cast<char*>(0) )) == 0 )
796         boost::throw_exception(
797           filesystem_error( "boost::filesystem::current_path",
798             "size is 0" ) );
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 );
805 #   endif
806     }
807
808     BOOST_FILESYSTEM_DECL const path & initial_path()
809     {
810       static path init_path;
811       if ( init_path.empty() ) init_path = current_path();
812       return init_path;
813     }
814
815     BOOST_FILESYSTEM_DECL path system_complete( const path & ph )
816     {
817 #   ifdef BOOST_WINDOWS
818       if ( ph.empty() ) return ph;
819       char buf[MAX_PATH];
820       char * pfn;
821       std::size_t len = ::GetFullPathNameA( ph.string().c_str(),
822                                             sizeof(buf) , buf, &pfn );
823       if ( !len )
824         { boost::throw_exception(
825             filesystem_error( "boost::filesystem::system_complete",
826               ph, "size is 0" ) ); }
827       buf[len] = '\0';
828       return path( buf, native );
829 #   else
830       return (ph.empty() || ph.is_complete())
831         ? ph : current_path() / ph;
832 #   endif
833     }
834     
835     BOOST_FILESYSTEM_DECL path complete( const path & ph, const path & base )
836     {
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
844           : base / ph;
845       return base / ph;
846 #   else
847       return (ph.empty() || ph.is_complete()) ? ph : base / ph;
848 #   endif
849     }
850   } // namespace filesystem
851 } // namespace boost
852