mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
sys,dll: FspFileSystemResolveReparsePoints: use IO_REPARSE_TAG_SYMLINK instead of IO_REPARSE for symlink resolution
- FspFsvolCreateComplete STATUS_REPARSE handling changed to support device-relative symlink reparse points
This commit is contained in:
parent
46a29f663a
commit
5771eedc45
@ -1057,6 +1057,7 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent0,
|
PWSTR FileName, UINT32 ReparsePointIndex, BOOLEAN ResolveLastPathComponent0,
|
||||||
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
|
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer, PSIZE_T PSize)
|
||||||
{
|
{
|
||||||
|
PREPARSE_DATA_BUFFER OutputReparseData;
|
||||||
PWSTR TargetPath, RemainderPath, LastPathComponent, NewRemainderPath, ReparseTargetPath;
|
PWSTR TargetPath, RemainderPath, LastPathComponent, NewRemainderPath, ReparseTargetPath;
|
||||||
WCHAR RemainderChar;
|
WCHAR RemainderChar;
|
||||||
union
|
union
|
||||||
@ -1070,10 +1071,17 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
ULONG MaxTries = 32;
|
ULONG MaxTries = 32;
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
|
||||||
TargetPath = Buffer;
|
|
||||||
RemainderPathSize = (lstrlenW(FileName) + 1) * sizeof(WCHAR);
|
RemainderPathSize = (lstrlenW(FileName) + 1) * sizeof(WCHAR);
|
||||||
if (RemainderPathSize > *PSize)
|
if (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
|
||||||
|
RemainderPathSize > *PSize)
|
||||||
return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||||
|
|
||||||
|
OutputReparseData = Buffer;
|
||||||
|
memset(OutputReparseData, 0,
|
||||||
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer));
|
||||||
|
OutputReparseData->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||||
|
OutputReparseData->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
|
||||||
|
TargetPath = OutputReparseData->SymbolicLinkReparseBuffer.PathBuffer;
|
||||||
memcpy(TargetPath, FileName, RemainderPathSize);
|
memcpy(TargetPath, FileName, RemainderPathSize);
|
||||||
|
|
||||||
ResolveLastPathComponent = ResolveLastPathComponent0;
|
ResolveLastPathComponent = ResolveLastPathComponent0;
|
||||||
@ -1089,7 +1097,7 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (L'\0' == *RemainderPath)
|
if (L'\0' == *RemainderPath)
|
||||||
{
|
{
|
||||||
if (!ResolveLastPathComponent)
|
if (!ResolveLastPathComponent)
|
||||||
goto exit;
|
goto symlink_exit;
|
||||||
ResolveLastPathComponent = FALSE;
|
ResolveLastPathComponent = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1164,44 +1172,57 @@ FSP_API NTSTATUS FspFileSystemResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
if (IO_REPARSE_TAG_SYMLINK != ReparseData->ReparseTag)
|
if (IO_REPARSE_TAG_SYMLINK != ReparseData->ReparseTag)
|
||||||
goto reparse_data_exit;
|
goto reparse_data_exit;
|
||||||
|
|
||||||
|
if (0 == --MaxTries)
|
||||||
|
return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||||
|
|
||||||
ReparseTargetPath = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
ReparseTargetPath = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
||||||
ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
ReparseTargetPathLength = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||||
|
|
||||||
/* if an absolute (in the NT namespace) symlink return the full reparse point */
|
|
||||||
if (0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) &&
|
|
||||||
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
|
|
||||||
goto reparse_data_exit;
|
|
||||||
|
|
||||||
if (0 == --MaxTries)
|
|
||||||
return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
|
||||||
|
|
||||||
/* if device relative symlink replace whole path; else replace last path component */
|
/* if device relative symlink replace whole path; else replace last path component */
|
||||||
NewRemainderPath = ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0] ?
|
NewRemainderPath = ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0] ?
|
||||||
TargetPath : LastPathComponent;
|
TargetPath : LastPathComponent;
|
||||||
|
|
||||||
reparse:
|
reparse:
|
||||||
RemainderPathSize = (lstrlenW(RemainderPath) + 1) * sizeof(WCHAR);
|
RemainderPathSize = (lstrlenW(RemainderPath) + 1) * sizeof(WCHAR);
|
||||||
if (NewRemainderPath + (ReparseTargetPathLength + RemainderPathSize) / sizeof(WCHAR) >
|
if ((PUINT8)NewRemainderPath + ReparseTargetPathLength + RemainderPathSize >
|
||||||
TargetPath + *PSize / sizeof(WCHAR))
|
(PUINT8)Buffer + *PSize)
|
||||||
return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||||
|
|
||||||
/* move remainder path to its new position */
|
/* move remainder path to its new position */
|
||||||
memmove(NewRemainderPath + ReparseTargetPathLength / sizeof(WCHAR),
|
memmove((PUINT8)NewRemainderPath + ReparseTargetPathLength,
|
||||||
RemainderPath, RemainderPathSize);
|
RemainderPath, RemainderPathSize);
|
||||||
|
|
||||||
/* copy symlink target */
|
/* copy symlink target */
|
||||||
memcpy(NewRemainderPath, ReparseTargetPath, ReparseTargetPathLength);
|
memcpy(NewRemainderPath, ReparseTargetPath, ReparseTargetPathLength);
|
||||||
|
|
||||||
|
/* if an absolute (in the NT namespace) symlink exit now */
|
||||||
|
if (0 != ReparseTargetPath /* ensure we are not doing dot handling */ &&
|
||||||
|
0 == (ReparseData->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) &&
|
||||||
|
ReparseTargetPathLength >= sizeof(WCHAR) && L'\\' == ReparseTargetPath[0])
|
||||||
|
{
|
||||||
|
OutputReparseData->SymbolicLinkReparseBuffer.Flags = 0;
|
||||||
|
goto symlink_exit;
|
||||||
|
}
|
||||||
|
|
||||||
ResolveLastPathComponent = ResolveLastPathComponent0;
|
ResolveLastPathComponent = ResolveLastPathComponent0;
|
||||||
RemainderPath = NewRemainderPath;
|
RemainderPath = NewRemainderPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
symlink_exit:
|
||||||
*PSize = (PUINT8)RemainderPath - (PUINT8)TargetPath;
|
OutputReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength =
|
||||||
|
OutputReparseData->SymbolicLinkReparseBuffer.PrintNameLength =
|
||||||
|
(USHORT)lstrlenW(OutputReparseData->SymbolicLinkReparseBuffer.PathBuffer) * sizeof(WCHAR);
|
||||||
|
OutputReparseData->ReparseDataLength =
|
||||||
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
|
||||||
|
FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer) +
|
||||||
|
OutputReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||||
|
|
||||||
|
*PSize = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer) +
|
||||||
|
OutputReparseData->ReparseDataLength;
|
||||||
|
|
||||||
PIoStatus->Status = STATUS_REPARSE;
|
PIoStatus->Status = STATUS_REPARSE;
|
||||||
PIoStatus->Information = 0/*IO_REPARSE*/;
|
PIoStatus->Information = ReparseData->ReparseTag;
|
||||||
return STATUS_REPARSE;
|
return STATUS_REPARSE;
|
||||||
|
|
||||||
reparse_data_exit:
|
reparse_data_exit:
|
||||||
|
@ -510,22 +510,24 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information)
|
IO_REPARSE_TAG_SYMLINK == Response->IoStatus.Information)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* IO_REPARSE means that the user-mode file system has returned a device-relative
|
* IO_REPARSE means that the user-mode file system has returned an absolute (in
|
||||||
* (absolute in the device namespace) path. Prefix it with our device name/prefix
|
* the device namespace) path. Send it as is to the IO Manager.
|
||||||
* and send it to the IO Manager.
|
|
||||||
*
|
*
|
||||||
* IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full
|
* IO_REPARSE_TAG_SYMLINK means that the user-mode file system has returned a full
|
||||||
* symbolic link reparse buffer with an absolute (in the NT namespace) path. Send
|
* symbolic link reparse buffer. If the symbolic link is absolute send it to the
|
||||||
* it as is to the IO Manager. The FSD cannot handle relative symbolic links, so
|
* IO Manager as is. If the symbolic link is device-relative (absolute in the
|
||||||
* it is the responsibility of the user-mode file system to resolve them.
|
* device namespace) prefix it with our volume name/prefix and then send it to the
|
||||||
|
* IO Manager.
|
||||||
|
*
|
||||||
|
* We do our own handling of IO_REPARSE_TAG_SYMLINK reparse points because
|
||||||
|
* experimentation with handling them directly to the IO Manager revealed problems
|
||||||
|
* with UNC paths (\??\UNC\{VolumePrefix}\{FilePath}).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (IO_REPARSE == Response->IoStatus.Information)
|
if (IO_REPARSE == Response->IoStatus.Information)
|
||||||
{
|
{
|
||||||
RtlCopyMemory(&ReparseTargetPrefix0, &FsvolDeviceExtension->VolumeName,
|
RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
|
||||||
sizeof ReparseTargetPrefix0);
|
RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
|
||||||
RtlCopyMemory(&ReparseTargetPrefix1, &FsvolDeviceExtension->VolumePrefix,
|
|
||||||
sizeof ReparseTargetPrefix1);
|
|
||||||
|
|
||||||
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
|
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
|
||||||
Response->Rsp.Create.Reparse.Buffer.Size;
|
Response->Rsp.Create.Reparse.Buffer.Size;
|
||||||
@ -552,16 +554,25 @@ NTSTATUS FspFsvolCreateComplete(
|
|||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||||
|
|
||||||
RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
|
if (!FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE))
|
||||||
RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
|
{
|
||||||
|
RtlZeroMemory(&ReparseTargetPrefix0, sizeof ReparseTargetPrefix0);
|
||||||
|
RtlZeroMemory(&ReparseTargetPrefix1, sizeof ReparseTargetPrefix1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RtlCopyMemory(&ReparseTargetPrefix0, &FsvolDeviceExtension->VolumeName,
|
||||||
|
sizeof ReparseTargetPrefix0);
|
||||||
|
RtlCopyMemory(&ReparseTargetPrefix1, &FsvolDeviceExtension->VolumePrefix,
|
||||||
|
sizeof ReparseTargetPrefix1);
|
||||||
|
}
|
||||||
|
|
||||||
ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
ReparseTargetPath.Buffer = ReparseData->SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
||||||
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
|
ReparseTargetPath.Length = ReparseTargetPath.MaximumLength =
|
||||||
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||||
|
|
||||||
if (FlagOn(ReparseData->SymbolicLinkReparseBuffer.Flags, SYMLINK_FLAG_RELATIVE) ||
|
if (ReparseTargetPath.Length < sizeof(WCHAR) || L'\\' != ReparseTargetPath.Buffer[0])
|
||||||
ReparseTargetPath.Length < sizeof(WCHAR) || L'\\' != ReparseTargetPath.Buffer[0])
|
|
||||||
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user