mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 09:22:57 -05:00
sys, dll: reparse point (symbolic link) support: WIP
This commit is contained in:
@ -335,9 +335,12 @@ static NTSTATUS FspFsvolCreateNoLock(
|
||||
}
|
||||
|
||||
/* fix FileAttributes */
|
||||
ClearFlag(FileAttributes, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY);
|
||||
ClearFlag(FileAttributes,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
if (CreateOptions & FILE_DIRECTORY_FILE)
|
||||
SetFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
|
||||
if (CreateOptions & FILE_OPEN_REPARSE_POINT)
|
||||
SetFlag(FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
|
||||
/*
|
||||
* The new request is associated with our IRP. Go ahead and associate our FileNode/FileDesc
|
||||
@ -486,6 +489,7 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
||||
FSP_FILE_NODE *OpenedFileNode;
|
||||
UNICODE_STRING ReparseFileName;
|
||||
PREPARSE_DATA_BUFFER ReparseData;
|
||||
|
||||
if (FspFsctlTransactCreateKind == Request->Kind)
|
||||
{
|
||||
@ -498,20 +502,25 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
}
|
||||
|
||||
/* special case STATUS_REPARSE */
|
||||
if (STATUS_REPARSE == Result)
|
||||
if (STATUS_REPARSE == Response->IoStatus.Status)
|
||||
{
|
||||
ReparseFileName.Buffer =
|
||||
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
|
||||
ReparseFileName.Length = ReparseFileName.MaximumLength =
|
||||
Response->Rsp.Create.Reparse.FileName.Size;
|
||||
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
if (IO_REPARSE == Response->IoStatus.Information)
|
||||
if (IO_REMOUNT == Response->IoStatus.Information)
|
||||
{
|
||||
if (0 == ReparseFileName.Length ||
|
||||
(PUINT8)ReparseFileName.Buffer + ReparseFileName.Length >
|
||||
(PUINT8)Response + Response->Size)
|
||||
FSP_RETURN();
|
||||
Irp->IoStatus.Information = IO_REMOUNT;
|
||||
Result = STATUS_REPARSE;
|
||||
FSP_RETURN();
|
||||
}
|
||||
else if (IO_REPARSE == Response->IoStatus.Information)
|
||||
{
|
||||
ReparseFileName.Buffer =
|
||||
(PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.FileName.Offset);
|
||||
ReparseFileName.Length = ReparseFileName.MaximumLength =
|
||||
Response->Rsp.Create.Reparse.FileName.Size;
|
||||
|
||||
if ((PUINT8)ReparseFileName.Buffer + ReparseFileName.Length >
|
||||
(PUINT8)Response + Response->Size ||
|
||||
0 == ReparseFileName.Length)
|
||||
FSP_RETURN(Result = STATUS_REPARSE_POINT_NOT_RESOLVED);
|
||||
|
||||
if (ReparseFileName.Length > FileObject->FileName.MaximumLength)
|
||||
{
|
||||
@ -539,19 +548,43 @@ NTSTATUS FspFsvolCreateComplete(
|
||||
* STATUS_REPARSE status returned by the filter. Therefore, it is not
|
||||
* the responsibility of the filter to free that file object.
|
||||
*/
|
||||
}
|
||||
else
|
||||
if (IO_REMOUNT == Response->IoStatus.Information)
|
||||
{
|
||||
if (0 != ReparseFileName.Length)
|
||||
FSP_RETURN();
|
||||
}
|
||||
else
|
||||
FSP_RETURN();
|
||||
|
||||
Irp->IoStatus.Information = (ULONG_PTR)Response->IoStatus.Information;
|
||||
Result = Response->IoStatus.Status;
|
||||
FSP_RETURN();
|
||||
Irp->IoStatus.Information = IO_REPARSE;
|
||||
Result = STATUS_REPARSE;
|
||||
FSP_RETURN();
|
||||
}
|
||||
else
|
||||
{
|
||||
ReparseData = (PVOID)(Response->Buffer + Response->Rsp.Create.Reparse.Data.Offset);
|
||||
|
||||
if ((PUINT8)ReparseData + Response->Rsp.Create.Reparse.Data.Size >
|
||||
(PUINT8)Response + Response->Size)
|
||||
{
|
||||
Result = STATUS_IO_REPARSE_DATA_INVALID;
|
||||
FSP_RETURN();
|
||||
}
|
||||
|
||||
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.Create.Reparse.Data.Size,
|
||||
ReparseData);
|
||||
if (!NT_SUCCESS(Result))
|
||||
FSP_RETURN();
|
||||
|
||||
ASSERT(0 == Irp->Tail.Overlay.AuxiliaryBuffer);
|
||||
Irp->Tail.Overlay.AuxiliaryBuffer = FspAllocNonPagedExternal(
|
||||
Response->Rsp.Create.Reparse.Data.Size);
|
||||
if (0 == Irp->Tail.Overlay.AuxiliaryBuffer)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
FSP_RETURN();
|
||||
}
|
||||
|
||||
RtlCopyMemory(Irp->Tail.Overlay.AuxiliaryBuffer, ReparseData,
|
||||
Response->Rsp.Create.Reparse.Data.Size);
|
||||
|
||||
Irp->IoStatus.Information = ReparseData->ReparseTag;
|
||||
Result = STATUS_REPARSE;
|
||||
FSP_RETURN();
|
||||
}
|
||||
}
|
||||
|
||||
/* fix FileNode->FileName if we were doing SL_OPEN_TARGET_DIRECTORY */
|
||||
|
218
src/sys/fsctl.c
218
src/sys/fsctl.c
@ -18,21 +18,36 @@
|
||||
#include <sys/driver.h>
|
||||
|
||||
static NTSTATUS FspFsctlFileSystemControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
BOOLEAN IsWrite);
|
||||
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
BOOLEAN IsWrite);
|
||||
static NTSTATUS FspFsvolFileSystemControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
||||
FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete;
|
||||
static FSP_IOP_REQUEST_FINI FspFsvolFileSystemControlRequestFini;
|
||||
FSP_DRIVER_DISPATCH FspFileSystemControl;
|
||||
|
||||
#ifdef ALLOC_PRAGMA
|
||||
#pragma alloc_text(PAGE, FspFsctlFileSystemControl)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePoint)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlReparsePointComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControl)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete)
|
||||
#pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini)
|
||||
#pragma alloc_text(PAGE, FspFileSystemControl)
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
RequestFileNode = 0,
|
||||
};
|
||||
|
||||
static NTSTATUS FspFsctlFileSystemControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
@ -44,32 +59,160 @@ static NTSTATUS FspFsctlFileSystemControl(
|
||||
{
|
||||
case FSP_FSCTL_VOLUME_NAME:
|
||||
if (0 != IrpSp->FileObject->FsContext2)
|
||||
Result = FspVolumeGetName(DeviceObject, Irp, IrpSp);
|
||||
Result = FspVolumeGetName(FsctlDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
case FSP_FSCTL_VOLUME_LIST:
|
||||
Result = FspVolumeGetNameList(DeviceObject, Irp, IrpSp);
|
||||
Result = FspVolumeGetNameList(FsctlDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
case FSP_FSCTL_TRANSACT:
|
||||
case FSP_FSCTL_TRANSACT_BATCH:
|
||||
if (0 != IrpSp->FileObject->FsContext2)
|
||||
Result = FspVolumeTransact(DeviceObject, Irp, IrpSp);
|
||||
Result = FspVolumeTransact(FsctlDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
case FSP_FSCTL_STOP:
|
||||
if (0 != IrpSp->FileObject->FsContext2)
|
||||
Result = FspVolumeStop(DeviceObject, Irp, IrpSp);
|
||||
Result = FspVolumeStop(FsctlDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IRP_MN_MOUNT_VOLUME:
|
||||
Result = FspVolumeMount(DeviceObject, Irp, IrpSp);
|
||||
Result = FspVolumeMount(FsctlDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolFileSystemControlReparsePoint(
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
|
||||
BOOLEAN IsWrite)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* is this a valid FileObject? */
|
||||
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
NTSTATUS Result;
|
||||
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
||||
ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
|
||||
PVOID InputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
PVOID OutputBuffer = Irp->UserBuffer;
|
||||
ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||
ULONG ReparseTag;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request;
|
||||
|
||||
ASSERT(FileNode == FileDesc->FileNode);
|
||||
|
||||
/* do we support reparse points? */
|
||||
if (!FsvolDeviceExtension->VolumeParams.ReparsePoints)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
if (IsWrite)
|
||||
{
|
||||
if (0 == InputBuffer || 0 == InputBufferLength ||
|
||||
FSP_FSCTL_TRANSACT_REQ_SIZEMAX - FIELD_OFFSET(FSP_FSCTL_TRANSACT_REQ, Buffer) -
|
||||
(FileNode->FileName.Length + sizeof(WCHAR)) < InputBufferLength)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
Result = FsRtlValidateReparsePointBuffer(InputBufferLength, InputBuffer);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
ReparseTag = ((PREPARSE_DATA_BUFFER)InputBuffer)->ReparseTag;
|
||||
|
||||
/* NTFS severely limits symbolic links; we will not do that unless our file system asks */
|
||||
if (FsvolDeviceExtension->VolumeParams.ReparsePointPrivilegeCheck)
|
||||
{
|
||||
if (IO_REPARSE_TAG_SYMLINK == ReparseTag &&
|
||||
KernelMode != Irp->RequestorMode &&
|
||||
SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_CREATE_SYMBOLIC_LINK_PRIVILEGE),
|
||||
UserMode))
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 != InputBuffer || 0 != InputBufferLength ||
|
||||
0 == OutputBuffer || 0 == OutputBufferLength)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
Result = FspBufferUserBuffer(Irp, OutputBufferLength, IoWriteAccess);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
|
||||
if (IsWrite)
|
||||
FspFileNodeAcquireExclusive(FileNode, Full);
|
||||
else
|
||||
FspFileNodeAcquireShared(FileNode, Full);
|
||||
|
||||
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, InputBufferLength,
|
||||
FspFsvolFileSystemControlRequestFini, &Request);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
FspFileNodeRelease(FileNode, Full);
|
||||
return Result;
|
||||
}
|
||||
|
||||
Request->Kind = FspFsctlTransactFileSystemControlKind;
|
||||
Request->Req.FileSystemControl.UserContext = FileNode->UserContext;
|
||||
Request->Req.FileSystemControl.UserContext2 = FileDesc->UserContext2;
|
||||
Request->Req.FileSystemControl.FsControlCode = FsControlCode;
|
||||
if (IsWrite)
|
||||
{
|
||||
Request->Req.FileSystemControl.Buffer.Offset = Request->FileName.Size;
|
||||
Request->Req.FileSystemControl.Buffer.Size = (UINT16)InputBufferLength;
|
||||
RtlCopyMemory(Request->Buffer + Request->Req.FileSystemControl.Buffer.Offset,
|
||||
InputBuffer, InputBufferLength);
|
||||
}
|
||||
|
||||
FspFileNodeSetOwner(FileNode, Full, Request);
|
||||
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
||||
|
||||
return FSP_STATUS_IOQ_POST;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolFileSystemControlReparsePointComplete(
|
||||
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
BOOLEAN IsWrite)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
if (!IsWrite)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
NTSTATUS Result;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer; /* see FspBufferUserBuffer call */
|
||||
ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
|
||||
|
||||
if (Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset +
|
||||
Response->Rsp.FileSystemControl.Buffer.Size > (PUINT8)Response + Response->Size)
|
||||
return STATUS_IO_REPARSE_DATA_INVALID;
|
||||
|
||||
Result = FsRtlValidateReparsePointBuffer(Response->Rsp.FileSystemControl.Buffer.Size,
|
||||
(PVOID)(Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset));
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (Response->Rsp.FileSystemControl.Buffer.Size > OutputBufferLength)
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
RtlCopyMemory(OutputBuffer, Response->Buffer + Response->Rsp.FileSystemControl.Buffer.Offset,
|
||||
Response->Rsp.FileSystemControl.Buffer.Size);
|
||||
|
||||
Irp->IoStatus.Information = Response->Rsp.FileSystemControl.Buffer.Size;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS FspFsvolFileSystemControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
@ -81,7 +224,14 @@ static NTSTATUS FspFsvolFileSystemControl(
|
||||
{
|
||||
case FSP_FSCTL_WORK:
|
||||
case FSP_FSCTL_WORK_BEST_EFFORT:
|
||||
Result = FspVolumeWork(DeviceObject, Irp, IrpSp);
|
||||
Result = FspVolumeWork(FsvolDeviceObject, Irp, IrpSp);
|
||||
break;
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, FALSE);
|
||||
break;
|
||||
case FSCTL_SET_REPARSE_POINT:
|
||||
case FSCTL_DELETE_REPARSE_POINT:
|
||||
Result = FspFsvolFileSystemControlReparsePoint(FsvolDeviceObject, Irp, IrpSp, TRUE);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -95,6 +245,44 @@ NTSTATUS FspFsvolFileSystemControlComplete(
|
||||
{
|
||||
FSP_ENTER_IOC(PAGED_CODE());
|
||||
|
||||
if (!NT_SUCCESS(Response->IoStatus.Status))
|
||||
{
|
||||
Irp->IoStatus.Information = 0;
|
||||
Result = Response->IoStatus.Status;
|
||||
FSP_RETURN();
|
||||
}
|
||||
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
||||
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
||||
|
||||
switch (IrpSp->MinorFunction)
|
||||
{
|
||||
case IRP_MN_USER_FS_REQUEST:
|
||||
switch (IrpSp->Parameters.FileSystemControl.FsControlCode)
|
||||
{
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, FALSE);
|
||||
break;
|
||||
case FSCTL_SET_REPARSE_POINT:
|
||||
case FSCTL_DELETE_REPARSE_POINT:
|
||||
Result = FspFsvolFileSystemControlReparsePointComplete(Irp, Response, TRUE);
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
Result = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
Result = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
FspIopRequestContext(Request, RequestFileNode) = 0;
|
||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||
|
||||
FSP_LEAVE_IOC(
|
||||
"%s%sFileObject=%p",
|
||||
IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ?
|
||||
@ -103,6 +291,16 @@ NTSTATUS FspFsvolFileSystemControlComplete(
|
||||
IrpSp->FileObject);
|
||||
}
|
||||
|
||||
static VOID FspFsvolFileSystemControlRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4])
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
||||
|
||||
if (0 != FileNode)
|
||||
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
||||
}
|
||||
|
||||
NTSTATUS FspFileSystemControl(
|
||||
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
|
Reference in New Issue
Block a user