Skip to content

Commit 15249ba

Browse files
committed
Added a workaround for (symlink_)status failing on Windows.
Apparently, GetFileInformationByHandleEx(FileAttributeTagInfo) fails with ERROR_INVALID_PARAMETER on FAT/exFAT filesystems, which used to be interpreted as "file not found" result in (symlink_)status(). The file is clearly present since it was successfully opened before, and the error is presumably because the filesystem does not support reparse points and cannot return a ReparseTag. Check that error code and also ERROR_NOT_SUPPORTED for good measure and fall back to the legacy code path that works for FAT/exFAT. Fixes boostorg#236.
1 parent 2896908 commit 15249ba

File tree

2 files changed

+39
-27
lines changed

2 files changed

+39
-27
lines changed

doc/release_history.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<h2>1.80.0</h2>
4343
<ul>
4444
<li>On Windows, added a fallback implementation for querying file attributes in case if the file cannot be opened with <code>ERROR_ACCESS_DENIED</code> error. This may allow <code>status</code> and <code>symlink_status</code> to succeed for system files and directories that are not reparse points or symlinks. (<a href="https://github.com/boostorg/filesystem/issues/234">#234</a>)</li>
45+
<li>On Windows, added a workaround for <code>status</code> and <code>symlink_status</code> reporting that files do not exist on FAT/exFAT filesystems. (<a href="https://github.com/boostorg/filesystem/issues/236">#236</a>)</li>
4546
</ul>
4647

4748
<h2>1.79.0</h2>

src/operations.cpp

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3865,54 +3865,65 @@ file_status symlink_status(path const& p, error_code* ec)
38653865
// For some system files and folders like "System Volume Information" CreateFileW fails
38663866
// with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that.
38673867
// Though this will only help if the file is not a reparse point (symlink or not).
3868-
DWORD err = GetLastError();
3868+
DWORD err = ::GetLastError();
38693869
if (err == ERROR_ACCESS_DENIED)
38703870
{
3871-
attrs = GetFileAttributesW(p.c_str());
3871+
attrs = ::GetFileAttributesW(p.c_str());
38723872
if (attrs != INVALID_FILE_ATTRIBUTES)
38733873
{
38743874
if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u)
3875-
return file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs));
3875+
goto done;
38763876
}
38773877
else
38783878
{
3879-
err = GetLastError();
3879+
err = ::GetLastError();
38803880
}
38813881
}
38823882

38833883
return process_status_failure(err, p, ec);
38843884
}
38853885

3886-
fs::perms permissions;
3887-
GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
3888-
if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL))
38893886
{
3890-
file_attribute_tag_info info;
3891-
BOOL res = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info));
3892-
if (BOOST_UNLIKELY(!res))
3893-
return process_status_failure(p, ec);
3887+
GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
3888+
if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL))
3889+
{
3890+
file_attribute_tag_info info;
3891+
BOOL res = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info));
3892+
if (BOOST_UNLIKELY(!res))
3893+
{
3894+
// On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER.
3895+
// Presumably, this is because these filesystems don't support reparse points, so ReparseTag
3896+
// cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy
3897+
// code path in this case.
3898+
DWORD err = ::GetLastError();
3899+
if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED)
3900+
goto use_get_file_information_by_handle;
3901+
3902+
return process_status_failure(err, p, ec);
3903+
}
38943904

3895-
attrs = info.FileAttributes;
3896-
permissions = make_permissions(p, attrs);
3905+
attrs = info.FileAttributes;
38973906

3898-
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3899-
return is_reparse_point_tag_a_symlink(info.ReparseTag) ? fs::file_status(fs::symlink_file, permissions) : fs::file_status(fs::reparse_file, permissions);
3900-
}
3901-
else
3902-
{
3903-
BY_HANDLE_FILE_INFORMATION info;
3904-
BOOL res = ::GetFileInformationByHandle(h.handle, &info);
3905-
if (BOOST_UNLIKELY(!res))
3906-
return process_status_failure(p, ec);
3907+
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3908+
return fs::file_status(is_reparse_point_tag_a_symlink(info.ReparseTag) ? fs::symlink_file : fs::reparse_file, make_permissions(p, attrs));
3909+
}
3910+
else
3911+
{
3912+
use_get_file_information_by_handle:
3913+
BY_HANDLE_FILE_INFORMATION info;
3914+
BOOL res = ::GetFileInformationByHandle(h.handle, &info);
3915+
if (BOOST_UNLIKELY(!res))
3916+
return process_status_failure(p, ec);
39073917

3908-
attrs = info.dwFileAttributes;
3909-
permissions = make_permissions(p, attrs);
3918+
attrs = info.dwFileAttributes;
39103919

3911-
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3912-
return is_reparse_point_a_symlink_ioctl(h.handle) ? fs::file_status(fs::symlink_file, permissions) : fs::file_status(fs::reparse_file, permissions);
3920+
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3921+
return fs::file_status(is_reparse_point_a_symlink_ioctl(h.handle) ? fs::symlink_file : fs::reparse_file, make_permissions(p, attrs));
3922+
}
39133923
}
39143924

3915-
return (attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::file_status(fs::directory_file, permissions) : fs::file_status(fs::regular_file, permissions);
3925+
done:
3926+
return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs));
39163927

39173928
#endif // defined(BOOST_POSIX_API)
39183929
}

0 commit comments

Comments
 (0)