Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/filesystem/src/operations_posix_windows.cpp @ 20

Last change on this file since 20 was 12, checked in by landauf, 18 years ago

added boost

File size: 29.4 KB
Line 
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
43namespace 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
87namespace 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
94namespace
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
233namespace 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
Note: See TracBrowser for help on using the repository browser.