diff options
author | neksard <neksard@yandex-team.ru> | 2022-02-10 16:45:33 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:33 +0300 |
commit | 1d9c550e7c38e051d7961f576013a482003a70d9 (patch) | |
tree | b2cc84ee7850122e7ccf51d0ea21e4fa7e7a5685 /contrib/restricted/boost/libs/filesystem | |
parent | 8f7cf138264e0caa318144bf8a2c950e0b0a8593 (diff) | |
download | ydb-1d9c550e7c38e051d7961f576013a482003a70d9.tar.gz |
Restoring authorship annotation for <neksard@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/restricted/boost/libs/filesystem')
9 files changed, 4057 insertions, 4057 deletions
diff --git a/contrib/restricted/boost/libs/filesystem/src/codecvt_error_category.cpp b/contrib/restricted/boost/libs/filesystem/src/codecvt_error_category.cpp index 65c46ebced..165c6ea7b8 100644 --- a/contrib/restricted/boost/libs/filesystem/src/codecvt_error_category.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/codecvt_error_category.cpp @@ -1,84 +1,84 @@ -// codecvt_error_category implementation file ----------------------------------------// - -// Copyright Beman Dawes 2009 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt) - -// Library home page at http://www.boost.org/libs/filesystem - -//--------------------------------------------------------------------------------------// - -#include <boost/config/warning_disable.hpp> - -// 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 - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#include <boost/filesystem/config.hpp> -#include <boost/filesystem/path_traits.hpp> -#include <boost/system/error_code.hpp> -#include <locale> -#include <vector> -#include <cstdlib> -#include <cassert> - -//--------------------------------------------------------------------------------------// - -namespace -{ - class codecvt_error_cat : public boost::system::error_category - { - public: - codecvt_error_cat(){} - const char* name() const BOOST_SYSTEM_NOEXCEPT; - std::string message(int ev) const; - }; - - const char* codecvt_error_cat::name() const BOOST_SYSTEM_NOEXCEPT - { - return "codecvt"; - } - - std::string codecvt_error_cat::message(int ev) const - { - std::string str; - switch (ev) - { - case std::codecvt_base::ok: - str = "ok"; - break; - case std::codecvt_base::partial: - str = "partial"; - break; - case std::codecvt_base::error: - str = "error"; - break; - case std::codecvt_base::noconv: - str = "noconv"; - break; - default: - str = "unknown error"; - } - return str; - } - -} // unnamed namespace - -namespace boost -{ - namespace filesystem - { - - BOOST_FILESYSTEM_DECL const boost::system::error_category& codecvt_error_category() - { - static const codecvt_error_cat codecvt_error_cat_const; - return codecvt_error_cat_const; - } - - } // namespace filesystem -} // namespace boost +// codecvt_error_category implementation file ----------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt) + +// Library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include <boost/config/warning_disable.hpp> + +// 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 + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include <boost/filesystem/config.hpp> +#include <boost/filesystem/path_traits.hpp> +#include <boost/system/error_code.hpp> +#include <locale> +#include <vector> +#include <cstdlib> +#include <cassert> + +//--------------------------------------------------------------------------------------// + +namespace +{ + class codecvt_error_cat : public boost::system::error_category + { + public: + codecvt_error_cat(){} + const char* name() const BOOST_SYSTEM_NOEXCEPT; + std::string message(int ev) const; + }; + + const char* codecvt_error_cat::name() const BOOST_SYSTEM_NOEXCEPT + { + return "codecvt"; + } + + std::string codecvt_error_cat::message(int ev) const + { + std::string str; + switch (ev) + { + case std::codecvt_base::ok: + str = "ok"; + break; + case std::codecvt_base::partial: + str = "partial"; + break; + case std::codecvt_base::error: + str = "error"; + break; + case std::codecvt_base::noconv: + str = "noconv"; + break; + default: + str = "unknown error"; + } + return str; + } + +} // unnamed namespace + +namespace boost +{ + namespace filesystem + { + + BOOST_FILESYSTEM_DECL const boost::system::error_category& codecvt_error_category() + { + static const codecvt_error_cat codecvt_error_cat_const; + return codecvt_error_cat_const; + } + + } // namespace filesystem +} // namespace boost diff --git a/contrib/restricted/boost/libs/filesystem/src/operations.cpp b/contrib/restricted/boost/libs/filesystem/src/operations.cpp index 7e4bab230c..044019ceb9 100644 --- a/contrib/restricted/boost/libs/filesystem/src/operations.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/operations.cpp @@ -1,2405 +1,2405 @@ -// operations.cpp --------------------------------------------------------------------// - -// Copyright 2002-2009, 2014 Beman Dawes -// Copyright 2001 Dietmar Kuehl - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// See library home page at http://www.boost.org/libs/filesystem - -//--------------------------------------------------------------------------------------// - +// operations.cpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2001 Dietmar Kuehl + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24 +// Android fully supports 64-bit file offsets only for API 24 and above. +#else +// define 64-bit offset macros BEFORE including boost/config.hpp (see ticket #5355) #if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24 // Android fully supports 64-bit file offsets only for API 24 and above. +// +// Trying to define _FILE_OFFSET_BITS=64 for APIs below 24 +// leads to compilation failure for one or another reason, +// depending on target Android API level, Android NDK version, +// used STL, order of include paths and more. +// For more information, please see: +// - https://github.com/boostorg/filesystem/issues/65 +// - https://github.com/boostorg/filesystem/pull/69 +// +// Android NDK developers consider it the expected behavior. +// See their official position here: +// - https://github.com/android-ndk/ndk/issues/501#issuecomment-326447479 +// - https://android.googlesource.com/platform/bionic/+/a34817457feee026e8702a1d2dffe9e92b51d7d1/docs/32-bit-abi.md#32_bit-abi-bugs +// +// Thus we do not define _FILE_OFFSET_BITS in such case. #else -// define 64-bit offset macros BEFORE including boost/config.hpp (see ticket #5355) -#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24 -// Android fully supports 64-bit file offsets only for API 24 and above. -// -// Trying to define _FILE_OFFSET_BITS=64 for APIs below 24 -// leads to compilation failure for one or another reason, -// depending on target Android API level, Android NDK version, -// used STL, order of include paths and more. -// For more information, please see: -// - https://github.com/boostorg/filesystem/issues/65 -// - https://github.com/boostorg/filesystem/pull/69 -// -// Android NDK developers consider it the expected behavior. -// See their official position here: -// - https://github.com/android-ndk/ndk/issues/501#issuecomment-326447479 -// - https://android.googlesource.com/platform/bionic/+/a34817457feee026e8702a1d2dffe9e92b51d7d1/docs/32-bit-abi.md#32_bit-abi-bugs -// -// Thus we do not define _FILE_OFFSET_BITS in such case. -#else -// Defining _FILE_OFFSET_BITS=64 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. -// -// At the time of this comment writing (March 2018), on most systems -// _FILE_OFFSET_BITS=64 definition is harmless: -// either the definition is supported and enables 64-bit off_t, -// or the definition is not supported and is ignored, in which case -// off_t does not change its default size for the target system -// (which may be 32-bit or 64-bit already). -// Thus it makes sense to have _FILE_OFFSET_BITS=64 defined by default, -// instead of listing every system that supports the definition. -// Those few systems, on which _FILE_OFFSET_BITS=64 is harmful, -// for example this definition causes compilation failure on those systems, -// should be exempt from defining _FILE_OFFSET_BITS by adding -// an appropriate #elif block above with the appropriate comment. -// -// _FILE_OFFSET_BITS must be defined before any headers are included -// to ensure that the definition is available to all included headers. -// That is required at least on Solaris, and possibly on other -// systems as well. -#define _FILE_OFFSET_BITS 64 -#endif +// Defining _FILE_OFFSET_BITS=64 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. +// +// At the time of this comment writing (March 2018), on most systems +// _FILE_OFFSET_BITS=64 definition is harmless: +// either the definition is supported and enables 64-bit off_t, +// or the definition is not supported and is ignored, in which case +// off_t does not change its default size for the target system +// (which may be 32-bit or 64-bit already). +// Thus it makes sense to have _FILE_OFFSET_BITS=64 defined by default, +// instead of listing every system that supports the definition. +// Those few systems, on which _FILE_OFFSET_BITS=64 is harmful, +// for example this definition causes compilation failure on those systems, +// should be exempt from defining _FILE_OFFSET_BITS by adding +// an appropriate #elif block above with the appropriate comment. +// +// _FILE_OFFSET_BITS must be defined before any headers are included +// to ensure that the definition is available to all included headers. +// That is required at least on Solaris, and possibly on other +// systems as well. +#define _FILE_OFFSET_BITS 64 #endif - -// 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 - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#ifndef _POSIX_PTHREAD_SEMANTICS -# define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r()needs this -#endif - -#include <boost/filesystem/operations.hpp> -#include <boost/scoped_array.hpp> -#include <boost/detail/workaround.hpp> -#include <limits> -#include <vector> -#include <cstdlib> // for malloc, free -#include <cstring> -#include <cstdio> // for remove, rename -#if defined(__QNXNTO__) // see ticket #5355 -# include <stdio.h> -#endif -#include <cerrno> - -#ifdef BOOST_FILEYSTEM_INCLUDE_IOSTREAM -# include <iostream> -#endif - -namespace fs = boost::filesystem; -using boost::filesystem::path; -using boost::filesystem::filesystem_error; -using boost::filesystem::perms; -using boost::system::error_code; -using boost::system::error_category; -using boost::system::system_category; -using std::string; -using std::wstring; - -# ifdef BOOST_POSIX_API - -# include <sys/types.h> -# include <sys/stat.h> -# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) \ - && !defined(__VXWORKS__) -# include <sys/statvfs.h> -# define BOOST_STATVFS statvfs -# define BOOST_STATVFS_F_FRSIZE vfs.f_frsize -# else -# ifdef __OpenBSD__ -# include <sys/param.h> -# elif defined(__ANDROID__) -# include <sys/vfs.h> -# endif -# if !defined(__VXWORKS__) -# include <sys/mount.h> -# endif -# 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" - -# else // BOOST_WINDOW_API - -# if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER) - // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501. - // See MinGW's windef.h -# define WINVER 0x501 -# endif -# include <cwchar> -# include <io.h> -# include <windows.h> -# include <winnt.h> -# if !defined(_WIN32_WINNT) -# define _WIN32_WINNT 0x0500 -# endif -# if defined(__BORLANDC__) || defined(__MWERKS__) -# if defined(__BORLANDC__) - using std::time_t; -# endif -# include <utime.h> -# else -# include <sys/utime.h> -# endif - -// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the -// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided -// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx - -#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) // mingw winnt.h does provide the defs - -#define SYMLINK_FLAG_RELATIVE 1 - -typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - /* Example of distinction between substitute and print names: - mklink /d ldrive c:\ - SubstituteName: c:\\??\ - PrintName: c:\ - */ - } SymbolicLinkReparseBuffer; - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; - -#define REPARSE_DATA_BUFFER_HEADER_SIZE \ - FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) - -#endif - -#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 ) -#endif - -# ifndef FSCTL_GET_REPARSE_POINT -# define FSCTL_GET_REPARSE_POINT 0x900a8 -# endif - -# ifndef IO_REPARSE_TAG_SYMLINK -# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) -# endif - -inline std::wstring wgetenv(const wchar_t* name) -{ - // use vector since for C++03 basic_string is not required to be contiguous - std::vector<wchar_t> buf(::GetEnvironmentVariableW(name, NULL, 0)); - - // C++03 vector does not have data() so use &buf[0] - return (buf.empty() - || ::GetEnvironmentVariableW(name, &buf[0], static_cast<DWORD>(buf.size())) == 0) - ? std::wstring() : std::wstring(&buf[0]); -} - -# endif // BOOST_WINDOWS_API - -// 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 -# define BOOST_FILESYSTEM_STATUS_CACHE -# endif - -// POSIX/Windows macros ----------------------------------------------------// - -// Portions of the POSIX and Windows API's are very similar, except for name, -// order of arguments, and meaning of zero/non-zero returns. The macros below -// abstract away those differences. They follow Windows naming and order of -// arguments, and return true to indicate no error occurred. [POSIX naming, -// order of arguments, and meaning of return were followed initially, but -// found to be less clear and cause more coding errors.] - -# if defined(BOOST_POSIX_API) - -typedef int err_t; - -// POSIX uses a 0 return to indicate success -# define BOOST_ERRNO errno -# define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0) -# define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0) -# define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0) -# define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0) -# define BOOST_REMOVE_DIRECTORY(P)(::rmdir(P)== 0) -# define BOOST_DELETE_FILE(P)(::unlink(P)== 0) -# define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\ - || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) -# define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) -# define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) -# define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) - -# define BOOST_ERROR_NOT_SUPPORTED ENOSYS -# define BOOST_ERROR_ALREADY_EXISTS EEXIST - -# else // BOOST_WINDOWS_API - -typedef DWORD err_t; - -// Windows uses a non-0 return to indicate success -# define BOOST_ERRNO ::GetLastError() -# define BOOST_SET_CURRENT_DIRECTORY(P)(::SetCurrentDirectoryW(P)!= 0) -# define BOOST_CREATE_DIRECTORY(P)(::CreateDirectoryW(P, 0)!= 0) -# define BOOST_CREATE_HARD_LINK(F,T)(create_hard_link_api(F, T, 0)!= 0) -# define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(create_symbolic_link_api(F, T, Flag)!= 0) -# define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0) -# define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0) -# define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0) -# define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0) -# define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)!= 0) -# define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0) -# define BOOST_READ_SYMLINK(P,T) - -# define BOOST_ERROR_ALREADY_EXISTS ERROR_ALREADY_EXISTS -# define BOOST_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED - -# endif - -//--------------------------------------------------------------------------------------// -// // -// helpers (all operating systems) // -// // -//--------------------------------------------------------------------------------------// - -namespace -{ - - fs::file_type query_file_type(const path& p, error_code* ec); - - boost::filesystem::directory_iterator end_dir_itr; - - // error handling helpers ----------------------------------------------------------// - - bool error(err_t error_num, error_code* ec, const char* message); - bool error(err_t error_num, const path& p, error_code* ec, const char* message); - bool error(err_t error_num, const path& p1, const path& p2, error_code* ec, - const char* message); - - const error_code ok; - - // error_num is value of errno on POSIX, error code (from ::GetLastError()) on Windows. - // Interface changed 30 Jan 15 to have caller supply error_num as ::SetLastError() - // values were apparently getting cleared before they could be retrieved by error(). - - bool error(err_t error_num, error_code* ec, const char* message) - { - if (!error_num) - { - if (ec != 0) ec->clear(); - } - else - { // error - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error(message, - error_code(error_num, system_category()))); - else - ec->assign(error_num, system_category()); - } - return error_num != 0; - } - - bool error(err_t error_num, const path& p, error_code* ec, const char* message) - { - if (!error_num) - { - if (ec != 0) ec->clear(); - } - else - { // error - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error(message, - p, error_code(error_num, system_category()))); - else - ec->assign(error_num, system_category()); - } - return error_num != 0; - } - - bool error(err_t error_num, const path& p1, const path& p2, error_code* ec, - const char* message) - { - if (!error_num) - { - if (ec != 0) ec->clear(); - } - else - { // error - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error(message, - p1, p2, error_code(error_num, system_category()))); - else - ec->assign(error_num, system_category()); - } - return error_num != 0; - } - - // general helpers -----------------------------------------------------------------// - - bool is_empty_directory(const path& p, error_code* ec) - { - return (ec != 0 ? fs::directory_iterator(p, *ec) : fs::directory_iterator(p)) - == end_dir_itr; - } - - bool not_found_error(int errval); // forward declaration - - // only called if directory exists - bool remove_directory(const path& p) // true if succeeds or not found - { - return BOOST_REMOVE_DIRECTORY(p.c_str()) - || not_found_error(BOOST_ERRNO); // mitigate possible file system race. See #11166 - } - - // only called if file exists - bool remove_file(const path& p) // true if succeeds or not found - { - return BOOST_DELETE_FILE(p.c_str()) - || not_found_error(BOOST_ERRNO); // mitigate possible file system race. See #11166 - } - - // called by remove and remove_all_aux - bool remove_file_or_directory(const path& p, fs::file_type type, error_code* ec) - // return true if file removed, false if not removed - { - if (type == fs::file_not_found) - { - if (ec != 0) ec->clear(); - return false; - } - - if (type == fs::directory_file -# ifdef BOOST_WINDOWS_API - || type == fs::_detail_directory_symlink -# endif - ) - { - if (error(!remove_directory(p) ? BOOST_ERRNO : 0, p, ec, - "boost::filesystem::remove")) - return false; - } - else - { - if (error(!remove_file(p) ? BOOST_ERRNO : 0, p, ec, - "boost::filesystem::remove")) - return false; - } - return true; - } - - boost::uintmax_t remove_all_aux(const path& p, fs::file_type type, - error_code* ec) - { - boost::uintmax_t count = 1; - if (type == fs::directory_file) // but not a directory symlink - { - fs::directory_iterator itr; - if (ec != 0) - { - itr = fs::directory_iterator(p, *ec); - if (*ec) - return count; - } - else - itr = fs::directory_iterator(p); - for (; itr != end_dir_itr; ++itr) - { - fs::file_type tmp_type = query_file_type(itr->path(), ec); - if (ec != 0 && *ec) - return count; - count += remove_all_aux(itr->path(), tmp_type, ec); - if (ec != 0 && *ec) - return count; - } - } - remove_file_or_directory(p, type, ec); - return count; - } - -#ifdef BOOST_POSIX_API - -//--------------------------------------------------------------------------------------// -// // -// POSIX-specific helpers // -// // -//--------------------------------------------------------------------------------------// - - const char dot = '.'; - - bool not_found_error(int errval) - { - return errno == ENOENT || errno == ENOTDIR; - } - - bool // true if ok - copy_file_api(const std::string& from_p, - const std::string& to_p, bool fail_if_exists) - { - 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 - - // bug fixed: code previously did a stat()on the from_file first, but that - // introduced a gratuitous race condition; the stat()is now done after the open() - - if ((infile = ::open(from_p.c_str(), O_RDONLY))< 0) - { return false; } - - struct stat from_stat; - if (::stat(from_p.c_str(), &from_stat)!= 0) - { - ::close(infile); - return false; - } - - int oflag = O_CREAT | O_WRONLY | O_TRUNC; - if (fail_if_exists) - oflag |= O_EXCL; - if ((outfile = ::open(to_p.c_str(), oflag, from_stat.st_mode))< 0) - { - int open_errno = errno; - BOOST_ASSERT(infile >= 0); - ::close(infile); - errno = open_errno; - return false; - } - - 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 - { - BOOST_ASSERT(sz_read - sz_write > 0); // #1 - // ticket 4438 claimed possible infinite loop if write returns 0. My analysis - // is that POSIX specifies 0 return only if 3rd arg is 0, and that will never - // happen due to loop entry and coninuation conditions. BOOST_ASSERT #1 above - // and #2 below added to verify that analysis. - if ((sz = ::write(outfile, buf.get() + sz_write, - sz_read - sz_write)) < 0) - { - sz_read = sz; // cause read loop termination - break; // and error reported after closes - } - BOOST_ASSERT(sz > 0); // #2 - sz_write += sz; - } while (sz_write < sz_read); - } - - if (::close(infile)< 0) - sz_read = -1; - if (::close(outfile)< 0) - sz_read = -1; - - return sz_read >= 0; - } - - inline fs::file_type query_file_type(const path& p, error_code* ec) - { - return fs::detail::symlink_status(p, ec).type(); - } - -# else - -//--------------------------------------------------------------------------------------// -// // -// Windows-specific helpers // -// // -//--------------------------------------------------------------------------------------// - - const std::size_t buf_size=128; - - const wchar_t dot = L'.'; - - bool not_found_error(int errval) - { - return errval == ERROR_FILE_NOT_FOUND - || errval == ERROR_PATH_NOT_FOUND - || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" - || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted - || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted - || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" - || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64 - || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32 - } - - static bool equal_extension( wchar_t const* p, wchar_t const (&x1)[ 5 ], wchar_t const (&x2)[ 5 ] ) - { - return - (p[0] == x1[0] || p[0] == x2[0]) && - (p[1] == x1[1] || p[1] == x2[1]) && - (p[2] == x1[2] || p[2] == x2[2]) && - (p[3] == x1[3] || p[3] == x2[3]) && - p[4] == 0; - } - - perms make_permissions(const path& p, DWORD attr) - { - perms prms = fs::owner_read | fs::group_read | fs::others_read; - if ((attr & FILE_ATTRIBUTE_READONLY) == 0) - prms |= fs::owner_write | fs::group_write | fs::others_write; - path ext = p.extension(); - wchar_t const* q = ext.c_str(); - if (equal_extension(q, L".exe", L".EXE") - || equal_extension(q, L".com", L".COM") - || equal_extension(q, L".bat", L".BAT") - || equal_extension(q, L".cmd", L".CMD")) - prms |= fs::owner_exe | fs::group_exe | fs::others_exe; - return prms; - } - - // 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); - } - - // 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); - } - }; - - HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess, - DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile) - { - return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, - hTemplateFile); - } - - bool is_reparse_point_a_symlink(const path& p) - { - handle_wrapper h(create_file_handle(p, FILE_READ_EA, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL)); - if (h.handle == INVALID_HANDLE_VALUE) - return false; - - boost::scoped_array<char> buf(new char [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); +#endif + +// 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 + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r()needs this +#endif + +#include <boost/filesystem/operations.hpp> +#include <boost/scoped_array.hpp> +#include <boost/detail/workaround.hpp> +#include <limits> +#include <vector> +#include <cstdlib> // for malloc, free +#include <cstring> +#include <cstdio> // for remove, rename +#if defined(__QNXNTO__) // see ticket #5355 +# include <stdio.h> +#endif +#include <cerrno> + +#ifdef BOOST_FILEYSTEM_INCLUDE_IOSTREAM +# include <iostream> +#endif + +namespace fs = boost::filesystem; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; +using boost::filesystem::perms; +using boost::system::error_code; +using boost::system::error_category; +using boost::system::system_category; +using std::string; +using std::wstring; + +# ifdef BOOST_POSIX_API + +# include <sys/types.h> +# include <sys/stat.h> +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) \ + && !defined(__VXWORKS__) +# include <sys/statvfs.h> +# define BOOST_STATVFS statvfs +# define BOOST_STATVFS_F_FRSIZE vfs.f_frsize +# else +# ifdef __OpenBSD__ +# include <sys/param.h> +# elif defined(__ANDROID__) +# include <sys/vfs.h> +# endif +# if !defined(__VXWORKS__) +# include <sys/mount.h> +# endif +# 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" + +# else // BOOST_WINDOW_API + +# if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER) + // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501. + // See MinGW's windef.h +# define WINVER 0x501 +# endif +# include <cwchar> +# include <io.h> +# include <windows.h> +# include <winnt.h> +# if !defined(_WIN32_WINNT) +# define _WIN32_WINNT 0x0500 +# endif +# if defined(__BORLANDC__) || defined(__MWERKS__) +# if defined(__BORLANDC__) + using std::time_t; +# endif +# include <utime.h> +# else +# include <sys/utime.h> +# endif + +// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the +// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided +// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx + +#if !defined(REPARSE_DATA_BUFFER_HEADER_SIZE) // mingw winnt.h does provide the defs + +#define SYMLINK_FLAG_RELATIVE 1 + +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + /* Example of distinction between substitute and print names: + mklink /d ldrive c:\ + SubstituteName: c:\\??\ + PrintName: c:\ + */ + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +#define REPARSE_DATA_BUFFER_HEADER_SIZE \ + FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer) + +#endif + +#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 ) +#endif + +# ifndef FSCTL_GET_REPARSE_POINT +# define FSCTL_GET_REPARSE_POINT 0x900a8 +# endif + +# ifndef IO_REPARSE_TAG_SYMLINK +# define IO_REPARSE_TAG_SYMLINK (0xA000000CL) +# endif + +inline std::wstring wgetenv(const wchar_t* name) +{ + // use vector since for C++03 basic_string is not required to be contiguous + std::vector<wchar_t> buf(::GetEnvironmentVariableW(name, NULL, 0)); + + // C++03 vector does not have data() so use &buf[0] + return (buf.empty() + || ::GetEnvironmentVariableW(name, &buf[0], static_cast<DWORD>(buf.size())) == 0) + ? std::wstring() : std::wstring(&buf[0]); +} + +# endif // BOOST_WINDOWS_API + +// 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 +# define BOOST_FILESYSTEM_STATUS_CACHE +# endif + +// POSIX/Windows macros ----------------------------------------------------// + +// Portions of the POSIX and Windows API's are very similar, except for name, +// order of arguments, and meaning of zero/non-zero returns. The macros below +// abstract away those differences. They follow Windows naming and order of +// arguments, and return true to indicate no error occurred. [POSIX naming, +// order of arguments, and meaning of return were followed initially, but +// found to be less clear and cause more coding errors.] + +# if defined(BOOST_POSIX_API) + +typedef int err_t; + +// POSIX uses a 0 return to indicate success +# define BOOST_ERRNO errno +# define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0) +# define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0) +# define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0) +# define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0) +# define BOOST_REMOVE_DIRECTORY(P)(::rmdir(P)== 0) +# define BOOST_DELETE_FILE(P)(::unlink(P)== 0) +# define BOOST_COPY_DIRECTORY(F,T)(!(::stat(from.c_str(), &from_stat)!= 0\ + || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) +# define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) +# define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) +# define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) + +# define BOOST_ERROR_NOT_SUPPORTED ENOSYS +# define BOOST_ERROR_ALREADY_EXISTS EEXIST + +# else // BOOST_WINDOWS_API + +typedef DWORD err_t; + +// Windows uses a non-0 return to indicate success +# define BOOST_ERRNO ::GetLastError() +# define BOOST_SET_CURRENT_DIRECTORY(P)(::SetCurrentDirectoryW(P)!= 0) +# define BOOST_CREATE_DIRECTORY(P)(::CreateDirectoryW(P, 0)!= 0) +# define BOOST_CREATE_HARD_LINK(F,T)(create_hard_link_api(F, T, 0)!= 0) +# define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(create_symbolic_link_api(F, T, Flag)!= 0) +# define BOOST_REMOVE_DIRECTORY(P)(::RemoveDirectoryW(P)!= 0) +# define BOOST_DELETE_FILE(P)(::DeleteFileW(P)!= 0) +# define BOOST_COPY_DIRECTORY(F,T)(::CreateDirectoryExW(F, T, 0)!= 0) +# define BOOST_COPY_FILE(F,T,FailIfExistsBool)(::CopyFileW(F, T, FailIfExistsBool)!= 0) +# define BOOST_MOVE_FILE(OLD,NEW)(::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING|MOVEFILE_COPY_ALLOWED)!= 0) +# define BOOST_RESIZE_FILE(P,SZ)(resize_file_api(P, SZ)!= 0) +# define BOOST_READ_SYMLINK(P,T) + +# define BOOST_ERROR_ALREADY_EXISTS ERROR_ALREADY_EXISTS +# define BOOST_ERROR_NOT_SUPPORTED ERROR_NOT_SUPPORTED + +# endif + +//--------------------------------------------------------------------------------------// +// // +// helpers (all operating systems) // +// // +//--------------------------------------------------------------------------------------// + +namespace +{ + + fs::file_type query_file_type(const path& p, error_code* ec); + + boost::filesystem::directory_iterator end_dir_itr; + + // error handling helpers ----------------------------------------------------------// + + bool error(err_t error_num, error_code* ec, const char* message); + bool error(err_t error_num, const path& p, error_code* ec, const char* message); + bool error(err_t error_num, const path& p1, const path& p2, error_code* ec, + const char* message); + + const error_code ok; + + // error_num is value of errno on POSIX, error code (from ::GetLastError()) on Windows. + // Interface changed 30 Jan 15 to have caller supply error_num as ::SetLastError() + // values were apparently getting cleared before they could be retrieved by error(). + + bool error(err_t error_num, error_code* ec, const char* message) + { + if (!error_num) + { + if (ec != 0) ec->clear(); + } + else + { // error + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error(message, + error_code(error_num, system_category()))); + else + ec->assign(error_num, system_category()); + } + return error_num != 0; + } + + bool error(err_t error_num, const path& p, error_code* ec, const char* message) + { + if (!error_num) + { + if (ec != 0) ec->clear(); + } + else + { // error + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error(message, + p, error_code(error_num, system_category()))); + else + ec->assign(error_num, system_category()); + } + return error_num != 0; + } + + bool error(err_t error_num, const path& p1, const path& p2, error_code* ec, + const char* message) + { + if (!error_num) + { + if (ec != 0) ec->clear(); + } + else + { // error + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error(message, + p1, p2, error_code(error_num, system_category()))); + else + ec->assign(error_num, system_category()); + } + return error_num != 0; + } + + // general helpers -----------------------------------------------------------------// + + bool is_empty_directory(const path& p, error_code* ec) + { + return (ec != 0 ? fs::directory_iterator(p, *ec) : fs::directory_iterator(p)) + == end_dir_itr; + } + + bool not_found_error(int errval); // forward declaration + + // only called if directory exists + bool remove_directory(const path& p) // true if succeeds or not found + { + return BOOST_REMOVE_DIRECTORY(p.c_str()) + || not_found_error(BOOST_ERRNO); // mitigate possible file system race. See #11166 + } - // Query the reparse data - DWORD dwRetLen; - BOOL result = ::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), - MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRetLen, NULL); - if (!result) return false; - - return reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag - == IO_REPARSE_TAG_SYMLINK - // Issue 9016 asked that NTFS directory junctions be recognized as directories. - // That is equivalent to recognizing them as symlinks, and then the normal symlink - // mechanism will take care of recognizing them as directories. - // - // Directory junctions are very similar to symlinks, but have some performance - // and other advantages over symlinks. They can be created from the command line - // with "mklink /j junction-name target-path". - || reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag - == IO_REPARSE_TAG_MOUNT_POINT; // aka "directory junction" or "junction" - } - - inline std::size_t get_full_path_name( - const path& src, std::size_t len, wchar_t* buf, wchar_t** p) - { - return static_cast<std::size_t>( - ::GetFullPathNameW(src.c_str(), static_cast<DWORD>(len), buf, p)); - } - - fs::file_status process_status_failure(const path& p, error_code* ec) - { - int errval(::GetLastError()); - if (ec != 0) // always report errval, even though some - ec->assign(errval, system_category()); // errval values are not status_errors - - if (not_found_error(errval)) - { - return fs::file_status(fs::file_not_found, fs::no_perms); - } - else if (errval == ERROR_SHARING_VIOLATION) - { - return fs::file_status(fs::type_unknown); - } - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", - p, error_code(errval, system_category()))); - return fs::file_status(fs::status_error); - } - - // differs from symlink_status() in that directory symlinks are reported as - // _detail_directory_symlink, as required on Windows by remove() and its helpers. - fs::file_type query_file_type(const path& p, error_code* ec) - { - DWORD attr(::GetFileAttributesW(p.c_str())); - if (attr == 0xFFFFFFFF) - { - return process_status_failure(p, ec).type(); - } - - if (ec != 0) ec->clear(); - - if (attr & FILE_ATTRIBUTE_REPARSE_POINT) - { - if (is_reparse_point_a_symlink(p)) - return (attr & FILE_ATTRIBUTE_DIRECTORY) - ? fs::_detail_directory_symlink - : fs::symlink_file; - return fs::reparse_file; - } - - return (attr & FILE_ATTRIBUTE_DIRECTORY) - ? fs::directory_file - : fs::regular_file; - } - - BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size) - { - handle_wrapper h(CreateFileW(p, GENERIC_WRITE, 0, 0, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0)); - LARGE_INTEGER sz; - sz.QuadPart = size; - return h.handle != INVALID_HANDLE_VALUE - && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN) - && ::SetEndOfFile(h.handle); - } - - // Windows kernel32.dll functions that may or may not be present - // must be accessed through pointers - - typedef BOOL (WINAPI *PtrCreateHardLinkW)( - /*__in*/ LPCWSTR lpFileName, - /*__in*/ LPCWSTR lpExistingFileName, - /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes - ); - - PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW( - ::GetProcAddress( - ::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); - - typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( - /*__in*/ LPCWSTR lpSymlinkFileName, - /*__in*/ LPCWSTR lpTargetFileName, - /*__in*/ DWORD dwFlags - ); - - PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( - ::GetProcAddress( - ::GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); - -#endif - -//#ifdef BOOST_WINDOWS_API -// -// -// 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; } -// -//#endif - -} // unnamed namespace - -//--------------------------------------------------------------------------------------// -// // -// operations functions declared in operations.hpp // -// in alphabetic order // -// // -//--------------------------------------------------------------------------------------// - -namespace boost -{ -namespace filesystem -{ - - BOOST_FILESYSTEM_DECL - path absolute(const path& p, const path& base) - { -// if ( p.empty() || p.is_absolute() ) -// return p; -// // recursively calling absolute is sub-optimal, but is simple -// path abs_base(base.is_absolute() ? base : absolute(base)); -//# ifdef BOOST_WINDOWS_API -// if (p.has_root_directory()) -// return abs_base.root_name() / p; -// // !p.has_root_directory -// if (p.has_root_name()) -// return p.root_name() -// / abs_base.root_directory() / abs_base.relative_path() / p.relative_path(); -// // !p.has_root_name() -//# endif -// return abs_base / p; - - // recursively calling absolute is sub-optimal, but is sure and simple - path abs_base(base.is_absolute() ? base : absolute(base)); - - // store expensive to compute values that are needed multiple times - path p_root_name (p.root_name()); - path base_root_name (abs_base.root_name()); - path p_root_directory (p.root_directory()); - - if (p.empty()) - return abs_base; - - if (!p_root_name.empty()) // p.has_root_name() - { - if (p_root_directory.empty()) // !p.has_root_directory() - return p_root_name / abs_base.root_directory() - / abs_base.relative_path() / p.relative_path(); - // p is absolute, so fall through to return p at end of block - } - - else if (!p_root_directory.empty()) // p.has_root_directory() - { -# ifdef BOOST_POSIX_API - // POSIX can have root name it it is a network path - if (base_root_name.empty()) // !abs_base.has_root_name() - return p; -# endif - return base_root_name / p; - } - - else - { - return abs_base / p; - } - - return p; // p.is_absolute() is true - } - -namespace detail -{ - 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 - } - - BOOST_FILESYSTEM_DECL - path canonical(const path& p, const path& base, system::error_code* ec) - { - path source (p.is_absolute() ? p : absolute(p, base)); - path root(source.root_path()); - path result; - - system::error_code local_ec; - file_status stat (status(source, local_ec)); - - if (stat.type() == fs::file_not_found) - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error( - "boost::filesystem::canonical", source, - error_code(system::errc::no_such_file_or_directory, system::generic_category()))); - ec->assign(system::errc::no_such_file_or_directory, system::generic_category()); - return result; - } - else if (local_ec) - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error( - "boost::filesystem::canonical", source, local_ec)); - *ec = local_ec; - return result; - } - - bool scan (true); - while (scan) - { - scan = false; - result.clear(); - for (path::iterator itr = source.begin(); itr != source.end(); ++itr) - { - if (*itr == dot_path()) - continue; - if (*itr == dot_dot_path()) - { - if (result != root) - result.remove_filename(); - continue; - } - - result /= *itr; - - bool is_sym (is_symlink(detail::symlink_status(result, ec))); - if (ec && *ec) - return path(); - - if (is_sym) - { - path link(detail::read_symlink(result, ec)); - if (ec && *ec) - return path(); - result.remove_filename(); - - if (link.is_absolute()) - { - for (++itr; itr != source.end(); ++itr) - link /= *itr; - source = link; - } - else // link is relative - { - path new_source(result); - new_source /= link; - for (++itr; itr != source.end(); ++itr) - new_source /= *itr; - source = new_source; - } - scan = true; // symlink causes scan to be restarted - break; - } - } - } - if (ec != 0) - ec->clear(); - BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); - return result; - } - - BOOST_FILESYSTEM_DECL - void copy(const path& from, const path& to, system::error_code* ec) - { - file_status s(symlink_status(from, ec)); - if (ec != 0 && *ec) return; - - if(is_symlink(s)) - { - copy_symlink(from, to, *ec); - } - else if(is_directory(s)) - { - copy_directory(from, to, *ec); - } - else if(is_regular_file(s)) - { - copy_file(from, to, fs::copy_option::fail_if_exists, *ec); - } - else - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", - from, to, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()))); - ec->assign(BOOST_ERROR_NOT_SUPPORTED, system_category()); - } - } - - BOOST_FILESYSTEM_DECL - void copy_directory(const path& from, const path& to, system::error_code* ec) - { -# ifdef BOOST_POSIX_API - struct stat from_stat; -# endif - error(!BOOST_COPY_DIRECTORY(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0, - from, to, ec, "boost::filesystem::copy_directory"); - } - - BOOST_FILESYSTEM_DECL - void copy_file(const path& from, const path& to, copy_option option, error_code* ec) - { - error(!BOOST_COPY_FILE(from.c_str(), to.c_str(), - option == fail_if_exists) ? BOOST_ERRNO : 0, - from, to, ec, "boost::filesystem::copy_file"); - } - - BOOST_FILESYSTEM_DECL - void copy_symlink(const path& existing_symlink, const path& new_symlink, - system::error_code* ec) - { -# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 - error(BOOST_ERROR_NOT_SUPPORTED, new_symlink, existing_symlink, ec, - "boost::filesystem::copy_symlink"); - -# else // modern Windows or BOOST_POSIX_API - path p(read_symlink(existing_symlink, ec)); - if (ec != 0 && *ec) return; - create_symlink(p, new_symlink, ec); - -# endif - } - - BOOST_FILESYSTEM_DECL - bool create_directories(const path& p, system::error_code* ec) - { - if (p.empty()) - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error( - "boost::filesystem::create_directories", p, - system::errc::make_error_code(system::errc::invalid_argument))); - else - ec->assign(system::errc::invalid_argument, system::generic_category()); - return false; - } - - if (p.filename_is_dot() || p.filename_is_dot_dot()) - return create_directories(p.parent_path(), ec); - - error_code local_ec; - file_status p_status = status(p, local_ec); - - if (p_status.type() == directory_file) - { - if (ec != 0) - ec->clear(); - return false; - } - - path parent = p.parent_path(); - BOOST_ASSERT_MSG(parent != p, "internal error: p == p.parent_path()"); - if (!parent.empty()) - { - // determine if the parent exists - file_status parent_status = status(parent, local_ec); - - // if the parent does not exist, create the parent - if (parent_status.type() == file_not_found) - { - create_directories(parent, local_ec); - if (local_ec) - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error( - "boost::filesystem::create_directories", parent, local_ec)); - else - *ec = local_ec; - return false; - } - } - } - - // create the directory - return create_directory(p, ec); - } - - BOOST_FILESYSTEM_DECL - bool create_directory(const path& p, error_code* ec) - { - if (BOOST_CREATE_DIRECTORY(p.c_str())) - { - if (ec != 0) - ec->clear(); - return true; - } - - // attempt to create directory failed - int errval(BOOST_ERRNO); // save reason for failure - error_code dummy; - - if (is_directory(p, dummy)) - { - if (ec != 0) - ec->clear(); - return false; - } - - // attempt to create directory failed && it doesn't already exist - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directory", - p, error_code(errval, system_category()))); - else - ec->assign(errval, system_category()); - - return false; - } - - BOOST_FILESYSTEM_DECL - void create_directory_symlink(const path& to, const path& from, - system::error_code* ec) - { -# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008 - - error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, - "boost::filesystem::create_directory_symlink"); -# else - -# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600 - // see if actually supported by Windows runtime dll - if (error(!create_symbolic_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec, - "boost::filesystem::create_directory_symlink")) - return; -# endif - - error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), - SYMBOLIC_LINK_FLAG_DIRECTORY) ? BOOST_ERRNO : 0, - to, from, ec, "boost::filesystem::create_directory_symlink"); -# endif - } - - BOOST_FILESYSTEM_DECL - void create_hard_link(const path& to, const path& from, error_code* ec) - { - -# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K - - error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, - "boost::filesystem::create_hard_link"); -# else - -# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0500 - // see if actually supported by Windows runtime dll - if (error(!create_hard_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec, - "boost::filesystem::create_hard_link")) - return; -# endif - - error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0, to, from, ec, - "boost::filesystem::create_hard_link"); -# endif - } - - BOOST_FILESYSTEM_DECL - void create_symlink(const path& to, const path& from, error_code* ec) - { -# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008 - error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, - "boost::filesystem::create_directory_symlink"); -# else - -# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600 - // see if actually supported by Windows runtime dll - if (error(!create_symbolic_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec, - "boost::filesystem::create_symlink")) - return; -# endif - - error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0) ? BOOST_ERRNO : 0, - to, from, ec, "boost::filesystem::create_symlink"); -# endif - } - - BOOST_FILESYSTEM_DECL - path current_path(error_code* ec) - { -# ifdef BOOST_POSIX_API - path cur; - for (long path_max = 128;; path_max *=2)// loop 'til buffer large enough + // only called if file exists + bool remove_file(const path& p) // true if succeeds or not found + { + return BOOST_DELETE_FILE(p.c_str()) + || not_found_error(BOOST_ERRNO); // mitigate possible file system race. See #11166 + } + + // called by remove and remove_all_aux + bool remove_file_or_directory(const path& p, fs::file_type type, error_code* ec) + // return true if file removed, false if not removed + { + if (type == fs::file_not_found) + { + if (ec != 0) ec->clear(); + return false; + } + + if (type == fs::directory_file +# ifdef BOOST_WINDOWS_API + || type == fs::_detail_directory_symlink +# endif + ) + { + if (error(!remove_directory(p) ? BOOST_ERRNO : 0, p, ec, + "boost::filesystem::remove")) + return false; + } + else + { + if (error(!remove_file(p) ? BOOST_ERRNO : 0, p, ec, + "boost::filesystem::remove")) + return false; + } + return true; + } + + boost::uintmax_t remove_all_aux(const path& p, fs::file_type type, + error_code* ec) + { + boost::uintmax_t count = 1; + if (type == fs::directory_file) // but not a directory symlink + { + fs::directory_iterator itr; + if (ec != 0) + { + itr = fs::directory_iterator(p, *ec); + if (*ec) + return count; + } + else + itr = fs::directory_iterator(p); + for (; itr != end_dir_itr; ++itr) + { + fs::file_type tmp_type = query_file_type(itr->path(), ec); + if (ec != 0 && *ec) + return count; + count += remove_all_aux(itr->path(), tmp_type, ec); + if (ec != 0 && *ec) + return count; + } + } + remove_file_or_directory(p, type, ec); + return count; + } + +#ifdef BOOST_POSIX_API + +//--------------------------------------------------------------------------------------// +// // +// POSIX-specific helpers // +// // +//--------------------------------------------------------------------------------------// + + const char dot = '.'; + + bool not_found_error(int errval) + { + return errno == ENOENT || errno == ENOTDIR; + } + + bool // true if ok + copy_file_api(const std::string& from_p, + const std::string& to_p, bool fail_if_exists) + { + 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 + + // bug fixed: code previously did a stat()on the from_file first, but that + // introduced a gratuitous race condition; the stat()is now done after the open() + + if ((infile = ::open(from_p.c_str(), O_RDONLY))< 0) + { return false; } + + struct stat from_stat; + if (::stat(from_p.c_str(), &from_stat)!= 0) { - 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 (error(errno != ERANGE ? errno : 0 - // 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 - , ec, "boost::filesystem::current_path")) + ::close(infile); + return false; + } + + int oflag = O_CREAT | O_WRONLY | O_TRUNC; + if (fail_if_exists) + oflag |= O_EXCL; + if ((outfile = ::open(to_p.c_str(), oflag, from_stat.st_mode))< 0) + { + int open_errno = errno; + BOOST_ASSERT(infile >= 0); + ::close(infile); + errno = open_errno; + return false; + } + + 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 + { + BOOST_ASSERT(sz_read - sz_write > 0); // #1 + // ticket 4438 claimed possible infinite loop if write returns 0. My analysis + // is that POSIX specifies 0 return only if 3rd arg is 0, and that will never + // happen due to loop entry and coninuation conditions. BOOST_ASSERT #1 above + // and #2 below added to verify that analysis. + if ((sz = ::write(outfile, buf.get() + sz_write, + sz_read - sz_write)) < 0) { - break; - } - } - else - { - cur = buf.get(); - if (ec != 0) ec->clear(); - break; - } - } - return cur; - -# else - DWORD sz; - if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0)sz = 1; - boost::scoped_array<path::value_type> buf(new path::value_type[sz]); - error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, - "boost::filesystem::current_path"); - return path(buf.get()); -# endif - } - - - BOOST_FILESYSTEM_DECL - void current_path(const path& p, system::error_code* ec) - { - error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::current_path"); - } - - BOOST_FILESYSTEM_DECL - bool equivalent(const path& p1, const path& p2, system::error_code* ec) - { -# ifdef BOOST_POSIX_API - struct stat s2; - int e2(::stat(p2.c_str(), &s2)); - struct stat s1; - int e1(::stat(p1.c_str(), &s1)); - - if (e1 != 0 || e2 != 0) - { - // if one is invalid and the other isn't then they aren't equivalent, - // but if both are invalid then it is an error - error (e1 != 0 && e2 != 0, p1, p2, ec, "boost::filesystem::equivalent"); - return false; - } - - // both stats now known to be valid - return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino - // According to the POSIX stat specs, "The st_ino and st_dev fields - // taken together uniquely identify the file within the system." - // Just to be sure, size and mod time are also checked. - && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; - -# else // Windows - - // 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. - - // p2 is done first, so any error reported is for p1 - handle_wrapper h2( - create_file_handle( - p2.c_str(), - 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - - handle_wrapper h1( - create_file_handle( - p1.c_str(), - 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); - - if (h1.handle == INVALID_HANDLE_VALUE - || h2.handle == INVALID_HANDLE_VALUE) - { - // if one is invalid and the other isn't, then they aren't equivalent, - // but if both are invalid then it is an error - error((h1.handle == INVALID_HANDLE_VALUE - && h2.handle == INVALID_HANDLE_VALUE) ? BOOST_ERROR_NOT_SUPPORTED : 0, p1, p2, ec, - "boost::filesystem::equivalent"); - return false; - } - - // at this point, both handles are known to be valid - - BY_HANDLE_FILE_INFORMATION info1, info2; - - if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0, - p1, p2, ec, "boost::filesystem::equivalent")) - return false; - - if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0, - p1, p2, ec, "boost::filesystem::equivalent")) - return 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 - info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber - && info1.nFileIndexHigh == info2.nFileIndexHigh - && info1.nFileIndexLow == info2.nFileIndexLow - && info1.nFileSizeHigh == info2.nFileSizeHigh - && info1.nFileSizeLow == info2.nFileSizeLow - && info1.ftLastWriteTime.dwLowDateTime - == info2.ftLastWriteTime.dwLowDateTime - && info1.ftLastWriteTime.dwHighDateTime - == info2.ftLastWriteTime.dwHighDateTime; - -# endif - } - - BOOST_FILESYSTEM_DECL - boost::uintmax_t file_size(const path& p, error_code* ec) - { -# ifdef BOOST_POSIX_API - - struct stat path_stat; - if (error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::file_size")) - return static_cast<boost::uintmax_t>(-1); - if (error(!S_ISREG(path_stat.st_mode) ? EPERM : 0, - p, ec, "boost::filesystem::file_size")) - return static_cast<boost::uintmax_t>(-1); - - return static_cast<boost::uintmax_t>(path_stat.st_size); - -# else // Windows - - // assume uintmax_t is 64-bits on all Windows compilers - - WIN32_FILE_ATTRIBUTE_DATA fad; - - if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0 - ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::file_size")) - return static_cast<boost::uintmax_t>(-1); - - if (error((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!= 0 - ? ERROR_NOT_SUPPORTED : 0, p, ec, "boost::filesystem::file_size")) - return static_cast<boost::uintmax_t>(-1); - - return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh) - << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow; -# endif - } - - BOOST_FILESYSTEM_DECL - boost::uintmax_t hard_link_count(const path& p, system::error_code* ec) - { -# ifdef BOOST_POSIX_API - - struct stat path_stat; - return error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::hard_link_count") - ? 0 - : static_cast<boost::uintmax_t>(path_stat.st_nlink); - -# else // Windows - - // Link count info is only available through GetFileInformationByHandle - BY_HANDLE_FILE_INFORMATION info; - handle_wrapper h( - create_file_handle(p.c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); + sz_read = sz; // cause read loop termination + break; // and error reported after closes + } + BOOST_ASSERT(sz > 0); // #2 + sz_write += sz; + } while (sz_write < sz_read); + } + + if (::close(infile)< 0) + sz_read = -1; + if (::close(outfile)< 0) + sz_read = -1; + + return sz_read >= 0; + } + + inline fs::file_type query_file_type(const path& p, error_code* ec) + { + return fs::detail::symlink_status(p, ec).type(); + } + +# else + +//--------------------------------------------------------------------------------------// +// // +// Windows-specific helpers // +// // +//--------------------------------------------------------------------------------------// + + const std::size_t buf_size=128; + + const wchar_t dot = L'.'; + + bool not_found_error(int errval) + { + return errval == ERROR_FILE_NOT_FOUND + || errval == ERROR_PATH_NOT_FOUND + || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" + || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted + || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted + || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" + || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64 + || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32 + } + + static bool equal_extension( wchar_t const* p, wchar_t const (&x1)[ 5 ], wchar_t const (&x2)[ 5 ] ) + { + return + (p[0] == x1[0] || p[0] == x2[0]) && + (p[1] == x1[1] || p[1] == x2[1]) && + (p[2] == x1[2] || p[2] == x2[2]) && + (p[3] == x1[3] || p[3] == x2[3]) && + p[4] == 0; + } + + perms make_permissions(const path& p, DWORD attr) + { + perms prms = fs::owner_read | fs::group_read | fs::others_read; + if ((attr & FILE_ATTRIBUTE_READONLY) == 0) + prms |= fs::owner_write | fs::group_write | fs::others_write; + path ext = p.extension(); + wchar_t const* q = ext.c_str(); + if (equal_extension(q, L".exe", L".EXE") + || equal_extension(q, L".com", L".COM") + || equal_extension(q, L".bat", L".BAT") + || equal_extension(q, L".cmd", L".CMD")) + prms |= fs::owner_exe | fs::group_exe | fs::others_exe; + return prms; + } + + // 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); + } + + // 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); + } + }; + + HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess, + DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile) + { + return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); + } + + bool is_reparse_point_a_symlink(const path& p) + { + handle_wrapper h(create_file_handle(p, FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL)); + if (h.handle == INVALID_HANDLE_VALUE) + return false; + + boost::scoped_array<char> buf(new char [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); + + // Query the reparse data + DWORD dwRetLen; + BOOL result = ::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dwRetLen, NULL); + if (!result) return false; + + return reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag + == IO_REPARSE_TAG_SYMLINK + // Issue 9016 asked that NTFS directory junctions be recognized as directories. + // That is equivalent to recognizing them as symlinks, and then the normal symlink + // mechanism will take care of recognizing them as directories. + // + // Directory junctions are very similar to symlinks, but have some performance + // and other advantages over symlinks. They can be created from the command line + // with "mklink /j junction-name target-path". + || reinterpret_cast<const REPARSE_DATA_BUFFER*>(buf.get())->ReparseTag + == IO_REPARSE_TAG_MOUNT_POINT; // aka "directory junction" or "junction" + } + + inline std::size_t get_full_path_name( + const path& src, std::size_t len, wchar_t* buf, wchar_t** p) + { + return static_cast<std::size_t>( + ::GetFullPathNameW(src.c_str(), static_cast<DWORD>(len), buf, p)); + } + + fs::file_status process_status_failure(const path& p, error_code* ec) + { + int errval(::GetLastError()); + if (ec != 0) // always report errval, even though some + ec->assign(errval, system_category()); // errval values are not status_errors + + if (not_found_error(errval)) + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + else if (errval == ERROR_SHARING_VIOLATION) + { + return fs::file_status(fs::type_unknown); + } + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", + p, error_code(errval, system_category()))); + return fs::file_status(fs::status_error); + } + + // differs from symlink_status() in that directory symlinks are reported as + // _detail_directory_symlink, as required on Windows by remove() and its helpers. + fs::file_type query_file_type(const path& p, error_code* ec) + { + DWORD attr(::GetFileAttributesW(p.c_str())); + if (attr == 0xFFFFFFFF) + { + return process_status_failure(p, ec).type(); + } + + if (ec != 0) ec->clear(); + + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) + { + if (is_reparse_point_a_symlink(p)) + return (attr & FILE_ATTRIBUTE_DIRECTORY) + ? fs::_detail_directory_symlink + : fs::symlink_file; + return fs::reparse_file; + } + + return (attr & FILE_ATTRIBUTE_DIRECTORY) + ? fs::directory_file + : fs::regular_file; + } + + BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size) + { + handle_wrapper h(CreateFileW(p, GENERIC_WRITE, 0, 0, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0)); + LARGE_INTEGER sz; + sz.QuadPart = size; + return h.handle != INVALID_HANDLE_VALUE + && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN) + && ::SetEndOfFile(h.handle); + } + + // Windows kernel32.dll functions that may or may not be present + // must be accessed through pointers + + typedef BOOL (WINAPI *PtrCreateHardLinkW)( + /*__in*/ LPCWSTR lpFileName, + /*__in*/ LPCWSTR lpExistingFileName, + /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes + ); + + PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW( + ::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); + + typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags + ); + + PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( + ::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); + +#endif + +//#ifdef BOOST_WINDOWS_API +// +// +// 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; } +// +//#endif + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// operations functions declared in operations.hpp // +// in alphabetic order // +// // +//--------------------------------------------------------------------------------------// + +namespace boost +{ +namespace filesystem +{ + + BOOST_FILESYSTEM_DECL + path absolute(const path& p, const path& base) + { +// if ( p.empty() || p.is_absolute() ) +// return p; +// // recursively calling absolute is sub-optimal, but is simple +// path abs_base(base.is_absolute() ? base : absolute(base)); +//# ifdef BOOST_WINDOWS_API +// if (p.has_root_directory()) +// return abs_base.root_name() / p; +// // !p.has_root_directory +// if (p.has_root_name()) +// return p.root_name() +// / abs_base.root_directory() / abs_base.relative_path() / p.relative_path(); +// // !p.has_root_name() +//# endif +// return abs_base / p; + + // recursively calling absolute is sub-optimal, but is sure and simple + path abs_base(base.is_absolute() ? base : absolute(base)); + + // store expensive to compute values that are needed multiple times + path p_root_name (p.root_name()); + path base_root_name (abs_base.root_name()); + path p_root_directory (p.root_directory()); + + if (p.empty()) + return abs_base; + + if (!p_root_name.empty()) // p.has_root_name() + { + if (p_root_directory.empty()) // !p.has_root_directory() + return p_root_name / abs_base.root_directory() + / abs_base.relative_path() / p.relative_path(); + // p is absolute, so fall through to return p at end of block + } + + else if (!p_root_directory.empty()) // p.has_root_directory() + { +# ifdef BOOST_POSIX_API + // POSIX can have root name it it is a network path + if (base_root_name.empty()) // !abs_base.has_root_name() + return p; +# endif + return base_root_name / p; + } + + else + { + return abs_base / p; + } + + return p; // p.is_absolute() is true + } + +namespace detail +{ + 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 + } + + BOOST_FILESYSTEM_DECL + path canonical(const path& p, const path& base, system::error_code* ec) + { + path source (p.is_absolute() ? p : absolute(p, base)); + path root(source.root_path()); + path result; + + system::error_code local_ec; + file_status stat (status(source, local_ec)); + + if (stat.type() == fs::file_not_found) + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::canonical", source, + error_code(system::errc::no_such_file_or_directory, system::generic_category()))); + ec->assign(system::errc::no_such_file_or_directory, system::generic_category()); + return result; + } + else if (local_ec) + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::canonical", source, local_ec)); + *ec = local_ec; + return result; + } + + bool scan (true); + while (scan) + { + scan = false; + result.clear(); + for (path::iterator itr = source.begin(); itr != source.end(); ++itr) + { + if (*itr == dot_path()) + continue; + if (*itr == dot_dot_path()) + { + if (result != root) + result.remove_filename(); + continue; + } + + result /= *itr; + + bool is_sym (is_symlink(detail::symlink_status(result, ec))); + if (ec && *ec) + return path(); + + if (is_sym) + { + path link(detail::read_symlink(result, ec)); + if (ec && *ec) + return path(); + result.remove_filename(); + + if (link.is_absolute()) + { + for (++itr; itr != source.end(); ++itr) + link /= *itr; + source = link; + } + else // link is relative + { + path new_source(result); + new_source /= link; + for (++itr; itr != source.end(); ++itr) + new_source /= *itr; + source = new_source; + } + scan = true; // symlink causes scan to be restarted + break; + } + } + } + if (ec != 0) + ec->clear(); + BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); + return result; + } + + BOOST_FILESYSTEM_DECL + void copy(const path& from, const path& to, system::error_code* ec) + { + file_status s(symlink_status(from, ec)); + if (ec != 0 && *ec) return; + + if(is_symlink(s)) + { + copy_symlink(from, to, *ec); + } + else if(is_directory(s)) + { + copy_directory(from, to, *ec); + } + else if(is_regular_file(s)) + { + copy_file(from, to, fs::copy_option::fail_if_exists, *ec); + } + else + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", + from, to, error_code(BOOST_ERROR_NOT_SUPPORTED, system_category()))); + ec->assign(BOOST_ERROR_NOT_SUPPORTED, system_category()); + } + } + + BOOST_FILESYSTEM_DECL + void copy_directory(const path& from, const path& to, system::error_code* ec) + { +# ifdef BOOST_POSIX_API + struct stat from_stat; +# endif + error(!BOOST_COPY_DIRECTORY(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0, + from, to, ec, "boost::filesystem::copy_directory"); + } + + BOOST_FILESYSTEM_DECL + void copy_file(const path& from, const path& to, copy_option option, error_code* ec) + { + error(!BOOST_COPY_FILE(from.c_str(), to.c_str(), + option == fail_if_exists) ? BOOST_ERRNO : 0, + from, to, ec, "boost::filesystem::copy_file"); + } + + BOOST_FILESYSTEM_DECL + void copy_symlink(const path& existing_symlink, const path& new_symlink, + system::error_code* ec) + { +# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 + error(BOOST_ERROR_NOT_SUPPORTED, new_symlink, existing_symlink, ec, + "boost::filesystem::copy_symlink"); + +# else // modern Windows or BOOST_POSIX_API + path p(read_symlink(existing_symlink, ec)); + if (ec != 0 && *ec) return; + create_symlink(p, new_symlink, ec); + +# endif + } + + BOOST_FILESYSTEM_DECL + bool create_directories(const path& p, system::error_code* ec) + { + if (p.empty()) + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::create_directories", p, + system::errc::make_error_code(system::errc::invalid_argument))); + else + ec->assign(system::errc::invalid_argument, system::generic_category()); + return false; + } + + if (p.filename_is_dot() || p.filename_is_dot_dot()) + return create_directories(p.parent_path(), ec); + + error_code local_ec; + file_status p_status = status(p, local_ec); + + if (p_status.type() == directory_file) + { + if (ec != 0) + ec->clear(); + return false; + } + + path parent = p.parent_path(); + BOOST_ASSERT_MSG(parent != p, "internal error: p == p.parent_path()"); + if (!parent.empty()) + { + // determine if the parent exists + file_status parent_status = status(parent, local_ec); + + // if the parent does not exist, create the parent + if (parent_status.type() == file_not_found) + { + create_directories(parent, local_ec); + if (local_ec) + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::create_directories", parent, local_ec)); + else + *ec = local_ec; + return false; + } + } + } + + // create the directory + return create_directory(p, ec); + } + + BOOST_FILESYSTEM_DECL + bool create_directory(const path& p, error_code* ec) + { + if (BOOST_CREATE_DIRECTORY(p.c_str())) + { + if (ec != 0) + ec->clear(); + return true; + } + + // attempt to create directory failed + int errval(BOOST_ERRNO); // save reason for failure + error_code dummy; + + if (is_directory(p, dummy)) + { + if (ec != 0) + ec->clear(); + return false; + } + + // attempt to create directory failed && it doesn't already exist + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directory", + p, error_code(errval, system_category()))); + else + ec->assign(errval, system_category()); + + return false; + } + + BOOST_FILESYSTEM_DECL + void create_directory_symlink(const path& to, const path& from, + system::error_code* ec) + { +# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008 + + error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, + "boost::filesystem::create_directory_symlink"); +# else + +# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600 + // see if actually supported by Windows runtime dll + if (error(!create_symbolic_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec, + "boost::filesystem::create_directory_symlink")) + return; +# endif + + error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), + SYMBOLIC_LINK_FLAG_DIRECTORY) ? BOOST_ERRNO : 0, + to, from, ec, "boost::filesystem::create_directory_symlink"); +# endif + } + + BOOST_FILESYSTEM_DECL + void create_hard_link(const path& to, const path& from, error_code* ec) + { + +# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K + + error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, + "boost::filesystem::create_hard_link"); +# else + +# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0500 + // see if actually supported by Windows runtime dll + if (error(!create_hard_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec, + "boost::filesystem::create_hard_link")) + return; +# endif + + error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0, to, from, ec, + "boost::filesystem::create_hard_link"); +# endif + } + + BOOST_FILESYSTEM_DECL + void create_symlink(const path& to, const path& from, error_code* ec) + { +# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008 + error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, + "boost::filesystem::create_directory_symlink"); +# else + +# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT >= 0x0600 + // see if actually supported by Windows runtime dll + if (error(!create_symbolic_link_api ? BOOST_ERROR_NOT_SUPPORTED : 0, to, from, ec, + "boost::filesystem::create_symlink")) + return; +# endif + + error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0) ? BOOST_ERRNO : 0, + to, from, ec, "boost::filesystem::create_symlink"); +# endif + } + + BOOST_FILESYSTEM_DECL + path current_path(error_code* ec) + { +# ifdef BOOST_POSIX_API + path cur; + for (long path_max = 128;; 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 (error(errno != ERANGE ? errno : 0 + // 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 + , ec, "boost::filesystem::current_path")) + { + break; + } + } + else + { + cur = buf.get(); + if (ec != 0) ec->clear(); + break; + } + } + return cur; + +# else + DWORD sz; + if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0)sz = 1; + boost::scoped_array<path::value_type> buf(new path::value_type[sz]); + error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, + "boost::filesystem::current_path"); + return path(buf.get()); +# endif + } + + + BOOST_FILESYSTEM_DECL + void current_path(const path& p, system::error_code* ec) + { + error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::current_path"); + } + + BOOST_FILESYSTEM_DECL + bool equivalent(const path& p1, const path& p2, system::error_code* ec) + { +# ifdef BOOST_POSIX_API + struct stat s2; + int e2(::stat(p2.c_str(), &s2)); + struct stat s1; + int e1(::stat(p1.c_str(), &s1)); + + if (e1 != 0 || e2 != 0) + { + // if one is invalid and the other isn't then they aren't equivalent, + // but if both are invalid then it is an error + error (e1 != 0 && e2 != 0, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + // both stats now known to be valid + return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino + // According to the POSIX stat specs, "The st_ino and st_dev fields + // taken together uniquely identify the file within the system." + // Just to be sure, size and mod time are also checked. + && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; + +# else // Windows + + // 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. + + // p2 is done first, so any error reported is for p1 + handle_wrapper h2( + create_file_handle( + p2.c_str(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + + handle_wrapper h1( + create_file_handle( + p1.c_str(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + + if (h1.handle == INVALID_HANDLE_VALUE + || h2.handle == INVALID_HANDLE_VALUE) + { + // if one is invalid and the other isn't, then they aren't equivalent, + // but if both are invalid then it is an error + error((h1.handle == INVALID_HANDLE_VALUE + && h2.handle == INVALID_HANDLE_VALUE) ? BOOST_ERROR_NOT_SUPPORTED : 0, p1, p2, ec, + "boost::filesystem::equivalent"); + return false; + } + + // at this point, both handles are known to be valid + + BY_HANDLE_FILE_INFORMATION info1, info2; + + if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0, + p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0, + p1, p2, ec, "boost::filesystem::equivalent")) + return 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 + info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber + && info1.nFileIndexHigh == info2.nFileIndexHigh + && info1.nFileIndexLow == info2.nFileIndexLow + && info1.nFileSizeHigh == info2.nFileSizeHigh + && info1.nFileSizeLow == info2.nFileSizeLow + && info1.ftLastWriteTime.dwLowDateTime + == info2.ftLastWriteTime.dwLowDateTime + && info1.ftLastWriteTime.dwHighDateTime + == info2.ftLastWriteTime.dwHighDateTime; + +# endif + } + + BOOST_FILESYSTEM_DECL + boost::uintmax_t file_size(const path& p, error_code* ec) + { +# ifdef BOOST_POSIX_API + + struct stat path_stat; + if (error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::file_size")) + return static_cast<boost::uintmax_t>(-1); + if (error(!S_ISREG(path_stat.st_mode) ? EPERM : 0, + p, ec, "boost::filesystem::file_size")) + return static_cast<boost::uintmax_t>(-1); + + return static_cast<boost::uintmax_t>(path_stat.st_size); + +# else // Windows + + // assume uintmax_t is 64-bits on all Windows compilers + + WIN32_FILE_ATTRIBUTE_DATA fad; + + if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0 + ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::file_size")) + return static_cast<boost::uintmax_t>(-1); + + if (error((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!= 0 + ? ERROR_NOT_SUPPORTED : 0, p, ec, "boost::filesystem::file_size")) + return static_cast<boost::uintmax_t>(-1); + + return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh) + << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow; +# endif + } + + BOOST_FILESYSTEM_DECL + boost::uintmax_t hard_link_count(const path& p, system::error_code* ec) + { +# ifdef BOOST_POSIX_API + + struct stat path_stat; + return error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::hard_link_count") + ? 0 + : static_cast<boost::uintmax_t>(path_stat.st_nlink); + +# else // Windows + + // Link count info is only available through GetFileInformationByHandle + BY_HANDLE_FILE_INFORMATION info; + handle_wrapper h( + create_file_handle(p.c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); + return + !error(h.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::hard_link_count") + && !error(::GetFileInformationByHandle(h.handle, &info)== 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::hard_link_count") + ? info.nNumberOfLinks + : 0; +# endif + } + + BOOST_FILESYSTEM_DECL + path initial_path(error_code* ec) + { + static path init_path; + if (init_path.empty()) + init_path = current_path(ec); + else if (ec != 0) ec->clear(); + return init_path; + } + + BOOST_FILESYSTEM_DECL + bool is_empty(const path& p, system::error_code* ec) + { +# ifdef BOOST_POSIX_API + + struct stat path_stat; + if (error(::stat(p.c_str(), &path_stat)!= 0, + p, ec, "boost::filesystem::is_empty")) + return false; + return S_ISDIR(path_stat.st_mode) + ? is_empty_directory(p, ec) + : path_stat.st_size == 0; +# else + + WIN32_FILE_ATTRIBUTE_DATA fad; + if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0 + ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::is_empty")) + return false; + + if (ec != 0) ec->clear(); return - !error(h.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::hard_link_count") - && !error(::GetFileInformationByHandle(h.handle, &info)== 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::hard_link_count") - ? info.nNumberOfLinks - : 0; -# endif - } - - BOOST_FILESYSTEM_DECL - path initial_path(error_code* ec) - { - static path init_path; - if (init_path.empty()) - init_path = current_path(ec); - else if (ec != 0) ec->clear(); - return init_path; - } - - BOOST_FILESYSTEM_DECL - bool is_empty(const path& p, system::error_code* ec) - { -# ifdef BOOST_POSIX_API - - struct stat path_stat; - if (error(::stat(p.c_str(), &path_stat)!= 0, - p, ec, "boost::filesystem::is_empty")) - return false; - return S_ISDIR(path_stat.st_mode) - ? is_empty_directory(p, ec) - : path_stat.st_size == 0; -# else - - WIN32_FILE_ATTRIBUTE_DATA fad; - if (error(::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad)== 0 - ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::is_empty")) - return false; - - if (ec != 0) ec->clear(); - return - (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - ? is_empty_directory(p, ec) - : (!fad.nFileSizeHigh && !fad.nFileSizeLow); -# endif - } - - BOOST_FILESYSTEM_DECL - std::time_t last_write_time(const path& p, system::error_code* ec) - { -# ifdef BOOST_POSIX_API - - struct stat path_stat; - if (error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::last_write_time")) - return std::time_t(-1); - return path_stat.st_mtime; - -# else - - handle_wrapper hw( - create_file_handle(p.c_str(), 0, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); - - if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::last_write_time")) - return std::time_t(-1); - - FILETIME lwt; - - if (error(::GetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::last_write_time")) - return std::time_t(-1); - - return to_time_t(lwt); -# endif - } - - BOOST_FILESYSTEM_DECL - void last_write_time(const path& p, const std::time_t new_time, - system::error_code* ec) - { -# ifdef BOOST_POSIX_API - - struct stat path_stat; - if (error(::stat(p.c_str(), &path_stat)!= 0, - p, ec, "boost::filesystem::last_write_time")) - return; - ::utimbuf buf; - buf.actime = path_stat.st_atime; // utime()updates access time too:-( - buf.modtime = new_time; - error(::utime(p.c_str(), &buf)!= 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::last_write_time"); - -# else - - handle_wrapper hw( - create_file_handle(p.c_str(), FILE_WRITE_ATTRIBUTES, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); - - if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::last_write_time")) - return; - - FILETIME lwt; - to_FILETIME(new_time, lwt); - - error(::SetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::last_write_time"); -# endif - } - -# ifdef BOOST_POSIX_API - const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); - inline mode_t mode_cast(perms prms) { return prms & active_bits; } -# endif - - BOOST_FILESYSTEM_DECL - void permissions(const path& p, perms prms, system::error_code* ec) - { - BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), - "add_perms and remove_perms are mutually exclusive"); - - if ((prms & add_perms) && (prms & remove_perms)) // precondition failed - return; - -# ifdef BOOST_POSIX_API - error_code local_ec; - file_status current_status((prms & symlink_perms) - ? fs::symlink_status(p, local_ec) - : fs::status(p, local_ec)); - if (local_ec) - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error( - "boost::filesystem::permissions", p, local_ec)); - else - *ec = local_ec; - return; - } - - if (prms & add_perms) - prms |= current_status.permissions(); - else if (prms & remove_perms) - prms = current_status.permissions() & ~prms; - - // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). - // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, - // and a runtime check is too much trouble. - // Linux does not support permissions on symbolic links and has no plans to - // support them in the future. The chmod() code is thus more practical, - // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. - // - See the 3rd paragraph of - // "Symbolic link ownership, permissions, and timestamps" at: - // "http://man7.org/linux/man-pages/man7/symlink.7.html" - // - See the fchmodat() Linux man page: - // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" -# if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) \ - && !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) \ - && !(defined(linux) || defined(__linux) || defined(__linux__)) \ - && !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ - && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) \ - && !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \ - && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) - if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), - !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) -# else // fallback if fchmodat() not supported - if (::chmod(p.c_str(), mode_cast(prms))) -# endif - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error( - "boost::filesystem::permissions", p, - error_code(errno, system::generic_category()))); - else - ec->assign(errno, system::generic_category()); - } - -# else // Windows - - // if not going to alter FILE_ATTRIBUTE_READONLY, just return - if (!(!((prms & (add_perms | remove_perms))) - || (prms & (owner_write|group_write|others_write)))) - return; - - DWORD attr = ::GetFileAttributesW(p.c_str()); - - if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) - return; - - if (prms & add_perms) - attr &= ~FILE_ATTRIBUTE_READONLY; - else if (prms & remove_perms) - attr |= FILE_ATTRIBUTE_READONLY; - else if (prms & (owner_write|group_write|others_write)) - attr &= ~FILE_ATTRIBUTE_READONLY; - else - attr |= FILE_ATTRIBUTE_READONLY; - - error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::permissions"); -# endif - } - - BOOST_FILESYSTEM_DECL - path read_symlink(const path& p, system::error_code* ec) - { - path symlink_path; - -# ifdef BOOST_POSIX_API - - for (std::size_t path_max = 64;; path_max *= 2)// loop 'til buffer large enough - { - boost::scoped_array<char> buf(new char[path_max]); - ssize_t result; - if ((result=::readlink(p.c_str(), buf.get(), path_max))== -1) - { - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", - p, error_code(errno, system_category()))); - else ec->assign(errno, system_category()); - break; - } - else - { - if(result != static_cast<ssize_t>(path_max)) - { - symlink_path.assign(buf.get(), buf.get() + result); - if (ec != 0) ec->clear(); - break; - } - } - } - -# elif _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008 - error(BOOST_ERROR_NOT_SUPPORTED, p, ec, - "boost::filesystem::read_symlink"); -# else // Vista and Server 2008 SDK, or later - - union info_t - { - char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - REPARSE_DATA_BUFFER rdb; - } info; - - handle_wrapper h( - create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0)); - - if (error(h.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::read_symlink")) - return symlink_path; - - DWORD sz; - - if (!error(::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, - 0, 0, info.buf, sizeof(info), &sz, 0) == 0 ? BOOST_ERRNO : 0, p, ec, - "boost::filesystem::read_symlink" )) - symlink_path.assign( - static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer) - + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t), - static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer) - + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t) - + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t)); -# endif - return symlink_path; - } - - BOOST_FILESYSTEM_DECL - path relative(const path& p, const path& base, error_code* ec) - { - error_code tmp_ec; - path wc_base(weakly_canonical(base, &tmp_ec)); - if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative")) - return path(); - path wc_p(weakly_canonical(p, &tmp_ec)); - if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative")) - return path(); - return wc_p.lexically_relative(wc_base); - } - - BOOST_FILESYSTEM_DECL - bool remove(const path& p, error_code* ec) - { - error_code tmp_ec; - file_type type = query_file_type(p, &tmp_ec); - if (error(type == status_error ? tmp_ec.value() : 0, p, ec, - "boost::filesystem::remove")) - return false; - - // Since POSIX remove() is specified to work with either files or directories, in a - // perfect world it could just be called. But some important real-world operating - // systems (Windows, Mac OS X, for example) don't implement the POSIX spec. So - // remove_file_or_directory() is always called to keep it simple. - return remove_file_or_directory(p, type, ec); - } - - BOOST_FILESYSTEM_DECL - boost::uintmax_t remove_all(const path& p, error_code* ec) - { - error_code tmp_ec; - file_type type = query_file_type(p, &tmp_ec); - if (error(type == status_error ? tmp_ec.value() : 0, p, ec, - "boost::filesystem::remove_all")) - return 0; - - return (type != status_error && type != file_not_found) // exists - ? remove_all_aux(p, type, ec) - : 0; - } - - BOOST_FILESYSTEM_DECL - void rename(const path& old_p, const path& new_p, error_code* ec) - { - error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, - ec, "boost::filesystem::rename"); - } - - BOOST_FILESYSTEM_DECL - void resize_file(const path& p, uintmax_t size, system::error_code* ec) - { -# if defined(BOOST_POSIX_API) - if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) { - error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); - return; - } -# endif - error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, - "boost::filesystem::resize_file"); - } - - BOOST_FILESYSTEM_DECL - space_info space(const path& p, error_code* ec) - { -# ifdef BOOST_POSIX_API - struct BOOST_STATVFS vfs; - space_info info; - if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::space")) - { - info.capacity - = static_cast<boost::uintmax_t>(vfs.f_blocks)* BOOST_STATVFS_F_FRSIZE; - info.free - = static_cast<boost::uintmax_t>(vfs.f_bfree)* BOOST_STATVFS_F_FRSIZE; - info.available - = static_cast<boost::uintmax_t>(vfs.f_bavail)* BOOST_STATVFS_F_FRSIZE; - } - -# else - ULARGE_INTEGER avail, total, free; - space_info info; - - if (!error(::GetDiskFreeSpaceExW(p.c_str(), &avail, &total, &free)== 0, - p, ec, "boost::filesystem::space")) - { + (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? is_empty_directory(p, ec) + : (!fad.nFileSizeHigh && !fad.nFileSizeLow); +# endif + } + + BOOST_FILESYSTEM_DECL + std::time_t last_write_time(const path& p, system::error_code* ec) + { +# ifdef BOOST_POSIX_API + + struct stat path_stat; + if (error(::stat(p.c_str(), &path_stat)!= 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::last_write_time")) + return std::time_t(-1); + return path_stat.st_mtime; + +# else + + handle_wrapper hw( + create_file_handle(p.c_str(), 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); + + if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::last_write_time")) + return std::time_t(-1); + + FILETIME lwt; + + if (error(::GetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::last_write_time")) + return std::time_t(-1); + + return to_time_t(lwt); +# endif + } + + BOOST_FILESYSTEM_DECL + void last_write_time(const path& p, const std::time_t new_time, + system::error_code* ec) + { +# ifdef BOOST_POSIX_API + + struct stat path_stat; + if (error(::stat(p.c_str(), &path_stat)!= 0, + p, ec, "boost::filesystem::last_write_time")) + return; + ::utimbuf buf; + buf.actime = path_stat.st_atime; // utime()updates access time too:-( + buf.modtime = new_time; + error(::utime(p.c_str(), &buf)!= 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::last_write_time"); + +# else + + handle_wrapper hw( + create_file_handle(p.c_str(), FILE_WRITE_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); + + if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::last_write_time")) + return; + + FILETIME lwt; + to_FILETIME(new_time, lwt); + + error(::SetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::last_write_time"); +# endif + } + +# ifdef BOOST_POSIX_API + const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); + inline mode_t mode_cast(perms prms) { return prms & active_bits; } +# endif + + BOOST_FILESYSTEM_DECL + void permissions(const path& p, perms prms, system::error_code* ec) + { + BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), + "add_perms and remove_perms are mutually exclusive"); + + if ((prms & add_perms) && (prms & remove_perms)) // precondition failed + return; + +# ifdef BOOST_POSIX_API + error_code local_ec; + file_status current_status((prms & symlink_perms) + ? fs::symlink_status(p, local_ec) + : fs::status(p, local_ec)); + if (local_ec) + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::permissions", p, local_ec)); + else + *ec = local_ec; + return; + } + + if (prms & add_perms) + prms |= current_status.permissions(); + else if (prms & remove_perms) + prms = current_status.permissions() & ~prms; + + // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). + // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, + // and a runtime check is too much trouble. + // Linux does not support permissions on symbolic links and has no plans to + // support them in the future. The chmod() code is thus more practical, + // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. + // - See the 3rd paragraph of + // "Symbolic link ownership, permissions, and timestamps" at: + // "http://man7.org/linux/man-pages/man7/symlink.7.html" + // - See the fchmodat() Linux man page: + // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" +# if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) \ + && !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) \ + && !(defined(linux) || defined(__linux) || defined(__linux__)) \ + && !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ + && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) \ + && !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \ + && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) + if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), + !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) +# else // fallback if fchmodat() not supported + if (::chmod(p.c_str(), mode_cast(prms))) +# endif + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::permissions", p, + error_code(errno, system::generic_category()))); + else + ec->assign(errno, system::generic_category()); + } + +# else // Windows + + // if not going to alter FILE_ATTRIBUTE_READONLY, just return + if (!(!((prms & (add_perms | remove_perms))) + || (prms & (owner_write|group_write|others_write)))) + return; + + DWORD attr = ::GetFileAttributesW(p.c_str()); + + if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) + return; + + if (prms & add_perms) + attr &= ~FILE_ATTRIBUTE_READONLY; + else if (prms & remove_perms) + attr |= FILE_ATTRIBUTE_READONLY; + else if (prms & (owner_write|group_write|others_write)) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + + error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::permissions"); +# endif + } + + BOOST_FILESYSTEM_DECL + path read_symlink(const path& p, system::error_code* ec) + { + path symlink_path; + +# ifdef BOOST_POSIX_API + + for (std::size_t path_max = 64;; path_max *= 2)// loop 'til buffer large enough + { + boost::scoped_array<char> buf(new char[path_max]); + ssize_t result; + if ((result=::readlink(p.c_str(), buf.get(), path_max))== -1) + { + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", + p, error_code(errno, system_category()))); + else ec->assign(errno, system_category()); + break; + } + else + { + if(result != static_cast<ssize_t>(path_max)) + { + symlink_path.assign(buf.get(), buf.get() + result); + if (ec != 0) ec->clear(); + break; + } + } + } + +# elif _WIN32_WINNT < 0x0600 // SDK earlier than Vista and Server 2008 + error(BOOST_ERROR_NOT_SUPPORTED, p, ec, + "boost::filesystem::read_symlink"); +# else // Vista and Server 2008 SDK, or later + + union info_t + { + char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER rdb; + } info; + + handle_wrapper h( + create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0)); + + if (error(h.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::read_symlink")) + return symlink_path; + + DWORD sz; + + if (!error(::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, + 0, 0, info.buf, sizeof(info), &sz, 0) == 0 ? BOOST_ERRNO : 0, p, ec, + "boost::filesystem::read_symlink" )) + symlink_path.assign( + static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer) + + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t), + static_cast<wchar_t*>(info.rdb.SymbolicLinkReparseBuffer.PathBuffer) + + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(wchar_t) + + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof(wchar_t)); +# endif + return symlink_path; + } + + BOOST_FILESYSTEM_DECL + path relative(const path& p, const path& base, error_code* ec) + { + error_code tmp_ec; + path wc_base(weakly_canonical(base, &tmp_ec)); + if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative")) + return path(); + path wc_p(weakly_canonical(p, &tmp_ec)); + if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative")) + return path(); + return wc_p.lexically_relative(wc_base); + } + + BOOST_FILESYSTEM_DECL + bool remove(const path& p, error_code* ec) + { + error_code tmp_ec; + file_type type = query_file_type(p, &tmp_ec); + if (error(type == status_error ? tmp_ec.value() : 0, p, ec, + "boost::filesystem::remove")) + return false; + + // Since POSIX remove() is specified to work with either files or directories, in a + // perfect world it could just be called. But some important real-world operating + // systems (Windows, Mac OS X, for example) don't implement the POSIX spec. So + // remove_file_or_directory() is always called to keep it simple. + return remove_file_or_directory(p, type, ec); + } + + BOOST_FILESYSTEM_DECL + boost::uintmax_t remove_all(const path& p, error_code* ec) + { + error_code tmp_ec; + file_type type = query_file_type(p, &tmp_ec); + if (error(type == status_error ? tmp_ec.value() : 0, p, ec, + "boost::filesystem::remove_all")) + return 0; + + return (type != status_error && type != file_not_found) // exists + ? remove_all_aux(p, type, ec) + : 0; + } + + BOOST_FILESYSTEM_DECL + void rename(const path& old_p, const path& new_p, error_code* ec) + { + error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, + ec, "boost::filesystem::rename"); + } + + BOOST_FILESYSTEM_DECL + void resize_file(const path& p, uintmax_t size, system::error_code* ec) + { +# if defined(BOOST_POSIX_API) + if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) { + error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); + return; + } +# endif + error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, + "boost::filesystem::resize_file"); + } + + BOOST_FILESYSTEM_DECL + space_info space(const path& p, error_code* ec) + { +# ifdef BOOST_POSIX_API + struct BOOST_STATVFS vfs; + space_info info; + if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::space")) + { info.capacity - = (static_cast<boost::uintmax_t>(total.HighPart)<< 32) - + total.LowPart; + = static_cast<boost::uintmax_t>(vfs.f_blocks)* BOOST_STATVFS_F_FRSIZE; info.free - = (static_cast<boost::uintmax_t>(free.HighPart)<< 32) - + free.LowPart; - info.available - = (static_cast<boost::uintmax_t>(avail.HighPart)<< 32) - + avail.LowPart; - } - -# endif - - else - { - info.capacity = info.free = info.available = 0; - } - return info; - } - - BOOST_FILESYSTEM_DECL - file_status status(const path& p, error_code* ec) - { -# ifdef BOOST_POSIX_API - - struct stat path_stat; - if (::stat(p.c_str(), &path_stat)!= 0) - { - if (ec != 0) // always report errno, even though some - ec->assign(errno, system_category()); // errno values are not status_errors - - if (not_found_error(errno)) - { - return fs::file_status(fs::file_not_found, fs::no_perms); - } - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", - p, error_code(errno, system_category()))); - return fs::file_status(fs::status_error); - } - if (ec != 0) ec->clear();; - if (S_ISDIR(path_stat.st_mode)) - return fs::file_status(fs::directory_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISREG(path_stat.st_mode)) - return fs::file_status(fs::regular_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISBLK(path_stat.st_mode)) - return fs::file_status(fs::block_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISCHR(path_stat.st_mode)) - return fs::file_status(fs::character_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISFIFO(path_stat.st_mode)) - return fs::file_status(fs::fifo_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISSOCK(path_stat.st_mode)) - return fs::file_status(fs::socket_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - return fs::file_status(fs::type_unknown); - -# else // Windows - - DWORD attr(::GetFileAttributesW(p.c_str())); - if (attr == 0xFFFFFFFF) - { - return process_status_failure(p, ec); - } - - // reparse point handling; - // since GetFileAttributesW does not resolve symlinks, try to open a file - // handle to discover if the file exists - if (attr & FILE_ATTRIBUTE_REPARSE_POINT) - { - handle_wrapper h( - create_file_handle( - p.c_str(), - 0, // dwDesiredAccess; attributes only - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - 0, // lpSecurityAttributes - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); // hTemplateFile - if (h.handle == INVALID_HANDLE_VALUE) - { - return process_status_failure(p, ec); - } - - if (!is_reparse_point_a_symlink(p)) - return file_status(reparse_file, make_permissions(p, attr)); - } - - if (ec != 0) ec->clear(); - return (attr & FILE_ATTRIBUTE_DIRECTORY) - ? file_status(directory_file, make_permissions(p, attr)) - : file_status(regular_file, make_permissions(p, attr)); - -# endif - } - - BOOST_FILESYSTEM_DECL - file_status symlink_status(const path& p, error_code* ec) - { -# ifdef BOOST_POSIX_API - - struct stat path_stat; - if (::lstat(p.c_str(), &path_stat)!= 0) - { - if (ec != 0) // always report errno, even though some - ec->assign(errno, system_category()); // errno values are not status_errors - - if (errno == ENOENT || errno == ENOTDIR) // these are not errors - { - return fs::file_status(fs::file_not_found, fs::no_perms); - } - if (ec == 0) - BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", - p, error_code(errno, system_category()))); - return fs::file_status(fs::status_error); - } - if (ec != 0) ec->clear(); - if (S_ISREG(path_stat.st_mode)) - return fs::file_status(fs::regular_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISDIR(path_stat.st_mode)) - return fs::file_status(fs::directory_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISLNK(path_stat.st_mode)) - return fs::file_status(fs::symlink_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISBLK(path_stat.st_mode)) - return fs::file_status(fs::block_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISCHR(path_stat.st_mode)) - return fs::file_status(fs::character_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISFIFO(path_stat.st_mode)) - return fs::file_status(fs::fifo_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - if (S_ISSOCK(path_stat.st_mode)) - return fs::file_status(fs::socket_file, - static_cast<perms>(path_stat.st_mode) & fs::perms_mask); - return fs::file_status(fs::type_unknown); - -# else // Windows - - DWORD attr(::GetFileAttributesW(p.c_str())); - if (attr == 0xFFFFFFFF) - { - return process_status_failure(p, ec); - } - - if (ec != 0) ec->clear(); - - if (attr & FILE_ATTRIBUTE_REPARSE_POINT) - return is_reparse_point_a_symlink(p) - ? file_status(symlink_file, make_permissions(p, attr)) - : file_status(reparse_file, make_permissions(p, attr)); - - return (attr & FILE_ATTRIBUTE_DIRECTORY) - ? file_status(directory_file, make_permissions(p, attr)) - : file_status(regular_file, make_permissions(p, attr)); - -# endif - } - - // contributed by Jeff Flinn - BOOST_FILESYSTEM_DECL - path temp_directory_path(system::error_code* ec) - { -# ifdef BOOST_POSIX_API - const char* val = 0; + = static_cast<boost::uintmax_t>(vfs.f_bfree)* BOOST_STATVFS_F_FRSIZE; + info.available + = static_cast<boost::uintmax_t>(vfs.f_bavail)* BOOST_STATVFS_F_FRSIZE; + } + +# else + ULARGE_INTEGER avail, total, free; + space_info info; + + if (!error(::GetDiskFreeSpaceExW(p.c_str(), &avail, &total, &free)== 0, + p, ec, "boost::filesystem::space")) + { + info.capacity + = (static_cast<boost::uintmax_t>(total.HighPart)<< 32) + + total.LowPart; + info.free + = (static_cast<boost::uintmax_t>(free.HighPart)<< 32) + + free.LowPart; + info.available + = (static_cast<boost::uintmax_t>(avail.HighPart)<< 32) + + avail.LowPart; + } + +# endif + + else + { + info.capacity = info.free = info.available = 0; + } + return info; + } + + BOOST_FILESYSTEM_DECL + file_status status(const path& p, error_code* ec) + { +# ifdef BOOST_POSIX_API + + struct stat path_stat; + if (::stat(p.c_str(), &path_stat)!= 0) + { + if (ec != 0) // always report errno, even though some + ec->assign(errno, system_category()); // errno values are not status_errors + + if (not_found_error(errno)) + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", + p, error_code(errno, system_category()))); + return fs::file_status(fs::status_error); + } + if (ec != 0) ec->clear();; + if (S_ISDIR(path_stat.st_mode)) + return fs::file_status(fs::directory_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISREG(path_stat.st_mode)) + return fs::file_status(fs::regular_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISBLK(path_stat.st_mode)) + return fs::file_status(fs::block_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISCHR(path_stat.st_mode)) + return fs::file_status(fs::character_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISFIFO(path_stat.st_mode)) + return fs::file_status(fs::fifo_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISSOCK(path_stat.st_mode)) + return fs::file_status(fs::socket_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + return fs::file_status(fs::type_unknown); + +# else // Windows + + DWORD attr(::GetFileAttributesW(p.c_str())); + if (attr == 0xFFFFFFFF) + { + return process_status_failure(p, ec); + } + + // reparse point handling; + // since GetFileAttributesW does not resolve symlinks, try to open a file + // handle to discover if the file exists + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) + { + handle_wrapper h( + create_file_handle( + p.c_str(), + 0, // dwDesiredAccess; attributes only + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); // hTemplateFile + if (h.handle == INVALID_HANDLE_VALUE) + { + return process_status_failure(p, ec); + } + + if (!is_reparse_point_a_symlink(p)) + return file_status(reparse_file, make_permissions(p, attr)); + } + + if (ec != 0) ec->clear(); + return (attr & FILE_ATTRIBUTE_DIRECTORY) + ? file_status(directory_file, make_permissions(p, attr)) + : file_status(regular_file, make_permissions(p, attr)); + +# endif + } + + BOOST_FILESYSTEM_DECL + file_status symlink_status(const path& p, error_code* ec) + { +# ifdef BOOST_POSIX_API + + struct stat path_stat; + if (::lstat(p.c_str(), &path_stat)!= 0) + { + if (ec != 0) // always report errno, even though some + ec->assign(errno, system_category()); // errno values are not status_errors + + if (errno == ENOENT || errno == ENOTDIR) // these are not errors + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + if (ec == 0) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", + p, error_code(errno, system_category()))); + return fs::file_status(fs::status_error); + } + if (ec != 0) ec->clear(); + if (S_ISREG(path_stat.st_mode)) + return fs::file_status(fs::regular_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISDIR(path_stat.st_mode)) + return fs::file_status(fs::directory_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISLNK(path_stat.st_mode)) + return fs::file_status(fs::symlink_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISBLK(path_stat.st_mode)) + return fs::file_status(fs::block_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISCHR(path_stat.st_mode)) + return fs::file_status(fs::character_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISFIFO(path_stat.st_mode)) + return fs::file_status(fs::fifo_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + if (S_ISSOCK(path_stat.st_mode)) + return fs::file_status(fs::socket_file, + static_cast<perms>(path_stat.st_mode) & fs::perms_mask); + return fs::file_status(fs::type_unknown); + +# else // Windows + + DWORD attr(::GetFileAttributesW(p.c_str())); + if (attr == 0xFFFFFFFF) + { + return process_status_failure(p, ec); + } + + if (ec != 0) ec->clear(); + + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) + return is_reparse_point_a_symlink(p) + ? file_status(symlink_file, make_permissions(p, attr)) + : file_status(reparse_file, make_permissions(p, attr)); + + return (attr & FILE_ATTRIBUTE_DIRECTORY) + ? file_status(directory_file, make_permissions(p, attr)) + : file_status(regular_file, make_permissions(p, attr)); + +# endif + } + + // contributed by Jeff Flinn + BOOST_FILESYSTEM_DECL + path temp_directory_path(system::error_code* ec) + { +# ifdef BOOST_POSIX_API + const char* val = 0; + + (val = std::getenv("TMPDIR" )) || + (val = std::getenv("TMP" )) || + (val = std::getenv("TEMP" )) || + (val = std::getenv("TEMPDIR")); + +# ifdef __ANDROID__ + const char* default_tmp = "/data/local/tmp"; +# else + const char* default_tmp = "/tmp"; +# endif + path p((val!=0) ? val : default_tmp); - (val = std::getenv("TMPDIR" )) || - (val = std::getenv("TMP" )) || - (val = std::getenv("TEMP" )) || - (val = std::getenv("TEMPDIR")); - -# ifdef __ANDROID__ - const char* default_tmp = "/data/local/tmp"; -# else - const char* default_tmp = "/tmp"; -# endif - path p((val!=0) ? val : default_tmp); + if (p.empty() || (ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p))) + { + error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); + return p; + } - if (p.empty() || (ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p))) - { - error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); - return p; - } - - return p; - -# else // Windows - - const wchar_t* tmp_env = L"TMP"; - const wchar_t* temp_env = L"TEMP"; - const wchar_t* localappdata_env = L"LOCALAPPDATA"; - const wchar_t* userprofile_env = L"USERPROFILE"; - const wchar_t* env_list[] - = {tmp_env, temp_env, localappdata_env, userprofile_env, 0}; - - path p; - for (int i = 0; env_list[i]; ++i) - { - std::wstring env = wgetenv(env_list[i]); - if (!env.empty()) - { - p = env; - if (i >= 2) - p /= L"Temp"; - error_code lcl_ec; - if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) - break; - p.clear(); - } - } - - if (p.empty()) - { - // use vector since in C++03 a string is not required to be contiguous - std::vector<wchar_t> buf(::GetWindowsDirectoryW(NULL, 0)); - - if (buf.empty() - || ::GetWindowsDirectoryW(&buf[0], static_cast<UINT>(buf.size())) == 0) - { - error(::GetLastError(), ec, "boost::filesystem::temp_directory_path"); - return path(); - } - p = &*buf.begin(); // do not depend on buf.size(); see ticket #10388 - p /= L"Temp"; - } - return p; - -# endif - } - - BOOST_FILESYSTEM_DECL - path system_complete(const path& p, system::error_code* ec) - { -# ifdef BOOST_POSIX_API - return (p.empty() || p.is_absolute()) - ? p : current_path()/ p; - -# else - if (p.empty()) - { - if (ec != 0) ec->clear(); - return p; - } - wchar_t buf[buf_size]; - wchar_t* pfn; - std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); - - if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) - return path(); - - if (len < buf_size)// len does not include null termination character - return path(&buf[0]); - - boost::scoped_array<wchar_t> big_buf(new wchar_t[len]); - - return error(get_full_path_name(p, len , big_buf.get(), &pfn)== 0 ? BOOST_ERRNO : 0, - p, ec, "boost::filesystem::system_complete") - ? path() - : path(big_buf.get()); -# endif - } - - BOOST_FILESYSTEM_DECL - path weakly_canonical(const path& p, system::error_code* ec) - { - path head(p); - path tail; - system::error_code tmp_ec; - path::iterator itr = p.end(); - - for (; !head.empty(); --itr) - { - file_status head_status = status(head, tmp_ec); - if (error(head_status.type() == fs::status_error, - head, ec, "boost::filesystem::weakly_canonical")) - return path(); - if (head_status.type() != fs::file_not_found) - break; - head.remove_filename(); - } - - bool tail_has_dots = false; - for (; itr != p.end(); ++itr) - { - tail /= *itr; - // for a later optimization, track if any dot or dot-dot elements are present - if (itr->native().size() <= 2 - && itr->native()[0] == dot - && (itr->native().size() == 1 || itr->native()[1] == dot)) - tail_has_dots = true; - } - - if (head.empty()) - return p.lexically_normal(); - head = canonical(head, tmp_ec); - if (error(tmp_ec.value(), head, ec, "boost::filesystem::weakly_canonical")) - return path(); - return tail.empty() - ? head - : (tail_has_dots // optimization: only normalize if tail had dot or dot-dot element - ? (head/tail).lexically_normal() - : head/tail); - } -} // namespace detail - -//--------------------------------------------------------------------------------------// -// // -// directory_entry // -// // -//--------------------------------------------------------------------------------------// - - file_status - directory_entry::m_get_status(system::error_code* ec) const - { - if (!status_known(m_status)) - { - // optimization: if the symlink status is known, and it isn't a symlink, - // then status and symlink_status are identical so just copy the - // symlink status to the regular status. - if (status_known(m_symlink_status) - && !is_symlink(m_symlink_status)) - { - m_status = m_symlink_status; - if (ec != 0) ec->clear(); - } - else m_status = detail::status(m_path, ec); - } - else if (ec != 0) ec->clear(); - return m_status; - } - - file_status - directory_entry::m_get_symlink_status(system::error_code* ec) const - { - if (!status_known(m_symlink_status)) - m_symlink_status = detail::symlink_status(m_path, ec); - else if (ec != 0) ec->clear(); - return m_symlink_status; - } - -// dispatch directory_entry supplied here rather than in -// <boost/filesystem/path_traits.hpp>, thus avoiding header circularity. -// test cases are in operations_unit_test.cpp - -namespace path_traits -{ - void dispatch(const directory_entry & de, -# ifdef BOOST_WINDOWS_API - std::wstring& to, -# else - std::string& to, -# endif - const codecvt_type &) - { - to = de.path().native(); - } - - void dispatch(const directory_entry & de, -# ifdef BOOST_WINDOWS_API - std::wstring& to -# else - std::string& to -# endif - ) - { - to = de.path().native(); - } -} // namespace path_traits -} // namespace filesystem -} // namespace boost - -//--------------------------------------------------------------------------------------// -// // -// directory_iterator // -// // -//--------------------------------------------------------------------------------------// - -namespace -{ -# ifdef BOOST_POSIX_API - - error_code path_max(std::size_t & result) - // this code is based on Stevens and Rago, Advanced Programming in the - // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49 - { -# 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; - } - -#if defined(__PGI) && defined(__USE_FILE_OFFSET64) -#define dirent dirent64 -#endif - - error_code dir_itr_first(void *& handle, void *& buffer, - const char* dir, string& target, - fs::file_status &, fs::file_status &) - { - if ((handle = ::opendir(dir))== 0) - return error_code(errno, system_category()); - target = string("."); // string was static but caused trouble - // when iteration called from dtor, after - // static had already been destroyed - std::size_t path_size (0); // initialization quiets gcc warning (ticket #3509) - 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; - } - - // warning: the only dirent member updated is d_name - inline int readdir_r_simulator(DIR * dirp, struct dirent * entry, - struct dirent ** result)// *result set to 0 on end of directory - { -# if !defined(__CYGWIN__)\ - && defined(_POSIX_THREAD_SAFE_FUNCTIONS)\ - && defined(_SC_THREAD_SAFE_FUNCTIONS)\ - && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0)\ - && (!defined(__hpux) || defined(_REENTRANT)) \ - && (!defined(_AIX) || defined(__THREAD_SAFE)) - - errno = 0; - - if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS)>= 0) - { return ::readdir_r(dirp, entry, result); } -# endif - - errno = 0; - - struct dirent * p; - *result = 0; - if ((p = ::readdir(dirp))== 0) - return errno; - std::strcpy(entry->d_name, p->d_name); - *result = entry; - return 0; - } - - error_code dir_itr_increment(void *& handle, void *& buffer, - string& target, fs::file_status & sf, fs::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 fs::detail::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_error); - } - 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_error); - symlink_sf = fs::file_status(fs::symlink_file); - } - else sf = symlink_sf = fs::file_status(fs::status_error); - } -# else - sf = symlink_sf = fs::file_status(fs::status_error); -# endif - return ok; - } - -# else // BOOST_WINDOWS_API - - error_code dir_itr_first(void *& handle, const fs::path& dir, - wstring& target, fs::file_status & sf, fs::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 - wstring dirpath(dir.wstring()); - dirpath += (dirpath.empty() - || (dirpath[dirpath.size()-1] != L'\\' - && dirpath[dirpath.size()-1] != L'/' - && dirpath[dirpath.size()-1] != L':'))? L"\\*" : L"*"; - - WIN32_FIND_DATAW data; - if ((handle = ::FindFirstFileW(dirpath.c_str(), &data)) - == INVALID_HANDLE_VALUE) - { - handle = 0; // signal eof - return error_code( (::GetLastError() == ERROR_FILE_NOT_FOUND - // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551 - || ::GetLastError() == ERROR_NO_MORE_FILES) - ? 0 : ::GetLastError(), system_category() ); - } - target = data.cFileName; - if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) - // reparse points are complex, so don't try to handle them here; instead just mark - // them as status_error which causes directory_entry caching to call status() - // and symlink_status() which do handle reparse points fully - { - sf.type(fs::status_error); - symlink_sf.type(fs::status_error); - } - else - { - if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - sf.type(fs::directory_file); - symlink_sf.type(fs::directory_file); - } - else - { - sf.type(fs::regular_file); - symlink_sf.type(fs::regular_file); - } - sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes)); - symlink_sf.permissions(sf.permissions()); - } - return error_code(); - } - - error_code dir_itr_increment(void *& handle, wstring& target, - fs::file_status & sf, fs::file_status & symlink_sf) - { - WIN32_FIND_DATAW data; - if (::FindNextFileW(handle, &data)== 0)// fails - { - int error = ::GetLastError(); - fs::detail::dir_itr_close(handle); - return error_code(error == ERROR_NO_MORE_FILES ? 0 : error, system_category()); - } - target = data.cFileName; - if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) - // reparse points are complex, so don't try to handle them here; instead just mark - // them as status_error which causes directory_entry caching to call status() - // and symlink_status() which do handle reparse points fully - { - sf.type(fs::status_error); - symlink_sf.type(fs::status_error); - } - else + return p; + +# else // Windows + + const wchar_t* tmp_env = L"TMP"; + const wchar_t* temp_env = L"TEMP"; + const wchar_t* localappdata_env = L"LOCALAPPDATA"; + const wchar_t* userprofile_env = L"USERPROFILE"; + const wchar_t* env_list[] + = {tmp_env, temp_env, localappdata_env, userprofile_env, 0}; + + path p; + for (int i = 0; env_list[i]; ++i) + { + std::wstring env = wgetenv(env_list[i]); + if (!env.empty()) + { + p = env; + if (i >= 2) + p /= L"Temp"; + error_code lcl_ec; + if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) + break; + p.clear(); + } + } + + if (p.empty()) + { + // use vector since in C++03 a string is not required to be contiguous + std::vector<wchar_t> buf(::GetWindowsDirectoryW(NULL, 0)); + + if (buf.empty() + || ::GetWindowsDirectoryW(&buf[0], static_cast<UINT>(buf.size())) == 0) + { + error(::GetLastError(), ec, "boost::filesystem::temp_directory_path"); + return path(); + } + p = &*buf.begin(); // do not depend on buf.size(); see ticket #10388 + p /= L"Temp"; + } + return p; + +# endif + } + + BOOST_FILESYSTEM_DECL + path system_complete(const path& p, system::error_code* ec) + { +# ifdef BOOST_POSIX_API + return (p.empty() || p.is_absolute()) + ? p : current_path()/ p; + +# else + if (p.empty()) + { + if (ec != 0) ec->clear(); + return p; + } + wchar_t buf[buf_size]; + wchar_t* pfn; + std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); + + if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) + return path(); + + if (len < buf_size)// len does not include null termination character + return path(&buf[0]); + + boost::scoped_array<wchar_t> big_buf(new wchar_t[len]); + + return error(get_full_path_name(p, len , big_buf.get(), &pfn)== 0 ? BOOST_ERRNO : 0, + p, ec, "boost::filesystem::system_complete") + ? path() + : path(big_buf.get()); +# endif + } + + BOOST_FILESYSTEM_DECL + path weakly_canonical(const path& p, system::error_code* ec) + { + path head(p); + path tail; + system::error_code tmp_ec; + path::iterator itr = p.end(); + + for (; !head.empty(); --itr) + { + file_status head_status = status(head, tmp_ec); + if (error(head_status.type() == fs::status_error, + head, ec, "boost::filesystem::weakly_canonical")) + return path(); + if (head_status.type() != fs::file_not_found) + break; + head.remove_filename(); + } + + bool tail_has_dots = false; + for (; itr != p.end(); ++itr) { - if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - sf.type(fs::directory_file); - symlink_sf.type(fs::directory_file); - } - else + tail /= *itr; + // for a later optimization, track if any dot or dot-dot elements are present + if (itr->native().size() <= 2 + && itr->native()[0] == dot + && (itr->native().size() == 1 || itr->native()[1] == dot)) + tail_has_dots = true; + } + + if (head.empty()) + return p.lexically_normal(); + head = canonical(head, tmp_ec); + if (error(tmp_ec.value(), head, ec, "boost::filesystem::weakly_canonical")) + return path(); + return tail.empty() + ? head + : (tail_has_dots // optimization: only normalize if tail had dot or dot-dot element + ? (head/tail).lexically_normal() + : head/tail); + } +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// directory_entry // +// // +//--------------------------------------------------------------------------------------// + + file_status + directory_entry::m_get_status(system::error_code* ec) const + { + if (!status_known(m_status)) + { + // optimization: if the symlink status is known, and it isn't a symlink, + // then status and symlink_status are identical so just copy the + // symlink status to the regular status. + if (status_known(m_symlink_status) + && !is_symlink(m_symlink_status)) { - sf.type(fs::regular_file); - symlink_sf.type(fs::regular_file); - } - sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes)); - symlink_sf.permissions(sf.permissions()); - } - return error_code(); - } -#endif - - const error_code not_found_error_code ( -# ifdef BOOST_WINDOWS_API - ERROR_PATH_NOT_FOUND -# else - ENOENT -# endif - , system_category()); - -} // unnamed namespace - -namespace boost -{ -namespace filesystem -{ - -namespace detail -{ - // dir_itr_close is called both from the ~dir_itr_imp()destructor - // and dir_itr_increment() - BOOST_FILESYSTEM_DECL - system::error_code dir_itr_close( // never throws - void *& handle -# if defined(BOOST_POSIX_API) - , void *& buffer -# endif - ) - { -# ifdef BOOST_POSIX_API - 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()); - -# else - if (handle != 0) - { - ::FindClose(handle); - handle = 0; - } - return ok; - -# endif - } - - void directory_iterator_construct(directory_iterator& it, - const path& p, system::error_code* ec) - { - if (error(p.empty() ? not_found_error_code.value() : 0, p, ec, - "boost::filesystem::directory_iterator::construct")) - return; - - path::string_type filename; - file_status file_stat, symlink_file_stat; - error_code result = dir_itr_first(it.m_imp->handle, -# if defined(BOOST_POSIX_API) - it.m_imp->buffer, -# endif - p.c_str(), filename, file_stat, symlink_file_stat); - - if (result) - { - it.m_imp.reset(); - error(result.value(), p, - ec, "boost::filesystem::directory_iterator::construct"); - return; - } - - if (it.m_imp->handle == 0) - it.m_imp.reset(); // eof, so make end iterator - else // not eof + m_status = m_symlink_status; + if (ec != 0) ec->clear(); + } + else m_status = detail::status(m_path, ec); + } + else if (ec != 0) ec->clear(); + return m_status; + } + + file_status + directory_entry::m_get_symlink_status(system::error_code* ec) const + { + if (!status_known(m_symlink_status)) + m_symlink_status = detail::symlink_status(m_path, ec); + else if (ec != 0) ec->clear(); + return m_symlink_status; + } + +// dispatch directory_entry supplied here rather than in +// <boost/filesystem/path_traits.hpp>, thus avoiding header circularity. +// test cases are in operations_unit_test.cpp + +namespace path_traits +{ + void dispatch(const directory_entry & de, +# ifdef BOOST_WINDOWS_API + std::wstring& to, +# else + std::string& to, +# endif + const codecvt_type &) + { + to = de.path().native(); + } + + void dispatch(const directory_entry & de, +# ifdef BOOST_WINDOWS_API + std::wstring& to +# else + std::string& to +# endif + ) + { + to = de.path().native(); + } +} // namespace path_traits +} // namespace filesystem +} // namespace boost + +//--------------------------------------------------------------------------------------// +// // +// directory_iterator // +// // +//--------------------------------------------------------------------------------------// + +namespace +{ +# ifdef BOOST_POSIX_API + + error_code path_max(std::size_t & result) + // this code is based on Stevens and Rago, Advanced Programming in the + // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49 + { +# 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; + } + +#if defined(__PGI) && defined(__USE_FILE_OFFSET64) +#define dirent dirent64 +#endif + + error_code dir_itr_first(void *& handle, void *& buffer, + const char* dir, string& target, + fs::file_status &, fs::file_status &) + { + if ((handle = ::opendir(dir))== 0) + return error_code(errno, system_category()); + target = string("."); // string was static but caused trouble + // when iteration called from dtor, after + // static had already been destroyed + std::size_t path_size (0); // initialization quiets gcc warning (ticket #3509) + 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; + } + + // warning: the only dirent member updated is d_name + inline int readdir_r_simulator(DIR * dirp, struct dirent * entry, + struct dirent ** result)// *result set to 0 on end of directory + { +# if !defined(__CYGWIN__)\ + && defined(_POSIX_THREAD_SAFE_FUNCTIONS)\ + && defined(_SC_THREAD_SAFE_FUNCTIONS)\ + && (_POSIX_THREAD_SAFE_FUNCTIONS+0 >= 0)\ + && (!defined(__hpux) || defined(_REENTRANT)) \ + && (!defined(_AIX) || defined(__THREAD_SAFE)) + + errno = 0; + + if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS)>= 0) + { return ::readdir_r(dirp, entry, result); } +# endif + + errno = 0; + + struct dirent * p; + *result = 0; + if ((p = ::readdir(dirp))== 0) + return errno; + std::strcpy(entry->d_name, p->d_name); + *result = entry; + return 0; + } + + error_code dir_itr_increment(void *& handle, void *& buffer, + string& target, fs::file_status & sf, fs::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 fs::detail::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_error); + } + 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_error); + symlink_sf = fs::file_status(fs::symlink_file); + } + else sf = symlink_sf = fs::file_status(fs::status_error); + } +# else + sf = symlink_sf = fs::file_status(fs::status_error); +# endif + return ok; + } + +# else // BOOST_WINDOWS_API + + error_code dir_itr_first(void *& handle, const fs::path& dir, + wstring& target, fs::file_status & sf, fs::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 + wstring dirpath(dir.wstring()); + dirpath += (dirpath.empty() + || (dirpath[dirpath.size()-1] != L'\\' + && dirpath[dirpath.size()-1] != L'/' + && dirpath[dirpath.size()-1] != L':'))? L"\\*" : L"*"; + + WIN32_FIND_DATAW data; + if ((handle = ::FindFirstFileW(dirpath.c_str(), &data)) + == INVALID_HANDLE_VALUE) { - it.m_imp->dir_entry.assign(p / filename, file_stat, symlink_file_stat); - if (filename[0] == dot // dot or dot-dot - && (filename.size()== 1 - || (filename[1] == dot - && filename.size()== 2))) + handle = 0; // signal eof + return error_code( (::GetLastError() == ERROR_FILE_NOT_FOUND + // Windows Mobile returns ERROR_NO_MORE_FILES; see ticket #3551 + || ::GetLastError() == ERROR_NO_MORE_FILES) + ? 0 : ::GetLastError(), system_category() ); + } + target = data.cFileName; + if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + // reparse points are complex, so don't try to handle them here; instead just mark + // them as status_error which causes directory_entry caching to call status() + // and symlink_status() which do handle reparse points fully + { + sf.type(fs::status_error); + symlink_sf.type(fs::status_error); + } + else + { + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + sf.type(fs::directory_file); + symlink_sf.type(fs::directory_file); + } + else + { + sf.type(fs::regular_file); + symlink_sf.type(fs::regular_file); + } + sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes)); + symlink_sf.permissions(sf.permissions()); + } + return error_code(); + } + + error_code dir_itr_increment(void *& handle, wstring& target, + fs::file_status & sf, fs::file_status & symlink_sf) + { + WIN32_FIND_DATAW data; + if (::FindNextFileW(handle, &data)== 0)// fails + { + int error = ::GetLastError(); + fs::detail::dir_itr_close(handle); + return error_code(error == ERROR_NO_MORE_FILES ? 0 : error, system_category()); + } + target = data.cFileName; + if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + // reparse points are complex, so don't try to handle them here; instead just mark + // them as status_error which causes directory_entry caching to call status() + // and symlink_status() which do handle reparse points fully + { + sf.type(fs::status_error); + symlink_sf.type(fs::status_error); + } + else + { + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + sf.type(fs::directory_file); + symlink_sf.type(fs::directory_file); + } + else + { + sf.type(fs::regular_file); + symlink_sf.type(fs::regular_file); + } + sf.permissions(make_permissions(data.cFileName, data.dwFileAttributes)); + symlink_sf.permissions(sf.permissions()); + } + return error_code(); + } +#endif + + const error_code not_found_error_code ( +# ifdef BOOST_WINDOWS_API + ERROR_PATH_NOT_FOUND +# else + ENOENT +# endif + , system_category()); + +} // unnamed namespace + +namespace boost +{ +namespace filesystem +{ + +namespace detail +{ + // dir_itr_close is called both from the ~dir_itr_imp()destructor + // and dir_itr_increment() + BOOST_FILESYSTEM_DECL + system::error_code dir_itr_close( // never throws + void *& handle +# if defined(BOOST_POSIX_API) + , void *& buffer +# endif + ) + { +# ifdef BOOST_POSIX_API + 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()); + +# else + if (handle != 0) + { + ::FindClose(handle); + handle = 0; + } + return ok; + +# endif + } + + void directory_iterator_construct(directory_iterator& it, + const path& p, system::error_code* ec) + { + if (error(p.empty() ? not_found_error_code.value() : 0, p, ec, + "boost::filesystem::directory_iterator::construct")) + return; + + path::string_type filename; + file_status file_stat, symlink_file_stat; + error_code result = dir_itr_first(it.m_imp->handle, +# if defined(BOOST_POSIX_API) + it.m_imp->buffer, +# endif + p.c_str(), filename, file_stat, symlink_file_stat); + + if (result) + { + it.m_imp.reset(); + error(result.value(), p, + ec, "boost::filesystem::directory_iterator::construct"); + return; + } + + if (it.m_imp->handle == 0) + it.m_imp.reset(); // eof, so make end iterator + else // not eof + { + it.m_imp->dir_entry.assign(p / filename, file_stat, symlink_file_stat); + if (filename[0] == dot // dot or dot-dot + && (filename.size()== 1 + || (filename[1] == dot + && filename.size()== 2))) { detail::directory_iterator_increment(it, ec); } - } - } - - void directory_iterator_increment(directory_iterator& it, - system::error_code* ec) - { - BOOST_ASSERT_MSG(it.m_imp.get(), "attempt to increment end iterator"); - BOOST_ASSERT_MSG(it.m_imp->handle != 0, "internal program error"); - - path::string_type filename; - file_status file_stat, symlink_file_stat; - system::error_code temp_ec; - - for (;;) - { - temp_ec = dir_itr_increment(it.m_imp->handle, -# if defined(BOOST_POSIX_API) - it.m_imp->buffer, -# endif - filename, file_stat, symlink_file_stat); - - if (temp_ec) // happens if filesystem is corrupt, such as on a damaged optical disc - { - path error_path(it.m_imp->dir_entry.path().parent_path()); // fix ticket #5900 - it.m_imp.reset(); - if (ec == 0) - BOOST_FILESYSTEM_THROW( - filesystem_error("boost::filesystem::directory_iterator::operator++", - error_path, - error_code(BOOST_ERRNO, system_category()))); - ec->assign(BOOST_ERRNO, system_category()); - return; - } - else if (ec != 0) ec->clear(); - - if (it.m_imp->handle == 0) // eof, make end - { - it.m_imp.reset(); - return; - } - - if (!(filename[0] == dot // !(dot or dot-dot) - && (filename.size()== 1 - || (filename[1] == dot - && filename.size()== 2)))) - { - it.m_imp->dir_entry.replace_filename( - filename, file_stat, symlink_file_stat); - return; - } - } - } -} // namespace detail -} // namespace filesystem -} // namespace boost + } + } + + void directory_iterator_increment(directory_iterator& it, + system::error_code* ec) + { + BOOST_ASSERT_MSG(it.m_imp.get(), "attempt to increment end iterator"); + BOOST_ASSERT_MSG(it.m_imp->handle != 0, "internal program error"); + + path::string_type filename; + file_status file_stat, symlink_file_stat; + system::error_code temp_ec; + + for (;;) + { + temp_ec = dir_itr_increment(it.m_imp->handle, +# if defined(BOOST_POSIX_API) + it.m_imp->buffer, +# endif + filename, file_stat, symlink_file_stat); + + if (temp_ec) // happens if filesystem is corrupt, such as on a damaged optical disc + { + path error_path(it.m_imp->dir_entry.path().parent_path()); // fix ticket #5900 + it.m_imp.reset(); + if (ec == 0) + BOOST_FILESYSTEM_THROW( + filesystem_error("boost::filesystem::directory_iterator::operator++", + error_path, + error_code(BOOST_ERRNO, system_category()))); + ec->assign(BOOST_ERRNO, system_category()); + return; + } + else if (ec != 0) ec->clear(); + + if (it.m_imp->handle == 0) // eof, make end + { + it.m_imp.reset(); + return; + } + + if (!(filename[0] == dot // !(dot or dot-dot) + && (filename.size()== 1 + || (filename[1] == dot + && filename.size()== 2)))) + { + it.m_imp->dir_entry.replace_filename( + filename, file_stat, symlink_file_stat); + return; + } + } + } +} // namespace detail +} // namespace filesystem +} // namespace boost diff --git a/contrib/restricted/boost/libs/filesystem/src/path.cpp b/contrib/restricted/boost/libs/filesystem/src/path.cpp index 01dc143d15..a4588654ba 100644 --- a/contrib/restricted/boost/libs/filesystem/src/path.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/path.cpp @@ -1,953 +1,953 @@ -// filesystem path.cpp ------------------------------------------------------------- // - -// Copyright Beman Dawes 2008 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// Library home page: http://www.boost.org/libs/filesystem - -// Old standard library configurations, particularly MingGW, don't support wide strings. -// Report this with an explicit error message. -#include <boost/config.hpp> -# if defined( BOOST_NO_STD_WSTRING ) -# error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support -# endif - -// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows -// the library is being built (possibly exporting rather than importing code) -#define BOOST_FILESYSTEM_SOURCE - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#include <boost/filesystem/config.hpp> -#include <boost/filesystem/path.hpp> -#include <boost/filesystem/operations.hpp> // for filesystem_error -#include <boost/scoped_array.hpp> -#include <boost/system/error_code.hpp> -#include <boost/assert.hpp> -#include <algorithm> -#include <cstddef> -#include <cstring> -#include <cassert> - -#ifdef BOOST_WINDOWS_API -# include "windows_file_codecvt.hpp" -# include <windows.h> -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) -# include <boost/filesystem/detail/utf8_codecvt_facet.hpp> -#endif - -#ifdef BOOST_FILESYSTEM_DEBUG -# include <iostream> -# include <iomanip> -#endif - -namespace fs = boost::filesystem; - -using boost::filesystem::path; - -using std::string; -using std::wstring; - -using boost::system::error_code; - -//--------------------------------------------------------------------------------------// -// // -// class path helpers // -// // -//--------------------------------------------------------------------------------------// - -namespace -{ - //------------------------------------------------------------------------------------// - // miscellaneous class path helpers // - //------------------------------------------------------------------------------------// - - typedef path::value_type value_type; - typedef path::string_type string_type; - typedef string_type::size_type size_type; - -# ifdef BOOST_WINDOWS_API - - const wchar_t* const separators = L"/\\"; - const wchar_t* separator_string = L"/"; - const wchar_t* preferred_separator_string = L"\\"; - const wchar_t colon = L':'; - const wchar_t questionmark = L'?'; - - inline bool is_letter(wchar_t c) - { - return (c >= L'a' && c <=L'z') || (c >= L'A' && c <=L'Z'); - } - -# else - - const char* const separators = "/"; - const char* separator_string = "/"; - const char* preferred_separator_string = "/"; - -# endif - - bool is_root_separator(const string_type& str, size_type pos); - // pos is position of the separator - - size_type filename_pos(const string_type& str, - size_type end_pos); // end_pos is past-the-end position - // Returns: 0 if str itself is filename (or empty) - - size_type root_directory_start(const string_type& path, size_type size); - // Returns: npos if no root_directory found - - void first_element( - const string_type& src, - size_type& element_pos, - size_type& element_size, -# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) // VC++ 7.1 - size_type size = string_type::npos -# else - size_type size = -1 -# endif - ); - -} // unnamed namespace - -//--------------------------------------------------------------------------------------// -// // -// class path implementation // -// // -//--------------------------------------------------------------------------------------// - -namespace boost -{ -namespace filesystem -{ - path& path::operator/=(const path& p) - { - if (p.empty()) - return *this; - if (this == &p) // self-append - { - path rhs(p); - if (!detail::is_directory_separator(rhs.m_pathname[0])) - m_append_separator_if_needed(); - m_pathname += rhs.m_pathname; - } - else - { - if (!detail::is_directory_separator(*p.m_pathname.begin())) - m_append_separator_if_needed(); - m_pathname += p.m_pathname; - } - return *this; - } - - path& path::operator/=(const value_type* ptr) - { - if (!*ptr) - return *this; - if (ptr >= m_pathname.data() - && ptr < m_pathname.data() + m_pathname.size()) // overlapping source - { - path rhs(ptr); - if (!detail::is_directory_separator(rhs.m_pathname[0])) - m_append_separator_if_needed(); - m_pathname += rhs.m_pathname; - } - else - { - if (!detail::is_directory_separator(*ptr)) - m_append_separator_if_needed(); - m_pathname += ptr; - } - return *this; - } - - int path::compare(const path& p) const BOOST_NOEXCEPT - { - return detail::lex_compare(begin(), end(), p.begin(), p.end()); - } - -# ifdef BOOST_WINDOWS_API - - const std::string path::generic_string() const - { - path tmp(*this); - std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); - return tmp.string(); - } - - const std::string path::generic_string(const codecvt_type& cvt) const - { - path tmp(*this); - std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); - return tmp.string(cvt); - } - - const std::wstring path::generic_wstring() const - { - path tmp(*this); - std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); - return tmp.wstring(); - } - -# endif // BOOST_WINDOWS_API - - // m_append_separator_if_needed ----------------------------------------------------// - - path::string_type::size_type path::m_append_separator_if_needed() - { - if (!m_pathname.empty() && -# ifdef BOOST_WINDOWS_API - *(m_pathname.end()-1) != colon && -# endif - !detail::is_directory_separator(*(m_pathname.end()-1))) - { - string_type::size_type tmp(m_pathname.size()); - m_pathname += preferred_separator; - return tmp; - } - return 0; - } - - // m_erase_redundant_separator -----------------------------------------------------// - - void path::m_erase_redundant_separator(string_type::size_type sep_pos) - { - if (sep_pos // a separator was added - && sep_pos < m_pathname.size() // and something was appended - && (m_pathname[sep_pos+1] == separator // and it was also separator -# ifdef BOOST_WINDOWS_API - || m_pathname[sep_pos+1] == preferred_separator // or preferred_separator -# endif -)) { m_pathname.erase(sep_pos, 1); } // erase the added separator - } - - // modifiers -----------------------------------------------------------------------// - -# ifdef BOOST_WINDOWS_API - path & path::make_preferred() - { - std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); - return *this; - } -# endif - - path& path::remove_filename() - { - m_pathname.erase(m_parent_path_end()); - return *this; - } - - path& path::remove_trailing_separator() - { - if (!m_pathname.empty() - && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) - m_pathname.erase(m_pathname.size() - 1); - return *this; - } - - path& path::replace_extension(const path& new_extension) - { - // erase existing extension, including the dot, if any - m_pathname.erase(m_pathname.size()-extension().m_pathname.size()); - - if (!new_extension.empty()) +// filesystem path.cpp ------------------------------------------------------------- // + +// Copyright Beman Dawes 2008 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +// Old standard library configurations, particularly MingGW, don't support wide strings. +// Report this with an explicit error message. +#include <boost/config.hpp> +# if defined( BOOST_NO_STD_WSTRING ) +# error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support +# endif + +// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_FILESYSTEM_SOURCE + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include <boost/filesystem/config.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> // for filesystem_error +#include <boost/scoped_array.hpp> +#include <boost/system/error_code.hpp> +#include <boost/assert.hpp> +#include <algorithm> +#include <cstddef> +#include <cstring> +#include <cassert> + +#ifdef BOOST_WINDOWS_API +# include "windows_file_codecvt.hpp" +# include <windows.h> +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +# include <boost/filesystem/detail/utf8_codecvt_facet.hpp> +#endif + +#ifdef BOOST_FILESYSTEM_DEBUG +# include <iostream> +# include <iomanip> +#endif + +namespace fs = boost::filesystem; + +using boost::filesystem::path; + +using std::string; +using std::wstring; + +using boost::system::error_code; + +//--------------------------------------------------------------------------------------// +// // +// class path helpers // +// // +//--------------------------------------------------------------------------------------// + +namespace +{ + //------------------------------------------------------------------------------------// + // miscellaneous class path helpers // + //------------------------------------------------------------------------------------// + + typedef path::value_type value_type; + typedef path::string_type string_type; + typedef string_type::size_type size_type; + +# ifdef BOOST_WINDOWS_API + + const wchar_t* const separators = L"/\\"; + const wchar_t* separator_string = L"/"; + const wchar_t* preferred_separator_string = L"\\"; + const wchar_t colon = L':'; + const wchar_t questionmark = L'?'; + + inline bool is_letter(wchar_t c) + { + return (c >= L'a' && c <=L'z') || (c >= L'A' && c <=L'Z'); + } + +# else + + const char* const separators = "/"; + const char* separator_string = "/"; + const char* preferred_separator_string = "/"; + +# endif + + bool is_root_separator(const string_type& str, size_type pos); + // pos is position of the separator + + size_type filename_pos(const string_type& str, + size_type end_pos); // end_pos is past-the-end position + // Returns: 0 if str itself is filename (or empty) + + size_type root_directory_start(const string_type& path, size_type size); + // Returns: npos if no root_directory found + + void first_element( + const string_type& src, + size_type& element_pos, + size_type& element_size, +# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) // VC++ 7.1 + size_type size = string_type::npos +# else + size_type size = -1 +# endif + ); + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// class path implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace boost +{ +namespace filesystem +{ + path& path::operator/=(const path& p) + { + if (p.empty()) + return *this; + if (this == &p) // self-append + { + path rhs(p); + if (!detail::is_directory_separator(rhs.m_pathname[0])) + m_append_separator_if_needed(); + m_pathname += rhs.m_pathname; + } + else + { + if (!detail::is_directory_separator(*p.m_pathname.begin())) + m_append_separator_if_needed(); + m_pathname += p.m_pathname; + } + return *this; + } + + path& path::operator/=(const value_type* ptr) + { + if (!*ptr) + return *this; + if (ptr >= m_pathname.data() + && ptr < m_pathname.data() + m_pathname.size()) // overlapping source + { + path rhs(ptr); + if (!detail::is_directory_separator(rhs.m_pathname[0])) + m_append_separator_if_needed(); + m_pathname += rhs.m_pathname; + } + else + { + if (!detail::is_directory_separator(*ptr)) + m_append_separator_if_needed(); + m_pathname += ptr; + } + return *this; + } + + int path::compare(const path& p) const BOOST_NOEXCEPT + { + return detail::lex_compare(begin(), end(), p.begin(), p.end()); + } + +# ifdef BOOST_WINDOWS_API + + const std::string path::generic_string() const + { + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp.string(); + } + + const std::string path::generic_string(const codecvt_type& cvt) const + { + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp.string(cvt); + } + + const std::wstring path::generic_wstring() const + { + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp.wstring(); + } + +# endif // BOOST_WINDOWS_API + + // m_append_separator_if_needed ----------------------------------------------------// + + path::string_type::size_type path::m_append_separator_if_needed() + { + if (!m_pathname.empty() && +# ifdef BOOST_WINDOWS_API + *(m_pathname.end()-1) != colon && +# endif + !detail::is_directory_separator(*(m_pathname.end()-1))) + { + string_type::size_type tmp(m_pathname.size()); + m_pathname += preferred_separator; + return tmp; + } + return 0; + } + + // m_erase_redundant_separator -----------------------------------------------------// + + void path::m_erase_redundant_separator(string_type::size_type sep_pos) + { + if (sep_pos // a separator was added + && sep_pos < m_pathname.size() // and something was appended + && (m_pathname[sep_pos+1] == separator // and it was also separator +# ifdef BOOST_WINDOWS_API + || m_pathname[sep_pos+1] == preferred_separator // or preferred_separator +# endif +)) { m_pathname.erase(sep_pos, 1); } // erase the added separator + } + + // modifiers -----------------------------------------------------------------------// + +# ifdef BOOST_WINDOWS_API + path & path::make_preferred() + { + std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); + return *this; + } +# endif + + path& path::remove_filename() + { + m_pathname.erase(m_parent_path_end()); + return *this; + } + + path& path::remove_trailing_separator() + { + if (!m_pathname.empty() + && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) + m_pathname.erase(m_pathname.size() - 1); + return *this; + } + + path& path::replace_extension(const path& new_extension) + { + // erase existing extension, including the dot, if any + m_pathname.erase(m_pathname.size()-extension().m_pathname.size()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != dot) + m_pathname.push_back(dot); + m_pathname.append(new_extension.m_pathname); + } + + return *this; + } + + // decomposition -------------------------------------------------------------------// + + path path::root_path() const + { + path temp(root_name()); + if (!root_directory().empty()) temp.m_pathname += root_directory().c_str(); + return temp; + } + + path path::root_name() const + { + iterator itr(begin()); + + return (itr.m_pos != m_pathname.size() + && ( + (itr.m_element.m_pathname.size() > 1 + && detail::is_directory_separator(itr.m_element.m_pathname[0]) + && detail::is_directory_separator(itr.m_element.m_pathname[1]) + ) +# ifdef BOOST_WINDOWS_API + || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon +# endif + )) + ? itr.m_element + : path(); + } + + path path::root_directory() const + { + size_type pos(root_directory_start(m_pathname, m_pathname.size())); + + return pos == string_type::npos + ? path() + : path(m_pathname.c_str() + pos, m_pathname.c_str() + pos + 1); + } + + path path::relative_path() const + { + iterator itr(begin()); + + for (; itr.m_pos != m_pathname.size() + && (detail::is_directory_separator(itr.m_element.m_pathname[0]) +# ifdef BOOST_WINDOWS_API + || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon +# endif + ); ++itr) {} + + return path(m_pathname.c_str() + itr.m_pos); + } + + string_type::size_type path::m_parent_path_end() const + { + size_type end_pos(filename_pos(m_pathname, m_pathname.size())); + + bool filename_was_separator(m_pathname.size() + && detail::is_directory_separator(m_pathname[end_pos])); + + // skip separators unless root directory + size_type root_dir_pos(root_directory_start(m_pathname, end_pos)); + for (; + end_pos > 0 + && (end_pos-1) != root_dir_pos + && detail::is_directory_separator(m_pathname[end_pos-1]) + ; + --end_pos) {} + + return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator) + ? string_type::npos + : end_pos; + } + + path path::parent_path() const + { + size_type end_pos(m_parent_path_end()); + return end_pos == string_type::npos + ? path() + : path(m_pathname.c_str(), m_pathname.c_str() + end_pos); + } + + path path::filename() const + { + size_type pos(filename_pos(m_pathname, m_pathname.size())); + return (m_pathname.size() + && pos + && detail::is_directory_separator(m_pathname[pos]) + && !is_root_separator(m_pathname, pos)) + ? detail::dot_path() + : path(m_pathname.c_str() + pos); + } + + path path::stem() const + { + path name(filename()); + if (name == detail::dot_path() || name == detail::dot_dot_path()) return name; + size_type pos(name.m_pathname.rfind(dot)); + return pos == string_type::npos + ? name + : path(name.m_pathname.c_str(), name.m_pathname.c_str() + pos); + } + + path path::extension() const + { + path name(filename()); + if (name == detail::dot_path() || name == detail::dot_dot_path()) return path(); + size_type pos(name.m_pathname.rfind(dot)); + return pos == string_type::npos + ? path() + : path(name.m_pathname.c_str() + pos); + } + + // lexical operations --------------------------------------------------------------// + + namespace detail + { + // C++14 provide a mismatch algorithm with four iterator arguments(), but earlier + // standard libraries didn't, so provide this needed functionality. + inline + std::pair<path::iterator, path::iterator> mismatch(path::iterator it1, + path::iterator it1end, path::iterator it2, path::iterator it2end) + { + for (; it1 != it1end && it2 != it2end && *it1 == *it2;) + { + ++it1; + ++it2; + } + return std::make_pair(it1, it2); + } + } + + path path::lexically_relative(const path& base) const + { + std::pair<path::iterator, path::iterator> mm + = detail::mismatch(begin(), end(), base.begin(), base.end()); + if (mm.first == begin() && mm.second == base.begin()) + return path(); + if (mm.first == end() && mm.second == base.end()) + return detail::dot_path(); + path tmp; + for (; mm.second != base.end(); ++mm.second) + tmp /= detail::dot_dot_path(); + for (; mm.first != end(); ++mm.first) + tmp /= *mm.first; + return tmp; + } + + // normal --------------------------------------------------------------------------// + + path path::lexically_normal() const + { + if (m_pathname.empty()) + return *this; + + path temp; + iterator start(begin()); + iterator last(end()); + iterator stop(last--); + for (iterator itr(start); itr != stop; ++itr) + { + // ignore "." except at start and last + if (itr->native().size() == 1 + && (itr->native())[0] == dot + && itr != start + && itr != last) continue; + + // ignore a name and following ".." + if (!temp.empty() + && itr->native().size() == 2 + && (itr->native())[0] == dot + && (itr->native())[1] == dot) // dot dot + { + string_type lf(temp.filename().native()); + if (lf.size() > 0 + && (lf.size() != 1 + || (lf[0] != dot + && lf[0] != separator)) + && (lf.size() != 2 + || (lf[0] != dot + && lf[1] != dot +# ifdef BOOST_WINDOWS_API + && lf[1] != colon +# endif + ) + ) + ) + { + temp.remove_filename(); + //// if not root directory, must also remove "/" if any + //if (temp.native().size() > 0 + // && temp.native()[temp.native().size()-1] + // == separator) + //{ + // string_type::size_type rds( + // root_directory_start(temp.native(), temp.native().size())); + // if (rds == string_type::npos + // || rds != temp.native().size()-1) + // { + // temp.m_pathname.erase(temp.native().size()-1); + // } + //} + + iterator next(itr); + if (temp.empty() && ++next != stop + && next == last && *last == detail::dot_path()) + { + temp /= detail::dot_path(); + } + continue; + } + } + + temp /= *itr; + }; + + if (temp.empty()) + temp /= detail::dot_path(); + return temp; + } + +} // namespace filesystem +} // namespace boost + +//--------------------------------------------------------------------------------------// +// // +// class path helpers implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace +{ + + // is_root_separator ---------------------------------------------------------------// + + bool is_root_separator(const string_type & str, size_type pos) + // pos is position of the separator + { + BOOST_ASSERT_MSG(!str.empty() && fs::detail::is_directory_separator(str[pos]), + "precondition violation"); + + // subsequent logic expects pos to be for leftmost slash of a set + while (pos > 0 && fs::detail::is_directory_separator(str[pos-1])) + --pos; + + // "/" [...] + if (pos == 0) + return true; + +# ifdef BOOST_WINDOWS_API + // "c:/" [...] + if (pos == 2 && is_letter(str[0]) && str[1] == colon) + return true; +# endif + + // "//" name "/" + if (pos < 3 || !fs::detail::is_directory_separator(str[0]) + || !fs::detail::is_directory_separator(str[1])) + return false; + + return str.find_first_of(separators, 2) == pos; + } + + // filename_pos --------------------------------------------------------------------// + + size_type filename_pos(const string_type & str, + size_type end_pos) // end_pos is past-the-end position + // return 0 if str itself is filename (or empty) + { + // case: "//" + if (end_pos == 2 + && fs::detail::is_directory_separator(str[0]) + && fs::detail::is_directory_separator(str[1])) return 0; + + // case: ends in "/" + if (end_pos && fs::detail::is_directory_separator(str[end_pos-1])) + return end_pos-1; + + // set pos to start of last element + size_type pos(str.find_last_of(separators, end_pos-1)); + +# ifdef BOOST_WINDOWS_API + if (pos == string_type::npos && end_pos > 1) + pos = str.find_last_of(colon, end_pos-2); +# endif + + return (pos == string_type::npos // path itself must be a filename (or empty) + || (pos == 1 && fs::detail::is_directory_separator(str[0]))) // or net + ? 0 // so filename is entire string + : pos + 1; // or starts after delimiter + } + + // root_directory_start ------------------------------------------------------------// + + size_type root_directory_start(const string_type & path, size_type size) + // return npos if no root_directory found + { + +# ifdef BOOST_WINDOWS_API + // case "c:/" + if (size > 2 + && path[1] == colon + && fs::detail::is_directory_separator(path[2])) return 2; +# endif + + // case "//" + if (size == 2 + && fs::detail::is_directory_separator(path[0]) + && fs::detail::is_directory_separator(path[1])) return string_type::npos; + +# ifdef BOOST_WINDOWS_API + // case "\\?\" + if (size > 4 + && fs::detail::is_directory_separator(path[0]) + && fs::detail::is_directory_separator(path[1]) + && path[2] == questionmark + && fs::detail::is_directory_separator(path[3])) + { + string_type::size_type pos(path.find_first_of(separators, 4)); + return pos < size ? pos : string_type::npos; + } +# endif + + // case "//net {/}" + if (size > 3 + && fs::detail::is_directory_separator(path[0]) + && fs::detail::is_directory_separator(path[1]) + && !fs::detail::is_directory_separator(path[2])) + { + string_type::size_type pos(path.find_first_of(separators, 2)); + return pos < size ? pos : string_type::npos; + } + + // case "/" + if (size > 0 && fs::detail::is_directory_separator(path[0])) return 0; + + return string_type::npos; + } + + // first_element --------------------------------------------------------------------// + // sets pos and len of first element, excluding extra separators + // if src.empty(), sets pos,len, to 0,0. + + void first_element( + const string_type & src, + size_type & element_pos, + size_type & element_size, + size_type size +) + { + if (size == string_type::npos) size = src.size(); + element_pos = 0; + element_size = 0; + if (src.empty()) return; + + string_type::size_type cur(0); + + // deal with // [network] + if (size >= 2 && fs::detail::is_directory_separator(src[0]) + && fs::detail::is_directory_separator(src[1]) + && (size == 2 + || !fs::detail::is_directory_separator(src[2]))) { - // append new_extension, adding the dot if necessary - if (new_extension.m_pathname[0] != dot) - m_pathname.push_back(dot); - m_pathname.append(new_extension.m_pathname); - } - - return *this; - } - - // decomposition -------------------------------------------------------------------// - - path path::root_path() const - { - path temp(root_name()); - if (!root_directory().empty()) temp.m_pathname += root_directory().c_str(); - return temp; - } - - path path::root_name() const - { - iterator itr(begin()); - - return (itr.m_pos != m_pathname.size() - && ( - (itr.m_element.m_pathname.size() > 1 - && detail::is_directory_separator(itr.m_element.m_pathname[0]) - && detail::is_directory_separator(itr.m_element.m_pathname[1]) - ) -# ifdef BOOST_WINDOWS_API - || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon -# endif - )) - ? itr.m_element - : path(); - } - - path path::root_directory() const - { - size_type pos(root_directory_start(m_pathname, m_pathname.size())); - - return pos == string_type::npos - ? path() - : path(m_pathname.c_str() + pos, m_pathname.c_str() + pos + 1); - } - - path path::relative_path() const - { - iterator itr(begin()); - - for (; itr.m_pos != m_pathname.size() - && (detail::is_directory_separator(itr.m_element.m_pathname[0]) -# ifdef BOOST_WINDOWS_API - || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon -# endif - ); ++itr) {} - - return path(m_pathname.c_str() + itr.m_pos); - } - - string_type::size_type path::m_parent_path_end() const - { - size_type end_pos(filename_pos(m_pathname, m_pathname.size())); - - bool filename_was_separator(m_pathname.size() - && detail::is_directory_separator(m_pathname[end_pos])); - - // skip separators unless root directory - size_type root_dir_pos(root_directory_start(m_pathname, end_pos)); - for (; - end_pos > 0 - && (end_pos-1) != root_dir_pos - && detail::is_directory_separator(m_pathname[end_pos-1]) + cur += 2; + element_size += 2; + } + + // leading (not non-network) separator + else if (fs::detail::is_directory_separator(src[0])) + { + ++element_size; + // bypass extra leading separators + while (cur+1 < size + && fs::detail::is_directory_separator(src[cur+1])) + { + ++cur; + ++element_pos; + } + return; + } + + // at this point, we have either a plain name, a network name, + // or (on Windows only) a device name + + // find the end + while (cur < size +# ifdef BOOST_WINDOWS_API + && src[cur] != colon +# endif + && !fs::detail::is_directory_separator(src[cur])) + { + ++cur; + ++element_size; + } + +# ifdef BOOST_WINDOWS_API + if (cur == size) return; + // include device delimiter + if (src[cur] == colon) + { ++element_size; } +# endif + + return; + } + +} // unnamed namespace + + +namespace boost +{ +namespace filesystem +{ + namespace detail + { + BOOST_FILESYSTEM_DECL + int lex_compare(path::iterator first1, path::iterator last1, + path::iterator first2, path::iterator last2) + { + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) return -1; + if (first2->native() < first1->native()) return 1; + BOOST_ASSERT(first2->native() == first1->native()); + ++first1; + ++first2; + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; + } + + BOOST_FILESYSTEM_DECL + const path& dot_path() + { +# ifdef BOOST_WINDOWS_API + static const fs::path dot_pth(L"."); +# else + static const fs::path dot_pth("."); +# endif + return dot_pth; + } + + BOOST_FILESYSTEM_DECL + const path& dot_dot_path() + { +# ifdef BOOST_WINDOWS_API + static const fs::path dot_dot(L".."); +# else + static const fs::path dot_dot(".."); +# endif + return dot_dot; + } + } + +//--------------------------------------------------------------------------------------// +// // +// class path::iterator implementation // +// // +//--------------------------------------------------------------------------------------// + + path::iterator path::begin() const + { + iterator itr; + itr.m_path_ptr = this; + size_type element_size; + first_element(m_pathname, itr.m_pos, element_size); + itr.m_element = m_pathname.substr(itr.m_pos, element_size); + if (itr.m_element.m_pathname == preferred_separator_string) + itr.m_element.m_pathname = separator_string; // needed for Windows, harmless on POSIX + return itr; + } + + path::iterator path::end() const + { + iterator itr; + itr.m_path_ptr = this; + itr.m_pos = m_pathname.size(); + return itr; + } + + void path::m_path_iterator_increment(path::iterator & it) + { + BOOST_ASSERT_MSG(it.m_pos < it.m_path_ptr->m_pathname.size(), + "path::basic_iterator increment past end()"); + + // increment to position past current element; if current element is implicit dot, + // this will cause it.m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos == it.m_path_ptr->m_pathname.size()) + { + it.m_element.clear(); // aids debugging, may release unneeded memory + return; + } + + // both POSIX and Windows treat paths that begin with exactly two separators specially + bool was_net(it.m_element.m_pathname.size() > 2 + && detail::is_directory_separator(it.m_element.m_pathname[0]) + && detail::is_directory_separator(it.m_element.m_pathname[1]) + && !detail::is_directory_separator(it.m_element.m_pathname[2])); + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + // detect root directory + if (was_net +# ifdef BOOST_WINDOWS_API + // case "c:/" + || it.m_element.m_pathname[it.m_element.m_pathname.size()-1] == colon +# endif + ) + { + it.m_element.m_pathname = separator; // generic format; see docs + return; + } + + // skip separators until it.m_pos points to the start of the next element + while (it.m_pos != it.m_path_ptr->m_pathname.size() + && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { ++it.m_pos; } + + // detect trailing separator, and treat it as ".", per POSIX spec + if (it.m_pos == it.m_path_ptr->m_pathname.size() + && !is_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + } + + // get m_element + size_type end_pos(it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos)); + if (end_pos == string_type::npos) + end_pos = it.m_path_ptr->m_pathname.size(); + it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos); + } + + void path::m_path_iterator_decrement(path::iterator & it) + { + BOOST_ASSERT_MSG(it.m_pos, "path::iterator decrement past begin()"); + + size_type end_pos(it.m_pos); + + // if at end and there was a trailing non-root '/', return "." + if (it.m_pos == it.m_path_ptr->m_pathname.size() + && it.m_path_ptr->m_pathname.size() > 1 + && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos-1]) + && !is_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1) + ) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + + size_type root_dir_pos(root_directory_start(it.m_path_ptr->m_pathname, end_pos)); + + // skip separators unless root directory + for ( ; - --end_pos) {} - - return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator) - ? string_type::npos - : end_pos; - } - - path path::parent_path() const - { - size_type end_pos(m_parent_path_end()); - return end_pos == string_type::npos - ? path() - : path(m_pathname.c_str(), m_pathname.c_str() + end_pos); - } - - path path::filename() const - { - size_type pos(filename_pos(m_pathname, m_pathname.size())); - return (m_pathname.size() - && pos - && detail::is_directory_separator(m_pathname[pos]) - && !is_root_separator(m_pathname, pos)) - ? detail::dot_path() - : path(m_pathname.c_str() + pos); - } - - path path::stem() const - { - path name(filename()); - if (name == detail::dot_path() || name == detail::dot_dot_path()) return name; - size_type pos(name.m_pathname.rfind(dot)); - return pos == string_type::npos - ? name - : path(name.m_pathname.c_str(), name.m_pathname.c_str() + pos); - } - - path path::extension() const - { - path name(filename()); - if (name == detail::dot_path() || name == detail::dot_dot_path()) return path(); - size_type pos(name.m_pathname.rfind(dot)); - return pos == string_type::npos - ? path() - : path(name.m_pathname.c_str() + pos); - } - - // lexical operations --------------------------------------------------------------// - - namespace detail - { - // C++14 provide a mismatch algorithm with four iterator arguments(), but earlier - // standard libraries didn't, so provide this needed functionality. - inline - std::pair<path::iterator, path::iterator> mismatch(path::iterator it1, - path::iterator it1end, path::iterator it2, path::iterator it2end) - { - for (; it1 != it1end && it2 != it2end && *it1 == *it2;) - { - ++it1; - ++it2; - } - return std::make_pair(it1, it2); - } - } - - path path::lexically_relative(const path& base) const - { - std::pair<path::iterator, path::iterator> mm - = detail::mismatch(begin(), end(), base.begin(), base.end()); - if (mm.first == begin() && mm.second == base.begin()) - return path(); - if (mm.first == end() && mm.second == base.end()) - return detail::dot_path(); - path tmp; - for (; mm.second != base.end(); ++mm.second) - tmp /= detail::dot_dot_path(); - for (; mm.first != end(); ++mm.first) - tmp /= *mm.first; - return tmp; - } - - // normal --------------------------------------------------------------------------// - - path path::lexically_normal() const - { - if (m_pathname.empty()) - return *this; - - path temp; - iterator start(begin()); - iterator last(end()); - iterator stop(last--); - for (iterator itr(start); itr != stop; ++itr) - { - // ignore "." except at start and last - if (itr->native().size() == 1 - && (itr->native())[0] == dot - && itr != start - && itr != last) continue; - - // ignore a name and following ".." - if (!temp.empty() - && itr->native().size() == 2 - && (itr->native())[0] == dot - && (itr->native())[1] == dot) // dot dot - { - string_type lf(temp.filename().native()); - if (lf.size() > 0 - && (lf.size() != 1 - || (lf[0] != dot - && lf[0] != separator)) - && (lf.size() != 2 - || (lf[0] != dot - && lf[1] != dot -# ifdef BOOST_WINDOWS_API - && lf[1] != colon -# endif - ) - ) - ) - { - temp.remove_filename(); - //// if not root directory, must also remove "/" if any - //if (temp.native().size() > 0 - // && temp.native()[temp.native().size()-1] - // == separator) - //{ - // string_type::size_type rds( - // root_directory_start(temp.native(), temp.native().size())); - // if (rds == string_type::npos - // || rds != temp.native().size()-1) - // { - // temp.m_pathname.erase(temp.native().size()-1); - // } - //} - - iterator next(itr); - if (temp.empty() && ++next != stop - && next == last && *last == detail::dot_path()) - { - temp /= detail::dot_path(); - } - continue; - } - } - - temp /= *itr; - }; - - if (temp.empty()) - temp /= detail::dot_path(); - return temp; - } - -} // namespace filesystem -} // namespace boost - -//--------------------------------------------------------------------------------------// -// // -// class path helpers implementation // -// // -//--------------------------------------------------------------------------------------// - -namespace -{ - - // is_root_separator ---------------------------------------------------------------// - - bool is_root_separator(const string_type & str, size_type pos) - // pos is position of the separator - { - BOOST_ASSERT_MSG(!str.empty() && fs::detail::is_directory_separator(str[pos]), - "precondition violation"); - - // subsequent logic expects pos to be for leftmost slash of a set - while (pos > 0 && fs::detail::is_directory_separator(str[pos-1])) - --pos; - - // "/" [...] - if (pos == 0) - return true; - -# ifdef BOOST_WINDOWS_API - // "c:/" [...] - if (pos == 2 && is_letter(str[0]) && str[1] == colon) - return true; -# endif - - // "//" name "/" - if (pos < 3 || !fs::detail::is_directory_separator(str[0]) - || !fs::detail::is_directory_separator(str[1])) - return false; - - return str.find_first_of(separators, 2) == pos; - } - - // filename_pos --------------------------------------------------------------------// - - size_type filename_pos(const string_type & str, - size_type end_pos) // end_pos is past-the-end position - // return 0 if str itself is filename (or empty) - { - // case: "//" - if (end_pos == 2 - && fs::detail::is_directory_separator(str[0]) - && fs::detail::is_directory_separator(str[1])) return 0; - - // case: ends in "/" - if (end_pos && fs::detail::is_directory_separator(str[end_pos-1])) - return end_pos-1; - - // set pos to start of last element - size_type pos(str.find_last_of(separators, end_pos-1)); - -# ifdef BOOST_WINDOWS_API - if (pos == string_type::npos && end_pos > 1) - pos = str.find_last_of(colon, end_pos-2); -# endif - - return (pos == string_type::npos // path itself must be a filename (or empty) - || (pos == 1 && fs::detail::is_directory_separator(str[0]))) // or net - ? 0 // so filename is entire string - : pos + 1; // or starts after delimiter - } - - // root_directory_start ------------------------------------------------------------// - - size_type root_directory_start(const string_type & path, size_type size) - // return npos if no root_directory found - { - -# ifdef BOOST_WINDOWS_API - // case "c:/" - if (size > 2 - && path[1] == colon - && fs::detail::is_directory_separator(path[2])) return 2; -# endif - - // case "//" - if (size == 2 - && fs::detail::is_directory_separator(path[0]) - && fs::detail::is_directory_separator(path[1])) return string_type::npos; - -# ifdef BOOST_WINDOWS_API - // case "\\?\" - if (size > 4 - && fs::detail::is_directory_separator(path[0]) - && fs::detail::is_directory_separator(path[1]) - && path[2] == questionmark - && fs::detail::is_directory_separator(path[3])) - { - string_type::size_type pos(path.find_first_of(separators, 4)); - return pos < size ? pos : string_type::npos; - } -# endif - - // case "//net {/}" - if (size > 3 - && fs::detail::is_directory_separator(path[0]) - && fs::detail::is_directory_separator(path[1]) - && !fs::detail::is_directory_separator(path[2])) - { - string_type::size_type pos(path.find_first_of(separators, 2)); - return pos < size ? pos : string_type::npos; - } - - // case "/" - if (size > 0 && fs::detail::is_directory_separator(path[0])) return 0; - - return string_type::npos; - } - - // first_element --------------------------------------------------------------------// - // sets pos and len of first element, excluding extra separators - // if src.empty(), sets pos,len, to 0,0. - - void first_element( - const string_type & src, - size_type & element_pos, - size_type & element_size, - size_type size -) - { - if (size == string_type::npos) size = src.size(); - element_pos = 0; - element_size = 0; - if (src.empty()) return; - - string_type::size_type cur(0); - - // deal with // [network] - if (size >= 2 && fs::detail::is_directory_separator(src[0]) - && fs::detail::is_directory_separator(src[1]) - && (size == 2 - || !fs::detail::is_directory_separator(src[2]))) - { - cur += 2; - element_size += 2; - } - - // leading (not non-network) separator - else if (fs::detail::is_directory_separator(src[0])) - { - ++element_size; - // bypass extra leading separators - while (cur+1 < size - && fs::detail::is_directory_separator(src[cur+1])) - { - ++cur; - ++element_pos; - } - return; - } - - // at this point, we have either a plain name, a network name, - // or (on Windows only) a device name - - // find the end - while (cur < size -# ifdef BOOST_WINDOWS_API - && src[cur] != colon -# endif - && !fs::detail::is_directory_separator(src[cur])) - { - ++cur; - ++element_size; - } - -# ifdef BOOST_WINDOWS_API - if (cur == size) return; - // include device delimiter - if (src[cur] == colon) - { ++element_size; } -# endif - - return; - } - -} // unnamed namespace - - -namespace boost -{ -namespace filesystem -{ - namespace detail - { - BOOST_FILESYSTEM_DECL - int lex_compare(path::iterator first1, path::iterator last1, - path::iterator first2, path::iterator last2) - { - for (; first1 != last1 && first2 != last2;) - { - if (first1->native() < first2->native()) return -1; - if (first2->native() < first1->native()) return 1; - BOOST_ASSERT(first2->native() == first1->native()); - ++first1; - ++first2; - } - if (first1 == last1 && first2 == last2) - return 0; - return first1 == last1 ? -1 : 1; - } - - BOOST_FILESYSTEM_DECL - const path& dot_path() - { -# ifdef BOOST_WINDOWS_API - static const fs::path dot_pth(L"."); -# else - static const fs::path dot_pth("."); -# endif - return dot_pth; - } - - BOOST_FILESYSTEM_DECL - const path& dot_dot_path() - { -# ifdef BOOST_WINDOWS_API - static const fs::path dot_dot(L".."); -# else - static const fs::path dot_dot(".."); -# endif - return dot_dot; - } - } - -//--------------------------------------------------------------------------------------// -// // -// class path::iterator implementation // -// // -//--------------------------------------------------------------------------------------// - - path::iterator path::begin() const - { - iterator itr; - itr.m_path_ptr = this; - size_type element_size; - first_element(m_pathname, itr.m_pos, element_size); - itr.m_element = m_pathname.substr(itr.m_pos, element_size); - if (itr.m_element.m_pathname == preferred_separator_string) - itr.m_element.m_pathname = separator_string; // needed for Windows, harmless on POSIX - return itr; - } - - path::iterator path::end() const - { - iterator itr; - itr.m_path_ptr = this; - itr.m_pos = m_pathname.size(); - return itr; - } - - void path::m_path_iterator_increment(path::iterator & it) - { - BOOST_ASSERT_MSG(it.m_pos < it.m_path_ptr->m_pathname.size(), - "path::basic_iterator increment past end()"); - - // increment to position past current element; if current element is implicit dot, - // this will cause it.m_pos to represent the end iterator - it.m_pos += it.m_element.m_pathname.size(); - - // if the end is reached, we are done - if (it.m_pos == it.m_path_ptr->m_pathname.size()) - { - it.m_element.clear(); // aids debugging, may release unneeded memory - return; - } - - // both POSIX and Windows treat paths that begin with exactly two separators specially - bool was_net(it.m_element.m_pathname.size() > 2 - && detail::is_directory_separator(it.m_element.m_pathname[0]) - && detail::is_directory_separator(it.m_element.m_pathname[1]) - && !detail::is_directory_separator(it.m_element.m_pathname[2])); - - // process separator (Windows drive spec is only case not a separator) - if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) - { - // detect root directory - if (was_net -# ifdef BOOST_WINDOWS_API - // case "c:/" - || it.m_element.m_pathname[it.m_element.m_pathname.size()-1] == colon -# endif - ) - { - it.m_element.m_pathname = separator; // generic format; see docs - return; - } - - // skip separators until it.m_pos points to the start of the next element - while (it.m_pos != it.m_path_ptr->m_pathname.size() - && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) - { ++it.m_pos; } - - // detect trailing separator, and treat it as ".", per POSIX spec - if (it.m_pos == it.m_path_ptr->m_pathname.size() - && !is_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1)) - { - --it.m_pos; - it.m_element = detail::dot_path(); - return; - } - } - - // get m_element - size_type end_pos(it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos)); - if (end_pos == string_type::npos) - end_pos = it.m_path_ptr->m_pathname.size(); - it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos); - } - - void path::m_path_iterator_decrement(path::iterator & it) - { - BOOST_ASSERT_MSG(it.m_pos, "path::iterator decrement past begin()"); - - size_type end_pos(it.m_pos); - - // if at end and there was a trailing non-root '/', return "." - if (it.m_pos == it.m_path_ptr->m_pathname.size() - && it.m_path_ptr->m_pathname.size() > 1 - && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos-1]) - && !is_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1) - ) - { - --it.m_pos; - it.m_element = detail::dot_path(); - return; - } - - size_type root_dir_pos(root_directory_start(it.m_path_ptr->m_pathname, end_pos)); - - // skip separators unless root directory - for ( - ; - end_pos > 0 - && (end_pos-1) != root_dir_pos - && detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos-1]) - ; - --end_pos) {} - - it.m_pos = filename_pos(it.m_path_ptr->m_pathname, end_pos); - it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos); - if (it.m_element.m_pathname == preferred_separator_string) // needed for Windows, harmless on POSIX - it.m_element.m_pathname = separator_string; // generic format; see docs - } - -} // namespace filesystem -} // namespace boost - -namespace -{ - - //------------------------------------------------------------------------------------// - // locale helpers // - //------------------------------------------------------------------------------------// - - // Prior versions of these locale and codecvt implementations tried to take advantage - // of static initialization where possible, kept a local copy of the current codecvt - // facet (to avoid codecvt() having to call use_facet()), and was not multi-threading - // safe (again for efficiency). - // - // This was error prone, and required different implementation techniques depending - // on the compiler and also whether static or dynamic linking was used. Furthermore, - // users could not easily provide their multi-threading safe wrappers because the - // path interface requires the implementation itself to call codecvt() to obtain the - // default facet, and the initialization of the static within path_locale() could race. - // - // The code below is portable to all platforms, is much simpler, and hopefully will be - // much more robust. Timing tests (on Windows, using a Visual C++ release build) - // indicated the current code is roughly 9% slower than the previous code, and that - // seems a small price to pay for better code that is easier to use. - - std::locale default_locale() - { -# if defined(BOOST_WINDOWS_API) - std::locale global_loc = std::locale(); - return std::locale(global_loc, new windows_file_codecvt); -# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) - // "All BSD system functions expect their string parameters to be in UTF-8 encoding - // and nothing else." See - // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html - // - // "The kernel will reject any filename that is not a valid UTF-8 string, and it will - // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. - // The right way to deal with it would be to always convert the filename to UTF-8 - // before trying to open/create a file." See - // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html - // - // "How a file name looks at the API level depends on the API. Current Carbon APIs - // handle file names as an array of UTF-16 characters; POSIX ones handle them as an - // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk - // depends on the disk format; HFS+ uses UTF-16, but that's not important in most - // cases." See - // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html - // - // Many thanks to Peter Dimov for digging out the above references! - - std::locale global_loc = std::locale(); - return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet); -# else // Other POSIX - // ISO C calls std::locale("") "the locale-specific native environment", and this - // locale is the default for many POSIX-based operating systems such as Linux. - return std::locale(""); -# endif - } - - std::locale& path_locale() - // std::locale("") construction, needed on non-Apple POSIX systems, can throw - // (if environmental variables LC_MESSAGES or LANG are wrong, for example), so - // path_locale() provides lazy initialization via a local static to ensure that any - // exceptions occur after main() starts and so can be caught. Furthermore, - // path_locale() is only called if path::codecvt() or path::imbue() are themselves - // actually called, ensuring that an exception will only be thrown if std::locale("") - // is really needed. - { - // [locale] paragraph 6: Once a facet reference is obtained from a locale object by - // calling use_facet<>, that reference remains usable, and the results from member - // functions of it may be cached and re-used, as long as some locale object refers - // to that facet. - static std::locale loc(default_locale()); -#ifdef BOOST_FILESYSTEM_DEBUG - std::cout << "***** path_locale() called" << std::endl; -#endif - return loc; - } -} // unnamed namespace - -//--------------------------------------------------------------------------------------// -// path::codecvt() and path::imbue() implementation // -//--------------------------------------------------------------------------------------// - -namespace boost -{ -namespace filesystem -{ - // See comments above - - const path::codecvt_type& path::codecvt() - { -#ifdef BOOST_FILESYSTEM_DEBUG - std::cout << "***** path::codecvt() called" << std::endl; -#endif - BOOST_ASSERT_MSG(&path_locale(), "boost::filesystem::path locale initialization error"); - - return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(path_locale()); - } - - std::locale path::imbue(const std::locale& loc) - { -#ifdef BOOST_FILESYSTEM_DEBUG - std::cout << "***** path::imbue() called" << std::endl; -#endif - std::locale temp(path_locale()); - path_locale() = loc; - return temp; - } - -} // namespace filesystem -} // namespace boost + end_pos > 0 + && (end_pos-1) != root_dir_pos + && detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos-1]) + ; + --end_pos) {} + + it.m_pos = filename_pos(it.m_path_ptr->m_pathname, end_pos); + it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos); + if (it.m_element.m_pathname == preferred_separator_string) // needed for Windows, harmless on POSIX + it.m_element.m_pathname = separator_string; // generic format; see docs + } + +} // namespace filesystem +} // namespace boost + +namespace +{ + + //------------------------------------------------------------------------------------// + // locale helpers // + //------------------------------------------------------------------------------------// + + // Prior versions of these locale and codecvt implementations tried to take advantage + // of static initialization where possible, kept a local copy of the current codecvt + // facet (to avoid codecvt() having to call use_facet()), and was not multi-threading + // safe (again for efficiency). + // + // This was error prone, and required different implementation techniques depending + // on the compiler and also whether static or dynamic linking was used. Furthermore, + // users could not easily provide their multi-threading safe wrappers because the + // path interface requires the implementation itself to call codecvt() to obtain the + // default facet, and the initialization of the static within path_locale() could race. + // + // The code below is portable to all platforms, is much simpler, and hopefully will be + // much more robust. Timing tests (on Windows, using a Visual C++ release build) + // indicated the current code is roughly 9% slower than the previous code, and that + // seems a small price to pay for better code that is easier to use. + + std::locale default_locale() + { +# if defined(BOOST_WINDOWS_API) + std::locale global_loc = std::locale(); + return std::locale(global_loc, new windows_file_codecvt); +# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + // "All BSD system functions expect their string parameters to be in UTF-8 encoding + // and nothing else." See + // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html + // + // "The kernel will reject any filename that is not a valid UTF-8 string, and it will + // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. + // The right way to deal with it would be to always convert the filename to UTF-8 + // before trying to open/create a file." See + // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html + // + // "How a file name looks at the API level depends on the API. Current Carbon APIs + // handle file names as an array of UTF-16 characters; POSIX ones handle them as an + // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk + // depends on the disk format; HFS+ uses UTF-16, but that's not important in most + // cases." See + // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html + // + // Many thanks to Peter Dimov for digging out the above references! + + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet); +# else // Other POSIX + // ISO C calls std::locale("") "the locale-specific native environment", and this + // locale is the default for many POSIX-based operating systems such as Linux. + return std::locale(""); +# endif + } + + std::locale& path_locale() + // std::locale("") construction, needed on non-Apple POSIX systems, can throw + // (if environmental variables LC_MESSAGES or LANG are wrong, for example), so + // path_locale() provides lazy initialization via a local static to ensure that any + // exceptions occur after main() starts and so can be caught. Furthermore, + // path_locale() is only called if path::codecvt() or path::imbue() are themselves + // actually called, ensuring that an exception will only be thrown if std::locale("") + // is really needed. + { + // [locale] paragraph 6: Once a facet reference is obtained from a locale object by + // calling use_facet<>, that reference remains usable, and the results from member + // functions of it may be cached and re-used, as long as some locale object refers + // to that facet. + static std::locale loc(default_locale()); +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path_locale() called" << std::endl; +#endif + return loc; + } +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path::codecvt() and path::imbue() implementation // +//--------------------------------------------------------------------------------------// + +namespace boost +{ +namespace filesystem +{ + // See comments above + + const path::codecvt_type& path::codecvt() + { +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::codecvt() called" << std::endl; +#endif + BOOST_ASSERT_MSG(&path_locale(), "boost::filesystem::path locale initialization error"); + + return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(path_locale()); + } + + std::locale path::imbue(const std::locale& loc) + { +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::imbue() called" << std::endl; +#endif + std::locale temp(path_locale()); + path_locale() = loc; + return temp; + } + +} // namespace filesystem +} // namespace boost diff --git a/contrib/restricted/boost/libs/filesystem/src/path_traits.cpp b/contrib/restricted/boost/libs/filesystem/src/path_traits.cpp index 0aa64024ae..07b92c0f12 100644 --- a/contrib/restricted/boost/libs/filesystem/src/path_traits.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/path_traits.cpp @@ -1,200 +1,200 @@ -// filesystem path_traits.cpp --------------------------------------------------------// - -// Copyright Beman Dawes 2008, 2009 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// Library home page: http://www.boost.org/libs/filesystem - -//--------------------------------------------------------------------------------------// - -// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows -// the library is being built (possibly exporting rather than importing code) -#define BOOST_FILESYSTEM_SOURCE - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#include <boost/filesystem/config.hpp> -#include <boost/filesystem/path_traits.hpp> -#include <boost/system/system_error.hpp> -#include <boost/scoped_array.hpp> -#include <locale> // for codecvt_base::result -#include <cstring> // for strlen -#include <cwchar> // for wcslen - -namespace pt = boost::filesystem::path_traits; -namespace fs = boost::filesystem; -namespace bs = boost::system; - -//--------------------------------------------------------------------------------------// -// configuration // -//--------------------------------------------------------------------------------------// - -#ifndef BOOST_FILESYSTEM_CODECVT_BUF_SIZE -# define BOOST_FILESYSTEM_CODECVT_BUF_SIZE 256 -#endif - -namespace { - - const std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM_CODECVT_BUF_SIZE; - - -//--------------------------------------------------------------------------------------// -// // -// The public convert() functions do buffer management, and then forward to the // -// convert_aux() functions for the actual call to the codecvt facet. // -// // -//--------------------------------------------------------------------------------------// - -//--------------------------------------------------------------------------------------// -// convert_aux const char* to wstring // -//--------------------------------------------------------------------------------------// - - void convert_aux( - const char* from, - const char* from_end, - wchar_t* to, wchar_t* to_end, - std::wstring & target, - const pt::codecvt_type & cvt) - { - //std::cout << std::hex - // << " from=" << std::size_t(from) - // << " from_end=" << std::size_t(from_end) - // << " to=" << std::size_t(to) - // << " to_end=" << std::size_t(to_end) - // << std::endl; - - std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports - const char* from_next; - wchar_t* to_next; - - std::codecvt_base::result res; - - if ((res=cvt.in(state, from, from_end, from_next, - to, to_end, to_next)) != std::codecvt_base::ok) - { - //std::cout << " result is " << static_cast<int>(res) << std::endl; - BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), - "boost::filesystem::path codecvt to wstring")); - } - target.append(to, to_next); - } - -//--------------------------------------------------------------------------------------// -// convert_aux const wchar_t* to string // -//--------------------------------------------------------------------------------------// - - void convert_aux( - const wchar_t* from, - const wchar_t* from_end, - char* to, char* to_end, - std::string & target, - const pt::codecvt_type & cvt) - { - //std::cout << std::hex - // << " from=" << std::size_t(from) - // << " from_end=" << std::size_t(from_end) - // << " to=" << std::size_t(to) - // << " to_end=" << std::size_t(to_end) - // << std::endl; - - std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports - const wchar_t* from_next; - char* to_next; - - std::codecvt_base::result res; - - if ((res=cvt.out(state, from, from_end, from_next, - to, to_end, to_next)) != std::codecvt_base::ok) - { - //std::cout << " result is " << static_cast<int>(res) << std::endl; - BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), - "boost::filesystem::path codecvt to string")); - } - target.append(to, to_next); - } - -} // unnamed namespace - -//--------------------------------------------------------------------------------------// -// path_traits // -//--------------------------------------------------------------------------------------// - -namespace boost { namespace filesystem { namespace path_traits { - -//--------------------------------------------------------------------------------------// -// convert const char* to wstring // -//--------------------------------------------------------------------------------------// - - BOOST_FILESYSTEM_DECL - void convert(const char* from, - const char* from_end, // 0 for null terminated MBCS - std::wstring & to, - const codecvt_type & cvt) - { - BOOST_ASSERT(from); - - if (!from_end) // null terminated - { - from_end = from + std::strlen(from); - } - - if (from == from_end) return; - - std::size_t buf_size = (from_end - from) * 3; // perhaps too large, but that's OK - - // dynamically allocate a buffer only if source is unusually large - if (buf_size > default_codecvt_buf_size) - { - boost::scoped_array< wchar_t > buf(new wchar_t [buf_size]); - convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to, cvt); - } - else - { - wchar_t buf[default_codecvt_buf_size]; - convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt); - } - } - -//--------------------------------------------------------------------------------------// -// convert const wchar_t* to string // -//--------------------------------------------------------------------------------------// - - BOOST_FILESYSTEM_DECL - void convert(const wchar_t* from, - const wchar_t* from_end, // 0 for null terminated MBCS - std::string & to, - const codecvt_type & cvt) - { - BOOST_ASSERT(from); - - if (!from_end) // null terminated - { - from_end = from + std::wcslen(from); - } - - if (from == from_end) return; - - // The codecvt length functions may not be implemented, and I don't really - // understand them either. Thus this code is just a guess; if it turns - // out the buffer is too small then an error will be reported and the code - // will have to be fixed. - std::size_t buf_size = (from_end - from) * 4; // perhaps too large, but that's OK - buf_size += 4; // encodings like shift-JIS need some prefix space - - // dynamically allocate a buffer only if source is unusually large - if (buf_size > default_codecvt_buf_size) - { - boost::scoped_array< char > buf(new char [buf_size]); - convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to, cvt); - } - else - { - char buf[default_codecvt_buf_size]; - convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt); - } - } -}}} // namespace boost::filesystem::path_traits +// filesystem path_traits.cpp --------------------------------------------------------// + +// Copyright Beman Dawes 2008, 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_FILESYSTEM_SOURCE + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include <boost/filesystem/config.hpp> +#include <boost/filesystem/path_traits.hpp> +#include <boost/system/system_error.hpp> +#include <boost/scoped_array.hpp> +#include <locale> // for codecvt_base::result +#include <cstring> // for strlen +#include <cwchar> // for wcslen + +namespace pt = boost::filesystem::path_traits; +namespace fs = boost::filesystem; +namespace bs = boost::system; + +//--------------------------------------------------------------------------------------// +// configuration // +//--------------------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_CODECVT_BUF_SIZE +# define BOOST_FILESYSTEM_CODECVT_BUF_SIZE 256 +#endif + +namespace { + + const std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM_CODECVT_BUF_SIZE; + + +//--------------------------------------------------------------------------------------// +// // +// The public convert() functions do buffer management, and then forward to the // +// convert_aux() functions for the actual call to the codecvt facet. // +// // +//--------------------------------------------------------------------------------------// + +//--------------------------------------------------------------------------------------// +// convert_aux const char* to wstring // +//--------------------------------------------------------------------------------------// + + void convert_aux( + const char* from, + const char* from_end, + wchar_t* to, wchar_t* to_end, + std::wstring & target, + const pt::codecvt_type & cvt) + { + //std::cout << std::hex + // << " from=" << std::size_t(from) + // << " from_end=" << std::size_t(from_end) + // << " to=" << std::size_t(to) + // << " to_end=" << std::size_t(to_end) + // << std::endl; + + std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports + const char* from_next; + wchar_t* to_next; + + std::codecvt_base::result res; + + if ((res=cvt.in(state, from, from_end, from_next, + to, to_end, to_next)) != std::codecvt_base::ok) + { + //std::cout << " result is " << static_cast<int>(res) << std::endl; + BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), + "boost::filesystem::path codecvt to wstring")); + } + target.append(to, to_next); + } + +//--------------------------------------------------------------------------------------// +// convert_aux const wchar_t* to string // +//--------------------------------------------------------------------------------------// + + void convert_aux( + const wchar_t* from, + const wchar_t* from_end, + char* to, char* to_end, + std::string & target, + const pt::codecvt_type & cvt) + { + //std::cout << std::hex + // << " from=" << std::size_t(from) + // << " from_end=" << std::size_t(from_end) + // << " to=" << std::size_t(to) + // << " to_end=" << std::size_t(to_end) + // << std::endl; + + std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports + const wchar_t* from_next; + char* to_next; + + std::codecvt_base::result res; + + if ((res=cvt.out(state, from, from_end, from_next, + to, to_end, to_next)) != std::codecvt_base::ok) + { + //std::cout << " result is " << static_cast<int>(res) << std::endl; + BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), + "boost::filesystem::path codecvt to string")); + } + target.append(to, to_next); + } + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path_traits // +//--------------------------------------------------------------------------------------// + +namespace boost { namespace filesystem { namespace path_traits { + +//--------------------------------------------------------------------------------------// +// convert const char* to wstring // +//--------------------------------------------------------------------------------------// + + BOOST_FILESYSTEM_DECL + void convert(const char* from, + const char* from_end, // 0 for null terminated MBCS + std::wstring & to, + const codecvt_type & cvt) + { + BOOST_ASSERT(from); + + if (!from_end) // null terminated + { + from_end = from + std::strlen(from); + } + + if (from == from_end) return; + + std::size_t buf_size = (from_end - from) * 3; // perhaps too large, but that's OK + + // dynamically allocate a buffer only if source is unusually large + if (buf_size > default_codecvt_buf_size) + { + boost::scoped_array< wchar_t > buf(new wchar_t [buf_size]); + convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to, cvt); + } + else + { + wchar_t buf[default_codecvt_buf_size]; + convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt); + } + } + +//--------------------------------------------------------------------------------------// +// convert const wchar_t* to string // +//--------------------------------------------------------------------------------------// + + BOOST_FILESYSTEM_DECL + void convert(const wchar_t* from, + const wchar_t* from_end, // 0 for null terminated MBCS + std::string & to, + const codecvt_type & cvt) + { + BOOST_ASSERT(from); + + if (!from_end) // null terminated + { + from_end = from + std::wcslen(from); + } + + if (from == from_end) return; + + // The codecvt length functions may not be implemented, and I don't really + // understand them either. Thus this code is just a guess; if it turns + // out the buffer is too small then an error will be reported and the code + // will have to be fixed. + std::size_t buf_size = (from_end - from) * 4; // perhaps too large, but that's OK + buf_size += 4; // encodings like shift-JIS need some prefix space + + // dynamically allocate a buffer only if source is unusually large + if (buf_size > default_codecvt_buf_size) + { + boost::scoped_array< char > buf(new char [buf_size]); + convert_aux(from, from_end, buf.get(), buf.get()+buf_size, to, cvt); + } + else + { + char buf[default_codecvt_buf_size]; + convert_aux(from, from_end, buf, buf+default_codecvt_buf_size, to, cvt); + } + } +}}} // namespace boost::filesystem::path_traits diff --git a/contrib/restricted/boost/libs/filesystem/src/portability.cpp b/contrib/restricted/boost/libs/filesystem/src/portability.cpp index a44ea78568..b1a1352d9a 100644 --- a/contrib/restricted/boost/libs/filesystem/src/portability.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/portability.cpp @@ -1,119 +1,119 @@ -// portability.cpp -------------------------------------------------------------------// - -// Copyright 2002-2005 Beman Dawes -// 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 - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#include <boost/filesystem/config.hpp> -#include <boost/filesystem/path.hpp> - -namespace fs = boost::filesystem; - -#include <cstring> // SGI MIPSpro compilers need this - -# ifdef BOOST_NO_STDC_NAMESPACE - namespace std { using ::strerror; } -# endif - +// portability.cpp -------------------------------------------------------------------// + +// Copyright 2002-2005 Beman Dawes +// 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 + //--------------------------------------------------------------------------------------// - -namespace -{ - const char invalid_chars[] = - "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" - "<>:\"/\\|"; - // note that the terminating '\0' is part of the string - thus the size below - // is sizeof(invalid_chars) rather than sizeof(invalid_chars)-1. I - const std::string windows_invalid_chars(invalid_chars, sizeof(invalid_chars)); - - const std::string valid_posix( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"); - -} // unnamed namespace - -namespace boost -{ - namespace filesystem - { - - // name_check functions ----------------------------------------------// - -# ifdef BOOST_WINDOWS - BOOST_FILESYSTEM_DECL bool native(const std::string & name) - { - return windows_name(name); - } -# else - BOOST_FILESYSTEM_DECL bool native(const std::string & name) - { - return name.size() != 0 - && name[0] != ' ' - && name.find('/') == std::string::npos; - } -# endif - - BOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name) - { - return name.size() != 0 - && name.find_first_not_of(valid_posix) == std::string::npos; - } - - BOOST_FILESYSTEM_DECL bool windows_name(const std::string & name) - { - return name.size() != 0 - && name[0] != ' ' - && name.find_first_of(windows_invalid_chars) == std::string::npos - && *(name.end()-1) != ' ' - && (*(name.end()-1) != '.' - || name.length() == 1 || name == ".."); - } - - BOOST_FILESYSTEM_DECL bool portable_name(const std::string & name) - { - return - name.size() != 0 - && (name == "." - || name == ".." - || (windows_name(name) - && portable_posix_name(name) - && name[0] != '.' && name[0] != '-')); - } - - BOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name) - { - return - name == "." - || name == ".." - || (portable_name(name) - && name.find('.') == std::string::npos); - } - - BOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name) - { - std::string::size_type pos; - return - portable_name(name) - && name != "." - && name != ".." - && ((pos = name.find('.')) == std::string::npos - || (name.find('.', pos+1) == std::string::npos - && (pos + 5) > name.length())) - ; - } - - } // namespace filesystem -} // namespace boost + +// 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 + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include <boost/filesystem/config.hpp> +#include <boost/filesystem/path.hpp> + +namespace fs = boost::filesystem; + +#include <cstring> // SGI MIPSpro compilers need this + +# ifdef BOOST_NO_STDC_NAMESPACE + namespace std { using ::strerror; } +# endif + +//--------------------------------------------------------------------------------------// + +namespace +{ + const char invalid_chars[] = + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + "<>:\"/\\|"; + // note that the terminating '\0' is part of the string - thus the size below + // is sizeof(invalid_chars) rather than sizeof(invalid_chars)-1. I + const std::string windows_invalid_chars(invalid_chars, sizeof(invalid_chars)); + + const std::string valid_posix( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"); + +} // unnamed namespace + +namespace boost +{ + namespace filesystem + { + + // name_check functions ----------------------------------------------// + +# ifdef BOOST_WINDOWS + BOOST_FILESYSTEM_DECL bool native(const std::string & name) + { + return windows_name(name); + } +# else + BOOST_FILESYSTEM_DECL bool native(const std::string & name) + { + return name.size() != 0 + && name[0] != ' ' + && name.find('/') == std::string::npos; + } +# endif + + BOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name) + { + return name.size() != 0 + && name.find_first_not_of(valid_posix) == std::string::npos; + } + + BOOST_FILESYSTEM_DECL bool windows_name(const std::string & name) + { + return name.size() != 0 + && name[0] != ' ' + && name.find_first_of(windows_invalid_chars) == std::string::npos + && *(name.end()-1) != ' ' + && (*(name.end()-1) != '.' + || name.length() == 1 || name == ".."); + } + + BOOST_FILESYSTEM_DECL bool portable_name(const std::string & name) + { + return + name.size() != 0 + && (name == "." + || name == ".." + || (windows_name(name) + && portable_posix_name(name) + && name[0] != '.' && name[0] != '-')); + } + + BOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name) + { + return + name == "." + || name == ".." + || (portable_name(name) + && name.find('.') == std::string::npos); + } + + BOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name) + { + std::string::size_type pos; + return + portable_name(name) + && name != "." + && name != ".." + && ((pos = name.find('.')) == std::string::npos + || (name.find('.', pos+1) == std::string::npos + && (pos + 5) > name.length())) + ; + } + + } // namespace filesystem +} // namespace boost diff --git a/contrib/restricted/boost/libs/filesystem/src/unique_path.cpp b/contrib/restricted/boost/libs/filesystem/src/unique_path.cpp index aa45c43ba9..1b05c83944 100644 --- a/contrib/restricted/boost/libs/filesystem/src/unique_path.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/unique_path.cpp @@ -1,163 +1,163 @@ -// filesystem unique_path.cpp --------------------------------------------------------// - -// Copyright Beman Dawes 2010 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// Library home page: 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 - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#include <boost/filesystem/operations.hpp> -#include <cassert> - -# ifdef BOOST_POSIX_API -# include <fcntl.h> -# ifdef BOOST_HAS_UNISTD_H -# include <unistd.h> -# endif -# else // BOOST_WINDOWS_API -# include <windows.h> -# include <wincrypt.h> -# ifdef _MSC_VER -# pragma comment(lib, "Advapi32.lib") -# endif -# endif - -namespace { - -void fail(int err, boost::system::error_code* ec) -{ - if (ec == 0) - BOOST_FILESYSTEM_THROW( boost::system::system_error(err, - boost::system::system_category(), - "boost::filesystem::unique_path")); - - ec->assign(err, boost::system::system_category()); - return; -} - -#ifdef BOOST_WINDOWS_API - -int acquire_crypt_handle(HCRYPTPROV& handle) -{ - if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - return 0; - - int errval = ::GetLastError(); - if (errval != NTE_BAD_KEYSET) - return errval; - - if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - return 0; - - errval = ::GetLastError(); - // Another thread could have attempted to create the keyset at the same time. - if (errval != NTE_EXISTS) - return errval; - - if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - return 0; - - return ::GetLastError(); -} - -#endif - -void system_crypt_random(void* buf, std::size_t len, boost::system::error_code* ec) -{ -# ifdef BOOST_POSIX_API - - int file = open("/dev/urandom", O_RDONLY); - if (file == -1) - { - file = open("/dev/random", O_RDONLY); - if (file == -1) - { - fail(errno, ec); - return; - } - } - - size_t bytes_read = 0; - while (bytes_read < len) - { - ssize_t n = read(file, buf, len - bytes_read); - if (n == -1) - { - close(file); - fail(errno, ec); - return; - } - bytes_read += n; - buf = static_cast<char*>(buf) + n; - } - - close(file); - -# else // BOOST_WINDOWS_API - - HCRYPTPROV handle; - int errval = acquire_crypt_handle(handle); - - if (!errval) - { - BOOL gen_ok = ::CryptGenRandom(handle, len, static_cast<unsigned char*>(buf)); - if (!gen_ok) - errval = ::GetLastError(); - ::CryptReleaseContext(handle, 0); - } - - if (!errval) return; - - fail(errval, ec); -# endif -} - -} // unnamed namespace - -namespace boost { namespace filesystem { namespace detail { - -BOOST_FILESYSTEM_DECL -path unique_path(const path& model, system::error_code* ec) -{ - std::wstring s (model.wstring()); // std::string ng for MBCS encoded POSIX - const wchar_t hex[] = L"0123456789abcdef"; - char ran[] = "123456789abcdef"; // init to avoid clang static analyzer message - // see ticket #8954 - assert(sizeof(ran) == 16); - const int max_nibbles = 2 * sizeof(ran); // 4-bits per nibble - - int nibbles_used = max_nibbles; - for(std::wstring::size_type i=0; i < s.size(); ++i) - { - if (s[i] == L'%') // digit request - { - if (nibbles_used == max_nibbles) - { - system_crypt_random(ran, sizeof(ran), ec); - if (ec != 0 && *ec) - return ""; - nibbles_used = 0; - } - int c = ran[nibbles_used/2]; - c >>= 4 * (nibbles_used++ & 1); // if odd, shift right 1 nibble - s[i] = hex[c & 0xf]; // convert to hex digit and replace - } - } - - if (ec != 0) ec->clear(); - - return s; -} - -}}} +// filesystem unique_path.cpp --------------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: 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 + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include <boost/filesystem/operations.hpp> +#include <cassert> + +# ifdef BOOST_POSIX_API +# include <fcntl.h> +# ifdef BOOST_HAS_UNISTD_H +# include <unistd.h> +# endif +# else // BOOST_WINDOWS_API +# include <windows.h> +# include <wincrypt.h> +# ifdef _MSC_VER +# pragma comment(lib, "Advapi32.lib") +# endif +# endif + +namespace { + +void fail(int err, boost::system::error_code* ec) +{ + if (ec == 0) + BOOST_FILESYSTEM_THROW( boost::system::system_error(err, + boost::system::system_category(), + "boost::filesystem::unique_path")); + + ec->assign(err, boost::system::system_category()); + return; +} + +#ifdef BOOST_WINDOWS_API + +int acquire_crypt_handle(HCRYPTPROV& handle) +{ + if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return 0; + + int errval = ::GetLastError(); + if (errval != NTE_BAD_KEYSET) + return errval; + + if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return 0; + + errval = ::GetLastError(); + // Another thread could have attempted to create the keyset at the same time. + if (errval != NTE_EXISTS) + return errval; + + if (::CryptAcquireContextW(&handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return 0; + + return ::GetLastError(); +} + +#endif + +void system_crypt_random(void* buf, std::size_t len, boost::system::error_code* ec) +{ +# ifdef BOOST_POSIX_API + + int file = open("/dev/urandom", O_RDONLY); + if (file == -1) + { + file = open("/dev/random", O_RDONLY); + if (file == -1) + { + fail(errno, ec); + return; + } + } + + size_t bytes_read = 0; + while (bytes_read < len) + { + ssize_t n = read(file, buf, len - bytes_read); + if (n == -1) + { + close(file); + fail(errno, ec); + return; + } + bytes_read += n; + buf = static_cast<char*>(buf) + n; + } + + close(file); + +# else // BOOST_WINDOWS_API + + HCRYPTPROV handle; + int errval = acquire_crypt_handle(handle); + + if (!errval) + { + BOOL gen_ok = ::CryptGenRandom(handle, len, static_cast<unsigned char*>(buf)); + if (!gen_ok) + errval = ::GetLastError(); + ::CryptReleaseContext(handle, 0); + } + + if (!errval) return; + + fail(errval, ec); +# endif +} + +} // unnamed namespace + +namespace boost { namespace filesystem { namespace detail { + +BOOST_FILESYSTEM_DECL +path unique_path(const path& model, system::error_code* ec) +{ + std::wstring s (model.wstring()); // std::string ng for MBCS encoded POSIX + const wchar_t hex[] = L"0123456789abcdef"; + char ran[] = "123456789abcdef"; // init to avoid clang static analyzer message + // see ticket #8954 + assert(sizeof(ran) == 16); + const int max_nibbles = 2 * sizeof(ran); // 4-bits per nibble + + int nibbles_used = max_nibbles; + for(std::wstring::size_type i=0; i < s.size(); ++i) + { + if (s[i] == L'%') // digit request + { + if (nibbles_used == max_nibbles) + { + system_crypt_random(ran, sizeof(ran), ec); + if (ec != 0 && *ec) + return ""; + nibbles_used = 0; + } + int c = ran[nibbles_used/2]; + c >>= 4 * (nibbles_used++ & 1); // if odd, shift right 1 nibble + s[i] = hex[c & 0xf]; // convert to hex digit and replace + } + } + + if (ec != 0) ec->clear(); + + return s; +} + +}}} diff --git a/contrib/restricted/boost/libs/filesystem/src/utf8_codecvt_facet.cpp b/contrib/restricted/boost/libs/filesystem/src/utf8_codecvt_facet.cpp index f380c3f753..8a5af1e07c 100644 --- a/contrib/restricted/boost/libs/filesystem/src/utf8_codecvt_facet.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/utf8_codecvt_facet.cpp @@ -1,27 +1,27 @@ -// Copyright Vladimir Prus 2004. -// Distributed under 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) - -// For HP-UX, request that WCHAR_MAX and WCHAR_MIN be defined as macros, -// not casts. See ticket 5048 -#define _INCLUDE_STDCSOURCE_199901 - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#define BOOST_FILESYSTEM_SOURCE -#include <boost/filesystem/config.hpp> - -#define BOOST_UTF8_BEGIN_NAMESPACE \ - namespace boost { namespace filesystem { namespace detail { - -#define BOOST_UTF8_END_NAMESPACE }}} -#define BOOST_UTF8_DECL BOOST_FILESYSTEM_DECL - -#include <boost/detail/utf8_codecvt_facet.ipp> - -#undef BOOST_UTF8_BEGIN_NAMESPACE -#undef BOOST_UTF8_END_NAMESPACE -#undef BOOST_UTF8_DECL +// Copyright Vladimir Prus 2004. +// Distributed under 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) + +// For HP-UX, request that WCHAR_MAX and WCHAR_MIN be defined as macros, +// not casts. See ticket 5048 +#define _INCLUDE_STDCSOURCE_199901 + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#define BOOST_FILESYSTEM_SOURCE +#include <boost/filesystem/config.hpp> + +#define BOOST_UTF8_BEGIN_NAMESPACE \ + namespace boost { namespace filesystem { namespace detail { + +#define BOOST_UTF8_END_NAMESPACE }}} +#define BOOST_UTF8_DECL BOOST_FILESYSTEM_DECL + +#include <boost/detail/utf8_codecvt_facet.ipp> + +#undef BOOST_UTF8_BEGIN_NAMESPACE +#undef BOOST_UTF8_END_NAMESPACE +#undef BOOST_UTF8_DECL diff --git a/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.cpp b/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.cpp index 33638cefe1..998db60221 100644 --- a/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.cpp +++ b/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.cpp @@ -1,75 +1,75 @@ -// filesystem windows_file_codecvt.cpp -----------------------------------------// - -// Copyright Beman Dawes 2009 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// Library home page: http://www.boost.org/libs/filesystem - -//--------------------------------------------------------------------------------------// - -// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows -// the library is being built (possibly exporting rather than importing code) -#define BOOST_FILESYSTEM_SOURCE - -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED -#endif - -#include <boost/filesystem/config.hpp> -#include <cwchar> // for mbstate_t - -#ifdef BOOST_WINDOWS_API - -#include "windows_file_codecvt.hpp" - -// Versions of MinGW prior to GCC 4.6 requires this -#ifndef WINVER -# define WINVER 0x0500 -#endif - -#include <windows.h> - - std::codecvt_base::result windows_file_codecvt::do_in( - std::mbstate_t &, - const char* from, const char* from_end, const char*& from_next, - wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const - { - UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - - int count; - if ((count = ::MultiByteToWideChar(codepage, MB_PRECOMPOSED, from, - from_end - from, to, to_end - to)) == 0) - { - return error; // conversion failed - } - - from_next = from_end; - to_next = to + count; - *to_next = L'\0'; - return ok; - } - - std::codecvt_base::result windows_file_codecvt::do_out( +// filesystem windows_file_codecvt.cpp -----------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +// define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_FILESYSTEM_SOURCE + +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED +#endif + +#include <boost/filesystem/config.hpp> +#include <cwchar> // for mbstate_t + +#ifdef BOOST_WINDOWS_API + +#include "windows_file_codecvt.hpp" + +// Versions of MinGW prior to GCC 4.6 requires this +#ifndef WINVER +# define WINVER 0x0500 +#endif + +#include <windows.h> + + std::codecvt_base::result windows_file_codecvt::do_in( std::mbstate_t &, - const wchar_t* from, const wchar_t* from_end, const wchar_t* & from_next, - char* to, char* to_end, char* & to_next) const - { - UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - - int count; - if ((count = ::WideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, from, - from_end - from, to, to_end - to, 0, 0)) == 0) - { - return error; // conversion failed - } - - from_next = from_end; - to_next = to + count; - *to_next = '\0'; - return ok; - } - - # endif // BOOST_WINDOWS_API - + const char* from, const char* from_end, const char*& from_next, + wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const + { + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + + int count; + if ((count = ::MultiByteToWideChar(codepage, MB_PRECOMPOSED, from, + from_end - from, to, to_end - to)) == 0) + { + return error; // conversion failed + } + + from_next = from_end; + to_next = to + count; + *to_next = L'\0'; + return ok; + } + + std::codecvt_base::result windows_file_codecvt::do_out( + std::mbstate_t &, + const wchar_t* from, const wchar_t* from_end, const wchar_t* & from_next, + char* to, char* to_end, char* & to_next) const + { + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + + int count; + if ((count = ::WideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, from, + from_end - from, to, to_end - to, 0, 0)) == 0) + { + return error; // conversion failed + } + + from_next = from_end; + to_next = to + count; + *to_next = '\0'; + return ok; + } + + # endif // BOOST_WINDOWS_API + diff --git a/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.hpp b/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.hpp index f19a27c30c..d4ad1b7daf 100644 --- a/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.hpp +++ b/contrib/restricted/boost/libs/filesystem/src/windows_file_codecvt.hpp @@ -1,56 +1,56 @@ -// filesystem windows_file_codecvt.hpp -----------------------------------------------// - -// Copyright Beman Dawes 2009 - -// Distributed under the Boost Software License, Version 1.0. -// See http://www.boost.org/LICENSE_1_0.txt - -// Library home page: http://www.boost.org/libs/filesystem - -#ifndef BOOST_FILESYSTEM3_WIN_FILE_CODECVT_HPP -#define BOOST_FILESYSTEM3_WIN_FILE_CODECVT_HPP - -#include <boost/filesystem/config.hpp> -#include <locale> - - //------------------------------------------------------------------------------------// - // // - // class windows_file_codecvt // - // // - // Warning: partial implementation; even do_in and do_out only partially meet the // - // standard library specifications as the "to" buffer must hold the entire result. // - // // - //------------------------------------------------------------------------------------// - - class BOOST_FILESYSTEM_DECL windows_file_codecvt - : public std::codecvt< wchar_t, char, std::mbstate_t > - { - public: - explicit windows_file_codecvt(std::size_t refs = 0) - : std::codecvt<wchar_t, char, std::mbstate_t>(refs) {} - protected: - +// filesystem windows_file_codecvt.hpp -----------------------------------------------// + +// Copyright Beman Dawes 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM3_WIN_FILE_CODECVT_HPP +#define BOOST_FILESYSTEM3_WIN_FILE_CODECVT_HPP + +#include <boost/filesystem/config.hpp> +#include <locale> + + //------------------------------------------------------------------------------------// + // // + // class windows_file_codecvt // + // // + // Warning: partial implementation; even do_in and do_out only partially meet the // + // standard library specifications as the "to" buffer must hold the entire result. // + // // + //------------------------------------------------------------------------------------// + + class BOOST_FILESYSTEM_DECL windows_file_codecvt + : public std::codecvt< wchar_t, char, std::mbstate_t > + { + public: + explicit windows_file_codecvt(std::size_t refs = 0) + : std::codecvt<wchar_t, char, std::mbstate_t>(refs) {} + protected: + virtual bool do_always_noconv() const noexcept { return false; } - - // seems safest to assume variable number of characters since we don't - // actually know what codepage is active + + // seems safest to assume variable number of characters since we don't + // actually know what codepage is active virtual int do_encoding() const noexcept { return 0; } - - virtual std::codecvt_base::result do_in(std::mbstate_t& state, - const char* from, const char* from_end, const char*& from_next, - wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const; - - virtual std::codecvt_base::result do_out(std::mbstate_t & state, - const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, - char* to, char* to_end, char*& to_next) const; - - virtual std::codecvt_base::result do_unshift(std::mbstate_t&, - char* /*from*/, char* /*to*/, char* & /*next*/) const { return ok; } - - virtual int do_length(std::mbstate_t&, - const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const { return 0; } - + + virtual std::codecvt_base::result do_in(std::mbstate_t& state, + const char* from, const char* from_end, const char*& from_next, + wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const; + + virtual std::codecvt_base::result do_out(std::mbstate_t & state, + const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, + char* to, char* to_end, char*& to_next) const; + + virtual std::codecvt_base::result do_unshift(std::mbstate_t&, + char* /*from*/, char* /*to*/, char* & /*next*/) const { return ok; } + + virtual int do_length(std::mbstate_t&, + const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const { return 0; } + virtual int do_max_length() const noexcept { return 0; } - }; - -#endif // BOOST_FILESYSTEM3_WIN_FILE_CODECVT_HPP + }; + +#endif // BOOST_FILESYSTEM3_WIN_FILE_CODECVT_HPP |