mirror of
https://github.com/boostorg/filesystem.git
synced 2026-01-19 04:12:09 +00:00
Use GetFileAttributesW in symlink_status if CreateFileW fails.
For some system files and folders like "System Volume Information" CreateFileW fails with ERROR_ACCESS_DENIED while GetFileAttributesW succeeds. GetFileAttributesW doesn't allow to discover whether the file is a symlink or some other kind of a reparse point, so this fallback will only work for files that are not reparse points, symlinks or not. For reparse points continue to report error. Closes https://github.com/boostorg/filesystem/issues/234.
This commit is contained in:
@@ -39,6 +39,11 @@
|
||||
</td>
|
||||
</table>
|
||||
|
||||
<h2>1.80.0</h2>
|
||||
<ul>
|
||||
<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>
|
||||
</ul>
|
||||
|
||||
<h2>1.79.0</h2>
|
||||
<ul>
|
||||
<li><b>v3:</b> <code>path::replace_extension</code> now works in terms of <b>v3</b> definition of <code>path::extension</code> rather than <b>v4</b>.</li>
|
||||
|
||||
@@ -1284,9 +1284,8 @@ inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t*
|
||||
return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p));
|
||||
}
|
||||
|
||||
inline fs::file_status process_status_failure(path const& p, error_code* ec)
|
||||
inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec)
|
||||
{
|
||||
DWORD errval = ::GetLastError();
|
||||
if (ec) // always report errval, even though some
|
||||
ec->assign(errval, system_category()); // errval values are not status_errors
|
||||
|
||||
@@ -1305,6 +1304,11 @@ inline fs::file_status process_status_failure(path const& p, error_code* ec)
|
||||
return fs::file_status(fs::status_error);
|
||||
}
|
||||
|
||||
inline fs::file_status process_status_failure(path const& p, error_code* ec)
|
||||
{
|
||||
return process_status_failure(::GetLastError(), p, ec);
|
||||
}
|
||||
|
||||
//! remove() implementation for Windows XP and older
|
||||
bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec)
|
||||
{
|
||||
@@ -3855,13 +3859,30 @@ file_status symlink_status(path const& p, error_code* ec)
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT));
|
||||
|
||||
DWORD attrs;
|
||||
if (h.handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return_status_failure:
|
||||
return process_status_failure(p, ec);
|
||||
// For some system files and folders like "System Volume Information" CreateFileW fails
|
||||
// with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that.
|
||||
// Though this will only help if the file is not a reparse point (symlink or not).
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
attrs = GetFileAttributesW(p.c_str());
|
||||
if (attrs != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u)
|
||||
return file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs));
|
||||
}
|
||||
else
|
||||
{
|
||||
err = GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
return process_status_failure(err, p, ec);
|
||||
}
|
||||
|
||||
DWORD attrs;
|
||||
fs::perms permissions;
|
||||
GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
|
||||
if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL))
|
||||
@@ -3869,7 +3890,7 @@ file_status symlink_status(path const& p, error_code* ec)
|
||||
file_attribute_tag_info info;
|
||||
BOOL res = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info));
|
||||
if (BOOST_UNLIKELY(!res))
|
||||
goto return_status_failure;
|
||||
return process_status_failure(p, ec);
|
||||
|
||||
attrs = info.FileAttributes;
|
||||
permissions = make_permissions(p, attrs);
|
||||
@@ -3882,7 +3903,7 @@ file_status symlink_status(path const& p, error_code* ec)
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
BOOL res = ::GetFileInformationByHandle(h.handle, &info);
|
||||
if (BOOST_UNLIKELY(!res))
|
||||
goto return_status_failure;
|
||||
return process_status_failure(p, ec);
|
||||
|
||||
attrs = info.dwFileAttributes;
|
||||
permissions = make_permissions(p, attrs);
|
||||
|
||||
@@ -1069,6 +1069,18 @@ void predicate_and_status_tests()
|
||||
BOOST_TEST(!fs::is_regular_file(stat));
|
||||
BOOST_TEST(!fs::is_other(stat));
|
||||
BOOST_TEST(!fs::is_symlink(stat));
|
||||
|
||||
#ifdef BOOST_WINDOWS_API
|
||||
stat = fs::status(L"\\System Volume Information");
|
||||
BOOST_TEST(fs::type_present(stat));
|
||||
BOOST_TEST(fs::permissions_present(stat));
|
||||
BOOST_TEST(fs::status_known(stat));
|
||||
BOOST_TEST(fs::exists(stat));
|
||||
BOOST_TEST(fs::is_directory(stat));
|
||||
BOOST_TEST(!fs::is_regular_file(stat));
|
||||
BOOST_TEST(!fs::is_other(stat));
|
||||
BOOST_TEST(!fs::is_symlink(stat));
|
||||
#endif // BOOST_WINDOWS_API
|
||||
}
|
||||
|
||||
// create_directory_tests ----------------------------------------------------------//
|
||||
|
||||
Reference in New Issue
Block a user