From ea16ee630b4467384cb385729ed19cc18f0e175a Mon Sep 17 00:00:00 2001 From: Timothy Stack Date: Wed, 6 Jul 2022 22:30:51 -0700 Subject: [PATCH] [libs] bump ghc::filesystem --- src/ghc/filesystem.hpp | 585 ++++++++++++++++++++++++++-------------- src/ghc/fs_std.hpp | 4 + src/ghc/fs_std_fwd.hpp | 3 + src/ghc/fs_std_impl.hpp | 3 + 4 files changed, 393 insertions(+), 202 deletions(-) diff --git a/src/ghc/filesystem.hpp b/src/ghc/filesystem.hpp index e4e0e276..9540b440 100644 --- a/src/ghc/filesystem.hpp +++ b/src/ghc/filesystem.hpp @@ -67,6 +67,8 @@ #define GHC_OS_WIN32 #elif defined(__CYGWIN__) #define GHC_OS_CYGWIN +#elif defined(__sun) && defined(__SVR4) +#define GHC_OS_SOLARIS #elif defined(__svr4__) #define GHC_OS_SYS5R4 #elif defined(BSD) @@ -74,6 +76,8 @@ #elif defined(__EMSCRIPTEN__) #define GHC_OS_WEB #include +#elif defined(__QNX__) +#define GHC_OS_QNX #else #error "Operating system currently not supported!" #endif @@ -240,6 +244,9 @@ #define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW #elif defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)) && (__cplusplus >= 201402) #define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW +#elif defined(__GLIBCXX__) && defined(_GLIBCXX_USE_DUAL_ABI) && (__cplusplus >= 201402) +// macro _GLIBCXX_USE_DUAL_ABI is always defined in libstdc++ from gcc-5 and newer +#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW #endif #if defined(GHC_HAS_STD_STRING_VIEW) @@ -248,6 +255,10 @@ #include #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): //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -268,19 +279,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 // * 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) #define LWG_2936_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) #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 -// 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 -// 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 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found, @@ -295,7 +306,7 @@ //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) -#define GHC_FILESYSTEM_VERSION 10504L +#define GHC_FILESYSTEM_VERSION 10512L #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #define GHC_WITH_EXCEPTIONS @@ -351,7 +362,7 @@ bool has_executable_extension(const path& p); } #endif -// 30.10.8 class path +// [fs.class.path] class path class GHC_FS_API_CLASS path #if defined(GHC_OS_WINDOWS) && !defined(GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE) #define GHC_USE_WCHAR_T @@ -372,7 +383,7 @@ public: using string_type = std::basic_string; using path_helper_base::preferred_separator; - // 30.10.10.1 enumeration format + // [fs.enum.path.format] enumeration format /// The path format in which the constructor argument is given. enum format { generic_format, ///< The generic format, internally used by @@ -408,12 +419,25 @@ public: template using path_type = typename std::enable_if::value, path>::type; template - using path_from_string = typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || - std::is_same::type>::value || std::is_same::type>::value, - path>::type; +#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) + using path_from_string = + typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || + std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || + std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || + std::is_same::type>::value, + path>::type; + template + using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; +#else + using path_from_string = + typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || + std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || + std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value, + path>::type; template using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; - // 30.10.8.4.1 constructors and destructor +#endif + // [fs.path.construct] constructors and destructor path() noexcept; path(const path& p); path(path&& p) noexcept; @@ -430,7 +454,7 @@ public: #endif ~path(); - // 30.10.8.4.2 assignments + // [fs.path.assign] assignments path& operator=(const path& p); path& operator=(path&& p) noexcept; path& operator=(string_type&& source); @@ -442,7 +466,7 @@ public: template path& assign(InputIterator first, InputIterator last); - // 30.10.8.4.3 appends + // [fs.path.append] appends path& operator/=(const path& p); template path& operator/=(const Source& source); @@ -451,7 +475,7 @@ public: template path& append(InputIterator first, InputIterator last); - // 30.10.8.4.4 concatenation + // [fs.path.concat] concatenation path& operator+=(const path& x); path& operator+=(const string_type& x); #ifdef GHC_WITH_STRING_VIEW @@ -468,7 +492,7 @@ public: template path& concat(InputIterator first, InputIterator last); - // 30.10.8.4.5 modifiers + // [fs.path.modifiers] modifiers void clear() noexcept; path& make_preferred(); path& remove_filename(); @@ -476,7 +500,7 @@ public: path& replace_extension(const path& replacement = path()); void swap(path& rhs) noexcept; - // 30.10.8.4.6 native format observers + // [fs.path.native.obs] native format observers const string_type& native() const noexcept; const value_type* c_str() const noexcept; operator string_type() const; @@ -492,7 +516,7 @@ public: std::u16string u16string() const; std::u32string u32string() const; - // 30.10.8.4.7 generic format observers + // [fs.path.generic.obs] generic format observers template , class Allocator = std::allocator> std::basic_string generic_string(const Allocator& a = Allocator()) const; std::string generic_string() const; @@ -505,7 +529,7 @@ public: std::u16string generic_u16string() const; std::u32string generic_u32string() const; - // 30.10.8.4.8 compare + // [fs.path.compare] compare int compare(const path& p) const noexcept; int compare(const string_type& s) const; #ifdef GHC_WITH_STRING_VIEW @@ -513,7 +537,7 @@ public: #endif int compare(const value_type* s) const; - // 30.10.8.4.9 decomposition + // [fs.path.decompose] decomposition path root_name() const; path root_directory() const; path root_path() const; @@ -523,7 +547,7 @@ public: path stem() const; path extension() const; - // 30.10.8.4.10 query + // [fs.path.query] query bool empty() const noexcept; bool has_root_name() const; bool has_root_directory() const; @@ -536,12 +560,12 @@ public: bool is_absolute() const; bool is_relative() const; - // 30.10.8.4.11 generation + // [fs.path.gen] generation path lexically_normal() const; path lexically_relative(const path& base) const; path lexically_proximate(const path& base) const; - // 30.10.8.5 iterators + // [fs.path.itr] iterators class iterator; using const_iterator = iterator; iterator begin() const; @@ -577,6 +601,7 @@ private: friend void swap(path& lhs, path& rhs) noexcept; friend size_t hash_value(const path& p) noexcept; friend path canonical(const path& p, std::error_code& ec); + friend bool create_directories(const path& p, std::error_code& ec) noexcept; string_type::size_type root_name_length() const noexcept; void postprocess_path_with_format(format fmt); void check_long_path(); @@ -586,7 +611,7 @@ private: friend bool detail::has_executable_extension(const path& p); #ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH string_type::size_type _prefixLength{0}; -#else // GHC_WIN_AUTO_PREFIX_LONG_PATH +#else // GHC_WIN_AUTO_PREFIX_LONG_PATH static const string_type::size_type _prefixLength{0}; #endif // GHC_WIN_AUTO_PREFIX_LONG_PATH #else @@ -594,7 +619,7 @@ private: #endif }; -// 30.10.8.6 path non-member functions +// [fs.path.nonmember] path non-member functions GHC_FS_API void swap(path& lhs, path& rhs) noexcept; GHC_FS_API size_t hash_value(const path& p) noexcept; #ifdef GHC_HAS_THREEWAY_COMP @@ -608,13 +633,13 @@ GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept; GHC_FS_API path operator/(const path& lhs, const path& rhs); -// 30.10.8.6.1 path inserter and extractor +// [fs.path.io] path inserter and extractor template std::basic_ostream& operator<<(std::basic_ostream& os, const path& p); template std::basic_istream& operator>>(std::basic_istream& is, path& p); -// 30.10.8.6.2 path factory functions +// [pfs.path.factory] path factory functions template > #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) [[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] @@ -626,7 +651,7 @@ template #endif path u8path(InputIterator first, InputIterator last); -// 30.10.9 class filesystem_error +// [fs.class.filesystem_error] class filesystem_error class GHC_FS_API_CLASS filesystem_error : public std::system_error { public: @@ -683,7 +708,8 @@ struct space_info uintmax_t available; }; -// 30.10.10, enumerations +// [fs.enum] enumerations +// [fs.enum.file_type] enum class file_type { none, not_found, @@ -697,6 +723,7 @@ enum class file_type { unknown, }; +// [fs.enum.perms] enum class perms : uint16_t { none = 0, @@ -724,6 +751,7 @@ enum class perms : uint16_t { unknown = 0xffff }; +// [fs.enum.perm.opts] enum class perm_options : uint16_t { replace = 3, add = 1, @@ -731,6 +759,7 @@ enum class perm_options : uint16_t { nofollow = 4, }; +// [fs.enum.copy.opts] enum class copy_options : uint16_t { none = 0, @@ -750,17 +779,18 @@ enum class copy_options : uint16_t { #endif }; +// [fs.enum.dir.opts] enum class directory_options : uint16_t { none = 0, follow_directory_symlink = 1, skip_permission_denied = 2, }; -// 30.10.11 class file_status +// [fs.class.file_status] class file_status class GHC_FS_API_CLASS file_status { public: - // 30.10.11.1 constructors and destructor + // [fs.file_status.cons] constructors and destructor file_status() noexcept; explicit file_status(file_type ft, perms prms = perms::unknown) noexcept; file_status(const file_status&) noexcept; @@ -769,13 +799,14 @@ public: // assignments: file_status& operator=(const file_status&) noexcept; file_status& operator=(file_status&&) noexcept; - // 30.10.11.3 modifiers + // [fs.file_status.mods] modifiers void type(file_type ft) noexcept; void permissions(perms prms) noexcept; - // 30.10.11.2 observers + // [fs.file_status.obs] observers file_type type() 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(); } + private: file_type _type; perms _perms; @@ -783,11 +814,11 @@ private: using file_time_type = std::chrono::time_point; -// 30.10.12 Class directory_entry +// [fs.class.directory_entry] Class directory_entry class GHC_FS_API_CLASS directory_entry { public: - // 30.10.12.1 constructors and destructor + // [fs.dir.entry.cons] constructors and destructor directory_entry() noexcept = default; directory_entry(const directory_entry&) = default; directory_entry(directory_entry&&) noexcept = default; @@ -801,7 +832,7 @@ public: directory_entry& operator=(const directory_entry&) = default; directory_entry& operator=(directory_entry&&) noexcept = default; - // 30.10.12.2 modifiers + // [fs.dir.entry.mods] modifiers #ifdef GHC_WITH_EXCEPTIONS void assign(const path& p); void replace_filename(const path& p); @@ -811,7 +842,7 @@ public: void replace_filename(const path& p, std::error_code& ec); void refresh(std::error_code& ec) noexcept; - // 30.10.12.3 observers + // [fs.dir.entry.obs] observers const filesystem::path& path() const noexcept; operator const filesystem::path&() const noexcept; #ifdef GHC_WITH_EXCEPTIONS @@ -876,7 +907,7 @@ private: time_t _last_write_time = 0; }; -// 30.10.13 Class directory_iterator +// [fs.class.directory.iterator] Class directory_iterator class GHC_FS_API_CLASS directory_iterator { public: @@ -901,7 +932,7 @@ public: using pointer = const directory_entry*; using reference = const directory_entry&; - // 30.10.13.1 member functions + // [fs.dir.itr.members] member functions directory_iterator() noexcept; #ifdef GHC_WITH_EXCEPTIONS explicit directory_iterator(const path& p); @@ -921,7 +952,7 @@ public: #endif directory_iterator& increment(std::error_code& ec) noexcept; - // other members as required by 27.2.3, input iterators + // other members as required by [input.iterators] #ifdef GHC_WITH_EXCEPTIONS proxy operator++(int) { @@ -939,11 +970,11 @@ private: std::shared_ptr _impl; }; -// 30.10.13.2 directory_iterator non-member functions +// [fs.dir.itr.nonmembers] directory_iterator non-member functions GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept; GHC_FS_API directory_iterator end(const directory_iterator&) noexcept; -// 30.10.14 class recursive_directory_iterator +// [fs.class.re.dir.itr] class recursive_directory_iterator class GHC_FS_API_CLASS recursive_directory_iterator { public: @@ -953,7 +984,7 @@ public: using pointer = const directory_entry*; using reference = const directory_entry&; - // 30.10.14.1 constructors and destructor + // [fs.rec.dir.itr.members] constructors and destructor recursive_directory_iterator() noexcept; #ifdef GHC_WITH_EXCEPTIONS explicit recursive_directory_iterator(const path& p); @@ -965,7 +996,7 @@ public: recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept; ~recursive_directory_iterator(); - // 30.10.14.1 observers + // [fs.rec.dir.itr.members] observers directory_options options() const; int depth() const; bool recursion_pending() const; @@ -973,7 +1004,7 @@ public: const directory_entry& operator*() const; const directory_entry* operator->() const; - // 30.10.14.1 modifiers 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 @@ -987,7 +1018,7 @@ public: void pop(std::error_code& ec); void disable_recursion_pending(); - // other members as required by 27.2.3, input iterators + // other members as required by [input.iterators] #ifdef GHC_WITH_EXCEPTIONS directory_iterator::proxy operator++(int) { @@ -1014,11 +1045,11 @@ private: std::shared_ptr _impl; }; -// 30.10.14.2 directory_iterator non-member functions +// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; -// 30.10.15 filesystem operations +// [fs.op.funcs] filesystem operations #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API path absolute(const path& p); GHC_FS_API path canonical(const path& p); @@ -1272,6 +1303,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); #else GHC_FS_API std::error_code make_system_error(int err = 0); + +template +struct has_d_type : std::false_type{}; + +template +struct has_d_type : std::true_type {}; + +template +GHC_INLINE file_type file_type_from_dirent_impl(const T&, std::false_type) +{ + return file_type::none; +} + +template +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 +GHC_INLINE file_type file_type_from_dirent(const T& t) +{ + return file_type_from_dirent_impl(t, has_d_type{}); +} #endif } // namespace detail @@ -1673,7 +1763,7 @@ inline std::wstring toWChar(const charT* unicodeString) return toWChar(std::basic_string>(unicodeString)); #endif } -#endif // GHC_USE_WCHAR_T +#endif // GHC_USE_WCHAR_T } // namespace detail @@ -1792,16 +1882,16 @@ GHC_INLINE bool equals_simple_insensitive(const path::value_type* str1, const pa return true; } return false; -#else // __GNUC__ +#else // __GNUC__ #ifdef GHC_USE_WCHAR_T return 0 == ::_wcsicmp(str1, str2); -#else // GHC_USE_WCHAR_T +#else // GHC_USE_WCHAR_T return 0 == ::_stricmp(str1, str2); -#endif // GHC_USE_WCHAR_T -#endif // __GNUC__ -#else // GHC_OS_WINDOWS +#endif // GHC_USE_WCHAR_T +#endif // __GNUC__ +#else // GHC_OS_WINDOWS return 0 == ::strcasecmp(str1, str2); -#endif // GHC_OS_WINDOWS +#endif // GHC_OS_WINDOWS } GHC_INLINE int compare_simple_insensitive(const path::value_type* str1, size_t len1, const path::value_type* str2, size_t len2) @@ -1871,9 +1961,9 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, #pragma GCC diagnostic pop #endif if (api_call) { - if (api_call(detail::fromUtf8(new_symlink.u8string()).c_str(), detail::fromUtf8(target_name.u8string()).c_str(), to_directory ? 1 : 0) == 0) { + if (api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 1 : 0) == 0) { auto result = ::GetLastError(); - if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(detail::fromUtf8(new_symlink.u8string()).c_str(), detail::fromUtf8(target_name.u8string()).c_str(), to_directory ? 3 : 2) != 0) { + if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(GHC_NATIVEWP(new_symlink), GHC_NATIVEWP(target_name), to_directory ? 3 : 2) != 0) { return; } ec = detail::make_system_error(result); @@ -1980,56 +2070,122 @@ GHC_INLINE file_status file_status_from_st_mode(T mode) #endif } -GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) -{ #ifdef GHC_OS_WINDOWS -#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE - typedef struct _REPARSE_DATA_BUFFER + +class unique_handle +{ +public: + typedef HANDLE element_type; + + unique_handle() noexcept + : _handle(INVALID_HANDLE_VALUE) { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union + } + 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 +typedef struct _REPARSE_DATA_BUFFER +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + struct { - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct - { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct - { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - } DUMMYUNIONNAME; - } REPARSE_DATA_BUFFER; + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; +} REPARSE_DATA_BUFFER; #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) #endif #endif - std::shared_ptr 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) { +template +struct free_deleter +{ + void operator()(T* p) const { std::free(p); } +}; + +GHC_INLINE std::unique_ptr> 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(); - return path(); + return nullptr; } - std::shared_ptr reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free); + std::unique_ptr> reparseData(reinterpret_cast(std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE))); ULONG bufferUsed; - path result; if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { - if (IsReparseTagMicrosoft(reparseData->ReparseTag)) { + return reparseData; + } + else { + ec = detail::make_system_error(); + } + return nullptr; +} +#endif + +GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) +{ +#ifdef GHC_OS_WINDOWS + path result; + auto reparseData = detail::getReparseData(p, ec); + if (!ec) { + if (reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag)) { switch (reparseData->ReparseTag) { case IO_REPARSE_TAG_SYMLINK: { auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR)); @@ -2047,16 +2203,14 @@ GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) break; } case IO_REPARSE_TAG_MOUNT_POINT: - result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); + result = detail::getFullPathName(GHC_NATIVEWP(p), ec); + // result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); break; default: break; } } } - else { - ec = detail::make_system_error(); - } return result; #else size_t bufferSize = 256; @@ -2106,13 +2260,35 @@ GHC_INLINE uintmax_t hard_links_from_INFO(const BY_H } template -GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr) +GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*) +{ + return 0; +} + +template <> +GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info) +{ + return info->dwReserved0; +} + +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) { file_type ft = file_type::unknown; - if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { - ft = file_type::symlink; + 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) { + ft = file_type::symlink; + } + } + } + if (ft == file_type::unknown) { if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { ft = file_type::directory; } @@ -2161,9 +2337,6 @@ GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uin if (nhl) { *nhl = 0; } - if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - fs.type(file_type::symlink); - } } if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found); @@ -2201,15 +2374,18 @@ GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status ec = detail::make_system_error(); } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - path target = resolveSymlink(p, ec); - file_status result; - if (!ec && !target.empty()) { - if (sls) { - *sls = status_from_INFO(p, &attr, ec); + auto reparseData = detail::getReparseData(p, ec); + if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + path target = resolveSymlink(p, ec); + file_status result; + if (!ec && !target.empty()) { + if (sls) { + *sls = status_from_INFO(p, &attr, ec); + } + return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); } - return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); + return file_status(file_type::unknown); } - return file_status(file_type::unknown); } if (ec) { if (detail::is_not_found_error(ec)) { @@ -2299,7 +2475,7 @@ GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv) } //----------------------------------------------------------------------------- -// 30.10.8.4.1 constructors and destructor +// [fs.path.construct] constructors and destructor GHC_INLINE path::path() noexcept {} @@ -2354,7 +2530,7 @@ inline path::path(InputIterator first, InputIterator last, const std::locale& lo GHC_INLINE path::~path() {} //----------------------------------------------------------------------------- -// 30.10.8.4.2 assignments +// [fs.path.assign] assignments GHC_INLINE path& path::operator=(const path& p) { @@ -2427,7 +2603,7 @@ inline path& path::assign(InputIterator first, InputIterator last) #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- -// 30.10.8.4.3 appends +// [fs.path.append] appends GHC_INLINE path& path::operator/=(const path& p) { @@ -2508,7 +2684,7 @@ inline path& path::append(InputIterator first, InputIterator last) #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- -// 30.10.8.4.4 concatenation +// [fs.path.concat] concatenation GHC_INLINE path& path::operator+=(const path& x) { @@ -2590,7 +2766,7 @@ inline path& path::concat(InputIterator first, InputIterator last) #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- -// 30.10.8.4.5 modifiers +// [fs.path.modifiers] modifiers GHC_INLINE void path::clear() noexcept { _path.clear(); @@ -2640,7 +2816,7 @@ GHC_INLINE void path::swap(path& rhs) noexcept } //----------------------------------------------------------------------------- -// 30.10.8.4.6, native format observers +// [fs.path.native.obs] native format observers GHC_INLINE const path::string_type& path::native() const noexcept { return _path; @@ -2723,7 +2899,7 @@ GHC_INLINE std::u32string path::u32string() const #endif // GHC_EXPAND_IMPL //----------------------------------------------------------------------------- -// 30.10.8.4.7, generic format observers +// [fs.path.generic.obs] generic format observers template inline std::basic_string path::generic_string(const Allocator& a) const { @@ -2803,7 +2979,7 @@ GHC_INLINE std::u32string path::generic_u32string() const } //----------------------------------------------------------------------------- -// 30.10.8.4.8, compare +// [fs.path.compare] compare GHC_INLINE int path::compare(const path& p) const noexcept { #ifdef LWG_2936_BEHAVIOUR @@ -2877,7 +3053,7 @@ GHC_INLINE int path::compare(const value_type* s) const } //----------------------------------------------------------------------------- -// 30.10.8.4.9, decomposition +// [fs.path.decompose] decomposition #ifdef GHC_OS_WINDOWS GHC_INLINE void path::handle_prefixes() { @@ -2999,7 +3175,8 @@ GHC_INLINE bool has_executable_extension(const path& p) return false; } 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; } } @@ -3009,7 +3186,7 @@ GHC_INLINE bool has_executable_extension(const path& p) #endif //----------------------------------------------------------------------------- -// 30.10.8.4.10, query +// [fs.path.query] query GHC_INLINE bool path::empty() const noexcept { return _path.empty(); @@ -3072,7 +3249,7 @@ GHC_INLINE bool path::is_relative() const } //----------------------------------------------------------------------------- -// 30.10.8.4.11, generation +// [fs.path.gen] generation GHC_INLINE path path::lexically_normal() const { path dest; @@ -3148,7 +3325,7 @@ GHC_INLINE path path::lexically_proximate(const path& base) const } //----------------------------------------------------------------------------- -// 30.10.8.5, iterators +// [fs.path.itr] iterators GHC_INLINE path::iterator::iterator() {} GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos) @@ -3158,7 +3335,7 @@ GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const , _root(p.has_root_directory() ? _first + static_cast(p._prefixLength + p.root_name_length()) : _last) , _iter(pos) { - if(pos != _last) { + if (pos != _last) { updateCurrent(); } } @@ -3238,10 +3415,10 @@ GHC_INLINE void path::iterator::updateCurrent() GHC_INLINE path::iterator& path::iterator::operator++() { _iter = increment(_iter); - while (_iter != _last && // we didn't reach the end - _iter != _root && // this is not a root position + while (_iter != _last && // we didn't reach the end + _iter != _root && // this is not a root position *_iter == preferred_separator && // we are on a separator - (_iter + 1) != _last // the slash is not the last char + (_iter + 1) != _last // the slash is not the last char ) { ++_iter; } @@ -3301,7 +3478,7 @@ GHC_INLINE path::iterator path::end() const } //----------------------------------------------------------------------------- -// 30.10.8.6, path non-member functions +// [fs.path.nonmember] path non-member functions GHC_INLINE void swap(path& lhs, path& rhs) noexcept { swap(lhs._path, rhs._path); @@ -3359,7 +3536,7 @@ GHC_INLINE path operator/(const path& lhs, const path& rhs) #endif // GHC_EXPAND_IMPL //----------------------------------------------------------------------------- -// 30.10.8.6.1 path inserter and extractor +// [fs.path.io] path inserter and extractor template inline std::basic_ostream& operator<<(std::basic_ostream& os, const path& p) { @@ -3416,7 +3593,7 @@ inline std::basic_istream& operator>>(std::basic_istream 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(); - std::shared_ptr 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 ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); #else @@ -4187,9 +4365,9 @@ GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcep ec.clear(); #ifdef GHC_OS_WINDOWS uintmax_t result = static_cast(-1); - std::shared_ptr 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; - if (file.get() == INVALID_HANDLE_VALUE) { + if (!file) { ec = detail::make_system_error(); } else { @@ -4418,7 +4596,7 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err ec.clear(); auto d = new_time.time_since_epoch(); #ifdef GHC_OS_WINDOWS - std::shared_ptr 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; auto tt = std::chrono::duration_cast(d).count() * 10 + 116444736000000000; ft.dwLowDateTime = static_cast(tt); @@ -4466,7 +4644,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 (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { #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 ec = detail::make_system_error(); } @@ -4629,6 +4807,13 @@ GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept } ec = detail::make_system_error(error); } + else if (attr & FILE_ATTRIBUTE_READONLY) { + auto new_attr = attr & ~static_cast(FILE_ATTRIBUTE_READONLY); + if (!SetFileAttributesW(cstr, new_attr)) { + auto error = ::GetLastError(); + ec = detail::make_system_error(error); + } + } if (!ec) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { if (!RemoveDirectoryW(cstr)) { @@ -4674,7 +4859,7 @@ GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept return static_cast(-1); } std::error_code tec; - auto fs = status(p, tec); + auto fs = symlink_status(p, tec); if (exists(fs) && is_directory(fs)) { for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) { if (ec && !detail::is_not_found_error(ec)) { @@ -4765,8 +4950,8 @@ GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) #endif return; } - std::shared_ptr 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(); } else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { @@ -4809,7 +4994,7 @@ GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept ec = detail::make_system_error(); return {static_cast(-1), static_cast(-1), static_cast(-1)}; } - return {static_cast(sfs.f_blocks * sfs.f_frsize), static_cast(sfs.f_bfree * sfs.f_frsize), static_cast(sfs.f_bavail * sfs.f_frsize)}; + return {static_cast(sfs.f_blocks) * static_cast(sfs.f_frsize), static_cast(sfs.f_bfree) * static_cast(sfs.f_frsize), static_cast(sfs.f_bavail) * static_cast(sfs.f_frsize)}; #endif } @@ -4940,8 +5125,8 @@ GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept } //----------------------------------------------------------------------------- -// 30.10.11 class file_status -// 30.10.11.1 constructors and destructor +// [fs.class.file_status] class file_status +// [fs.file_status.cons] constructors and destructor GHC_INLINE file_status::file_status() noexcept : file_status(file_type::none) { @@ -4982,7 +5167,7 @@ GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept return *this; } -// 30.10.11.3 modifiers +// [fs.file_status.mods] modifiers GHC_INLINE void file_status::type(file_type ft) noexcept { _type = ft; @@ -4993,7 +5178,7 @@ GHC_INLINE void file_status::permissions(perms prms) noexcept _perms = prms; } -// 30.10.11.2 observers +// [fs.file_status.obs] observers GHC_INLINE file_type file_status::type() const noexcept { return _type; @@ -5005,8 +5190,8 @@ GHC_INLINE perms file_status::permissions() const noexcept } //----------------------------------------------------------------------------- -// 30.10.12 class directory_entry -// 30.10.12.1 constructors and destructor +// [fs.class.directory_entry] class directory_entry +// [fs.dir.entry.cons] constructors and destructor // directory_entry::directory_entry() noexcept = default; // directory_entry::directory_entry(const directory_entry&) = default; // directory_entry::directory_entry(directory_entry&&) noexcept = default; @@ -5040,7 +5225,7 @@ GHC_INLINE directory_entry::~directory_entry() {} // directory_entry& directory_entry::operator=(const directory_entry&) = default; // directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default; -// 30.10.12.2 directory_entry modifiers +// [fs.dir.entry.mods] directory_entry modifiers #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void directory_entry::assign(const filesystem::path& p) { @@ -5089,7 +5274,7 @@ GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept #endif } -// 30.10.12.3 directory_entry observers +// [fs.dir.entry.obs] directory_entry observers GHC_INLINE const filesystem::path& directory_entry::path() const noexcept { return _path; @@ -5109,7 +5294,7 @@ GHC_INLINE file_type directory_entry::status_file_type() const GHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept { - if(_status.type() != file_type::none) { + if (_status.type() != file_type::none) { ec.clear(); return _status.type(); } @@ -5223,7 +5408,7 @@ GHC_INLINE bool directory_entry::is_symlink() const GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept { - if(_symlink_status.type() != file_type::none) { + if (_symlink_status.type() != file_type::none) { ec.clear(); return _symlink_status.type() == file_type::symlink; } @@ -5369,7 +5554,7 @@ GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const no } //----------------------------------------------------------------------------- -// 30.10.13 class directory_iterator +// [fs.class.directory_iterator] class directory_iterator #ifdef GHC_OS_WINDOWS class directory_iterator::impl @@ -5534,20 +5719,13 @@ public: } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); } } + void copyToDirEntry() { _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; - 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; } else { @@ -5567,7 +5745,7 @@ public: }; #endif -// 30.10.13.1 member functions +// [fs.dir.itr.members] member functions GHC_INLINE directory_iterator::directory_iterator() noexcept : _impl(new impl(path(), directory_options::none)) { @@ -5670,7 +5848,7 @@ GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) co return _impl->_dir_entry._path != rhs._impl->_dir_entry._path; } -// 30.10.13.2 directory_iterator non-member functions +// [fs.dir.itr.nonmembers] directory_iterator non-member functions GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept { @@ -5683,7 +5861,7 @@ GHC_INLINE directory_iterator end(const directory_iterator&) noexcept } //----------------------------------------------------------------------------- -// 30.10.14 class recursive_directory_iterator +// [fs.class.rec.dir.itr] class recursive_directory_iterator GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) @@ -5729,7 +5907,7 @@ GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_ GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {} -// 30.10.14.1 observers +// [fs.rec.dir.itr.members] observers GHC_INLINE directory_options recursive_directory_iterator::options() const { return _impl->_options; @@ -5755,7 +5933,7 @@ GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() con return &(*(_impl->_dir_iter_stack.top())); } -// 30.10.14.1 modifiers recursive_directory_iterator& +// [fs.rec.dir.itr.members] modifiers recursive_directory_iterator& GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs) { _impl = rhs._impl; @@ -5782,9 +5960,12 @@ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator+ GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept { - bool isDir = (*this)->is_directory(ec); - bool isSymLink = !ec && (*this)->is_symlink(ec); - if(!ec) { + bool isSymLink = (*this)->is_symlink(ec); + bool isDir = !ec && (*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)) { _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec)); } @@ -5834,7 +6015,7 @@ GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() _impl->_recursion_pending = false; } -// other members as required by 27.2.3, input iterators +// other members as required by [input.iterators] GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const { return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top(); @@ -5845,7 +6026,7 @@ GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directo return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top(); } -// 30.10.14.2 directory_iterator non-member functions +// [fs.rec.dir.itr.nonmembers] directory_iterator non-member functions GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept { return iter; diff --git a/src/ghc/fs_std.hpp b/src/ghc/fs_std.hpp index 0d9d3cc1..c9492fdc 100644 --- a/src/ghc/fs_std.hpp +++ b/src/ghc/fs_std.hpp @@ -30,6 +30,10 @@ // namespace fs. //--------------------------------------------------------------------------------------- #ifndef GHC_FILESYSTEM_STD_H +#define GHC_FILESYSTEM_STD_H +#if defined(__APPLE__) +#include +#endif #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 diff --git a/src/ghc/fs_std_fwd.hpp b/src/ghc/fs_std_fwd.hpp index 148751ed..163c956a 100644 --- a/src/ghc/fs_std_fwd.hpp +++ b/src/ghc/fs_std_fwd.hpp @@ -33,6 +33,9 @@ //--------------------------------------------------------------------------------------- #ifndef GHC_FILESYSTEM_STD_FWD_H #define GHC_FILESYSTEM_STD_FWD_H +#if defined(__APPLE__) +#include +#endif #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 diff --git a/src/ghc/fs_std_impl.hpp b/src/ghc/fs_std_impl.hpp index 455438d1..7042edca 100644 --- a/src/ghc/fs_std_impl.hpp +++ b/src/ghc/fs_std_impl.hpp @@ -31,6 +31,9 @@ // The cpp has to include this before including fs_std_fwd.hpp directly or via a different // header to work. //--------------------------------------------------------------------------------------- +#if defined(__APPLE__) +#include +#endif #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