mirror of
https://github.com/boostorg/filesystem.git
synced 2025-05-12 13:41:47 +00:00
Merge pull request #102 from stima/develop
Correct handling status of reparse point
This commit is contained in:
commit
a916a41602
@ -1987,6 +1987,8 @@ file_status status(const path& p, error_code* ec)
|
||||
return process_status_failure(p, ec);
|
||||
}
|
||||
|
||||
if (ec != 0) ec->clear();
|
||||
|
||||
perms permissions = make_permissions(p, attr);
|
||||
|
||||
// reparse point handling;
|
||||
@ -1994,6 +1996,12 @@ file_status status(const path& p, error_code* ec)
|
||||
// handle to discover if the file exists
|
||||
if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||
{
|
||||
if (!is_reparse_point_a_symlink(p))
|
||||
{
|
||||
return file_status(reparse_file, permissions);
|
||||
}
|
||||
|
||||
// try to resolve symlink
|
||||
handle_wrapper h(
|
||||
create_file_handle(
|
||||
p.c_str(),
|
||||
@ -2003,16 +2011,22 @@ file_status status(const path& p, error_code* ec)
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
0)); // hTemplateFile
|
||||
|
||||
if (h.handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return process_status_failure(p, ec);
|
||||
}
|
||||
|
||||
if (!is_reparse_point_a_symlink(p))
|
||||
return file_status(reparse_file, permissions);
|
||||
// take attributes of target
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!::GetFileInformationByHandle(h.handle, &info))
|
||||
{
|
||||
return process_status_failure(p, ec);
|
||||
}
|
||||
|
||||
attr = info.dwFileAttributes;
|
||||
}
|
||||
|
||||
if (ec != 0) ec->clear();
|
||||
return (attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
? file_status(directory_file, permissions)
|
||||
: file_status(regular_file, permissions);
|
||||
|
@ -78,3 +78,4 @@ run quick.cpp ;
|
||||
run issues/70-71-copy.cpp ;
|
||||
|
||||
run issues/99_canonical_with_junction_point.cpp : : : <conditional>@check-mklink ;
|
||||
run issues/reparce_tag_file_placeholder.cpp : : : <conditional>@check-mklink ;
|
||||
|
142
test/issues/reparce_tag_file_placeholder.cpp
Normal file
142
test/issues/reparce_tag_file_placeholder.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
// Boost operations_test.cpp ---------------------------------------------------------//
|
||||
|
||||
// Copyright Roman Savchenko 2020
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// Library home page: http://www.boost.org/libs/filesystem
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
|
||||
# include <windows.h>
|
||||
# include <winnt.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma comment(lib, "Advapi32.lib")
|
||||
#endif
|
||||
|
||||
// Test correct boost::filesystem::status when reparse point ReparseTag set to IO_REPARSE_TAG_FILE_PLACEHOLDER
|
||||
// https://docs.microsoft.com/en-us/windows/compatibility/placeholder-files?redirectedfrom=MSDN
|
||||
|
||||
#if !defined(__MINGW32__) || defined(__MINGW64__)
|
||||
typedef struct _REPARSE_DATA_BUFFER {
|
||||
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 {
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
};
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
#endif
|
||||
|
||||
#ifndef IO_REPARSE_TAG_FILE_PLACEHOLDER
|
||||
# define IO_REPARSE_TAG_FILE_PLACEHOLDER (0x80000015L)
|
||||
#endif
|
||||
|
||||
#ifndef FSCTL_SET_REPARSE_POINT
|
||||
# define FSCTL_SET_REPARSE_POINT (0x000900a4)
|
||||
#endif
|
||||
|
||||
#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
|
||||
# define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
|
||||
#endif
|
||||
|
||||
bool obtain_restore_privilege()
|
||||
{
|
||||
HANDLE hToken;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
|
||||
{
|
||||
std::cout << "OpenProcessToken() failed with: " << GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
TOKEN_PRIVILEGES tp;
|
||||
if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid))
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
std::cout << "LookupPrivilegeValue() failed with: " << GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
tp.PrivilegeCount = 1;
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
std::cout << "AdjustTokenPrivileges() failed with: " << GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(hToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool create_io_reparse_file_placeholder(const wchar_t* name)
|
||||
{
|
||||
if (!obtain_restore_privilege())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE hHandle = CreateFileW(name, GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT, 0);
|
||||
|
||||
if (hHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::cout << "CreateFile() failed with: " << GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
PREPARSE_DATA_BUFFER pReparse = reinterpret_cast<PREPARSE_DATA_BUFFER>(GlobalAlloc(GPTR, MAXIMUM_REPARSE_DATA_BUFFER_SIZE));
|
||||
//note: IO_REPARSE_TAG_FILE_PLACEHOLDER - just to show that reparse point could be not only symlink or junction
|
||||
pReparse->ReparseTag = IO_REPARSE_TAG_FILE_PLACEHOLDER;
|
||||
|
||||
DWORD dwLen;
|
||||
bool ret = DeviceIoControl(hHandle, FSCTL_SET_REPARSE_POINT, pReparse,
|
||||
pReparse->ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE,
|
||||
NULL, 0, &dwLen, NULL) != 0;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
std::cout << "DeviceIoControl() failed with: " << GetLastError() << std::endl;
|
||||
}
|
||||
|
||||
CloseHandle(hHandle);
|
||||
GlobalFree(pReparse);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::filesystem::path rpt = boost::filesystem::temp_directory_path() / "reparse_point_test.txt";
|
||||
|
||||
BOOST_TEST(create_io_reparse_file_placeholder(rpt.native().c_str()));
|
||||
BOOST_TEST(boost::filesystem::status(rpt).type() == boost::filesystem::reparse_file);
|
||||
BOOST_TEST(boost::filesystem::remove(rpt));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user