From 09b4200ed5bb66b58f4c77f439336398253f57ea Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Mon, 24 May 2021 12:01:38 +0200 Subject: Fixed endless loop issue following recursive symlink - Also updated GHC's filesystem.hpp to version v1.5.6 --- filesystem/filesystem.hpp | 324 ++++++++++++++++++++++++++++------------------ src/doxygen.cpp | 20 ++- 2 files changed, 214 insertions(+), 130 deletions(-) diff --git a/filesystem/filesystem.hpp b/filesystem/filesystem.hpp index e4e0e27..6cbc892 100644 --- a/filesystem/filesystem.hpp +++ b/filesystem/filesystem.hpp @@ -74,6 +74,9 @@ #elif defined(__EMSCRIPTEN__) #define GHC_OS_WEB #include +#elif defined(__QNX__) +#define GHC_OS_QNX +#define GHC_NO_DIRENT_D_TYPE #else #error "Operating system currently not supported!" #endif @@ -240,6 +243,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) @@ -295,7 +301,7 @@ //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) -#define GHC_FILESYSTEM_VERSION 10504L +#define GHC_FILESYSTEM_VERSION 10506L #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #define GHC_WITH_EXCEPTIONS @@ -351,7 +357,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 +378,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 +414,24 @@ public: template using path_type = typename std::enable_if::value, path>::type; template +#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, - path>::type; + 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 +448,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 +460,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 +469,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 +486,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 +494,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 +510,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 +523,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 +531,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 +541,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 +554,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; @@ -594,7 +612,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 +626,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 +644,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 +701,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 +716,7 @@ enum class file_type { unknown, }; +// [fs.enum.perms] enum class perms : uint16_t { none = 0, @@ -724,6 +744,7 @@ enum class perms : uint16_t { unknown = 0xffff }; +// [fs.enum.perm.opts] enum class perm_options : uint16_t { replace = 3, add = 1, @@ -731,6 +752,7 @@ enum class perm_options : uint16_t { nofollow = 4, }; +// [fs.enum.copy.opts] enum class copy_options : uint16_t { none = 0, @@ -750,17 +772,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,10 +792,10 @@ 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(); } @@ -783,11 +806,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 +824,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 +834,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 +899,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 +924,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 +944,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 +962,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 +976,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 +988,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 +996,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 +1010,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 +1037,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); @@ -1980,56 +2003,70 @@ 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 +typedef struct _REPARSE_DATA_BUFFER +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union + 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 { - 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; + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + } DUMMYUNIONNAME; +} REPARSE_DATA_BUFFER; #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) #endif #endif +GHC_INLINE std::shared_ptr getReparseData(const path& p, std::error_code& ec) +{ 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) { 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); 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 +2084,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 +2141,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 +2218,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 +2255,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 +2356,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 +2411,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 +2484,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 +2565,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 +2647,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 +2697,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 +2780,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 +2860,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 +2934,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() { @@ -3009,7 +3066,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 +3129,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 +3205,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) @@ -3301,7 +3358,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 +3416,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 +3473,7 @@ inline std::basic_istream& operator>>(std::basic_istream(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)) { @@ -4940,8 +5004,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 +5046,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 +5057,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 +5069,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 +5104,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 +5153,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; @@ -5369,7 +5433,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,8 +5598,13 @@ public: } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); } } + 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); switch(_entry->d_type) { case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break; @@ -5545,6 +5614,7 @@ public: 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) { @@ -5554,6 +5624,7 @@ public: _dir_entry._status.type(file_type::none); _dir_entry._status.permissions(perms::unknown); } +#endif _dir_entry._file_size = static_cast(-1); _dir_entry._hard_link_count = static_cast(-1); _dir_entry._last_write_time = 0; @@ -5567,7 +5638,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 +5741,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 +5754,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 +5800,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 +5826,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,8 +5853,11 @@ 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); + 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 +5908,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 +5919,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/doxygen.cpp b/src/doxygen.cpp index 9e2f737..5f8adc2 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -9848,7 +9848,6 @@ static std::string resolveSymlink(const std::string &path) return Dir::cleanDirPath(result.str()); } -static std::mutex g_pathsVisitedMutex; static StringUnorderedSet g_pathsVisited(1009); //---------------------------------------------------------------------------- @@ -9875,15 +9874,24 @@ static void readDir(FileInfo *fi, { paths->insert(dirName); } + //printf("%s isSymLink()=%d\n",qPrint(dirName),fi->isSymLink()); if (fi->isSymLink()) { dirName = resolveSymlink(dirName); - if (dirName.empty()) return; // recursive symlink + if (dirName.empty()) + { + //printf("RECURSIVE SYMLINK: %s\n",qPrint(dirName)); + return; // recursive symlink + } + } - std::lock_guard lock(g_pathsVisitedMutex); - if (g_pathsVisited.find(dirName)!=g_pathsVisited.end()) return; // already visited path - g_pathsVisited.insert(dirName); + if (g_pathsVisited.find(dirName)!=g_pathsVisited.end()) + { + //printf("PATH ALREADY VISITED: %s\n",qPrint(dirName)); + return; // already visited path } + g_pathsVisited.insert(dirName); + Dir dir(dirName); msg("Searching for files in directory %s\n", qPrint(fi->absFilePath())); //printf("killSet=%p count=%d\n",killSet,killSet ? (int)killSet->count() : -1); @@ -9967,6 +9975,8 @@ void readFileOrDirectory(const QCString &s, // strip trailing slashes if (s.isEmpty()) return; + g_pathsVisited.clear(); + FileInfo fi(s.str()); //printf("readFileOrDirectory(%s)\n",s); { -- cgit v0.12