Browse Source

Update ghc::filesystem to v1.5.14

pull/1213/head
Antonio SJ Musumeci 1 year ago
parent
commit
543603bdfc
  1. 314
      src/ghc/filesystem.hpp

314
src/ghc/filesystem.hpp

@ -67,6 +67,8 @@
#define GHC_OS_WIN32 #define GHC_OS_WIN32
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
#define GHC_OS_CYGWIN #define GHC_OS_CYGWIN
#elif defined(__sun) && defined(__SVR4)
#define GHC_OS_SOLARIS
#elif defined(__svr4__) #elif defined(__svr4__)
#define GHC_OS_SYS5R4 #define GHC_OS_SYS5R4
#elif defined(BSD) #elif defined(BSD)
@ -76,7 +78,8 @@
#include <wasi/api.h> #include <wasi/api.h>
#elif defined(__QNX__) #elif defined(__QNX__)
#define GHC_OS_QNX #define GHC_OS_QNX
#define GHC_NO_DIRENT_D_TYPE
#elif defined(__HAIKU__)
#define GHC_OS_HAIKU
#else #else
#error "Operating system currently not supported!" #error "Operating system currently not supported!"
#endif #endif
@ -214,6 +217,7 @@
#include <compare> #include <compare>
#endif #endif
#endif #endif
#include <chrono>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <stack> #include <stack>
@ -253,6 +257,10 @@
#include <experimental/string_view> #include <experimental/string_view>
#endif #endif
#if !defined(GHC_OS_WINDOWS) && !defined(PATH_MAX)
#define PATH_MAX 4096
#endif
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): // Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp):
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -264,7 +272,7 @@
// configure LWG conformance () // configure LWG conformance ()
#define LWG_2682_BEHAVIOUR #define LWG_2682_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// LWG #2395 makes create_directory/create_directories not emit an error if there is a regular
// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular
// file with that name, it is superseded by P1164R1, so only activate if really needed // file with that name, it is superseded by P1164R1, so only activate if really needed
// #define LWG_2935_BEHAVIOUR // #define LWG_2935_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -273,19 +281,19 @@
// * if this->has_root_directory() and !p.has_root_directory() return -1 // * if this->has_root_directory() and !p.has_root_directory() return -1
// * if !this->has_root_directory() and p.has_root_directory() return -1 // * if !this->has_root_directory() and p.has_root_directory() return -1
// * else result of element wise comparison of path iteration where first comparison is != 0 or 0 // * else result of element wise comparison of path iteration where first comparison is != 0 or 0
// if all comparisons are 0 (on Windows this implementation does case insensitive root_name()
// if all comparisons are 0 (on Windows this implementation does case-insensitive root_name()
// comparison) // comparison)
#define LWG_2936_BEHAVIOUR #define LWG_2936_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) // LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)
#define LWG_2937_BEHAVIOUR #define LWG_2937_BEHAVIOUR
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the windows
// UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the Windows
// version defaults to std::wstring storage backend. Still all std::string will be interpreted // version defaults to std::wstring storage backend. Still all std::string will be interpreted
// as UTF-8 encoded. With this define you can enfoce the old behavior on Windows, using
// as UTF-8 encoded. With this define you can enforce the old behavior on Windows, using
// std::string as backend and for fs::path::native() and char for fs::path::c_str(). This // std::string as backend and for fs::path::native() and char for fs::path::c_str(). This
// needs more conversions so it is (an was before v1.5) slower, bot might help keeping source
// homogeneous in a multi platform project.
// needs more conversions, so it is (and was before v1.5) slower, bot might help keeping source
// homogeneous in a multi-platform project.
// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE // #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found, // Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found,
@ -300,7 +308,7 @@
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
#define GHC_FILESYSTEM_VERSION 10509L
#define GHC_FILESYSTEM_VERSION 10514L
#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
#define GHC_WITH_EXCEPTIONS #define GHC_WITH_EXCEPTIONS
@ -423,7 +431,8 @@ public:
template <typename T> template <typename T>
using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char8_t>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type; using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char8_t>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;
#else #else
using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value ||
using path_from_string =
typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value ||
std::is_same<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value || std::is_same<char32_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t const*, typename std::decay<T>::type>::value || std::is_same<char16_t*, typename std::decay<T>::type>::value || std::is_same<char32_t const*, typename std::decay<T>::type>::value ||
std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value, std::is_same<char32_t*, typename std::decay<T>::type>::value || std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value,
path>::type; path>::type;
@ -799,6 +808,7 @@ public:
file_type type() const noexcept; file_type type() const noexcept;
perms permissions() const noexcept; perms permissions() const noexcept;
friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); } friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); }
private: private:
file_type _type; file_type _type;
perms _perms; perms _perms;
@ -1295,6 +1305,65 @@ GHC_FS_API std::error_code make_error_code(portable_error err);
GHC_FS_API std::error_code make_system_error(uint32_t err = 0); GHC_FS_API std::error_code make_system_error(uint32_t err = 0);
#else #else
GHC_FS_API std::error_code make_system_error(int err = 0); GHC_FS_API std::error_code make_system_error(int err = 0);
template <typename T, typename = int>
struct has_d_type : std::false_type{};
template <typename T>
struct has_d_type<T, decltype((void)T::d_type, 0)> : std::true_type {};
template <typename T>
GHC_INLINE file_type file_type_from_dirent_impl(const T&, std::false_type)
{
return file_type::none;
}
template <typename T>
GHC_INLINE file_type file_type_from_dirent_impl(const T& t, std::true_type)
{
switch (t.d_type) {
#ifdef DT_BLK
case DT_BLK:
return file_type::block;
#endif
#ifdef DT_CHR
case DT_CHR:
return file_type::character;
#endif
#ifdef DT_DIR
case DT_DIR:
return file_type::directory;
#endif
#ifdef DT_FIFO
case DT_FIFO:
return file_type::fifo;
#endif
#ifdef DT_LNK
case DT_LNK:
return file_type::symlink;
#endif
#ifdef DT_REG
case DT_REG:
return file_type::regular;
#endif
#ifdef DT_SOCK
case DT_SOCK:
return file_type::socket;
#endif
#ifdef DT_UNKNOWN
case DT_UNKNOWN:
return file_type::none;
#endif
default:
return file_type::unknown;
}
}
template <class T>
GHC_INLINE file_type file_type_from_dirent(const T& t)
{
return file_type_from_dirent_impl(t, has_d_type<T>{});
}
#endif #endif
} // namespace detail } // namespace detail
@ -1888,10 +1957,15 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink,
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 4191)
#endif #endif
static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(pop)
#endif #endif
if (api_call) { if (api_call) {
if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) { if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) {
@ -1912,10 +1986,15 @@ GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlin
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type" #pragma GCC diagnostic ignored "-Wcast-function-type"
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(push)
#pragma warning(disable : 4191)
#endif #endif
static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
#if defined(__GNUC__) && __GNUC__ >= 8 #if defined(__GNUC__) && __GNUC__ >= 8
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__)
#pragma warning(pop)
#endif #endif
if (api_call) { if (api_call) {
if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) { if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) {
@ -2004,6 +2083,52 @@ GHC_INLINE file_status file_status_from_st_mode(T mode)
} }
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
class unique_handle
{
public:
typedef HANDLE element_type;
unique_handle() noexcept
: _handle(INVALID_HANDLE_VALUE)
{
}
explicit unique_handle(element_type h) noexcept
: _handle(h)
{
}
unique_handle(unique_handle&& u) noexcept
: _handle(u.release())
{
}
~unique_handle() { reset(); }
unique_handle& operator=(unique_handle&& u) noexcept
{
reset(u.release());
return *this;
}
element_type get() const noexcept { return _handle; }
explicit operator bool() const noexcept { return _handle != INVALID_HANDLE_VALUE; }
element_type release() noexcept
{
element_type tmp = _handle;
_handle = INVALID_HANDLE_VALUE;
return tmp;
}
void reset(element_type h = INVALID_HANDLE_VALUE) noexcept
{
element_type tmp = _handle;
_handle = h;
if (tmp != INVALID_HANDLE_VALUE) {
CloseHandle(tmp);
}
}
void swap(unique_handle& u) noexcept { std::swap(_handle, u._handle); }
private:
element_type _handle;
};
#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
typedef struct _REPARSE_DATA_BUFFER typedef struct _REPARSE_DATA_BUFFER
{ {
@ -2040,15 +2165,21 @@ typedef struct _REPARSE_DATA_BUFFER
#endif #endif
#endif #endif
GHC_INLINE std::shared_ptr<REPARSE_DATA_BUFFER> getReparseData(const path& p, std::error_code& ec)
template <class T>
struct free_deleter
{ {
std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
if (file.get() == INVALID_HANDLE_VALUE) {
void operator()(T* p) const { std::free(p); }
};
GHC_INLINE std::unique_ptr<REPARSE_DATA_BUFFER, free_deleter<REPARSE_DATA_BUFFER>> getReparseData(const path& p, std::error_code& ec)
{
unique_handle file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0));
if (!file) {
ec = detail::make_system_error(); ec = detail::make_system_error();
return nullptr; return nullptr;
} }
std::shared_ptr<REPARSE_DATA_BUFFER> reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free);
std::unique_ptr<REPARSE_DATA_BUFFER, free_deleter<REPARSE_DATA_BUFFER>> reparseData(reinterpret_cast<REPARSE_DATA_BUFFER*>(std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)));
ULONG bufferUsed; ULONG bufferUsed;
if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) {
return reparseData; return reparseData;
@ -2122,10 +2253,10 @@ GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft)
GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft)
{ {
LONGLONG ll;
ll = Int32x32To64(t, 10000000) + 116444736000000000;
ft.dwLowDateTime = static_cast<DWORD>(ll);
ft.dwHighDateTime = static_cast<DWORD>(ll >> 32);
ULARGE_INTEGER ull;
ull.QuadPart = static_cast<ULONGLONG>((t * 10000000LL) + 116444736000000000LL);
ft.dwLowDateTime = ull.LowPart;
ft.dwHighDateTime = ull.HighPart;
} }
template <typename INFO> template <typename INFO>
@ -2141,42 +2272,44 @@ GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_H
} }
template <typename INFO> template <typename INFO>
GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*)
GHC_INLINE bool is_symlink_from_INFO(const path &p, const INFO* info, std::error_code& ec)
{ {
return 0;
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
auto reparseData = detail::getReparseData(p, ec);
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
return true;
}
}
return false;
} }
template <> template <>
GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info)
GHC_INLINE bool is_symlink_from_INFO(const path &, const WIN32_FIND_DATAW* info, std::error_code&)
{ {
return info->dwReserved0;
// dwReserved0 is undefined unless dwFileAttributes includes the
// FILE_ATTRIBUTE_REPARSE_POINT attribute according to microsoft
// documentation. In practice, dwReserved0 is not reset which
// causes it to report the incorrect symlink status.
// Note that microsoft documentation does not say whether there is
// a null value for dwReserved0, so we test for symlink directly
// instead of returning the tag which requires returning a null
// value for non-reparse-point files.
return (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && info->dwReserved0 == IO_REPARSE_TAG_SYMLINK;
} }
template <typename INFO> template <typename INFO>
GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr) GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code& ec, uintmax_t* sz = nullptr, time_t* lwt = nullptr)
{ {
file_type ft = file_type::unknown; file_type ft = file_type::unknown;
if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) {
if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) {
ft = file_type::symlink;
}
}
else {
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
auto reparseData = detail::getReparseData(p, ec);
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
if (is_symlink_from_INFO(p, info, ec)) {
ft = file_type::symlink; ft = file_type::symlink;
} }
}
}
if (ft == file_type::unknown) {
if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
else if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
ft = file_type::directory; ft = file_type::directory;
} }
else { else {
ft = file_type::regular; ft = file_type::regular;
} }
}
perms prms = perms::owner_read | perms::group_read | perms::others_read; perms prms = perms::owner_read | perms::group_read | perms::others_read;
if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
prms = prms | perms::owner_write | perms::group_write | perms::others_write; prms = prms | perms::owner_write | perms::group_write | perms::others_write;
@ -3056,7 +3189,8 @@ GHC_INLINE bool has_executable_extension(const path& p)
return false; return false;
} }
const path::value_type* ext = fn._path.c_str() + pos + 1; const path::value_type* ext = fn._path.c_str() + pos + 1;
if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) {
if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) ||
detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) {
return true; return true;
} }
} }
@ -3232,7 +3366,7 @@ GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(cons
// we can only sit on a slash if it is a network name or a root // we can only sit on a slash if it is a network name or a root
if (i != _last && *i == preferred_separator) { if (i != _last && *i == preferred_separator) {
if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) { if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) {
// leading double slashes detected, treat this and the
// leadind double slashes detected, treat this and the
// following until a slash as one unit // following until a slash as one unit
i = std::find(++i, _last, preferred_separator); i = std::find(++i, _last, preferred_separator);
} }
@ -3245,10 +3379,14 @@ GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(cons
} }
} }
else { else {
#ifdef GHC_OS_WINDOWS
if (fromStart && i != _last && *i == ':') { if (fromStart && i != _last && *i == ':') {
++i; ++i;
} }
else { else {
#else
{
#endif
i = std::find(i, _last, preferred_separator); i = std::find(i, _last, preferred_separator);
} }
} }
@ -3792,11 +3930,14 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options
ec = tecf; ec = tecf;
return false; return false;
} }
if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) {
if (exists(st)) {
if ((options & copy_options::skip_existing) == copy_options::skip_existing) {
return false;
}
if (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none) {
ec = tect ? tect : detail::make_error_code(detail::portable_error::exists); ec = tect ? tect : detail::make_error_code(detail::portable_error::exists);
return false; return false;
} }
if (exists(st)) {
if ((options & copy_options::update_existing) == copy_options::update_existing) { if ((options & copy_options::update_existing) == copy_options::update_existing) {
auto from_time = last_write_time(from, ec); auto from_time = last_write_time(from, ec);
if (ec) { if (ec) {
@ -3836,15 +3977,33 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options
::close(in); ::close(in);
return false; return false;
} }
if (st.permissions() != sf.permissions()) {
if (::fchmod(out, static_cast<mode_t>(sf.permissions() & perms::all)) != 0) {
ec = detail::make_system_error();
::close(in);
::close(out);
return false;
}
}
ssize_t br, bw; ssize_t br, bw;
while ((br = ::read(in, buffer.data(), buffer.size())) > 0) {
while (true) {
do { br = ::read(in, buffer.data(), buffer.size()); } while(errno == EINTR);
if(!br) {
break;
}
if(br < 0) {
ec = detail::make_system_error();
::close(in);
::close(out);
return false;
}
ssize_t offset = 0; ssize_t offset = 0;
do { do {
if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) { if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) {
br -= bw; br -= bw;
offset += bw; offset += bw;
} }
else if (bw < 0) {
else if (bw < 0 && errno != EINTR) {
ec = detail::make_system_error(); ec = detail::make_system_error();
::close(in); ::close(in);
::close(out); ::close(out);
@ -4079,6 +4238,13 @@ GHC_INLINE path current_path(std::error_code& ec)
return path(); return path();
} }
return path(std::wstring(buffer.get()), path::native_format); return path(std::wstring(buffer.get()), path::native_format);
#elif defined(__GLIBC__)
std::unique_ptr<char, decltype(&std::free)> buffer { ::getcwd(NULL, 0), std::free };
if (buffer == nullptr) {
ec = detail::make_system_error();
return path();
}
return path(buffer.get());
#else #else
size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX))); size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX)));
std::unique_ptr<char[]> buffer(new char[pathlen + 1]); std::unique_ptr<char[]> buffer(new char[pathlen + 1]);
@ -4152,10 +4318,10 @@ GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec)
{ {
ec.clear(); ec.clear();
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
std::shared_ptr<void> file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
detail::unique_handle file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
auto e1 = ::GetLastError(); auto e1 = ::GetLastError();
std::shared_ptr<void> file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) {
detail::unique_handle file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
if (!file1 || !file2) {
#ifdef LWG_2937_BEHAVIOUR #ifdef LWG_2937_BEHAVIOUR
ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
#else #else
@ -4245,9 +4411,9 @@ GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcep
ec.clear(); ec.clear();
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
uintmax_t result = static_cast<uintmax_t>(-1); uintmax_t result = static_cast<uintmax_t>(-1);
std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0));
BY_HANDLE_FILE_INFORMATION inf; BY_HANDLE_FILE_INFORMATION inf;
if (file.get() == INVALID_HANDLE_VALUE) {
if (!file) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
else { else {
@ -4476,7 +4642,7 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
ec.clear(); ec.clear();
auto d = new_time.time_since_epoch(); auto d = new_time.time_since_epoch();
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle);
detail::unique_handle file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL));
FILETIME ft; FILETIME ft;
auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000; auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000;
ft.dwLowDateTime = static_cast<DWORD>(tt); ft.dwLowDateTime = static_cast<DWORD>(tt);
@ -4484,9 +4650,9 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
if (!::SetFileTime(file.get(), 0, 0, &ft)) { if (!::SetFileTime(file.get(), 0, 0, &ft)) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
#elif defined(GHC_OS_MACOS)
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
#elif defined(GHC_OS_MACOS) && \
(__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_11_0) || \
(__TV_OS_VERSION_MIN_REQUIRED < __TVOS_11_0) || (__WATCH_OS_VERSION_MIN_REQUIRED < __WATCHOS_4_0)
struct ::stat fs; struct ::stat fs;
if (::stat(p.c_str(), &fs) == 0) { if (::stat(p.c_str(), &fs) == 0) {
struct ::timeval tv[2]; struct ::timeval tv[2];
@ -4500,18 +4666,6 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
} }
ec = detail::make_system_error(); ec = detail::make_system_error();
return; return;
#else
struct ::timespec times[2];
times[0].tv_sec = 0;
times[0].tv_nsec = UTIME_OMIT;
times[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();
times[1].tv_nsec = 0; // std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;
if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
ec = detail::make_system_error();
}
return;
#endif
#endif
#else #else
#ifndef UTIME_OMIT #ifndef UTIME_OMIT
#define UTIME_OMIT ((1l << 30) - 2l) #define UTIME_OMIT ((1l << 30) - 2l)
@ -4524,7 +4678,7 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
#if defined(__ANDROID_API__) && __ANDROID_API__ < 12 #if defined(__ANDROID_API__) && __ANDROID_API__ < 12
if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
#else #else
if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
if (::utimensat((int)AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
#endif #endif
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
@ -4739,7 +4893,7 @@ GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept
return static_cast<uintmax_t>(-1); return static_cast<uintmax_t>(-1);
} }
std::error_code tec; std::error_code tec;
auto fs = status(p, tec);
auto fs = symlink_status(p, tec);
if (exists(fs) && is_directory(fs)) { if (exists(fs) && is_directory(fs)) {
for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) { for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) {
if (ec && !detail::is_not_found_error(ec)) { if (ec && !detail::is_not_found_error(ec)) {
@ -4830,8 +4984,8 @@ GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec)
#endif #endif
return; return;
} }
std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle);
if (file.get() == INVALID_HANDLE_VALUE) {
detail::unique_handle file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL));
if (!file) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) {
@ -5139,7 +5293,7 @@ GHC_INLINE void directory_entry::refresh()
{ {
std::error_code ec; std::error_code ec;
refresh(ec); refresh(ec);
if (ec) {
if (ec && (_status.type() == file_type::none || _symlink_status.type() != file_type::symlink)) {
throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec); throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec);
} }
} }
@ -5550,7 +5704,7 @@ public:
, _entry(nullptr) , _entry(nullptr)
{ {
if (!path.empty()) { if (!path.empty()) {
_dir = ::opendir(path.native().c_str());
do { _dir = ::opendir(path.native().c_str()); } while(errno == EINTR);
if (!_dir) { if (!_dir) {
auto error = errno; auto error = errno;
_base = filesystem::path(); _base = filesystem::path();
@ -5577,7 +5731,7 @@ public:
do { do {
skip = false; skip = false;
errno = 0; errno = 0;
_entry = ::readdir(_dir);
do { _entry = ::readdir(_dir); } while(errno == EINTR);
if (_entry) { if (_entry) {
_dir_entry._path = _base; _dir_entry._path = _base;
_dir_entry._path.append_name(_entry->d_name); _dir_entry._path.append_name(_entry->d_name);
@ -5591,7 +5745,7 @@ public:
::closedir(_dir); ::closedir(_dir);
_dir = nullptr; _dir = nullptr;
_dir_entry._path.clear(); _dir_entry._path.clear();
if (errno) {
if (errno && errno != EINTR) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
break; break;
@ -5602,30 +5756,16 @@ public:
void copyToDirEntry() void copyToDirEntry()
{ {
#ifdef GHC_NO_DIRENT_D_TYPE
_dir_entry._symlink_status = file_status();
_dir_entry._status = file_status();
#else
_dir_entry._symlink_status.permissions(perms::unknown); _dir_entry._symlink_status.permissions(perms::unknown);
switch(_entry->d_type) {
case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break;
case DT_CHR: _dir_entry._symlink_status.type(file_type::character); break;
case DT_DIR: _dir_entry._symlink_status.type(file_type::directory); break;
case DT_FIFO: _dir_entry._symlink_status.type(file_type::fifo); break;
case DT_LNK: _dir_entry._symlink_status.type(file_type::symlink); break;
case DT_REG: _dir_entry._symlink_status.type(file_type::regular); break;
case DT_SOCK: _dir_entry._symlink_status.type(file_type::socket); break;
case DT_UNKNOWN: _dir_entry._symlink_status.type(file_type::none); break;
default: _dir_entry._symlink_status.type(file_type::unknown); break;
}
if (_entry->d_type != DT_LNK) {
auto ft = detail::file_type_from_dirent(*_entry);
_dir_entry._symlink_status.type(ft);
if (ft != file_type::symlink) {
_dir_entry._status = _dir_entry._symlink_status; _dir_entry._status = _dir_entry._symlink_status;
} }
else { else {
_dir_entry._status.type(file_type::none); _dir_entry._status.type(file_type::none);
_dir_entry._status.permissions(perms::unknown); _dir_entry._status.permissions(perms::unknown);
} }
#endif
_dir_entry._file_size = static_cast<uintmax_t>(-1); _dir_entry._file_size = static_cast<uintmax_t>(-1);
_dir_entry._hard_link_count = static_cast<uintmax_t>(-1); _dir_entry._hard_link_count = static_cast<uintmax_t>(-1);
_dir_entry._last_write_time = 0; _dir_entry._last_write_time = 0;

Loading…
Cancel
Save