From 25457b916d265537b40e8185ce7fd722fa6b0408 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 2 Dec 2015 19:40:40 -0800 Subject: [PATCH] sys: IRP_MJ_CREATE --- build/VStudio/winfsp_sys.vcxproj | 1 + build/VStudio/winfsp_sys.vcxproj.filters | 3 ++ inc/winfsp/fsctl.h | 6 ++- src/sys/create.c | 67 +++++++++++++++++++++++- src/sys/driver.h | 24 +++++++-- src/sys/fileobj.c | 56 ++++++++++++++++++++ 6 files changed, 150 insertions(+), 7 deletions(-) create mode 100644 src/sys/fileobj.c diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index 58d10448..b20b231b 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -145,6 +145,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index cf1748c9..07e25c08 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -83,6 +83,9 @@ Source + + Source + diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 9b2b27d4..3ccd1a7b 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -62,7 +62,11 @@ typedef struct UINT8 Kind; union { - UINT8 Placeholder; // !!!: REMOVE + struct + { + UINT8 Placeholder; + WCHAR FileName[]; + } Create; } Req; } FSP_FSCTL_TRANSACT_REQ; typedef struct diff --git a/src/sys/create.c b/src/sys/create.c index c181cc33..cd8efe23 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -48,6 +48,7 @@ static NTSTATUS FspFsvolCreate( { PAGED_CODE(); + NTSTATUS Result; FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject); @@ -67,12 +68,14 @@ static NTSTATUS FspFsvolCreate( PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG EaLength = IrpSp->Parameters.Create.EaLength; BOOLEAN HasTraversePrivilege = BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE); + BOOLEAN HasTrailingBackslash = FALSE; + FSP_FILE_CONTEXT *FsContext = 0; /* cannot open the volume object */ if (0 == RelatedFileObject && 0 == FileName.Length) - return STATUS_ACCESS_DENIED; // need error code like UNIX EPERM (STATUS_NOT_SUPPORTED?) + return STATUS_ACCESS_DENIED; /* need error code like UNIX EPERM (STATUS_NOT_SUPPORTED?) */ - /* cannot open paging file */ + /* cannot open a paging file */ if (FlagOn(Flags, SL_OPEN_PAGING_FILE)) return STATUS_ACCESS_DENIED; @@ -97,6 +100,66 @@ static NTSTATUS FspFsvolCreate( return STATUS_OBJECT_NAME_INVALID; } + /* check for trailing backslash */ + if (sizeof(WCHAR) * 2/* root can have trailing backslash */ <= FileName.Length && + L'\\' == FileName.Buffer[FileName.Length / 2 - 1]) + { + FileName.Length -= sizeof(WCHAR); + HasTrailingBackslash = TRUE; + + if (sizeof(WCHAR) * 2 <= FileName.Length && L'\\' == FileName.Buffer[FileName.Length / 2 - 1]) + return STATUS_OBJECT_NAME_INVALID; + } + + /* is this a relative or absolute open? */ + if (0 != RelatedFileObject) + { + /* must be a relative path */ + if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0]) + return STATUS_OBJECT_NAME_INVALID; + + FSP_FILE_CONTEXT *RelatedFsContext = RelatedFileObject->FsContext; + ASSERT(0 != RelatedFsContext); + + /* + * There is no need to lock our accesses of RelatedFileObject->FsContext->FileName, + * because RelatedFileObject->FsContext->Filename is read-only (after creation) and + * because RelatedFileObject->FsContext is guaranteed to exist while RelatedFileObject + * exists. + */ + Result = FspFileContextCreate( + RelatedFsContext->FileName.Length + sizeof(WCHAR)/* backslash */ + FileName.Length, + &FsContext); + if (!NT_SUCCESS(Result)) + return Result; + + Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &RelatedFsContext->FileName); + ASSERT(NT_SUCCESS(Result)); + if (HasTrailingBackslash) + { + Result = RtlAppendUnicodeToString(&FsContext->FileName, L"\\"); + ASSERT(NT_SUCCESS(Result)); + } + Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &FileName); + ASSERT(NT_SUCCESS(Result)); + } + else + { + /* absolute open */ + Result = FspFileContextCreate( + FileName.Length, + &FsContext); + if (!NT_SUCCESS(Result)) + return Result; + + Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &FileName); + ASSERT(NT_SUCCESS(Result)); + } + + /* + * From this point forward we MUST remember to delete the FsContext on error. + */ + return STATUS_PENDING; } diff --git a/src/sys/driver.h b/src/sys/driver.h index 0969a99f..1acf6109 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -192,7 +192,7 @@ _Dispatch_type_(IRP_MJ_SET_VOLUME_INFORMATION) FSP_DRIVER_DISPATCH FspSetVolumeI _Dispatch_type_(IRP_MJ_SHUTDOWN) FSP_DRIVER_DISPATCH FspShutdown; _Dispatch_type_(IRP_MJ_WRITE) FSP_DRIVER_DISPATCH FspWrite; -/* I/O process functions */ +/* I/O processing functions */ _IRQL_requires_max_(APC_LEVEL) _IRQL_requires_same_ typedef VOID FSP_IOCMPL_DISPATCH( @@ -245,6 +245,10 @@ PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, ULONG millis); BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp); PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint); +/* I/O processing */ +VOID FspIopCompleteRequest(PIRP Irp, NTSTATUS Result); +VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); + /* device management */ enum { @@ -321,9 +325,21 @@ VOID FspDeviceDeleteList( PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount); VOID FspDeviceDeleteAll(VOID); -/* I/O processing */ -VOID FspIopCompleteRequest(PIRP Irp, NTSTATUS Result); -VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); +/* file objects */ +typedef struct +{ + FAST_MUTEX HeaderFastMutex; +} FSP_FILE_CONTEXT_NONPAGED; +typedef struct +{ + FSRTL_ADVANCED_FCB_HEADER Header; + FSP_FILE_CONTEXT_NONPAGED *NonPaged; + BOOLEAN HasTrailingBackslash; + UNICODE_STRING FileName; + WCHAR FileNameBuf[]; +} FSP_FILE_CONTEXT; +NTSTATUS FspFileContextCreate(SIZE_T ExtraSize, FSP_FILE_CONTEXT **PContext); +VOID FspFileContextDelete(FSP_FILE_CONTEXT *Context); /* misc */ NTSTATUS FspCreateGuid(GUID *Guid); diff --git a/src/sys/fileobj.c b/src/sys/fileobj.c new file mode 100644 index 00000000..5d83ec36 --- /dev/null +++ b/src/sys/fileobj.c @@ -0,0 +1,56 @@ +/** + * @file sys/fileobj.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +NTSTATUS FspFileContextCreate(SIZE_T ExtraSize, FSP_FILE_CONTEXT **PContext); +VOID FspFileContextDelete(FSP_FILE_CONTEXT *Context); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFileContextCreate) +#pragma alloc_text(PAGE, FspFileContextDelete) +#endif + +NTSTATUS FspFileContextCreate(SIZE_T ExtraSize, FSP_FILE_CONTEXT **PFsContext) +{ + PAGED_CODE(); + + *PFsContext = 0; + + FSP_FILE_CONTEXT_NONPAGED *NonPaged = ExAllocatePoolWithTag(NonPagedPool, + sizeof *NonPaged, FSP_TAG); + if (0 == NonPaged) + return STATUS_INSUFFICIENT_RESOURCES; + + FSP_FILE_CONTEXT *FsContext = ExAllocatePoolWithTag(PagedPool, + sizeof *FsContext + ExtraSize, FSP_TAG); + if (0 == FsContext) + { + ExFreePoolWithTag(NonPaged, FSP_TAG); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(NonPaged, sizeof *NonPaged); + ExInitializeFastMutex(&NonPaged->HeaderFastMutex); + + RtlZeroMemory(FsContext, sizeof *FsContext + ExtraSize); + FsRtlSetupAdvancedHeader(&FsContext->Header, &NonPaged->HeaderFastMutex); + FsContext->NonPaged = NonPaged; + RtlInitEmptyUnicodeString(&FsContext->FileName, FsContext->FileNameBuf, (USHORT)ExtraSize); + + *PFsContext = FsContext; + + return STATUS_SUCCESS; +} + +VOID FspFileContextDelete(FSP_FILE_CONTEXT *FsContext) +{ + PAGED_CODE(); + + FsRtlTeardownPerStreamContexts(&FsContext->Header); + ExFreePoolWithTag(FsContext->NonPaged, FSP_TAG); + ExFreePoolWithTag(FsContext, FSP_TAG); +}