Merge branch 'feature-124-mapped-volumes-wrongly-handled-as-symlinks'

This commit is contained in:
Steffen Schümann 2021-05-23 16:06:13 +02:00
commit 70cf2f03ba

View File

@ -2000,56 +2000,70 @@ GHC_INLINE file_status file_status_from_st_mode(T mode)
#endif #endif
} }
GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec)
{
#ifdef GHC_OS_WINDOWS #ifdef GHC_OS_WINDOWS
#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
typedef struct _REPARSE_DATA_BUFFER typedef struct _REPARSE_DATA_BUFFER
{
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union
{ {
ULONG ReparseTag; struct
USHORT ReparseDataLength;
USHORT Reserved;
union
{ {
struct USHORT SubstituteNameOffset;
{ USHORT SubstituteNameLength;
USHORT SubstituteNameOffset; USHORT PrintNameOffset;
USHORT SubstituteNameLength; USHORT PrintNameLength;
USHORT PrintNameOffset; ULONG Flags;
USHORT PrintNameLength; WCHAR PathBuffer[1];
ULONG Flags; } SymbolicLinkReparseBuffer;
WCHAR PathBuffer[1]; struct
} SymbolicLinkReparseBuffer; {
struct USHORT SubstituteNameOffset;
{ USHORT SubstituteNameLength;
USHORT SubstituteNameOffset; USHORT PrintNameOffset;
USHORT SubstituteNameLength; USHORT PrintNameLength;
USHORT PrintNameOffset; WCHAR PathBuffer[1];
USHORT PrintNameLength; } MountPointReparseBuffer;
WCHAR PathBuffer[1]; struct
} MountPointReparseBuffer; {
struct UCHAR DataBuffer[1];
{ } GenericReparseBuffer;
UCHAR DataBuffer[1]; } DUMMYUNIONNAME;
} GenericReparseBuffer; } REPARSE_DATA_BUFFER;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER;
#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024)
#endif #endif
#endif #endif
GHC_INLINE std::shared_ptr<REPARSE_DATA_BUFFER> getReparseData(const path& p, std::error_code& ec)
{
std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);
if (file.get() == INVALID_HANDLE_VALUE) { if (file.get() == INVALID_HANDLE_VALUE) {
ec = detail::make_system_error(); ec = detail::make_system_error();
return path(); return nullptr;
} }
std::shared_ptr<REPARSE_DATA_BUFFER> reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free); std::shared_ptr<REPARSE_DATA_BUFFER> reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free);
ULONG bufferUsed; ULONG bufferUsed;
path result;
if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) {
if (IsReparseTagMicrosoft(reparseData->ReparseTag)) { return reparseData;
}
else {
ec = detail::make_system_error();
}
return nullptr;
}
#endif
GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec)
{
#ifdef GHC_OS_WINDOWS
path result;
auto reparseData = detail::getReparseData(p, ec);
if (!ec) {
if (reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag)) {
switch (reparseData->ReparseTag) { switch (reparseData->ReparseTag) {
case IO_REPARSE_TAG_SYMLINK: { case IO_REPARSE_TAG_SYMLINK: {
auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR)); auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR));
@ -2067,16 +2081,14 @@ GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec)
break; break;
} }
case IO_REPARSE_TAG_MOUNT_POINT: case IO_REPARSE_TAG_MOUNT_POINT:
result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); result = detail::getFullPathName(GHC_NATIVEWP(p), ec);
//result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
break; break;
default: default:
break; break;
} }
} }
} }
else {
ec = detail::make_system_error();
}
return result; return result;
#else #else
size_t bufferSize = 256; size_t bufferSize = 256;
@ -2126,13 +2138,35 @@ GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_H
} }
template <typename INFO> template <typename INFO>
GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr) GHC_INLINE DWORD reparse_tag_from_INFO(const INFO*)
{
return 0;
}
template <>
GHC_INLINE DWORD reparse_tag_from_INFO(const WIN32_FIND_DATAW* info)
{
return info->dwReserved0;
}
template <typename INFO>
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)
{ {
file_type ft = file_type::unknown; file_type ft = file_type::unknown;
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { if (sizeof(INFO) == sizeof(WIN32_FIND_DATAW)) {
ft = file_type::symlink; if (detail::reparse_tag_from_INFO(info) == IO_REPARSE_TAG_SYMLINK) {
ft = file_type::symlink;
}
} }
else { else {
if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
auto reparseData = detail::getReparseData(p, ec);
if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
ft = file_type::symlink;
}
}
}
if (ft == file_type::unknown) {
if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
ft = file_type::directory; ft = file_type::directory;
} }
@ -2181,9 +2215,6 @@ GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uin
if (nhl) { if (nhl) {
*nhl = 0; *nhl = 0;
} }
if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
fs.type(file_type::symlink);
}
} }
if (detail::is_not_found_error(ec)) { if (detail::is_not_found_error(ec)) {
return file_status(file_type::not_found); return file_status(file_type::not_found);
@ -2221,15 +2252,18 @@ GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
path target = resolveSymlink(p, ec); auto reparseData = detail::getReparseData(p, ec);
file_status result; if (!ec && reparseData && IsReparseTagMicrosoft(reparseData->ReparseTag) && reparseData->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
if (!ec && !target.empty()) { path target = resolveSymlink(p, ec);
if (sls) { file_status result;
*sls = status_from_INFO(p, &attr, ec); if (!ec && !target.empty()) {
if (sls) {
*sls = status_from_INFO(p, &attr, ec);
}
return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1);
} }
return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); return file_status(file_type::unknown);
} }
return file_status(file_type::unknown);
} }
if (ec) { if (ec) {
if (detail::is_not_found_error(ec)) { if (detail::is_not_found_error(ec)) {