#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
+# define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r() needs this
+#endif
+
+// Include Boost.Predef first so that windows.h is guaranteed to be not included
+#include <boost/predef/os/windows.h>
+#if BOOST_OS_WINDOWS
+#include <boost/winapi/config.hpp>
#endif
+#include <boost/filesystem/config.hpp>
#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/file_status.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/filesystem/directory.hpp>
#include <boost/system/error_code.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
-#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <boost/detail/workaround.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/assert.hpp>
#include <new> // std::bad_alloc
#include <limits>
-#include <vector>
+#include <string>
+#include <cstddef>
#include <cstdlib> // for malloc, free
#include <cstring>
#include <cstdio> // for remove, rename
# 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>
# 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>
+# if _POSIX_C_SOURCE < 200809L
+# include <utime.h>
+# endif
# include "limits.h"
-# else // BOOST_WINDOW_API
+# else // BOOST_WINDOWS_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 <boost/winapi/dll.hpp> // get_proc_address, GetModuleHandleW
# 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;
# include <sys/utime.h>
# endif
+#include "windows_tools.hpp"
+
+# endif // BOOST_WINDOWS_API
+
+#include "error_handling.hpp"
+
+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::system_category;
+
+# if defined(BOOST_WINDOWS_API)
+
// 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
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
- } MountPointReparseBuffer;
+ } MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
# 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,
# 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_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_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
+namespace boost {
+namespace filesystem {
+namespace detail {
+
//--------------------------------------------------------------------------------------//
// //
// helpers (all operating systems) //
// //
//--------------------------------------------------------------------------------------//
-namespace
-{
-
- // Absolute maximum path length, in bytes, that we're willing to accept from various system calls.
- // This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion
- // in some of the algorithms below in case of some corrupted or maliciously broken filesystem.
- BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 16u * 1024u * 1024u;
+namespace {
- fs::file_type query_file_type(const path& p, error_code* ec);
+// Absolute maximum path length, in bytes, that we're willing to accept from various system calls.
+// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion
+// in some of the algorithms below in case of some corrupted or maliciously broken filesystem.
+BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 16u * 1024u * 1024u;
- boost::filesystem::directory_iterator end_dir_itr;
+fs::file_type query_file_type(const path& p, error_code* ec);
- // error handling helpers ----------------------------------------------------------//
+// general 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;
+bool is_empty_directory(const path& p, error_code* ec)
+{
+ return (ec != 0 ? fs::directory_iterator(p, *ec) : fs::directory_iterator(p))
+ == fs::directory_iterator();
+}
- // 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 not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration
- 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;
- }
+// 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
+}
- 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;
- }
+// 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
+}
- bool error(err_t error_num, const path& p1, const path& p2, error_code* ec,
- const char* message)
+// 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 (!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;
+ if (ec != 0) ec->clear();
+ return false;
}
- // general helpers -----------------------------------------------------------------//
-
- bool is_empty_directory(const path& p, error_code* ec)
+ if (type == fs::directory_file
+# ifdef BOOST_WINDOWS_API
+ || type == fs::_detail_directory_symlink
+# endif
+ )
{
- return (ec != 0 ? fs::directory_iterator(p, *ec) : fs::directory_iterator(p))
- == end_dir_itr;
+ if (error(!remove_directory(p) ? BOOST_ERRNO : 0, p, ec,
+ "boost::filesystem::remove"))
+ return false;
}
-
- bool not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration
-
- // only called if directory exists
- bool remove_directory(const path& p) // true if succeeds or not found
+ else
{
- return BOOST_REMOVE_DIRECTORY(p.c_str())
- || not_found_error(BOOST_ERRNO); // mitigate possible file system race. See #11166
+ if (error(!remove_file(p) ? BOOST_ERRNO : 0, p, ec,
+ "boost::filesystem::remove"))
+ return false;
}
+ return true;
+}
- // 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
- }
+boost::uintmax_t remove_all_aux(const path& p, fs::file_type type,
+ error_code* ec)
+{
+ boost::uintmax_t count = 0;
- // 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::directory_file) // but not a directory symlink
{
- 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
- )
+ fs::directory_iterator itr;
+ if (ec != 0)
{
- if (error(!remove_directory(p) ? BOOST_ERRNO : 0, p, ec,
- "boost::filesystem::remove"))
- return false;
+ itr = fs::directory_iterator(p, *ec);
+ if (*ec)
+ return count;
}
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 = 0;
+ itr = fs::directory_iterator(p);
- if (type == fs::directory_file) // but not a directory symlink
+ const fs::directory_iterator end_dit;
+ while(itr != end_dit)
{
- fs::directory_iterator itr;
- if (ec != 0)
- {
- itr = fs::directory_iterator(p, *ec);
- if (*ec)
- return count;
- }
- else
- itr = fs::directory_iterator(p);
-
- while(itr != end_dir_itr)
- {
- fs::file_type tmp_type = query_file_type(itr->path(), ec);
- if (ec != 0 && *ec)
- return count;
+ 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;
+ count += remove_all_aux(itr->path(), tmp_type, ec);
+ if (ec != 0 && *ec)
+ return count;
- fs::detail::directory_iterator_increment(itr, ec);
- if (ec != 0 && *ec)
- return count;
- }
+ fs::detail::directory_iterator_increment(itr, ec);
+ if (ec != 0 && *ec)
+ return count;
}
+ }
- remove_file_or_directory(p, type, ec);
- if (ec != 0 && *ec)
- return count;
+ remove_file_or_directory(p, type, ec);
+ if (ec != 0 && *ec)
+ return count;
- return ++count;
- }
+ return ++count;
+}
#ifdef BOOST_POSIX_API
// //
//--------------------------------------------------------------------------------------//
- BOOST_CONSTEXPR_OR_CONST char dot = '.';
- BOOST_CONSTEXPR_OR_CONST char end_of_string = '\0';
+BOOST_CONSTEXPR_OR_CONST char dot = '.';
- inline bool not_found_error(int errval) BOOST_NOEXCEPT
- {
- return errval == ENOENT || errval == ENOTDIR;
- }
+inline bool not_found_error(int errval) BOOST_NOEXCEPT
+{
+ return errval == ENOENT || errval == ENOTDIR;
+}
- bool // true if ok
- copy_file_api(const std::string& from_p,
- const std::string& to_p, bool fail_if_exists)
- {
- BOOST_CONSTEXPR_OR_CONST std::size_t buf_sz = 65536;
- boost::scoped_array<char> buf(new char [buf_sz]);
- int infile=-1, outfile=-1; // -1 means not open
+bool // true if ok
+copy_file_api(const std::string& from_p,
+ const std::string& to_p, bool fail_if_exists)
+{
+ BOOST_CONSTEXPR_OR_CONST std::size_t buf_sz = 65536;
+ 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()
+ // 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; }
+ 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;
- }
+ 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)
- {
- const int open_errno = errno;
- BOOST_ASSERT(infile >= 0);
- ::close(infile);
- errno = open_errno;
- 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)
+ {
+ const 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)
+ 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
{
- // 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)
{
- 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);
- }
+ 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;
+ if (::close(infile)< 0)
+ sz_read = -1;
+ if (::close(outfile)< 0)
+ sz_read = -1;
- return sz_read >= 0;
- }
+ 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();
- }
+inline fs::file_type query_file_type(const path& p, error_code* ec)
+{
+ return fs::detail::symlink_status(p, ec).type();
+}
# else
// //
//--------------------------------------------------------------------------------------//
- BOOST_CONSTEXPR_OR_CONST std::size_t buf_size=128;
+BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128;
- BOOST_CONSTEXPR_OR_CONST wchar_t dot = L'.';
- BOOST_CONSTEXPR_OR_CONST wchar_t end_of_string = L'\0';
+BOOST_CONSTEXPR_OR_CONST wchar_t dot = L'.';
- inline bool not_found_error(int errval) BOOST_NOEXCEPT
+inline std::wstring wgetenv(const wchar_t* name)
+{
+ // use a separate buffer since C++03 basic_string is not required to be contiguous
+ const DWORD size = ::GetEnvironmentVariableW(name, NULL, 0);
+ if (size > 0)
{
- 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
+ boost::scoped_array<wchar_t> buf(new wchar_t[size]);
+ if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0))
+ return std::wstring(buf.get());
}
- 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;
- }
+ return std::wstring();
+}
- 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;
- }
+inline bool not_found_error(int errval) BOOST_NOEXCEPT
+{
+ 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
+}
- // 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;
+// 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;
+ t -= 116444736000000000LL;
# else
- t -= 116444736000000000;
+ t -= 116444736000000000;
# endif
- t /= 10000000;
- return static_cast<std::time_t>(t);
- }
+ t /= 10000000;
+ return static_cast<std::time_t>(t);
+}
- void to_FILETIME(std::time_t t, FILETIME & ft)
- {
- __int64 temp = t;
- temp *= 10000000;
+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;
+ temp += 116444736000000000LL;
# else
- temp += 116444736000000000;
+ 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.
+ ft.dwLowDateTime = static_cast<DWORD>(temp);
+ ft.dwHighDateTime = static_cast<DWORD>(temp >> 32);
+}
- struct handle_wrapper
- {
- HANDLE handle;
- handle_wrapper(HANDLE h)
- : handle(h){}
- ~handle_wrapper()
- {
- if (handle != INVALID_HANDLE_VALUE)
- ::CloseHandle(handle);
- }
- };
+// 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.
- HANDLE create_file_handle(const path& p, DWORD dwDesiredAccess,
- DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
- HANDLE hTemplateFile)
+struct handle_wrapper
+{
+ HANDLE handle;
+ handle_wrapper(HANDLE h)
+ : handle(h){}
+ ~handle_wrapper()
{
- return ::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode,
- lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
- hTemplateFile);
+ if (handle != INVALID_HANDLE_VALUE)
+ ::CloseHandle(handle);
}
+};
- 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;
+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);
+}
- 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"
- }
+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
- inline std::size_t get_full_path_name(
- const path& src, std::size_t len, wchar_t* buf, wchar_t** p)
+ if (not_found_error(errval))
{
- return static_cast<std::size_t>(
- ::GetFullPathNameW(src.c_str(), static_cast<DWORD>(len), buf, p));
+ return fs::file_status(fs::file_not_found, fs::no_perms);
}
-
- fs::file_status process_status_failure(const path& p, error_code* ec)
+ else if (errval == ERROR_SHARING_VIOLATION)
{
- 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);
+ 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)
+// 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)
{
- 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;
+ return process_status_failure(p, ec).type();
}
- BOOL resize_file_api(const wchar_t* p, boost::uintmax_t size)
+ if (ec != 0) ec->clear();
+
+ if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
{
- 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);
+ if (is_reparse_point_a_symlink(p))
+ return (attr & FILE_ATTRIBUTE_DIRECTORY)
+ ? fs::_detail_directory_symlink
+ : fs::symlink_file;
+ return fs::reparse_file;
}
- // Windows kernel32.dll functions that may or may not be present
- // must be accessed through pointers
+ 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
- );
+typedef BOOL (WINAPI *PtrCreateHardLinkW)(
+ /*__in*/ LPCWSTR lpFileName,
+ /*__in*/ LPCWSTR lpExistingFileName,
+ /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes
+ );
- PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW(
- boost::winapi::get_proc_address(
- boost::winapi::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
+PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW(
+ boost::winapi::get_proc_address(
+ boost::winapi::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
- typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
- /*__in*/ LPCWSTR lpSymlinkFileName,
- /*__in*/ LPCWSTR lpTargetFileName,
- /*__in*/ DWORD dwFlags
- );
+typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)(
+ /*__in*/ LPCWSTR lpSymlinkFileName,
+ /*__in*/ LPCWSTR lpTargetFileName,
+ /*__in*/ DWORD dwFlags
+ );
- PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
- boost::winapi::get_proc_address(
- boost::winapi::GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
+PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW(
+ boost::winapi::get_proc_address(
+ boost::winapi::GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
#endif
//#endif
} // unnamed namespace
+} // namespace detail
//--------------------------------------------------------------------------------------//
// //
// //
//--------------------------------------------------------------------------------------//
-namespace boost
+BOOST_FILESYSTEM_DECL
+path absolute(const path& p, const path& base)
{
-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));
+// 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()
+// 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));
+// return abs_base / p;
- // 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());
+ // recursively calling absolute is sub-optimal, but is sure and simple
+ path abs_base(base.is_absolute() ? base : absolute(base));
- if (p.empty())
- return abs_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_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;
- }
+ if (p.empty())
+ return abs_base;
- return p; // p.is_absolute() is true
+ 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
}
-
-namespace detail
-{
- BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
+ else if (!p_root_directory.empty()) // p.has_root_directory()
{
# ifdef BOOST_POSIX_API
- struct stat lcl_stat;
- return sizeof(lcl_stat.st_size)> 4;
-# else
- return true;
+ // 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;
}
-
- BOOST_FILESYSTEM_DECL
- path canonical(const path& p, const path& base, system::error_code* ec)
+ else
{
- path source (p.is_absolute() ? p : absolute(p, base));
- path root(source.root_path());
- path result;
+ return abs_base / p;
+ }
- system::error_code local_ec;
- file_status stat (status(source, local_ec));
+ return p; // p.is_absolute() is true
+}
- 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;
- }
+namespace detail {
- bool scan (true);
- while (scan)
+BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
+{
+# ifdef BOOST_POSIX_API
+ typedef struct stat struct_stat;
+ return sizeof(struct_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)
{
- 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 (*itr == dot_path())
- continue;
- if (*itr == dot_dot_path())
- {
- if (result != root)
- result.remove_filename();
- continue;
- }
+ if (result != root)
+ result.remove_filename();
+ continue;
+ }
+
+ result /= *itr;
- result /= *itr;
+ bool is_sym (is_symlink(detail::symlink_status(result, ec)));
+ if (ec && *ec)
+ return path();
- bool is_sym (is_symlink(detail::symlink_status(result, ec)));
+ if (is_sym)
+ {
+ path link(detail::read_symlink(result, ec));
if (ec && *ec)
return path();
+ result.remove_filename();
- if (is_sym)
+ if (link.is_absolute())
{
- 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;
+ 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;
}
+ 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(detail::symlink_status(from, ec));
- if (ec != 0 && *ec) return;
+BOOST_FILESYSTEM_DECL
+void copy(const path& from, const path& to, system::error_code* ec)
+{
+ file_status s(detail::symlink_status(from, ec));
+ if (ec != 0 && *ec) return;
- if(is_symlink(s))
- {
- detail::copy_symlink(from, to, ec);
- }
- else if(is_directory(s))
- {
- detail::copy_directory(from, to, ec);
- }
- else if(is_regular_file(s))
- {
- detail::copy_file(from, to, detail::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());
- }
+ if(is_symlink(s))
+ {
+ detail::copy_symlink(from, to, ec);
}
-
- BOOST_FILESYSTEM_DECL
- void copy_directory(const path& from, const path& to, system::error_code* ec)
+ else if(is_directory(s))
{
-# 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");
+ detail::copy_directory(from, to, ec);
}
-
- BOOST_FILESYSTEM_DECL
- void copy_file(const path& from, const path& to, copy_option option, error_code* ec)
+ else if(is_regular_file(s))
{
- error(!BOOST_COPY_FILE(from.c_str(), to.c_str(),
- option == fail_if_exists) ? BOOST_ERRNO : 0,
- from, to, ec, "boost::filesystem::copy_file");
+ detail::copy_file(from, to, detail::fail_if_exists, ec);
}
-
- BOOST_FILESYSTEM_DECL
- void copy_symlink(const path& existing_symlink, const path& new_symlink,
- system::error_code* 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");
+ 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);
+ 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;
- }
+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;
+ }
- 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 (p.filename_is_dot() || p.filename_is_dot_dot())
+ return create_directories(p.parent_path(), 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;
- }
- }
- }
+ error_code local_ec;
+ file_status p_status = status(p, local_ec);
- // create the directory
- return create_directory(p, ec);
+ if (p_status.type() == directory_file)
+ {
+ if (ec != 0)
+ ec->clear();
+ return false;
}
- BOOST_FILESYSTEM_DECL
- bool create_directory(const path& p, error_code* ec)
+ path parent = p.parent_path();
+ BOOST_ASSERT_MSG(parent != p, "internal error: p == p.parent_path()");
+ if (!parent.empty())
{
- if (BOOST_CREATE_DIRECTORY(p.c_str()))
+ // 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)
{
- if (ec != 0)
- ec->clear();
- return true;
+ 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;
+ }
}
+ }
- // attempt to create directory failed
- int errval(BOOST_ERRNO); // save reason for failure
- error_code dummy;
+ // create the directory
+ return create_directory(p, ec);
+}
- if (is_directory(p, dummy))
- {
- if (ec != 0)
- ec->clear();
- return false;
- }
+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 && 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());
+ // 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;
}
- 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
+ // 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());
- error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec,
- "boost::filesystem::create_directory_symlink");
-# else
+ return false;
+}
-# 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
+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_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
- }
+ error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec,
+ "boost::filesystem::create_directory_symlink");
+# else
- BOOST_FILESYSTEM_DECL
- void create_hard_link(const path& to, const path& from, error_code* ec)
- {
+# 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
-# if defined(BOOST_WINDOWS_API) && _WIN32_WINNT < 0x0500 // SDK earlier than Win 2K
+ 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
+}
- error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec,
- "boost::filesystem::create_hard_link");
-# else
+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
-# 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_ERROR_NOT_SUPPORTED, to, from, ec,
+ "boost::filesystem::create_hard_link");
+# else
- error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0, to, from, ec,
- "boost::filesystem::create_hard_link");
+# 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
- }
- 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
+ error(!BOOST_CREATE_HARD_LINK(from.c_str(), to.c_str()) ? BOOST_ERRNO : 0, to, from, ec,
+ "boost::filesystem::create_hard_link");
+# endif
+}
-# 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
+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
- error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0) ? BOOST_ERRNO : 0,
- to, from, ec, "boost::filesystem::create_symlink");
+# 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
- }
- BOOST_FILESYSTEM_DECL
- path current_path(error_code* ec)
- {
-# ifdef BOOST_POSIX_API
- struct local
- {
- static bool getcwd_error(error_code* ec)
- {
- const int err = errno;
- return error((err != ERANGE
- // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
-# if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
- && err != 0
-# endif
- ) ? err : 0, ec, "boost::filesystem::current_path");
- }
- };
+ error(!BOOST_CREATE_SYMBOLIC_LINK(from.c_str(), to.c_str(), 0) ? BOOST_ERRNO : 0,
+ to, from, ec, "boost::filesystem::create_symlink");
+# endif
+}
- path cur;
- char small_buf[1024];
- const char* p = ::getcwd(small_buf, sizeof(small_buf));
- if (BOOST_LIKELY(!!p))
+BOOST_FILESYSTEM_DECL
+path current_path(error_code* ec)
+{
+# ifdef BOOST_POSIX_API
+ struct local
+ {
+ static bool getcwd_error(error_code* ec)
{
- cur = p;
- if (ec != 0) ec->clear();
+ const int err = errno;
+ return error((err != ERANGE
+ // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
+# if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
+ && err != 0
+# endif
+ ) ? err : 0, ec, "boost::filesystem::current_path");
}
- else if (BOOST_LIKELY(!local::getcwd_error(ec)))
+ };
+
+ path cur;
+ char small_buf[1024];
+ const char* p = ::getcwd(small_buf, sizeof(small_buf));
+ if (BOOST_LIKELY(!!p))
+ {
+ cur = p;
+ if (ec != 0) ec->clear();
+ }
+ else if (BOOST_LIKELY(!local::getcwd_error(ec)))
+ {
+ for (std::size_t path_max = sizeof(small_buf);; path_max *= 2u) // loop 'til buffer large enough
{
- for (std::size_t path_max = sizeof(small_buf);; path_max *= 2u) // loop 'til buffer large enough
+ if (BOOST_UNLIKELY(path_max > absolute_path_max))
{
- if (BOOST_UNLIKELY(path_max > absolute_path_max))
- {
- if (ec == 0)
- BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::current_path",
- error_code(ENAMETOOLONG, system_category())));
- else
- ec->assign(ENAMETOOLONG, system_category());
- break;
- }
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::current_path",
+ error_code(ENAMETOOLONG, system_category())));
+ else
+ ec->assign(ENAMETOOLONG, system_category());
+ break;
+ }
- boost::scoped_array<char> buf(new char[path_max]);
- p = ::getcwd(buf.get(), path_max);
- if (BOOST_LIKELY(!!p))
- {
- cur = buf.get();
- if (ec != 0)
- ec->clear();
- break;
- }
- else if (BOOST_UNLIKELY(local::getcwd_error(ec)))
- {
- break;
- }
+ boost::scoped_array<char> buf(new char[path_max]);
+ p = ::getcwd(buf.get(), path_max);
+ if (BOOST_LIKELY(!!p))
+ {
+ cur = buf.get();
+ if (ec != 0)
+ ec->clear();
+ break;
+ }
+ else if (BOOST_UNLIKELY(local::getcwd_error(ec)))
+ {
+ break;
}
}
+ }
- return cur;
+ return cur;
-# elif defined(UNDER_CE)
- // Windows CE has no current directory, so everything's relative to the root of the directory tree
- return L"\\";
-# 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
- }
+# elif defined(UNDER_CE)
+ // Windows CE has no current directory, so everything's relative to the root of the directory tree
+ return L"\\";
+# 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)
+BOOST_FILESYSTEM_DECL
+void current_path(const path& p, system::error_code* ec)
+{
+# ifdef UNDER_CE
+ error(BOOST_ERROR_NOT_SUPPORTED, p, ec,
+ "boost::filesystem::current_path");
+# else
+ error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0,
+ p, ec, "boost::filesystem::current_path");
+# endif
+}
+
+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)
{
-# ifdef UNDER_CE
- error(BOOST_ERROR_NOT_SUPPORTED, p, ec,
- "boost::filesystem::current_path");
-# else
- error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0,
- p, ec, "boost::filesystem::current_path");
-# endif
+ // 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;
}
- 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));
+ // 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;
- 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;
- }
+# else // Windows
- // 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;
+ // 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;
+ }
-# else // Windows
+ // at this point, both handles are known to be valid
- // 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.
+ BY_HANDLE_FILE_INFORMATION info1, info2;
- // 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));
+ if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0,
+ p1, p2, ec, "boost::filesystem::equivalent"))
+ return false;
- 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 (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0,
+ p1, p2, ec, "boost::filesystem::equivalent"))
+ return false;
- 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;
- }
+ // 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;
- // at this point, both handles are known to be valid
+# endif
+}
- BY_HANDLE_FILE_INFORMATION info1, info2;
+BOOST_FILESYSTEM_DECL
+boost::uintmax_t file_size(const path& p, error_code* ec)
+{
+# ifdef BOOST_POSIX_API
- if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0,
- p1, p2, ec, "boost::filesystem::equivalent"))
- return false;
+ 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);
- if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0,
- p1, p2, ec, "boost::filesystem::equivalent"))
- return false;
+ return static_cast<boost::uintmax_t>(path_stat.st_size);
- // 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;
+# else // Windows
-# endif
- }
+ // assume uintmax_t is 64-bits on all Windows compilers
- BOOST_FILESYSTEM_DECL
- boost::uintmax_t file_size(const path& p, error_code* ec)
- {
-# ifdef BOOST_POSIX_API
+ WIN32_FILE_ATTRIBUTE_DATA fad;
- 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);
+ 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);
- return static_cast<boost::uintmax_t>(path_stat.st_size);
+ 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);
-# else // Windows
+ return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh)
+ << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow;
+# endif
+}
- // assume uintmax_t is 64-bits on all Windows compilers
+BOOST_FILESYSTEM_DECL
+boost::uintmax_t hard_link_count(const path& p, system::error_code* ec)
+{
+# ifdef BOOST_POSIX_API
- WIN32_FILE_ATTRIBUTE_DATA fad;
+ 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);
- 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);
+# else // Windows
- 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);
+ // 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
+}
- return (static_cast<boost::uintmax_t>(fad.nFileSizeHigh)
- << (sizeof(fad.nFileSizeLow)*8)) + fad.nFileSizeLow;
-# 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
- boost::uintmax_t hard_link_count(const path& p, system::error_code* ec)
- {
-# ifdef BOOST_POSIX_API
+BOOST_FILESYSTEM_DECL
+bool is_empty(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);
+ 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 // Windows
+# else
- // 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
- }
+ 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;
- 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;
- }
+ if (ec != 0) ec->clear();
+ return
+ (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ? is_empty_directory(p, ec)
+ : (!fad.nFileSizeHigh && !fad.nFileSizeLow);
- BOOST_FILESYSTEM_DECL
- bool is_empty(const path& p, system::error_code* ec)
- {
-# ifdef BOOST_POSIX_API
+# endif
+}
- 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
+BOOST_FILESYSTEM_DECL
+std::time_t last_write_time(const path& p, system::error_code* ec)
+{
+# ifdef BOOST_POSIX_API
- 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;
+ 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;
- if (ec != 0) ec->clear();
- return
- (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- ? is_empty_directory(p, ec)
- : (!fad.nFileSizeHigh && !fad.nFileSizeLow);
-# endif
- }
+# else
- BOOST_FILESYSTEM_DECL
- std::time_t last_write_time(const path& p, system::error_code* ec)
- {
-# ifdef BOOST_POSIX_API
+ 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));
- 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;
+ if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
+ p, ec, "boost::filesystem::last_write_time"))
+ return std::time_t(-1);
-# else
+ FILETIME lwt;
- 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(::GetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0,
+ p, ec, "boost::filesystem::last_write_time"))
+ return std::time_t(-1);
- if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
- p, ec, "boost::filesystem::last_write_time"))
- return std::time_t(-1);
+ return to_time_t(lwt);
- FILETIME lwt;
+# endif
+}
- if (error(::GetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0,
- p, ec, "boost::filesystem::last_write_time"))
- return std::time_t(-1);
+BOOST_FILESYSTEM_DECL
+void last_write_time(const path& p, const std::time_t new_time,
+ system::error_code* ec)
+{
+# ifdef BOOST_POSIX_API
+# if _POSIX_C_SOURCE >= 200809L
- return to_time_t(lwt);
-# endif
- }
+ struct timespec times[2] = {};
+
+ // Keep the last access time unchanged
+ times[0].tv_nsec = UTIME_OMIT;
- BOOST_FILESYSTEM_DECL
- void last_write_time(const path& p, const std::time_t new_time,
- system::error_code* ec)
+ times[1].tv_sec = new_time;
+
+ if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0))
{
-# ifdef BOOST_POSIX_API
+ error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time");
+ return;
+ }
- 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 // _POSIX_C_SOURCE >= 200809L
-# else
+ 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");
- 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));
+# endif // _POSIX_C_SOURCE >= 200809L
- if (error(hw.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
- p, ec, "boost::filesystem::last_write_time"))
- return;
+# else
- FILETIME lwt;
- to_FILETIME(new_time, lwt);
+ 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));
- error(::SetFileTime(hw.handle, 0, 0, &lwt)== 0 ? BOOST_ERRNO : 0,
- p, ec, "boost::filesystem::last_write_time");
-# endif
- }
+ 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; }
+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");
+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;
+ 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) \
- && !(defined(__QNX__) && (_NTO_VERSION <= 700))
- 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
- {
- const int err = errno;
- if (ec == 0)
- BOOST_FILESYSTEM_THROW(filesystem_error(
- "boost::filesystem::permissions", p,
- error_code(err, system::generic_category())));
- else
- ec->assign(err, 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;
+ 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
- attr |= FILE_ATTRIBUTE_READONLY;
-
- error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0,
- p, ec, "boost::filesystem::permissions");
+ *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) \
+ && !(defined(__QNX__) && (_NTO_VERSION <= 700))
+ 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
- }
-
- BOOST_FILESYSTEM_DECL
- path read_symlink(const path& p, system::error_code* ec)
{
- path symlink_path;
-
-# ifdef BOOST_POSIX_API
- const char* const path_str = p.c_str();
- char small_buf[1024];
- ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf));
- if (BOOST_UNLIKELY(result < 0))
- {
- fail:
- const int err = errno;
- if (ec == 0)
- BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
- p, error_code(err, system_category())));
- else
- ec->assign(err, system_category());
- }
- else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf)))
- {
- symlink_path.assign(small_buf, small_buf + result);
- if (ec != 0)
- ec->clear();
- }
+ const int err = errno;
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error(
+ "boost::filesystem::permissions", p,
+ error_code(err, system::generic_category())));
else
- {
- for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough
- {
- if (BOOST_UNLIKELY(path_max > absolute_path_max))
- {
- if (ec == 0)
- BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
- p, error_code(ENAMETOOLONG, system_category())));
- else
- ec->assign(ENAMETOOLONG, system_category());
- break;
- }
+ ec->assign(err, system::generic_category());
+ }
- boost::scoped_array<char> buf(new char[path_max]);
- result = ::readlink(path_str, buf.get(), path_max);
- if (BOOST_UNLIKELY(result < 0))
- {
- goto fail;
- }
- else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max))
- {
- symlink_path.assign(buf.get(), buf.get() + result);
- if (ec != 0) ec->clear();
- break;
- }
- }
- }
+# else // Windows
-# 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
+ // if not going to alter FILE_ATTRIBUTE_READONLY, just return
+ if (!(!((prms & (add_perms | remove_perms)))
+ || (prms & (owner_write|group_write|others_write))))
+ return;
- union info_t
- {
- char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
- REPARSE_DATA_BUFFER rdb;
- } info;
+ DWORD attr = ::GetFileAttributesW(p.c_str());
- 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;
- }
+ if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"))
+ return;
- 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);
- }
+ 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;
- 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;
- }
+ error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0,
+ p, ec, "boost::filesystem::permissions");
+# endif
+}
- 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
+path read_symlink(const path& p, system::error_code* ec)
+{
+ path symlink_path;
- BOOST_FILESYSTEM_DECL
- void resize_file(const path& p, uintmax_t size, system::error_code* ec)
+# ifdef BOOST_POSIX_API
+ const char* const path_str = p.c_str();
+ char small_buf[1024];
+ ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf));
+ if (BOOST_UNLIKELY(result < 0))
{
-# 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");
+ fail:
+ const int err = errno;
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
+ p, error_code(err, system_category())));
+ else
+ ec->assign(err, system_category());
}
-
- BOOST_FILESYSTEM_DECL
- space_info space(const path& p, error_code* ec)
+ else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf)))
{
-# 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"))
- {
- 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;
+ symlink_path.assign(small_buf, small_buf + result);
+ if (ec != 0)
+ ec->clear();
}
-
- BOOST_FILESYSTEM_DECL
- file_status status(const path& p, error_code* ec)
+ else
{
-# ifdef BOOST_POSIX_API
-
- struct stat path_stat;
- if (::stat(p.c_str(), &path_stat)!= 0)
+ for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough
{
- const int err = errno;
- if (ec != 0) // always report errno, even though some
- ec->assign(err, system_category()); // errno values are not status_errors
-
- if (not_found_error(err))
+ if (BOOST_UNLIKELY(path_max > absolute_path_max))
{
- return fs::file_status(fs::file_not_found, fs::no_perms);
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink",
+ p, error_code(ENAMETOOLONG, system_category())));
+ else
+ ec->assign(ENAMETOOLONG, system_category());
+ break;
}
- if (ec == 0)
- BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
- p, error_code(err, 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)
+ boost::scoped_array<char> buf(new char[path_max]);
+ result = ::readlink(path_str, buf.get(), path_max);
+ if (BOOST_UNLIKELY(result < 0))
{
- return process_status_failure(p, ec);
+ goto fail;
}
-
- 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)
- {
- const int err = errno;
- if (ec != 0) // always report errno, even though some
- ec->assign(err, system_category()); // errno values are not status_errors
-
- if (not_found_error(err)) // these are not errors
+ else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max))
{
- return fs::file_status(fs::file_not_found, fs::no_perms);
+ symlink_path.assign(buf.get(), buf.get() + result);
+ if (ec != 0) ec->clear();
+ break;
}
- if (ec == 0)
- BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
- p, error_code(err, 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);
-
- 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;
+# 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
-# else // Windows
+ union info_t
+ {
+ char buf[REPARSE_DATA_BUFFER_HEADER_SIZE+MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_DATA_BUFFER rdb;
+ } info;
- 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};
+ 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));
- 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 (error(h.handle == INVALID_HANDLE_VALUE ? BOOST_ERRNO : 0,
+ p, ec, "boost::filesystem::read_symlink"))
+ return symlink_path;
- 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));
+ DWORD sz;
- 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;
+ 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;
+}
-# endif
- }
+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
- path system_complete(const path& p, system::error_code* ec)
- {
-# ifdef BOOST_POSIX_API
- return (p.empty() || p.is_absolute())
- ? p : current_path()/ p;
+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;
-# 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);
+ // 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);
+}
- if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete"))
- return path();
+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;
- if (len < buf_size)// len does not include null termination character
- return path(&buf[0]);
+ return (type != status_error && type != file_not_found) // exists
+ ? remove_all_aux(p, type, ec)
+ : 0;
+}
- boost::scoped_array<wchar_t> big_buf(new wchar_t[len]);
+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");
+}
- 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
+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
- path weakly_canonical(const path& p, system::error_code* ec)
+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"))
{
- 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);
+ 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;
}
-} // namespace detail
-//--------------------------------------------------------------------------------------//
-// //
-// directory_entry //
-// //
-//--------------------------------------------------------------------------------------//
+# else
- BOOST_FILESYSTEM_DECL
- 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;
- }
+ ULARGE_INTEGER avail, total, free;
+ space_info info;
- BOOST_FILESYSTEM_DECL
- file_status directory_entry::m_get_symlink_status(system::error_code* ec) const
+ if (!error(::GetDiskFreeSpaceExW(p.c_str(), &avail, &total, &free)== 0,
+ p, ec, "boost::filesystem::space"))
{
- 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;
+ 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;
}
-// 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();
- }
+# endif
- void dispatch(const directory_entry & de,
-# ifdef BOOST_WINDOWS_API
- std::wstring& to
-# else
- std::string& to
-# endif
- )
+ else
{
- to = de.path().native();
+ info.capacity = info.free = info.available = 0;
}
-} // namespace path_traits
-} // namespace filesystem
-} // namespace boost
-
-//--------------------------------------------------------------------------------------//
-// //
-// directory_iterator //
-// //
-//--------------------------------------------------------------------------------------//
+ return info;
+}
-namespace
+BOOST_FILESYSTEM_DECL
+file_status status(const path& p, error_code* ec)
{
# 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
+ struct stat path_stat;
+ if (::stat(p.c_str(), &path_stat)!= 0)
{
-# 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)
- {
- const int err = errno;
- if (err == 0)// indeterminate
- max = 4096; // guess
- else
- return error_code(err, system_category());
- }
- else
- {
- max = static_cast<std::size_t>(tmp + 1); // relative root
- }
- }
- result = max;
- return ok;
- }
+ const int err = errno;
+ if (ec != 0) // always report errno, even though some
+ ec->assign(err, system_category()); // errno values are not status_errors
- 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)
+ if (not_found_error(err))
{
- const int err = errno;
- return error_code(err, system_category());
+ return fs::file_status(fs::file_not_found, fs::no_perms);
}
- 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;
- const std::size_t buffer_size = (sizeof(dirent) - sizeof(dirent().d_name))
- + path_size + 1; // + 1 for "\0"
- buffer = std::malloc(buffer_size);
- if (BOOST_UNLIKELY(!buffer))
- return make_error_code(boost::system::errc::not_enough_memory);
- std::memset(buffer, 0, buffer_size);
- return ok;
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
+ p, error_code(err, 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);
- // warning: the only dirent members updated are d_name and d_type
- 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(linux) || defined(__linux) || defined(__linux__))\
- && !defined(__ANDROID__)\
- && (!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;
-# ifdef BOOST_FILESYSTEM_STATUS_CACHE
- entry->d_type = p->d_type;
-# endif
- std::strcpy(entry->d_name, p->d_name);
- *result = entry;
- return 0;
- }
+# else // Windows
- error_code dir_itr_increment(void *& handle, void *& buffer,
- string& target, fs::file_status & sf, fs::file_status & symlink_sf)
+ DWORD attr(::GetFileAttributesW(p.c_str()));
+ if (attr == 0xFFFFFFFF)
{
- BOOST_ASSERT(buffer != 0);
- dirent * entry(static_cast<dirent *>(buffer));
- dirent * result;
- int err;
- if ((err = readdir_r_simulator(static_cast<DIR*>(handle), entry, &result)) != 0)
- return error_code(err, 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;
+ return process_status_failure(p, ec);
}
-# else // BOOST_WINDOWS_API
+ perms permissions = make_permissions(p, attr);
- 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.
+ // 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)
{
- // 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
+ 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)
{
- 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 process_status_failure(p, ec);
}
- 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();
+ if (!is_reparse_point_a_symlink(p))
+ return file_status(reparse_file, permissions);
}
-#endif
- const error_code not_found_error_code (
-# ifdef BOOST_WINDOWS_API
- ERROR_PATH_NOT_FOUND
-# else
- ENOENT
-# endif
- , system_category());
+ if (ec != 0) ec->clear();
+ return (attr & FILE_ATTRIBUTE_DIRECTORY)
+ ? file_status(directory_file, permissions)
+ : file_status(regular_file, permissions);
-} // unnamed namespace
+# endif
+}
-namespace boost
-{
-namespace filesystem
+BOOST_FILESYSTEM_DECL
+file_status symlink_status(const path& p, error_code* ec)
{
+# ifdef BOOST_POSIX_API
-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
- )
+ struct stat path_stat;
+ if (::lstat(p.c_str(), &path_stat)!= 0)
{
-# ifdef BOOST_POSIX_API
- std::free(buffer);
- buffer = 0;
- if (handle == 0)return ok;
- DIR * h(static_cast<DIR*>(handle));
- handle = 0;
- int err = 0;
- if (::closedir(h) != 0)
- err = errno;
- return error_code(err, system_category());
+ const int err = errno;
+ if (ec != 0) // always report errno, even though some
+ ec->assign(err, system_category()); // errno values are not status_errors
-# else
- if (handle != 0)
+ if (not_found_error(err)) // these are not errors
{
- ::FindClose(handle);
- handle = 0;
+ return fs::file_status(fs::file_not_found, fs::no_perms);
}
- return ok;
-
-# endif
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
+ p, error_code(err, 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);
- 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;
-
- try
- {
- 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);
- const path::string_type::value_type* filename_str = filename.c_str();
- if (filename_str[0] == dot // dot or dot-dot
- && (filename_str[1] == end_of_string ||
- (filename_str[1] == dot && filename_str[2] == end_of_string)))
- { detail::directory_iterator_increment(it, ec); }
- }
- }
- catch (std::bad_alloc&)
- {
- if (!ec)
- throw;
-
- *ec = make_error_code(boost::system::errc::not_enough_memory);
- it.m_imp.reset();
- }
- }
+# else // Windows
- void directory_iterator_increment(directory_iterator& it,
- system::error_code* ec)
+ DWORD attr(::GetFileAttributesW(p.c_str()));
+ if (attr == 0xFFFFFFFF)
{
- BOOST_ASSERT_MSG(it.m_imp.get(), "attempt to increment end iterator");
- BOOST_ASSERT_MSG(it.m_imp->handle != 0, "internal program error");
+ return process_status_failure(p, ec);
+ }
- if (ec != 0)
- ec->clear();
+ if (ec != 0) ec->clear();
- try
- {
- path::string_type filename;
- file_status file_stat, symlink_file_stat;
- system::error_code increment_ec;
+ perms permissions = make_permissions(p, attr);
- for (;;)
- {
- increment_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 (attr & FILE_ATTRIBUTE_REPARSE_POINT)
+ return is_reparse_point_a_symlink(p)
+ ? file_status(symlink_file, permissions)
+ : file_status(reparse_file, permissions);
- if (increment_ec) // happens if filesystem is corrupt, such as on a damaged optical disc
- {
- boost::intrusive_ptr< detail::dir_itr_imp > imp;
- imp.swap(it.m_imp);
- path error_path(imp->dir_entry.path().parent_path()); // fix ticket #5900
- if (ec == 0)
- BOOST_FILESYSTEM_THROW(
- filesystem_error("boost::filesystem::directory_iterator::operator++",
- error_path,
- increment_ec));
- *ec = increment_ec;
- return;
- }
+ return (attr & FILE_ATTRIBUTE_DIRECTORY)
+ ? file_status(directory_file, permissions)
+ : file_status(regular_file, permissions);
- if (it.m_imp->handle == 0) // eof, make end
- {
- it.m_imp.reset();
- return;
- }
+# endif
+}
- const path::string_type::value_type* filename_str = filename.c_str();
- if (!(filename_str[0] == dot // !(dot or dot-dot)
- && (filename_str[1] == end_of_string ||
- (filename_str[1] == dot && filename_str[2] == end_of_string))))
- {
- it.m_imp->dir_entry.replace_filename(
- filename, file_stat, symlink_file_stat);
- return;
- }
- }
- }
- catch (std::bad_alloc&)
- {
- if (!ec)
- throw;
+ // contributed by Jeff Flinn
+BOOST_FILESYSTEM_DECL
+path temp_directory_path(system::error_code* ec)
+{
+# ifdef BOOST_POSIX_API
+ const char* val = 0;
- *ec = make_error_code(boost::system::errc::not_enough_memory);
- }
- }
+ (val = std::getenv("TMPDIR" )) ||
+ (val = std::getenv("TMP" )) ||
+ (val = std::getenv("TEMP" )) ||
+ (val = std::getenv("TEMPDIR"));
-//--------------------------------------------------------------------------------------//
-// //
-// recursive_directory_iterator //
-// //
-//--------------------------------------------------------------------------------------//
+# ifdef __ANDROID__
+ const char* default_tmp = "/data/local/tmp";
+# else
+ const char* default_tmp = "/tmp";
+# endif
+ path p((val != NULL) ? val : default_tmp);
- // Returns: true if push occurs, otherwise false. Always returns false on error.
- BOOST_FILESYSTEM_DECL
- bool recur_dir_itr_imp::push_directory(system::error_code& ec) BOOST_NOEXCEPT
+ if (p.empty() || (ec && !is_directory(p, *ec)) || (!ec && !is_directory(p)))
{
- ec.clear();
-
- try
- {
- // Discover if the iterator is for a directory that needs to be recursed into,
- // taking symlinks and options into account.
-
- if ((m_options & static_cast< unsigned int >(symlink_option::_detail_no_push)) == static_cast< unsigned int >(symlink_option::_detail_no_push))
- {
- m_options &= ~static_cast< unsigned int >(symlink_option::_detail_no_push);
- return false;
- }
-
- file_status symlink_stat;
+ error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path");
+ return p;
+ }
- // if we are not recursing into symlinks, we are going to have to know if the
- // stack top is a symlink, so get symlink_status and verify no error occurred
- if ((m_options & static_cast< unsigned int >(symlink_option::recurse)) != static_cast< unsigned int >(symlink_option::recurse))
- {
- symlink_stat = m_stack.top()->symlink_status(ec);
- if (ec)
- return false;
- }
+ return p;
- // Logic for following predicate was contributed by Daniel Aarno to handle cyclic
- // symlinks correctly and efficiently, fixing ticket #5652.
- // if (((m_options & symlink_option::recurse) == symlink_option::recurse
- // || !is_symlink(m_stack.top()->symlink_status()))
- // && is_directory(m_stack.top()->status())) ...
- // The predicate code has since been rewritten to pass error_code arguments,
- // per ticket #5653.
+# else // Windows
- if ((m_options & static_cast< unsigned int >(symlink_option::recurse)) == static_cast< unsigned int >(symlink_option::recurse)
- || !is_symlink(symlink_stat))
- {
- file_status stat = m_stack.top()->status(ec);
- if (ec || !is_directory(stat))
- return false;
+ 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 };
- directory_iterator next(m_stack.top()->path(), ec);
- if (!ec && next != directory_iterator())
- {
-#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
- m_stack.push(std::move(next)); // may throw
-#else
- m_stack.push(next); // may throw
-#endif
- ++m_level;
- return true;
- }
- }
- }
- catch (std::bad_alloc&)
+ path p;
+ for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i)
+ {
+ std::wstring env = wgetenv(env_list[i]);
+ if (!env.empty())
{
- ec = make_error_code(system::errc::not_enough_memory);
+ 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();
}
-
- return false;
}
- // ec == 0 means throw on error
- //
- // Invariant: On return, the top of the iterator stack is the next valid (possibly
- // end) iterator, regardless of whether or not an error is reported, and regardless of
- // whether any error is reported by exception or error code. In other words, progress
- // is always made so a loop on the iterator will always eventually terminate
- // regardless of errors.
- BOOST_FILESYSTEM_DECL
- void recur_dir_itr_imp::increment(system::error_code* ec)
+ if (p.empty())
{
- system::error_code ec_push_directory;
-
- // if various conditions are met, push a directory_iterator into the iterator stack
- if (push_directory(ec_push_directory))
+ // use a separate buffer since in C++03 a string is not required to be contiguous
+ const UINT size = ::GetWindowsDirectoryW(NULL, 0);
+ if (BOOST_UNLIKELY(size == 0))
{
- if (ec)
- ec->clear();
- return;
+ getwindir_error:
+ int errval = ::GetLastError();
+ error(errval, ec, "boost::filesystem::temp_directory_path");
+ return path();
}
- // report errors if any
- if (ec_push_directory)
- {
- if (ec)
- {
- *ec = ec_push_directory;
- return;
- }
- else
- {
- BOOST_FILESYSTEM_THROW(filesystem_error(
- "filesystem::recursive_directory_iterator directory error",
- ec_push_directory));
- }
- }
+ boost::scoped_array<wchar_t> buf(new wchar_t[size]);
+ if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0))
+ goto getwindir_error;
- // Do the actual increment operation on the top iterator in the iterator
- // stack, popping the stack if necessary, until either the stack is empty or a
- // non-end iterator is reached.
- while (!m_stack.empty())
- {
- directory_iterator& it = m_stack.top();
- detail::directory_iterator_increment(it, ec);
- if (ec && *ec)
- return;
- if (it != directory_iterator())
- break;
+ p = buf.get(); // do not depend on initial buf size, see ticket #10388
+ p /= L"Temp";
+ }
- m_stack.pop();
- --m_level;
- }
+ return p;
- if (ec)
- ec->clear();
- }
+# endif
+}
- // ec == 0 means throw on error
- BOOST_FILESYSTEM_DECL
- void recur_dir_itr_imp::pop(system::error_code* ec)
+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())
{
- BOOST_ASSERT_MSG(m_level > 0,
- "pop() on recursive_directory_iterator with level < 1");
+ 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 (ec)
- ec->clear();
+ if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete"))
+ return path();
- while (true)
- {
- m_stack.pop();
- --m_level;
+ if (len < buf_size)// len does not include null termination character
+ return path(&buf[0]);
- if (m_stack.empty())
- break;
+ boost::scoped_array<wchar_t> big_buf(new wchar_t[len]);
- directory_iterator& it = m_stack.top();
- detail::directory_iterator_increment(it, ec);
- if (ec && *ec)
- break;
- if (it != directory_iterator())
- break;
- }
- }
+ 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
+} // namespace detail
} // namespace filesystem
} // namespace boost