diff --git a/README.md b/README.md index 27a4d4b..86fd959 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,6 @@ disabled by default https://github.com/fmtlib/fmt distributed under MIT license -* filesystem 1.5.14 +* filesystem 1.5.16 https://github.com/gulrak/filesystem distributed under MIT license diff --git a/libs/filesystem/filesystem.hpp b/libs/filesystem/filesystem.hpp index 53f4ad4..bc417e8 100644 --- a/libs/filesystem/filesystem.hpp +++ b/libs/filesystem/filesystem.hpp @@ -25,23 +25,6 @@ // SOFTWARE. // //--------------------------------------------------------------------------------------- -// -// To dynamically select std::filesystem where available on most platforms, -// you could use: -// -// #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) -// #if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) -// #define GHC_USE_STD_FS -// #include -// namespace fs = std::filesystem; -// #endif -// #endif -// #ifndef GHC_USE_STD_FS -// #include -// namespace fs = ghc::filesystem; -// #endif -// -//--------------------------------------------------------------------------------------- #ifndef GHC_FILESYSTEM_H #define GHC_FILESYSTEM_H @@ -53,7 +36,7 @@ #ifndef GHC_OS_DETECTED #if defined(__APPLE__) && defined(__MACH__) -#define GHC_OS_MACOS +#define GHC_OS_APPLE #elif defined(__linux__) #define GHC_OS_LINUX #if defined(__ANDROID__) @@ -181,7 +164,7 @@ #include #endif #endif -#ifdef GHC_OS_MACOS +#ifdef GHC_OS_APPLE #include #endif @@ -198,6 +181,7 @@ #include #include #include +#include #include #include #include @@ -308,7 +292,7 @@ //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) -#define GHC_FILESYSTEM_VERSION 10514L +#define GHC_FILESYSTEM_VERSION 10516L #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #define GHC_WITH_EXCEPTIONS @@ -821,7 +805,10 @@ class GHC_FS_API_CLASS directory_entry { public: // [fs.dir.entry.cons] constructors and destructor - directory_entry() noexcept = default; + directory_entry() noexcept + : _last_write_time((file_time_type::min)()) + { + } directory_entry(const directory_entry&) = default; directory_entry(directory_entry&&) noexcept = default; #ifdef GHC_WITH_EXCEPTIONS @@ -906,7 +893,7 @@ class GHC_FS_API_CLASS directory_entry #ifndef GHC_OS_WINDOWS uintmax_t _hard_link_count = static_cast(-1); #endif - time_t _last_write_time = 0; + file_time_type _last_write_time = (file_time_type::min)(); }; // [fs.class.directory.iterator] Class directory_iterator @@ -949,20 +936,16 @@ class GHC_FS_API_CLASS directory_iterator directory_iterator& operator=(directory_iterator&& rhs) noexcept; const directory_entry& operator*() const; const directory_entry* operator->() const; -#ifdef GHC_WITH_EXCEPTIONS directory_iterator& operator++(); -#endif directory_iterator& increment(std::error_code& ec) noexcept; // other members as required by [input.iterators] -#ifdef GHC_WITH_EXCEPTIONS proxy operator++(int) { proxy p{**this}; ++*this; return p; } -#endif bool operator==(const directory_iterator& rhs) const; bool operator!=(const directory_iterator& rhs) const; @@ -1009,9 +992,7 @@ class GHC_FS_API_CLASS recursive_directory_iterator // [fs.rec.dir.itr.members] modifiers recursive_directory_iterator& recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs); recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept; -#ifdef GHC_WITH_EXCEPTIONS recursive_directory_iterator& operator++(); -#endif recursive_directory_iterator& increment(std::error_code& ec) noexcept; #ifdef GHC_WITH_EXCEPTIONS @@ -1021,14 +1002,12 @@ class GHC_FS_API_CLASS recursive_directory_iterator void disable_recursion_pending(); // other members as required by [input.iterators] -#ifdef GHC_WITH_EXCEPTIONS directory_iterator::proxy operator++(int) { directory_iterator::proxy proxy{**this}; ++*this; return proxy; } -#endif bool operator==(const recursive_directory_iterator& rhs) const; bool operator!=(const recursive_directory_iterator& rhs) const; @@ -1159,6 +1138,10 @@ GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std: GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; #endif +#if defined(GHC_OS_WINDOWS) && (!defined(__GLIBCXX__) || (defined(_GLIBCXX_HAVE__WFOPEN) && defined(_GLIBCXX_USE_WCHAR_T))) +#define GHC_HAS_FSTREAM_OPEN_WITH_WCHAR +#endif + // Non-C++17 add-on std::fstream wrappers with path template > class basic_filebuf : public std::basic_filebuf @@ -1170,7 +1153,7 @@ class basic_filebuf : public std::basic_filebuf const basic_filebuf& operator=(const basic_filebuf&) = delete; basic_filebuf* open(const path& p, std::ios_base::openmode mode) { -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) +#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR return std::basic_filebuf::open(p.wstring().c_str(), mode) ? this : 0; #else return std::basic_filebuf::open(p.string().c_str(), mode) ? this : 0; @@ -1183,7 +1166,7 @@ class basic_ifstream : public std::basic_ifstream { public: basic_ifstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) +#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) : std::basic_ifstream(p.wstring().c_str(), mode) { @@ -1206,7 +1189,7 @@ class basic_ofstream : public std::basic_ofstream { public: basic_ofstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) +#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ofstream(p.wstring().c_str(), mode) { @@ -1229,7 +1212,7 @@ class basic_fstream : public std::basic_fstream { public: basic_fstream() {} -#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) +#ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_fstream(p.wstring().c_str(), mode) { @@ -1673,22 +1656,28 @@ inline std::string toUtf8(const strT& unicodeString) std::string result; for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) { char32_t c = *iter; - if (is_surrogate(c)) { - ++iter; - if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) { - appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00); + if (is_high_surrogate(c)) { + auto next = iter; + ++next; + if (next != unicodeString.end() && is_low_surrogate(*next)) { + appendUTF8(result, (char32_t(c) << 10) + *next - 0x35fdc00); + iter = next; } else { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence)); #else appendUTF8(result, 0xfffd); - if (iter == unicodeString.end()) { - break; - } #endif } } + else if (is_low_surrogate(c)) { +#ifdef GHC_RAISE_UNICODE_ERRORS + throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence)); +#else + appendUTF8(result, 0xfffd); +#endif + } else { appendUTF8(result, c); } @@ -1930,12 +1919,15 @@ template GHC_INLINE std::string systemErrorText(ErrorNumber code = 0) { #if defined(GHC_OS_WINDOWS) - LPVOID msgBuf; + LPWSTR msgBuf = nullptr; DWORD dw = code ? static_cast(code) : ::GetLastError(); - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL); - std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf)); - LocalFree(msgBuf); - return msg; + DWORD length = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&msgBuf), 0, NULL); + if (length != 0 && msgBuf != nullptr) { + std::string msg = toUtf8(std::wstring(msgBuf, length)); + LocalFree(msgBuf); + return msg; + } + return "Unknown system error " + std::to_string(dw); #else char buffer[512]; return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer); @@ -1954,7 +1946,7 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, ec = detail::make_error_code(detail::portable_error::not_supported); return; } -#if defined(__GNUC__) && __GNUC__ >= 8 +#if defined(__GNUC__) && __GNUC__ >= 8 || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) @@ -1962,7 +1954,7 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, #pragma warning(disable : 4191) #endif static CreateSymbolicLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); -#if defined(__GNUC__) && __GNUC__ >= 8 +#if defined(__GNUC__) && __GNUC__ >= 8 || defined(__clang__) #pragma GCC diagnostic pop #elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) #pragma warning(pop) @@ -1983,7 +1975,7 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) { -#if defined(__GNUC__) && __GNUC__ >= 8 +#if defined(__GNUC__) && __GNUC__ >= 8 || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) @@ -1991,7 +1983,7 @@ GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlin #pragma warning(disable : 4191) #endif static CreateHardLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); -#if defined(__GNUC__) && __GNUC__ >= 8 +#if defined(__GNUC__) && __GNUC__ >= 8 || defined(__clang__) #pragma GCC diagnostic pop #elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__clang__) #pragma warning(pop) @@ -2129,6 +2121,13 @@ class unique_handle element_type _handle; }; +// It seems GCC doesn't catch this, but Clang does +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=72751 +#if defined(__clang__) && defined(__MINGW32__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnested-anon-types" +#endif + #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE typedef struct _REPARSE_DATA_BUFFER { @@ -2165,6 +2164,10 @@ typedef struct _REPARSE_DATA_BUFFER #endif #endif +#if defined(__clang__) && defined(__MINGW32__) +#pragma clang diagnostic pop +#endif + template struct free_deleter { @@ -2243,12 +2246,14 @@ GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) } #ifdef GHC_OS_WINDOWS -GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft) +GHC_INLINE file_time_type timeFromFILETIME(const FILETIME& ft) { ULARGE_INTEGER ull; ull.LowPart = ft.dwLowDateTime; ull.HighPart = ft.dwHighDateTime; - return static_cast(ull.QuadPart / 10000000ULL - 11644473600ULL); + const int64_t ticks = static_cast(ull.QuadPart) - 116444736000000000LL; + const auto duration = std::chrono::duration>(ticks); + return file_time_type(std::chrono::duration_cast(duration)); } GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) @@ -2260,7 +2265,7 @@ GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) } template -GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info) +GHC_INLINE uintmax_t hard_links_from_INFO(const INFO*) { return static_cast(-1); } @@ -2298,7 +2303,7 @@ GHC_INLINE bool is_symlink_from_INFO(const path &, const WIN32_FIND_DATAW* info, } template -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, file_time_type* lwt = nullptr) { file_type ft = file_type::unknown; if (is_symlink_from_INFO(p, info, ec)) { @@ -2337,7 +2342,7 @@ GHC_INLINE bool is_not_found_error(std::error_code& ec) #endif } -GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept +GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, file_time_type* lwt = nullptr) noexcept { #ifdef GHC_OS_WINDOWS file_status fs; @@ -2375,7 +2380,7 @@ GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uin #endif } -GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept +GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, file_time_type* lwt = nullptr, int recurse_count = 0) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS @@ -2441,7 +2446,13 @@ GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status *nhl = st.st_nlink; } if (lwt) { - *lwt = st.st_mtime; +#ifdef GHC_OS_APPLE + const auto subsecond = std::chrono::nanoseconds(st.st_mtimespec.tv_nsec); +#else + const auto subsecond = std::chrono::nanoseconds(st.st_mtim.tv_nsec); +#endif + const auto duration = std::chrono::seconds(st.st_mtime) + subsecond; + *lwt = file_time_type(std::chrono::duration_cast(duration)); } return fs; } @@ -2632,10 +2643,16 @@ GHC_INLINE path& path::operator/=(const path& p) assign(p); return *this; } + bool isHostOnlyUncPath = false; +#ifdef GHC_OS_WINDOWS + const auto rootNameLength = root_name_length(); + isHostOnlyUncPath = rootNameLength == _path.length() && rootNameLength > _prefixLength + 2 && + _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator; +#endif if (p.has_root_directory()) { assign(root_name()); } - else if ((!has_root_directory() && is_absolute()) || has_filename()) { + else if ((!has_root_directory() && is_absolute()) || has_filename() || isHostOnlyUncPath) { _path += preferred_separator; } auto iter = p.begin(); @@ -3170,7 +3187,7 @@ GHC_INLINE path path::extension() const auto iter = end(); const auto& fn = *--iter; impl_string_type::size_type pos = fn._path.rfind('.'); - if (pos != std::string::npos && pos > 0) { + if (pos != std::string::npos && pos > 0 && fn._path != "..") { return path(fn._path.substr(pos), native_format); } } @@ -3278,16 +3295,27 @@ GHC_INLINE path path::lexically_normal() const if (dest == root) { continue; } - else if (*(--dest.end()) != "..") { - if (dest._path.back() == preferred_separator) { - dest._path.pop_back(); + else { + auto last = --dest.end(); + if (last->empty() && last != dest.begin()) { + --last; + } + if (!last->empty() && *last != "..") { + if (dest._path.back() == preferred_separator) { + dest._path.pop_back(); + } + dest.remove_filename(); + continue; } - dest.remove_filename(); - continue; } } if (!(s.empty() && lastDotDot)) { - dest /= s; + if (dest.has_relative_path()) { + dest.append_name(s.c_str()); + } + else { + dest /= s; + } } lastDotDot = s == ".."; } @@ -3319,6 +3347,9 @@ GHC_INLINE path path::lexically_relative(const path& base) const --count; } } + if (count == 0 && (a == end() || a->empty())) { + return path("."); + } if (count < 0) { return path(); } @@ -3742,6 +3773,19 @@ GHC_INLINE path canonical(const path& p, std::error_code& ec) return path(); } path work = p.is_absolute() ? p : absolute(p, ec); +#ifdef GHC_OS_WINDOWS + const path::impl_string_type deviceUncPrefix(GHC_PLATFORM_LITERAL("\\\\.\\UNC\\")); + const path::impl_string_type extendedUncPrefix(GHC_PLATFORM_LITERAL("\\\\?\\UNC\\")); + auto hasPrefix = [&work](const path::impl_string_type& prefix) { + return work._path.length() > prefix.length() && + std::equal(prefix.begin(), prefix.end(), work._path.begin(), [](path::value_type lhs, path::value_type rhs) { + return std::toupper(static_cast(lhs)) == std::toupper(static_cast(rhs)); + }); + }; + if (hasPrefix(deviceUncPrefix) || hasPrefix(extendedUncPrefix)) { + work = path(GHC_PLATFORM_LITERAL("\\\\") + work._path.substr(deviceUncPrefix.length()), path::native_format); + } +#endif path result; auto fs = status(work, ec); @@ -3927,7 +3971,15 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options bool overwrite = false; ec.clear(); if (!is_regular_file(sf)) { - ec = tecf; + if (tecf) { + ec = tecf; + } + else if (is_directory(sf)) { + ec = detail::make_error_code(detail::portable_error::is_a_directory); + } + else { + ec = detail::make_error_code(detail::portable_error::invalid_argument); + } return false; } if (exists(st)) { @@ -3987,7 +4039,7 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options } ssize_t br, bw; while (true) { - do { br = ::read(in, buffer.data(), buffer.size()); } while(errno == EINTR); + do { br = ::read(in, buffer.data(), buffer.size()); } while(br == -1 && errno == EINTR); if(!br) { break; } @@ -4239,7 +4291,7 @@ GHC_INLINE path current_path(std::error_code& ec) } return path(std::wstring(buffer.get()), path::native_format); #elif defined(__GLIBC__) - std::unique_ptr buffer { ::getcwd(NULL, 0), std::free }; + std::unique_ptr buffer { ::get_current_dir_name(), std::free }; if (buffer == nullptr) { ec = detail::make_system_error(); return path(); @@ -4340,8 +4392,7 @@ GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) ec = detail::make_system_error(); return false; } - return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow && - inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber; + return inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber; #else struct ::stat s1, s2; auto rc1 = ::stat(p1.c_str(), &s1); @@ -4357,7 +4408,7 @@ GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) #endif return false; } - return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; + return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; #endif } @@ -4620,10 +4671,10 @@ GHC_INLINE file_time_type last_write_time(const path& p) GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept { - time_t result = 0; + file_time_type result = (file_time_type::min)(); ec.clear(); file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result); - return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result); + return ec ? (file_time_type::min)() : result; } #ifdef GHC_WITH_EXCEPTIONS @@ -4644,15 +4695,17 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err #ifdef GHC_OS_WINDOWS 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; - auto tt = std::chrono::duration_cast(d).count() * 10 + 116444736000000000; + const auto tt = std::chrono::duration_cast>>(d).count() + 116444736000000000LL; ft.dwLowDateTime = static_cast(tt); ft.dwHighDateTime = static_cast(tt >> 32); if (!::SetFileTime(file.get(), 0, 0, &ft)) { ec = detail::make_system_error(); } -#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) +#elif defined(GHC_OS_APPLE) && \ + (__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 \ + || __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000 \ + || __TV_OS_VERSION_MIN_REQUIRED && __TVOS_VERSION_MIN_REQUIRED < 110000 \ + || __WATCH_OS_VERSION_MIN_REQUIRED && __WATCHOS_VERSION_MIN_REQUIRED < 40000) struct ::stat fs; if (::stat(p.c_str(), &fs) == 0) { struct ::timeval tv[2]; @@ -4676,9 +4729,9 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err times[1].tv_sec = static_cast(std::chrono::duration_cast(d).count()); times[1].tv_nsec = static_cast(std::chrono::duration_cast(d).count() % 1000000000); #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, 0) != 0) { #else - if (::utimensat((int)AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { + if (::utimensat((int)AT_FDCWD, p.c_str(), times, 0) != 0) { #endif ec = detail::make_system_error(); } @@ -4748,7 +4801,6 @@ GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::e #endif } -#ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path proximate(const path& p, std::error_code& ec) { auto cp = current_path(ec); @@ -4757,7 +4809,6 @@ GHC_INLINE path proximate(const path& p, std::error_code& ec) } return path(); } -#endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path proximate(const path& p, const path& base) @@ -5126,8 +5177,7 @@ GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept bool scan = true; for (auto pe : p) { if (scan) { - std::error_code tec; - if (exists(result / pe, tec)) { + if (exists(result / pe, ec)) { result /= pe; } else { @@ -5236,7 +5286,7 @@ GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) #ifndef GHC_OS_WINDOWS , _hard_link_count(static_cast(-1)) #endif - , _last_write_time(0) + , _last_write_time((file_time_type::min)()) { refresh(); } @@ -5248,7 +5298,7 @@ GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::erro #ifndef GHC_OS_WINDOWS , _hard_link_count(static_cast(-1)) #endif - , _last_write_time(0) + , _last_write_time((file_time_type::min)()) { refresh(ec); } @@ -5496,8 +5546,8 @@ GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_time_type directory_entry::last_write_time() const { - if (_last_write_time != 0) { - return std::chrono::system_clock::from_time_t(_last_write_time); + if (_last_write_time != (file_time_type::min)()) { + return _last_write_time; } return filesystem::last_write_time(path()); } @@ -5505,9 +5555,9 @@ GHC_INLINE file_time_type directory_entry::last_write_time() const GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept { - if (_last_write_time != 0) { + if (_last_write_time != (file_time_type::min)()) { ec.clear(); - return std::chrono::system_clock::from_time_t(_last_write_time); + return _last_write_time; } return filesystem::last_write_time(path(), ec); } @@ -5602,7 +5652,8 @@ class directory_iterator::impl if (!_base.empty()) { ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW)); if ((_dirHandle = FindFirstFileW(GHC_NATIVEWP((_base / "*")), &_findData)) != INVALID_HANDLE_VALUE) { - if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") { + if (wcscmp(_findData.cFileName, L".") == 0 || + wcscmp(_findData.cFileName, L"..") == 0) { increment(_ec); } else { @@ -5660,7 +5711,7 @@ class directory_iterator::impl _dir_entry._path.clear(); break; } - } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L".."); + } while (wcscmp(_findData.cFileName, L".") == 0 || wcscmp(_findData.cFileName, L"..") == 0); } else { ec = _ec; @@ -5681,7 +5732,7 @@ class directory_iterator::impl } else { _dir_entry._file_size = static_cast(-1); - _dir_entry._last_write_time = 0; + _dir_entry._last_write_time = (file_time_type::min)(); } } } @@ -5704,7 +5755,7 @@ class directory_iterator::impl , _entry(nullptr) { if (!path.empty()) { - do { _dir = ::opendir(path.native().c_str()); } while(errno == EINTR); + do { _dir = ::opendir(path.native().c_str()); } while(errno == EINTR && !_dir); if (!_dir) { auto error = errno; _base = filesystem::path(); @@ -5730,8 +5781,10 @@ class directory_iterator::impl bool skip; do { skip = false; - errno = 0; - do { _entry = ::readdir(_dir); } while(errno == EINTR); + do { + errno = 0; + _entry = ::readdir(_dir); + } while (errno == EINTR && !_entry); if (_entry) { _dir_entry._path = _base; _dir_entry._path.append_name(_entry->d_name); @@ -5768,7 +5821,7 @@ class directory_iterator::impl } _dir_entry._file_size = static_cast(-1); _dir_entry._hard_link_count = static_cast(-1); - _dir_entry._last_write_time = 0; + _dir_entry._last_write_time = (file_time_type::min)(); } path _base; directory_options _options; @@ -5854,17 +5907,19 @@ GHC_INLINE const directory_entry* directory_iterator::operator->() const return &_impl->_dir_entry; } -#ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_iterator& directory_iterator::operator++() { std::error_code ec; _impl->increment(ec); if (ec) { +#ifdef GHC_WITH_EXCEPTIONS throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec); +#else + std::terminate(); +#endif } return *this; } -#endif GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept { @@ -5980,27 +6035,30 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator= return *this; } -#ifdef GHC_WITH_EXCEPTIONS GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++() { std::error_code ec; increment(ec); if (ec) { +#ifdef GHC_WITH_EXCEPTIONS throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); +#else + std::terminate(); +#endif } return *this; } -#endif GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept { bool isSymLink = (*this)->is_symlink(ec); - bool isDir = !ec && (*this)->is_directory(ec); + const bool followSymlink = (options() & directory_options::follow_directory_symlink) != directory_options::none; + bool isDir = !ec && (!isSymLink || followSymlink) && (*this)->is_directory(ec); if (isSymLink && detail::is_not_found_error(ec)) { ec.clear(); } if (!ec) { - if (recursion_pending() && isDir && (!isSymLink || (options() & directory_options::follow_directory_symlink) != directory_options::none)) { + if (recursion_pending() && isDir) { _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec)); } else {