diff options
author | Remko Tronçon <git@el-tramo.be> | 2009-06-01 08:48:42 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2009-06-01 09:24:28 (GMT) |
commit | 2812bddd81f8a1b804c7460f4e14cd0aa393d129 (patch) | |
tree | d46294f35150c4f0f43deaf2d31fceaf945ae715 /3rdParty/Boost/libs/filesystem/src/operations.cpp | |
download | swift-2812bddd81f8a1b804c7460f4e14cd0aa393d129.zip swift-2812bddd81f8a1b804c7460f4e14cd0aa393d129.tar.bz2 |
Import.
Diffstat (limited to '3rdParty/Boost/libs/filesystem/src/operations.cpp')
-rw-r--r-- | 3rdParty/Boost/libs/filesystem/src/operations.cpp | 1367 |
1 files changed, 1367 insertions, 0 deletions
diff --git a/3rdParty/Boost/libs/filesystem/src/operations.cpp b/3rdParty/Boost/libs/filesystem/src/operations.cpp new file mode 100644 index 0000000..0c74504 --- /dev/null +++ b/3rdParty/Boost/libs/filesystem/src/operations.cpp @@ -0,0 +1,1367 @@ +// operations.cpp ----------------------------------------------------------// + +// Copyright 2002-2005 Beman Dawes +// Copyright 2001 Dietmar Kuehl +// 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 + +//----------------------------------------------------------------------------// + +// define BOOST_FILESYSTEM_SOURCE so that <boost/filesystem/config.hpp> knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_FILESYSTEM_SOURCE + +#define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r() needs this + +// enable the XPG-compliant version of readdir_r() on AIX +#if defined(_AIX) +# define _LINUX_SOURCE_COMPAT +#endif + +#if !(defined(__HP_aCC) && defined(_ILP32) && \ + !defined(_STATVFS_ACPP_PROBLEMS_FIXED)) +#define _FILE_OFFSET_BITS 64 // at worst, these defines may have no effect, +#endif +#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. + +// for some compilers (CodeWarrior, for example), windows.h +// is getting included by some other boost header, so do this early: +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0500 // Default to Windows 2K or later +#endif + + +#include <boost/filesystem/operations.hpp> +#include <boost/scoped_array.hpp> +#include <boost/throw_exception.hpp> +#include <boost/detail/workaround.hpp> + +namespace fs = boost::filesystem; +using boost::system::error_code; +using boost::system::system_category; + +# if defined(BOOST_WINDOWS_API) +# 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 + +# else // BOOST_POSIX_API +# include <sys/types.h> +# if !defined(__APPLE__) && !defined(__OpenBSD__) +# include <sys/statvfs.h> +# define BOOST_STATVFS statvfs +# define BOOST_STATVFS_F_FRSIZE vfs.f_frsize +# else +#ifdef __OpenBSD__ +# include <sys/param.h> +#endif +# include <sys/mount.h> +# define BOOST_STATVFS statfs +# define BOOST_STATVFS_F_FRSIZE static_cast<boost::uintmax_t>( vfs.f_bsize ) +# endif +# include <dirent.h> +# include <unistd.h> +# include <fcntl.h> +# include <utime.h> +# include "limits.h" +# endif + +// BOOST_FILESYSTEM_STATUS_CACHE enables file_status cache in +// dir_itr_increment. The config tests are placed here because some of the +// macros being tested come from dirent.h. +// +// TODO: find out what macros indicate dirent::d_type present in more libraries +# if defined(BOOST_WINDOWS_API) \ + || (defined(_DIRENT_HAVE_D_TYPE) /* defined by GNU C library if d_type present */ \ + && !(defined(__SUNPRO_CC) && !defined(__sun))) // _DIRENT_HAVE_D_TYPE wrong for Sun compiler on Linux +# define BOOST_FILESYSTEM_STATUS_CACHE +# endif + +#include <sys/stat.h> // even on Windows some functions use stat() +#include <string> +#include <cstring> +#include <cstdio> // for remove, rename +#include <cerrno> +#include <cassert> +// #include <iostream> // for debugging only; comment out when not in use + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std { using ::strcmp; using ::remove; using ::rename; } +#endif + +// helpers -----------------------------------------------------------------// + +namespace +{ + const error_code ok; + + bool is_empty_directory( const std::string & dir_path ) + { + static const fs::directory_iterator end_itr; + return fs::directory_iterator(fs::path(dir_path)) == end_itr; + } + +#ifdef BOOST_WINDOWS_API + +// 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.) + + inline DWORD get_file_attributes( const char * ph ) + { return ::GetFileAttributesA( ph ); } + +# ifndef BOOST_FILESYSTEM_NARROW_ONLY + + inline DWORD get_file_attributes( const wchar_t * ph ) + { return ::GetFileAttributesW( ph ); } + + bool is_empty_directory( const std::wstring & dir_path ) + { + static const fs::wdirectory_iterator wend_itr; + return fs::wdirectory_iterator(fs::wpath(dir_path)) == wend_itr; + } + + inline BOOL get_file_attributes_ex( const wchar_t * ph, + WIN32_FILE_ATTRIBUTE_DATA & fad ) + { return ::GetFileAttributesExW( ph, ::GetFileExInfoStandard, &fad ); } + + HANDLE create_file( const wchar_t * ph, DWORD dwDesiredAccess, + DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile ) + { + return ::CreateFileW( ph, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile ); + } + + inline DWORD get_current_directory( DWORD sz, wchar_t * buf ) + { return ::GetCurrentDirectoryW( sz, buf ); } + + inline bool set_current_directory( const wchar_t * buf ) + { return ::SetCurrentDirectoryW( buf ) != 0 ; } + + inline bool get_free_disk_space( const std::wstring & ph, + PULARGE_INTEGER avail, PULARGE_INTEGER total, PULARGE_INTEGER free ) + { return ::GetDiskFreeSpaceExW( ph.c_str(), avail, total, free ) != 0; } + + inline std::size_t get_full_path_name( + const std::wstring & ph, std::size_t len, wchar_t * buf, wchar_t ** p ) + { + return static_cast<std::size_t>( + ::GetFullPathNameW( ph.c_str(), + static_cast<DWORD>(len), buf, p )); + } + + inline bool remove_directory( const std::wstring & ph ) + { return ::RemoveDirectoryW( ph.c_str() ) != 0; } + + inline bool delete_file( const std::wstring & ph ) + { return ::DeleteFileW( ph.c_str() ) != 0; } + + inline bool create_directory( const std::wstring & dir ) + { return ::CreateDirectoryW( dir.c_str(), 0 ) != 0; } + +#if _WIN32_WINNT >= 0x500 + inline bool create_hard_link( const std::wstring & to_ph, + const std::wstring & from_ph ) + { return ::CreateHardLinkW( from_ph.c_str(), to_ph.c_str(), 0 ) != 0; } +#endif + +# endif // ifndef BOOST_FILESYSTEM_NARROW_ONLY + + template< class String > + fs::file_status status_template( const String & ph, error_code & ec ) + { + DWORD attr( get_file_attributes( ph.c_str() ) ); + if ( attr == 0xFFFFFFFF ) + { + ec = error_code( ::GetLastError(), system_category ); + if ((ec.value() == ERROR_FILE_NOT_FOUND) + || (ec.value() == ERROR_PATH_NOT_FOUND) + || (ec.value() == ERROR_INVALID_NAME) // "tools/jam/src/:sys:stat.h", "//foo" + || (ec.value() == ERROR_INVALID_DRIVE) // USB card reader with no card inserted + || (ec.value() == ERROR_INVALID_PARAMETER) // ":sys:stat.h" + || (ec.value() == ERROR_BAD_PATHNAME) // "//nosuch" on Win64 + || (ec.value() == ERROR_BAD_NETPATH)) // "//nosuch" on Win32 + { + ec = ok; // these are not considered errors; + // the status is considered not found + return fs::file_status( fs::file_not_found ); + } + else if ((ec.value() == ERROR_SHARING_VIOLATION)) + { + ec = ok; // these are not considered errors; + // the file exists but the type is not known + return fs::file_status( fs::type_unknown ); + } + return fs::file_status( fs::status_unknown ); + } + ec = ok;; + return (attr & FILE_ATTRIBUTE_DIRECTORY) + ? fs::file_status( fs::directory_file ) + : fs::file_status( fs::regular_file ); + } + + BOOL get_file_attributes_ex( const char * ph, + WIN32_FILE_ATTRIBUTE_DATA & fad ) + { return ::GetFileAttributesExA( ph, ::GetFileExInfoStandard, &fad ); } + + template< class String > + boost::filesystem::detail::query_pair + is_empty_template( const String & ph ) + { + WIN32_FILE_ATTRIBUTE_DATA fad; + if ( get_file_attributes_ex( ph.c_str(), fad ) == 0 ) + return std::make_pair( error_code( ::GetLastError(), system_category ), false ); + return std::make_pair( ok, + ( fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + ? is_empty_directory( ph ) + :( !fad.nFileSizeHigh && !fad.nFileSizeLow ) ); + } + + HANDLE create_file( const char * ph, DWORD dwDesiredAccess, + DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile ) + { + return ::CreateFileA( ph, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile ); + } + + // Thanks to Jeremy Maitin-Shepard for much help and for permission to + // base the equivalent() implementation on portions of his + // file-equivalence-win32.cpp experimental code. + struct handle_wrapper + { + HANDLE handle; + handle_wrapper( HANDLE h ) + : handle(h) {} + ~handle_wrapper() + { + if ( handle != INVALID_HANDLE_VALUE ) + ::CloseHandle(handle); + } + }; + + template< class String > + boost::filesystem::detail::query_pair + equivalent_template( const String & ph1, const String & ph2 ) + { + // 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( + create_file( + ph1.c_str(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0 ) ); + int error1(0); // save error code in case we have to throw + if ( p1.handle == INVALID_HANDLE_VALUE ) + error1 = ::GetLastError(); + handle_wrapper p2( + create_file( + ph2.c_str(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0 ) ); + if ( p1.handle == INVALID_HANDLE_VALUE + || p2.handle == INVALID_HANDLE_VALUE ) + { + if ( p1.handle != INVALID_HANDLE_VALUE + || p2.handle != INVALID_HANDLE_VALUE ) + { return std::make_pair( ok, false ); } + assert( p1.handle == INVALID_HANDLE_VALUE + && p2.handle == INVALID_HANDLE_VALUE ); + { return std::make_pair( error_code( error1, system_category), false ); } + } + // at this point, both handles are known to be valid + BY_HANDLE_FILE_INFORMATION info1, info2; + if ( !::GetFileInformationByHandle( p1.handle, &info1 ) ) + { return std::make_pair( error_code( ::GetLastError(), system_category ), false ); } + if ( !::GetFileInformationByHandle( p2.handle, &info2 ) ) + { return std::make_pair( error_code( ::GetLastError(), system_category ), false ); } + // 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 std::make_pair( ok, + 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 ); + } + + template< class String > + boost::filesystem::detail::uintmax_pair + file_size_template( const String & ph ) + { + WIN32_FILE_ATTRIBUTE_DATA fad; + // by now, intmax_t is 64-bits on all Windows compilers + if ( get_file_attributes_ex( ph.c_str(), fad ) == 0 ) + return std::make_pair( error_code( ::GetLastError(), system_category ), 0 ); + if ( (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) !=0 ) + return std::make_pair( error_code( ERROR_FILE_NOT_FOUND, system_category), 0 ); + return std::make_pair( ok, + (static_cast<boost::uintmax_t>(fad.nFileSizeHigh) + << (sizeof(fad.nFileSizeLow)*8)) + + fad.nFileSizeLow ); + } + + inline bool get_free_disk_space( const std::string & ph, + PULARGE_INTEGER avail, PULARGE_INTEGER total, PULARGE_INTEGER free ) + { return ::GetDiskFreeSpaceExA( ph.c_str(), avail, total, free ) != 0; } + + template< class String > + boost::filesystem::detail::space_pair + space_template( String & ph ) + { + ULARGE_INTEGER avail, total, free; + boost::filesystem::detail::space_pair result; + if ( get_free_disk_space( ph, &avail, &total, &free ) ) + { + result.first = ok; + result.second.capacity + = (static_cast<boost::uintmax_t>(total.HighPart) << 32) + + total.LowPart; + result.second.free + = (static_cast<boost::uintmax_t>(free.HighPart) << 32) + + free.LowPart; + result.second.available + = (static_cast<boost::uintmax_t>(avail.HighPart) << 32) + + avail.LowPart; + } + else + { + result.first = error_code( ::GetLastError(), system_category ); + result.second.capacity = result.second.free + = result.second.available = 0; + } + return result; + } + + inline DWORD get_current_directory( DWORD sz, char * buf ) + { return ::GetCurrentDirectoryA( sz, buf ); } + + template< class String > + error_code + get_current_path_template( String & ph ) + { + DWORD sz; + if ( (sz = get_current_directory( 0, + static_cast<typename String::value_type*>(0) )) == 0 ) + { sz = 1; } + typedef typename String::value_type value_type; + boost::scoped_array<value_type> buf( new value_type[sz] ); + if ( get_current_directory( sz, buf.get() ) == 0 ) + return error_code( ::GetLastError(), system_category ); + ph = buf.get(); + return ok; + } + + inline bool set_current_directory( const char * buf ) + { return ::SetCurrentDirectoryA( buf ) != 0; } + + template< class String > + error_code + set_current_path_template( const String & ph ) + { + return error_code( set_current_directory( ph.c_str() ) + ? 0 : ::GetLastError(), system_category ); + } + + inline std::size_t get_full_path_name( + const std::string & ph, std::size_t len, char * buf, char ** p ) + { + return static_cast<std::size_t>( + ::GetFullPathNameA( ph.c_str(), + static_cast<DWORD>(len), buf, p )); + } + + const std::size_t buf_size( 128 ); + + template<class String> + error_code + get_full_path_name_template( const String & ph, String & target ) + { + typename String::value_type buf[buf_size]; + typename String::value_type * pfn; + std::size_t len = get_full_path_name( ph, + buf_size , buf, &pfn ); + if ( len == 0 ) return error_code( ::GetLastError(), system_category ); + if ( len > buf_size ) + { + typedef typename String::value_type value_type; + boost::scoped_array<value_type> big_buf( new value_type[len] ); + if ( (len=get_full_path_name( ph, len , big_buf.get(), &pfn )) + == 0 ) return error_code( ::GetLastError(), system_category ); + big_buf[len] = '\0'; + target = big_buf.get(); + return ok; + } + buf[len] = '\0'; + target = buf; + return ok; + } + + template<class String> + error_code + get_file_write_time( const String & ph, FILETIME & last_write_time ) + { + handle_wrapper hw( + create_file( ph.c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ) ); + if ( hw.handle == INVALID_HANDLE_VALUE ) + return error_code( ::GetLastError(), system_category ); + return error_code( ::GetFileTime( hw.handle, 0, 0, &last_write_time ) != 0 + ? 0 : ::GetLastError(), system_category ); + } + + template<class String> + error_code + set_file_write_time( const String & ph, const FILETIME & last_write_time ) + { + handle_wrapper hw( + create_file( ph.c_str(), FILE_WRITE_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ) ); + if ( hw.handle == INVALID_HANDLE_VALUE ) + return error_code( ::GetLastError(), system_category ); + return error_code( ::SetFileTime( hw.handle, 0, 0, &last_write_time ) != 0 + ? 0 : ::GetLastError(), system_category ); + } + + // these constants come from inspecting some Microsoft sample code + std::time_t to_time_t( const FILETIME & ft ) + { + __int64 t = (static_cast<__int64>( ft.dwHighDateTime ) << 32) + + ft.dwLowDateTime; +# if !defined( BOOST_MSVC ) || BOOST_MSVC > 1300 // > VC++ 7.0 + t -= 116444736000000000LL; +# else + t -= 116444736000000000; +# endif + t /= 10000000; + return static_cast<std::time_t>( t ); + } + + void to_FILETIME( std::time_t t, FILETIME & ft ) + { + __int64 temp = t; + temp *= 10000000; +# if !defined( BOOST_MSVC ) || BOOST_MSVC > 1300 // > VC++ 7.0 + temp += 116444736000000000LL; +# else + temp += 116444736000000000; +# endif + ft.dwLowDateTime = static_cast<DWORD>( temp ); + ft.dwHighDateTime = static_cast<DWORD>( temp >> 32 ); + } + + template<class String> + boost::filesystem::detail::time_pair + last_write_time_template( const String & ph ) + { + FILETIME lwt; + error_code ec( + get_file_write_time( ph, lwt ) ); + return std::make_pair( ec, to_time_t( lwt ) ); + } + + template<class String> + error_code + last_write_time_template( const String & ph, const std::time_t new_time ) + { + FILETIME lwt; + to_FILETIME( new_time, lwt ); + return set_file_write_time( ph, lwt ); + } + + bool remove_directory( const std::string & ph ) + { return ::RemoveDirectoryA( ph.c_str() ) != 0; } + + bool delete_file( const std::string & ph ) + { return ::DeleteFileA( ph.c_str() ) != 0; } + + template<class String> + error_code + remove_template( const String & ph ) + { + // TODO: test this code in the presence of Vista symlinks, + // including dangling, self-referal, and cyclic symlinks + error_code ec; + fs::file_status sf( fs::detail::status_api( ph, ec ) ); + if ( ec ) + return ec; + if ( sf.type() == fs::file_not_found ) + return ok; + if ( fs::is_directory( sf ) ) + { + if ( !remove_directory( ph ) ) + return error_code(::GetLastError(), system_category); + } + else + { + if ( !delete_file( ph ) ) return error_code(::GetLastError(), system_category); + } + return ok; + } + + inline bool create_directory( const std::string & dir ) + { return ::CreateDirectoryA( dir.c_str(), 0 ) != 0; } + + template<class String> + boost::filesystem::detail::query_pair + create_directory_template( const String & dir_ph ) + { + error_code error, dummy; + if ( create_directory( dir_ph ) ) return std::make_pair( error, true ); + error = error_code( ::GetLastError(), system_category ); + // an error here may simply mean the postcondition is already met + if ( error.value() == ERROR_ALREADY_EXISTS + && fs::is_directory( fs::detail::status_api( dir_ph, dummy ) ) ) + return std::make_pair( ok, false ); + return std::make_pair( error, false ); + } + +#if _WIN32_WINNT >= 0x500 + inline bool create_hard_link( const std::string & to_ph, + const std::string & from_ph ) + { return ::CreateHardLinkA( from_ph.c_str(), to_ph.c_str(), 0 ) != 0; } +#endif + +#if _WIN32_WINNT >= 0x500 + template<class String> + error_code + create_hard_link_template( const String & to_ph, + const String & from_ph ) + { + return error_code( create_hard_link( to_ph.c_str(), from_ph.c_str() ) + ? 0 : ::GetLastError(), system_category ); + } +#endif + +#else // BOOST_POSIX_API + + int posix_remove( const char * p ) + { +# 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 also reported for QNX, with the same fix. + int err = ::unlink( p ); + if ( err == 0 || errno != EPERM ) + return err; + return ::rmdir( p ); +# else + return std::remove( p ); +# endif + } + +#endif +} // unnamed namespace + +namespace boost +{ + namespace filesystem + { + namespace detail + { + BOOST_FILESYSTEM_DECL system::error_code throws; + +// free functions ----------------------------------------------------------// + + BOOST_FILESYSTEM_DECL error_code not_found_error() + { +# ifdef BOOST_WINDOWS_API + return error_code(ERROR_PATH_NOT_FOUND, system_category); +# else + return error_code(ENOENT, system_category); +# endif + } + + BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() + { +# ifdef BOOST_POSIX_API + struct stat lcl_stat; + return sizeof( lcl_stat.st_size ) > 4; +# else + return true; +# endif + } + +# ifdef BOOST_WINDOWS_API + + BOOST_FILESYSTEM_DECL fs::file_status + status_api( const std::string & ph, error_code & ec ) + { return status_template( ph, ec ); } + +# ifndef BOOST_FILESYSTEM_NARROW_ONLY + + BOOST_FILESYSTEM_DECL fs::file_status + status_api( const std::wstring & ph, error_code & ec ) + { return status_template( ph, ec ); } + + BOOST_FILESYSTEM_DECL bool symbolic_link_exists_api( const std::wstring & ) + { return false; } + + BOOST_FILESYSTEM_DECL + fs::detail::query_pair is_empty_api( const std::wstring & ph ) + { return is_empty_template( ph ); } + + BOOST_FILESYSTEM_DECL + fs::detail::query_pair + equivalent_api( const std::wstring & ph1, const std::wstring & ph2 ) + { return equivalent_template( ph1, ph2 ); } + + BOOST_FILESYSTEM_DECL + fs::detail::uintmax_pair file_size_api( const std::wstring & ph ) + { return file_size_template( ph ); } + + BOOST_FILESYSTEM_DECL + fs::detail::space_pair space_api( const std::wstring & ph ) + { return space_template( ph ); } + + BOOST_FILESYSTEM_DECL + error_code + get_current_path_api( std::wstring & ph ) + { return get_current_path_template( ph ); } + + BOOST_FILESYSTEM_DECL + error_code + set_current_path_api( const std::wstring & ph ) + { return set_current_path_template( ph ); } + + BOOST_FILESYSTEM_DECL error_code + get_full_path_name_api( const std::wstring & ph, std::wstring & target ) + { return get_full_path_name_template( ph, target ); } + + BOOST_FILESYSTEM_DECL time_pair + last_write_time_api( const std::wstring & ph ) + { return last_write_time_template( ph ); } + + BOOST_FILESYSTEM_DECL error_code + last_write_time_api( const std::wstring & ph, std::time_t new_value ) + { return last_write_time_template( ph, new_value ); } + + BOOST_FILESYSTEM_DECL fs::detail::query_pair + create_directory_api( const std::wstring & ph ) + { return create_directory_template( ph ); } + +#if _WIN32_WINNT >= 0x500 + BOOST_FILESYSTEM_DECL error_code + create_hard_link_api( const std::wstring & to_ph, + const std::wstring & from_ph ) + { return create_hard_link_template( to_ph, from_ph ); } +#endif + + BOOST_FILESYSTEM_DECL error_code + create_symlink_api( const std::wstring & /*to_ph*/, + const std::wstring & /*from_ph*/ ) + { return error_code( ERROR_NOT_SUPPORTED, system_category ); } + + BOOST_FILESYSTEM_DECL error_code + remove_api( const std::wstring & ph ) { return remove_template( ph ); } + + BOOST_FILESYSTEM_DECL error_code + rename_api( const std::wstring & from, const std::wstring & to ) + { + return error_code( ::MoveFileW( from.c_str(), to.c_str() ) + ? 0 : ::GetLastError(), system_category ); + } + + BOOST_FILESYSTEM_DECL error_code + copy_file_api( const std::wstring & from, const std::wstring & to ) + { + return error_code( ::CopyFileW( from.c_str(), to.c_str(), /*fail_if_exists=*/true ) + ? 0 : ::GetLastError(), system_category ); + } + + BOOST_FILESYSTEM_DECL bool create_file_api( const std::wstring & ph, + std::ios_base::openmode mode ) // true if succeeds + { + DWORD access( + ((mode & std::ios_base::in) == 0 ? 0 : GENERIC_READ) + | ((mode & std::ios_base::out) == 0 ? 0 : GENERIC_WRITE) ); + + DWORD disposition(0); // see 27.8.1.3 Table 92 + if ( (mode&~std::ios_base::binary) + == (std::ios_base::out|std::ios_base::app) ) + disposition = OPEN_ALWAYS; + else if ( (mode&~(std::ios_base::binary|std::ios_base::out)) + == std::ios_base::in ) disposition = OPEN_EXISTING; + else if ( ((mode&~(std::ios_base::binary|std::ios_base::trunc)) + == std::ios_base::out ) + || ((mode&~std::ios_base::binary) + == (std::ios_base::in|std::ios_base::out|std::ios_base::trunc)) ) + disposition = CREATE_ALWAYS; + else assert( 0 && "invalid mode argument" ); + + HANDLE handle ( ::CreateFileW( ph.c_str(), access, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + disposition, (mode &std::ios_base::out) != 0 + ? FILE_ATTRIBUTE_ARCHIVE : FILE_ATTRIBUTE_NORMAL, 0 ) ); + if ( handle == INVALID_HANDLE_VALUE ) return false; + ::CloseHandle( handle ); + return true; + } + + BOOST_FILESYSTEM_DECL std::string narrow_path_api( + const std::wstring & ph ) // return is empty if fails + { + std::string narrow_short_form; + std::wstring short_form; + for ( DWORD buf_sz( static_cast<DWORD>( ph.size()+1 ));; ) + { + boost::scoped_array<wchar_t> buf( new wchar_t[buf_sz] ); + DWORD sz( ::GetShortPathNameW( ph.c_str(), buf.get(), buf_sz ) ); + if ( sz == 0 ) return narrow_short_form; + if ( sz <= buf_sz ) + { + short_form += buf.get(); + break; + } + buf_sz = sz + 1; + } + // contributed by Takeshi Mouri: + int narrow_sz( ::WideCharToMultiByte( CP_ACP, 0, + short_form.c_str(), static_cast<int>(short_form.size()), 0, 0, 0, 0 ) ); + boost::scoped_array<char> narrow_buf( new char[narrow_sz] ); + ::WideCharToMultiByte( CP_ACP, 0, + short_form.c_str(), static_cast<int>(short_form.size()), + narrow_buf.get(), narrow_sz, 0, 0 ); + narrow_short_form.assign(narrow_buf.get(), narrow_sz); + + return narrow_short_form; + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_first( void *& handle, const std::wstring & dir, + std::wstring & target, file_status & sf, file_status & symlink_sf ) + { + // use a form of search Sebastian Martel reports will work with Win98 + std::wstring dirpath( dir ); + dirpath += (dirpath.empty() + || dirpath[dirpath.size()-1] != L'\\') ? L"\\*" : L"*"; + + WIN32_FIND_DATAW data; + if ( (handle = ::FindFirstFileW( dirpath.c_str(), &data )) + == INVALID_HANDLE_VALUE ) + { + handle = 0; + return error_code( ::GetLastError() == ERROR_FILE_NOT_FOUND + ? 0 : ::GetLastError(), system_category ); + } + target = data.cFileName; + if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { sf.type( directory_file ); symlink_sf.type( directory_file ); } + else { sf.type( regular_file ); symlink_sf.type( regular_file ); } + return ok; + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_increment( void *& handle, std::wstring & target, + file_status & sf, file_status & symlink_sf ) + { + WIN32_FIND_DATAW data; + if ( ::FindNextFileW( handle, &data ) == 0 ) // fails + { + int error = ::GetLastError(); + dir_itr_close( handle ); + return error_code( error == ERROR_NO_MORE_FILES ? 0 : error, system_category ); + } + target = data.cFileName; + if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { sf.type( directory_file ); symlink_sf.type( directory_file ); } + else { sf.type( regular_file ); symlink_sf.type( regular_file ); } + return ok; + } + +# endif // ifndef BOOST_FILESYSTEM_NARROW_ONLY + + // suggested by Walter Landry + BOOST_FILESYSTEM_DECL bool symbolic_link_exists_api( const std::string & ) + { return false; } + + BOOST_FILESYSTEM_DECL + fs::detail::query_pair is_empty_api( const std::string & ph ) + { return is_empty_template( ph ); } + + BOOST_FILESYSTEM_DECL + fs::detail::query_pair + equivalent_api( const std::string & ph1, const std::string & ph2 ) + { return equivalent_template( ph1, ph2 ); } + + BOOST_FILESYSTEM_DECL + fs::detail::uintmax_pair file_size_api( const std::string & ph ) + { return file_size_template( ph ); } + + BOOST_FILESYSTEM_DECL + fs::detail::space_pair space_api( const std::string & ph ) + { return space_template( ph ); } + + BOOST_FILESYSTEM_DECL + error_code + get_current_path_api( std::string & ph ) + { return get_current_path_template( ph ); } + + BOOST_FILESYSTEM_DECL + error_code + set_current_path_api( const std::string & ph ) + { return set_current_path_template( ph ); } + + BOOST_FILESYSTEM_DECL error_code + get_full_path_name_api( const std::string & ph, std::string & target ) + { return get_full_path_name_template( ph, target ); } + + BOOST_FILESYSTEM_DECL time_pair + last_write_time_api( const std::string & ph ) + { return last_write_time_template( ph ); } + + BOOST_FILESYSTEM_DECL error_code + last_write_time_api( const std::string & ph, std::time_t new_value ) + { return last_write_time_template( ph, new_value ); } + + BOOST_FILESYSTEM_DECL fs::detail::query_pair + create_directory_api( const std::string & ph ) + { return create_directory_template( ph ); } + +#if _WIN32_WINNT >= 0x500 + BOOST_FILESYSTEM_DECL error_code + create_hard_link_api( const std::string & to_ph, + const std::string & from_ph ) + { + return create_hard_link_template( to_ph, from_ph ); + } +#endif + + BOOST_FILESYSTEM_DECL error_code + create_symlink_api( const std::string & /*to_ph*/, + const std::string & /*from_ph*/ ) + { return error_code( ERROR_NOT_SUPPORTED, system_category ); } + + BOOST_FILESYSTEM_DECL error_code + remove_api( const std::string & ph ) { return remove_template( ph ); } + + BOOST_FILESYSTEM_DECL error_code + rename_api( const std::string & from, const std::string & to ) + { + return error_code( ::MoveFileA( from.c_str(), to.c_str() ) + ? 0 : ::GetLastError(), system_category ); + } + + BOOST_FILESYSTEM_DECL error_code + copy_file_api( const std::string & from, const std::string & to ) + { + return error_code( ::CopyFileA( from.c_str(), to.c_str(), /*fail_if_exists=*/true ) + ? 0 : ::GetLastError(), system_category ); + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_first( void *& handle, const std::string & dir, + std::string & target, file_status & sf, file_status & symlink_sf ) + // 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. It is treated as eof instead. + { + // 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] != ':')) ? "\\*" : "*"; + + WIN32_FIND_DATAA data; + if ( (handle = ::FindFirstFileA( dirpath.c_str(), &data )) + == INVALID_HANDLE_VALUE ) + { + handle = 0; + return error_code( ::GetLastError() == ERROR_FILE_NOT_FOUND + ? 0 : ::GetLastError(), system_category ); + } + target = data.cFileName; + if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { sf.type( directory_file ); symlink_sf.type( directory_file ); } + else { sf.type( regular_file ); symlink_sf.type( regular_file ); } + return ok; + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_close( void *& handle ) + { + if ( handle != 0 ) + { + bool ok = ::FindClose( handle ) != 0; + handle = 0; + return error_code( ok ? 0 : ::GetLastError(), system_category ); + } + return ok; + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_increment( void *& handle, std::string & target, + file_status & sf, file_status & symlink_sf ) + { + WIN32_FIND_DATAA data; + if ( ::FindNextFileA( handle, &data ) == 0 ) // fails + { + int error = ::GetLastError(); + dir_itr_close( handle ); + return error_code( error == ERROR_NO_MORE_FILES ? 0 : error, system_category ); + } + target = data.cFileName; + if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + { sf.type( directory_file ); symlink_sf.type( directory_file ); } + else { sf.type( regular_file ); symlink_sf.type( regular_file ); } + return ok; + } + +# else // BOOST_POSIX_API + + BOOST_FILESYSTEM_DECL fs::file_status + status_api( const std::string & ph, error_code & ec ) + { + struct stat path_stat; + if ( ::stat( ph.c_str(), &path_stat ) != 0 ) + { + if ( errno == ENOENT || errno == ENOTDIR ) + { + ec = ok; + return fs::file_status( fs::file_not_found ); + } + ec = error_code( errno, system_category ); + return fs::file_status( fs::status_unknown ); + } + ec = ok; + if ( S_ISDIR( path_stat.st_mode ) ) + return fs::file_status( fs::directory_file ); + if ( S_ISREG( path_stat.st_mode ) ) + return fs::file_status( fs::regular_file ); + if ( S_ISBLK( path_stat.st_mode ) ) + return fs::file_status( fs::block_file ); + if ( S_ISCHR( path_stat.st_mode ) ) + return fs::file_status( fs::character_file ); + if ( S_ISFIFO( path_stat.st_mode ) ) + return fs::file_status( fs::fifo_file ); + if ( S_ISSOCK( path_stat.st_mode ) ) + return fs::file_status( fs::socket_file ); + return fs::file_status( fs::type_unknown ); + } + + BOOST_FILESYSTEM_DECL fs::file_status + symlink_status_api( const std::string & ph, error_code & ec ) + { + struct stat path_stat; + if ( ::lstat( ph.c_str(), &path_stat ) != 0 ) + { + if ( errno == ENOENT || errno == ENOTDIR ) + { + ec = ok; + return fs::file_status( fs::file_not_found ); + } + ec = error_code( errno, system_category ); + return fs::file_status( fs::status_unknown ); + } + ec = ok; + if ( S_ISREG( path_stat.st_mode ) ) + return fs::file_status( fs::regular_file ); + if ( S_ISDIR( path_stat.st_mode ) ) + return fs::file_status( fs::directory_file ); + if ( S_ISLNK( path_stat.st_mode ) ) + return fs::file_status( fs::symlink_file ); + if ( S_ISBLK( path_stat.st_mode ) ) + return fs::file_status( fs::block_file ); + if ( S_ISCHR( path_stat.st_mode ) ) + return fs::file_status( fs::character_file ); + if ( S_ISFIFO( path_stat.st_mode ) ) + return fs::file_status( fs::fifo_file ); + if ( S_ISSOCK( path_stat.st_mode ) ) + return fs::file_status( fs::socket_file ); + return fs::file_status( fs::type_unknown ); + } + + // suggested by Walter Landry + BOOST_FILESYSTEM_DECL bool + symbolic_link_exists_api( const std::string & ph ) + { + struct stat path_stat; + return ::lstat( ph.c_str(), &path_stat ) == 0 + && S_ISLNK( path_stat.st_mode ); + } + + BOOST_FILESYSTEM_DECL query_pair + is_empty_api( const std::string & ph ) + { + struct stat path_stat; + if ( (::stat( ph.c_str(), &path_stat )) != 0 ) + return std::make_pair( error_code( errno, system_category ), false ); + return std::make_pair( ok, S_ISDIR( path_stat.st_mode ) + ? is_empty_directory( ph ) + : path_stat.st_size == 0 ); + } + + BOOST_FILESYSTEM_DECL query_pair + equivalent_api( const std::string & ph1, const std::string & ph2 ) + { + struct stat s2; + int e2( ::stat( ph2.c_str(), &s2 ) ); + struct stat s1; + int e1( ::stat( ph1.c_str(), &s1 ) ); + if ( e1 != 0 || e2 != 0 ) + return std::make_pair( error_code( e1 != 0 && e2 != 0 ? errno : 0, system_category ), false ); + // at this point, both stats are known to be valid + return std::make_pair( ok, + 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 ); + } + + BOOST_FILESYSTEM_DECL uintmax_pair + file_size_api( const std::string & ph ) + { + struct stat path_stat; + if ( ::stat( ph.c_str(), &path_stat ) != 0 ) + return std::make_pair( error_code( errno, system_category ), 0 ); + if ( !S_ISREG( path_stat.st_mode ) ) + return std::make_pair( error_code( EPERM, system_category ), 0 ); + return std::make_pair( ok, + static_cast<boost::uintmax_t>(path_stat.st_size) ); + } + + BOOST_FILESYSTEM_DECL space_pair + space_api( const std::string & ph ) + { + struct BOOST_STATVFS vfs; + space_pair result; + if ( ::BOOST_STATVFS( ph.c_str(), &vfs ) != 0 ) + { + result.first = error_code( errno, system_category ); + result.second.capacity = result.second.free + = result.second.available = 0; + } + else + { + result.first = ok; + result.second.capacity + = static_cast<boost::uintmax_t>(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE; + result.second.free + = static_cast<boost::uintmax_t>(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE; + result.second.available + = static_cast<boost::uintmax_t>(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE; + } + return result; + } + + BOOST_FILESYSTEM_DECL time_pair + last_write_time_api( const std::string & ph ) + { + struct stat path_stat; + if ( ::stat( ph.c_str(), &path_stat ) != 0 ) + return std::make_pair( error_code( errno, system_category ), 0 ); + return std::make_pair( ok, path_stat.st_mtime ); + } + + BOOST_FILESYSTEM_DECL error_code + last_write_time_api( const std::string & ph, std::time_t new_value ) + { + struct stat path_stat; + if ( ::stat( ph.c_str(), &path_stat ) != 0 ) + return error_code( errno, system_category ); + ::utimbuf buf; + buf.actime = path_stat.st_atime; // utime() updates access time too:-( + buf.modtime = new_value; + return error_code( ::utime( ph.c_str(), &buf ) != 0 ? errno : 0, system_category ); + } + + BOOST_FILESYSTEM_DECL error_code + get_current_path_api( std::string & ph ) + { + for ( long path_max = 32;; path_max *=2 ) // loop 'til buffer large enough + { + boost::scoped_array<char> + buf( new char[static_cast<std::size_t>(path_max)] ); + if ( ::getcwd( buf.get(), static_cast<std::size_t>(path_max) ) == 0 ) + { + if ( errno != ERANGE + // 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 + ) return error_code( errno, system_category ); + } + else + { + ph = buf.get(); + break; + } + } + return ok; + } + + BOOST_FILESYSTEM_DECL error_code + set_current_path_api( const std::string & ph ) + { + return error_code( ::chdir( ph.c_str() ) + ? errno : 0, system_category ); + } + + BOOST_FILESYSTEM_DECL fs::detail::query_pair + create_directory_api( const std::string & ph ) + { + if ( ::mkdir( ph.c_str(), S_IRWXU|S_IRWXG|S_IRWXO ) == 0 ) + { return std::make_pair( ok, true ); } + int ec=errno; + error_code dummy; + if ( ec != EEXIST + || !fs::is_directory( status_api( ph, dummy ) ) ) + { return std::make_pair( error_code( ec, system_category ), false ); } + return std::make_pair( ok, false ); + } + + BOOST_FILESYSTEM_DECL error_code + create_hard_link_api( const std::string & to_ph, + const std::string & from_ph ) + { + return error_code( ::link( to_ph.c_str(), from_ph.c_str() ) == 0 + ? 0 : errno, system_category ); + } + + BOOST_FILESYSTEM_DECL error_code + create_symlink_api( const std::string & to_ph, + const std::string & from_ph ) + { + return error_code( ::symlink( to_ph.c_str(), from_ph.c_str() ) == 0 + ? 0 : errno, system_category ); + } + + BOOST_FILESYSTEM_DECL error_code + remove_api( const std::string & ph ) + { + if ( posix_remove( ph.c_str() ) == 0 ) + return ok; + int error = errno; + // 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; + + error_code ec; + + // ignore errors if post-condition satisfied + return status_api(ph, ec).type() == file_not_found + ? ok : error_code( error, system_category ) ; + } + + BOOST_FILESYSTEM_DECL error_code + rename_api( const std::string & from, const std::string & to ) + { + // POSIX is too permissive so must check + error_code dummy; + if ( fs::exists( status_api( to, dummy ) ) ) + return error_code( EEXIST, system_category ); + return error_code( std::rename( from.c_str(), to.c_str() ) != 0 + ? errno : 0, system_category ); + } + + BOOST_FILESYSTEM_DECL error_code + copy_file_api( const std::string & from_file_ph, + const std::string & to_file_ph ) + { + const std::size_t buf_sz = 32768; + boost::scoped_array<char> buf( new char [buf_sz] ); + int infile=-1, outfile=-1; // -1 means not open + struct stat from_stat; + + if ( ::stat( from_file_ph.c_str(), &from_stat ) != 0 + || (infile = ::open( from_file_ph.c_str(), + O_RDONLY )) < 0 + || (outfile = ::open( to_file_ph.c_str(), + O_WRONLY | O_CREAT | O_EXCL, + from_stat.st_mode )) < 0 ) + { + if ( infile >= 0 ) ::close( infile ); + return error_code( errno, system_category ); + } + + 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_write, + 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; + + return error_code( sz_read < 0 ? errno : 0, system_category ); + } + + // this code is based on Stevens and Rago, Advanced Programming in the + // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49 + error_code path_max( std::size_t & result ) + { +# ifdef PATH_MAX + static std::size_t max = PATH_MAX; +# else + static std::size_t max = 0; +# endif + if ( max == 0 ) + { + errno = 0; + long tmp = ::pathconf( "/", _PC_NAME_MAX ); + if ( tmp < 0 ) + { + if ( errno == 0 ) // indeterminate + max = 4096; // guess + else return error_code( errno, system_category ); + } + else max = static_cast<std::size_t>( tmp + 1 ); // relative root + } + result = max; + return ok; + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_first( void *& handle, void *& buffer, + const std::string & dir, std::string & target, + file_status &, file_status & ) + { + if ( (handle = ::opendir( dir.c_str() )) == 0 ) + return error_code( errno, system_category ); + target = std::string( "." ); // string was static but caused trouble + // when iteration called from dtor, after + // static had already been destroyed + std::size_t path_size; + error_code ec = path_max( path_size ); + if ( ec ) return ec; + dirent de; + buffer = std::malloc( (sizeof(dirent) - sizeof(de.d_name)) + + path_size + 1 ); // + 1 for "/0" + return ok; + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_close( void *& handle, void*& buffer ) + { + std::free( buffer ); + buffer = 0; + if ( handle == 0 ) return ok; + DIR * h( static_cast<DIR*>(handle) ); + handle = 0; + return error_code( ::closedir( h ) == 0 ? 0 : errno, system_category ); + } + + // 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 + { + errno = 0; + + # if !defined(__CYGWIN__) \ + && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \ + && defined(_SC_THREAD_SAFE_FUNCTIONS) \ + && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0) \ + && (!defined(__hpux) || (defined(__hpux) && defined(_REENTRANT))) + if ( ::sysconf( _SC_THREAD_SAFE_FUNCTIONS ) >= 0 ) + { return ::readdir_r( dirp, entry, result ); } + # endif + + struct dirent * p; + *result = 0; + if ( (p = ::readdir( dirp )) == 0 ) + return errno; + std::strcpy( entry->d_name, p->d_name ); + *result = entry; + return 0; + } + + BOOST_FILESYSTEM_DECL error_code + dir_itr_increment( void *& handle, void *& buffer, + std::string & target, file_status & sf, file_status & symlink_sf ) + { + BOOST_ASSERT( buffer != 0 ); + dirent * entry( static_cast<dirent *>(buffer) ); + dirent * result; + int return_code; + if ( (return_code = readdir_r_simulator( static_cast<DIR*>(handle), + entry, &result )) != 0 ) return error_code( errno, system_category ); + if ( result == 0 ) return dir_itr_close( handle, buffer ); + target = entry->d_name; +# ifdef BOOST_FILESYSTEM_STATUS_CACHE + if ( entry->d_type == DT_UNKNOWN ) // filesystem does not supply d_type value + { + sf = symlink_sf = fs::file_status(fs::status_unknown); + } + else // filesystem supplies d_type value + { + if ( entry->d_type == DT_DIR ) + sf = symlink_sf = fs::file_status( fs::directory_file ); + else if ( entry->d_type == DT_REG ) + sf = symlink_sf = fs::file_status( fs::regular_file ); + else if ( entry->d_type == DT_LNK ) + { + sf = fs::file_status( fs::status_unknown ); + symlink_sf = fs::file_status( fs::symlink_file ); + } + else sf = symlink_sf = fs::file_status( fs::status_unknown ); + } +# else + sf = symlink_sf = fs::file_status( fs::status_unknown ); +# endif + return ok; + } + +# endif + } // namespace detail + } // namespace filesystem +} // namespace boost |