Skip to content

Commit 97722a3

Browse files
committed
Reimplemented status() and symlink_status() in terms of handles on Windows.
Using handles allows to reduce the number of system calls and avoids requesting reparse point info, if the file is one. This should improve performance.
1 parent f793005 commit 97722a3

File tree

1 file changed

+68
-30
lines changed

1 file changed

+68
-30
lines changed

src/operations.cpp

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3521,25 +3521,13 @@ file_status status(path const& p, error_code* ec)
35213521

35223522
#else // defined(BOOST_POSIX_API)
35233523

3524-
DWORD attrs = ::GetFileAttributesW(p.c_str());
3525-
if (attrs == INVALID_FILE_ATTRIBUTES)
3524+
// We should first test if the file is a symlink or a reparse point. Resolving some reparse
3525+
// points by opening the file may fail, and status() should return file_status(reparse_file) in this case.
3526+
// Which is what symlink_status() returns.
3527+
fs::file_status st(detail::symlink_status(p, ec));
3528+
if (st.type() == symlink_file)
35263529
{
3527-
return process_status_failure(p, ec);
3528-
}
3529-
3530-
perms permissions = make_permissions(p, attrs);
3531-
3532-
// reparse point handling;
3533-
// since GetFileAttributesW does not resolve symlinks, try to open a file
3534-
// handle to discover if the file exists
3535-
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3536-
{
3537-
if (!is_reparse_point_a_symlink(p))
3538-
{
3539-
return file_status(reparse_file, permissions);
3540-
}
3541-
3542-
// try to resolve symlink
3530+
// Resolve the symlink
35433531
handle_wrapper h(
35443532
create_file_handle(
35453533
p.c_str(),
@@ -3551,20 +3539,36 @@ file_status status(path const& p, error_code* ec)
35513539

35523540
if (h.handle == INVALID_HANDLE_VALUE)
35533541
{
3542+
return_status_failure:
35543543
return process_status_failure(p, ec);
35553544
}
35563545

3557-
// take attributes of target
3558-
BY_HANDLE_FILE_INFORMATION info;
3559-
if (!::GetFileInformationByHandle(h.handle, &info))
3546+
DWORD attrs;
3547+
GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
3548+
if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL))
35603549
{
3561-
return process_status_failure(p, ec);
3550+
file_attribute_tag_info info;
3551+
BOOL res = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info));
3552+
if (BOOST_UNLIKELY(!res))
3553+
goto return_status_failure;
3554+
3555+
attrs = info.FileAttributes;
35623556
}
3557+
else
3558+
{
3559+
BY_HANDLE_FILE_INFORMATION info;
3560+
BOOL res = ::GetFileInformationByHandle(h.handle, &info);
3561+
if (BOOST_UNLIKELY(!res))
3562+
goto return_status_failure;
35633563

3564-
attrs = info.dwFileAttributes;
3564+
attrs = info.dwFileAttributes;
3565+
}
3566+
3567+
st.permissions(make_permissions(p, attrs));
3568+
st.type((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file);
35653569
}
35663570

3567-
return (attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_status(directory_file, permissions) : file_status(regular_file, permissions);
3571+
return st;
35683572

35693573
#endif // defined(BOOST_POSIX_API)
35703574
}
@@ -3627,18 +3631,52 @@ file_status symlink_status(path const& p, error_code* ec)
36273631

36283632
#else // defined(BOOST_POSIX_API)
36293633

3630-
DWORD attrs = ::GetFileAttributesW(p.c_str());
3631-
if (attrs == INVALID_FILE_ATTRIBUTES)
3634+
handle_wrapper h(
3635+
create_file_handle(
3636+
p.c_str(),
3637+
0u, // dwDesiredAccess; attributes only
3638+
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
3639+
NULL, // lpSecurityAttributes
3640+
OPEN_EXISTING,
3641+
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT));
3642+
3643+
if (h.handle == INVALID_HANDLE_VALUE)
36323644
{
3645+
return_status_failure:
36333646
return process_status_failure(p, ec);
36343647
}
36353648

3636-
perms permissions = make_permissions(p, attrs);
3649+
DWORD attrs;
3650+
fs::perms permissions;
3651+
GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
3652+
if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL))
3653+
{
3654+
file_attribute_tag_info info;
3655+
BOOL res = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info));
3656+
if (BOOST_UNLIKELY(!res))
3657+
goto return_status_failure;
3658+
3659+
attrs = info.FileAttributes;
3660+
permissions = make_permissions(p, attrs);
36373661

3638-
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3639-
return is_reparse_point_a_symlink(p) ? file_status(symlink_file, permissions) : file_status(reparse_file, permissions);
3662+
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3663+
return is_reparse_point_tag_a_symlink(info.ReparseTag) ? fs::file_status(fs::symlink_file, permissions) : fs::file_status(fs::reparse_file, permissions);
3664+
}
3665+
else
3666+
{
3667+
BY_HANDLE_FILE_INFORMATION info;
3668+
BOOL res = ::GetFileInformationByHandle(h.handle, &info);
3669+
if (BOOST_UNLIKELY(!res))
3670+
goto return_status_failure;
3671+
3672+
attrs = info.dwFileAttributes;
3673+
permissions = make_permissions(p, attrs);
3674+
3675+
if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
3676+
return is_reparse_point_a_symlink_ioctl(h.handle) ? fs::file_status(fs::symlink_file, permissions) : fs::file_status(fs::reparse_file, permissions);
3677+
}
36403678

3641-
return (attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_status(directory_file, permissions) : file_status(regular_file, permissions);
3679+
return (attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::file_status(fs::directory_file, permissions) : fs::file_status(fs::regular_file, permissions);
36423680

36433681
#endif // defined(BOOST_POSIX_API)
36443682
}

0 commit comments

Comments
 (0)