Skip to content

Commit 655b0b3

Browse files
authored
Merge pull request #162 from Qrox/patch-1
Fix directory iterator treating all files subsequent to a symlink as symlink on Windows
2 parents 3e5b930 + f0caeb7 commit 655b0b3

File tree

1 file changed

+24
-22
lines changed

1 file changed

+24
-22
lines changed

include/ghc/filesystem.hpp

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2260,41 +2260,43 @@ GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_H
22602260
}
22612261

22622262
template <typename INFO>
2263-
GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*)
2263+
GHC_INLINE bool is_symlink_from_INFO(const path &p, const INFO* info, std::error_code& ec)
22642264
{
2265-
return 0;
2265+
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
2266+
auto reparseData = detail::getReparseData(p, ec);
2267+
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
2268+
return true;
2269+
}
2270+
}
2271+
return false;
22662272
}
22672273

22682274
template <>
2269-
GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info)
2275+
GHC_INLINE bool is_symlink_from_INFO(const path &, const WIN32_FIND_DATAW* info, std::error_code&)
22702276
{
2271-
return info->dwReserved0;
2277+
// dwReserved0 is undefined unless dwFileAttributes includes the
2278+
// FILE_ATTRIBUTE_REPARSE_POINT attribute according to microsoft
2279+
// documentation. In practice, dwReserved0 is not reset which
2280+
// causes it to report the incorrect symlink status.
2281+
// Note that microsoft documentation does not say whether there is
2282+
// a null value for dwReserved0, so we test for symlink directly
2283+
// instead of returning the tag which requires returning a null
2284+
// value for non-reparse-point files.
2285+
return (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && info->dwReserved0 == IO_REPARSE_TAG_SYMLINK;
22722286
}
22732287

22742288
template <typename INFO>
22752289
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)
22762290
{
22772291
file_type ft = file_type::unknown;
2278-
if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) {
2279-
if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) {
2280-
ft = file_type::symlink;
2281-
}
2292+
if (is_symlink_from_INFO(p, info, ec)) {
2293+
ft = file_type::symlink;
22822294
}
2283-
else {
2284-
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
2285-
auto reparseData = detail::getReparseData(p, ec);
2286-
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
2287-
ft = file_type::symlink;
2288-
}
2289-
}
2295+
else if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
2296+
ft = file_type::directory;
22902297
}
2291-
if (ft == file_type::unknown) {
2292-
if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
2293-
ft = file_type::directory;
2294-
}
2295-
else {
2296-
ft = file_type::regular;
2297-
}
2298+
else {
2299+
ft = file_type::regular;
22982300
}
22992301
perms prms = perms::owner_read | perms::group_read | perms::others_read;
23002302
if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {

0 commit comments

Comments
 (0)