From 7197501c9acc5b4af0cd99c297a7097be2c700b6 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Sun, 20 Dec 2015 10:57:45 -0800 Subject: [PATCH] Major refactoring: WIP --- build/VStudio/testing/mirror.vcxproj | 3 - build/VStudio/testing/mirror.vcxproj.filters | 5 - build/VStudio/testing/winfsp-tests.vcxproj | 3 - .../testing/winfsp-tests.vcxproj.filters | 9 - build/VStudio/winfsp_dll.vcxproj | 12 - build/VStudio/winfsp_dll.vcxproj.filters | 28 - build/VStudio/winfsp_sys.vcxproj | 6 +- build/VStudio/winfsp_sys.vcxproj.filters | 48 +- inc/winfsp/fsctl.h | 20 - src/sys/cleanup.c | 109 +-- src/sys/close.c | 76 +- src/sys/create.c | 664 +-------------- src/sys/debug.c | 1 - src/sys/devctl.c | 22 +- src/sys/device.c | 440 +++++----- src/sys/dirctl.c | 22 +- src/sys/driver.c | 49 +- src/sys/driver.h | 257 +++--- src/sys/ea.c | 44 +- src/sys/fastio.c | 75 ++ src/sys/fileinfo.c | 44 +- src/sys/flush.c | 22 +- src/sys/fsctl.c | 572 ++++++------- src/sys/iop.c | 15 +- src/sys/ioq.c | 19 +- src/sys/lockctl.c | 22 +- src/sys/read.c | 22 +- src/sys/resource.c | 86 -- src/sys/security.c | 44 +- src/sys/shutdown.c | 22 +- src/sys/util.c | 61 ++ src/sys/volinfo.c | 44 +- src/sys/write.c | 22 +- {src => src0}/dll/debug.c | 0 {src => src0}/dll/fsctl.c | 0 {src => src0}/dll/library.c | 0 {src => src0}/dll/library.h | 0 {src => src0}/dll/loop.c | 0 {src => src0}/dll/ntstatus.c | 0 {src => src0}/dll/ntstatus.i | 0 src0/sys/cleanup.c | 176 ++++ src0/sys/close.c | 148 ++++ src0/sys/create.c | 767 ++++++++++++++++++ {src => src0}/sys/fileobj.c | 0 src0/sys/fsctl.c | 625 ++++++++++++++ {src => src0}/sys/idevctl.c | 0 {src => src0}/sys/misc.c | 0 47 files changed, 2622 insertions(+), 1982 deletions(-) delete mode 100644 src/sys/resource.c create mode 100644 src/sys/util.c rename {src => src0}/dll/debug.c (100%) rename {src => src0}/dll/fsctl.c (100%) rename {src => src0}/dll/library.c (100%) rename {src => src0}/dll/library.h (100%) rename {src => src0}/dll/loop.c (100%) rename {src => src0}/dll/ntstatus.c (100%) rename {src => src0}/dll/ntstatus.i (100%) create mode 100644 src0/sys/cleanup.c create mode 100644 src0/sys/close.c create mode 100644 src0/sys/create.c rename {src => src0}/sys/fileobj.c (100%) create mode 100644 src0/sys/fsctl.c rename {src => src0}/sys/idevctl.c (100%) rename {src => src0}/sys/misc.c (100%) diff --git a/build/VStudio/testing/mirror.vcxproj b/build/VStudio/testing/mirror.vcxproj index 62a93367..e3cbb944 100644 --- a/build/VStudio/testing/mirror.vcxproj +++ b/build/VStudio/testing/mirror.vcxproj @@ -165,9 +165,6 @@ true - - - {4a7c0b21-9e10-4c81-92de-1493efcf24eb} diff --git a/build/VStudio/testing/mirror.vcxproj.filters b/build/VStudio/testing/mirror.vcxproj.filters index 80ecc54c..ee7c46c8 100644 --- a/build/VStudio/testing/mirror.vcxproj.filters +++ b/build/VStudio/testing/mirror.vcxproj.filters @@ -6,9 +6,4 @@ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - Source - - \ No newline at end of file diff --git a/build/VStudio/testing/winfsp-tests.vcxproj b/build/VStudio/testing/winfsp-tests.vcxproj index 3447dde0..733437ce 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj +++ b/build/VStudio/testing/winfsp-tests.vcxproj @@ -176,9 +176,6 @@ TurnOffAllWarnings TurnOffAllWarnings - - - diff --git a/build/VStudio/testing/winfsp-tests.vcxproj.filters b/build/VStudio/testing/winfsp-tests.vcxproj.filters index c56a1e40..93e79dc7 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj.filters +++ b/build/VStudio/testing/winfsp-tests.vcxproj.filters @@ -10,18 +10,9 @@ - - Source - - - Source - Source\tlib - - Source - diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj index cc2cec8a..06bcac75 100644 --- a/build/VStudio/winfsp_dll.vcxproj +++ b/build/VStudio/winfsp_dll.vcxproj @@ -178,18 +178,6 @@ $(OutDir)$(TargetFileName).map - - - - - - - - - - - - diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters index 76348406..1b8d3f22 100644 --- a/build/VStudio/winfsp_dll.vcxproj.filters +++ b/build/VStudio/winfsp_dll.vcxproj.filters @@ -13,32 +13,4 @@ {1d6501f4-cebd-4a00-a774-deb782b59fb5} - - - Source - - - Source - - - Source - - - Source - - - Source - - - - - Include\winfsp - - - Include\winfsp - - - Source - - \ No newline at end of file diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index 856c099a..0bbf7bee 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -157,24 +157,20 @@ - - - - + - diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index cab112ad..eff809c7 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -14,16 +14,28 @@ - + Source - + + Source + + + Source + + + Source + + Source Source - + + Source + + Source @@ -32,33 +44,21 @@ Source - - Source - Source - - Source - Source Source - - Source - Source Source - - Source - Source @@ -71,22 +71,13 @@ Source - + Source - + Source - - Source - - - Source - - - Source - - + Source @@ -97,8 +88,5 @@ Include\winfsp - - Include\winfsp - \ No newline at end of file diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index bdc204e2..74eba980 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -28,18 +28,11 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid = /* fsctl device codes */ #define FSP_FSCTL_CREATE \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'C', METHOD_BUFFERED, FILE_ANY_ACCESS) - -/* fsvrt device codes */ -#define FSP_FSCTL_DELETE \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'D', METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSP_FSCTL_TRANSACT \ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'T', METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSP_FSCTL_CREATE_BUFFER_SIZEMIN 128 #define FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMIN 16384 /* checked by driver! */ -#define FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMIN 16384 /* not checked by driver! */ - -#define FSP_FSCTL_VOLUME_PARAMS_SIZE FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_VOLUME_PARAMS)) #define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */ #define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */ @@ -50,7 +43,6 @@ enum { FspFsctlTransactUnknownKind = 0, FspFsctlTransactCreateKind, - FspFsctlTransactCreateCleanupCloseKind, FspFsctlTransactCloseKind, FspFsctlTransactReadKind, FspFsctlTransactWriteKind, @@ -90,7 +82,6 @@ typedef struct UINT32 IrpTimeout; /* milliseconds; values between 1 min and 10 min */ UINT32 EaSupported:1; /* supports extended attributes (unimplemented; set to 0) */ UINT32 FileNameRequired:1; /* FileName required for all operations (not just Create) */ - UINT32 NoSystemAccessCheck:1; /* if set the user-mode flie system performs access checks */ } FSP_FSCTL_VOLUME_PARAMS; typedef struct { @@ -155,8 +146,6 @@ typedef struct { UINT64 UserContext; /* open file user context (unique file id) */ UINT64 UserContext2; /* kernel file object user context (only low 32 bits valid) */ - UINT32 FileAttributes; /* FILE_ATTRIBUTE_{NORMAL,DIRECTORY,etc.} */ - FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor */ } Opened; /* IoStatus.Status == STATUS_REPARSE */ struct @@ -210,15 +199,6 @@ static inline FSP_FSCTL_TRANSACT_RSP *FspFsctlTransactConsumeResponse( } #if !defined(WINFSP_SYS_INTERNAL) -FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath, - const FSP_FSCTL_VOLUME_PARAMS *Params, PSECURITY_DESCRIPTOR SecurityDescriptor, - PWCHAR VolumePathBuf, SIZE_T VolumePathSize); -FSP_API NTSTATUS FspFsctlOpenVolume(PWSTR VolumePath, - PHANDLE PVolumeHandle); -FSP_API NTSTATUS FspFsctlDeleteVolume(HANDLE VolumeHandle); -FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, - PVOID ResponseBuf, SIZE_T ResponseBufSize, - PVOID RequestBuf, SIZE_T *PRequestBufSize); #endif #endif diff --git a/src/sys/cleanup.c b/src/sys/cleanup.c index 4aea9e75..3ff58fb4 100644 --- a/src/sys/cleanup.c +++ b/src/sys/cleanup.c @@ -23,14 +23,18 @@ FSP_DRIVER_DISPATCH FspCleanup; #pragma alloc_text(PAGE, FspCleanup) #endif +VOID FspFsctlDeleteVolume( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); + static NTSTATUS FspFsctlCleanup( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); - NTSTATUS Result = STATUS_SUCCESS; + FspFsctlDeleteVolume(DeviceObject, Irp, IrpSp); + Irp->IoStatus.Information = 0; - return Result; + return STATUS_SUCCESS; } static NTSTATUS FspFsvrtCleanup( @@ -38,9 +42,8 @@ static NTSTATUS FspFsvrtCleanup( { PAGED_CODE(); - NTSTATUS Result = STATUS_SUCCESS; Irp->IoStatus.Information = 0; - return Result; + return STATUS_SUCCESS; } static NTSTATUS FspFsvolCleanup( @@ -48,101 +51,7 @@ static NTSTATUS FspFsvolCleanup( { PAGED_CODE(); - /* is this a valid FileObject? */ - if (!FspFileContextIsValid(IrpSp->FileObject->FsContext)) - return STATUS_SUCCESS; - - NTSTATUS Result; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - PFILE_OBJECT FileObject = IrpSp->FileObject; - FSP_FILE_CONTEXT *FsContext = FileObject->FsContext; - UINT64 UserContext = FsContext->UserContext; - UINT64 UserContext2 = (UINT_PTR)FileObject->FsContext2; - BOOLEAN DeletePending; - LONG OpenCount; - - /* lock the FsContext */ - ExAcquireResourceExclusiveLite(FsContext->Header.Resource, TRUE); - - /* propagate the FsContext DeleteOnClose to DeletePending */ - if (FsContext->DeleteOnClose) - FsContext->DeletePending = TRUE; - DeletePending = FsContext->DeletePending; - - /* all handles on this FileObject are gone; decrement its FsContext->OpenCount */ - OpenCount = FspFileContextClose(FsContext); - - /* unlock the FsContext */ - ExReleaseResourceLite(FsContext->Header.Resource); - - /* is the FsContext going away as well? */ - if (0 == OpenCount) - { - /* - * The following must be done under the file system volume device Resource, - * because we are manipulating its GenericTable. - */ - ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->Base.Resource, TRUE); - try - { - /* remove the FsContext from the file system volume device generic table */ - FspFsvolDeviceDeleteContext(DeviceObject, FsContext->UserContext, 0); - } - finally - { - ExReleaseResourceLite(&FsvolDeviceExtension->Base.Resource); - } - } - - PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; - if (!FspDeviceRetain(FsvrtDeviceObject)) - /* IRP_MJ_CLEANUP cannot really fail :-\ */ - return STATUS_SUCCESS; - - try - { - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); - BOOLEAN FileNameRequired = 0 != FsvrtDeviceExtension->VolumeParams.FileNameRequired; - FSP_FSCTL_TRANSACT_REQ *Request; - - /* create the user-mode file system request */ - Result = FspIopCreateRequest(Irp, FileNameRequired ? &FsContext->FileName : 0, 0, &Request); - if (!NT_SUCCESS(Result)) - goto leak_exit; - - /* - * The new request is associated with our IRP and will be deleted during its completion. - */ - - /* populate the Cleanup request */ - Request->Kind = FspFsctlTransactCleanupKind; - Request->Req.Cleanup.UserContext = UserContext; - Request->Req.Cleanup.UserContext2 = UserContext2; - Request->Req.Cleanup.Delete = DeletePending && 0 == OpenCount; - - Result = STATUS_PENDING; - - goto exit; - - leak_exit:; -#if DBG - DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%llx: " - "error: the user-mode file system handle will be leaked!", - IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, - UserContext, UserContext2); -#endif - - /* IRP_MJ_CLEANUP cannot really fail :-\ */ - Result = STATUS_SUCCESS; - - exit:; - } - finally - { - FspDeviceRelease(FsvrtDeviceObject); - } - - return Result; + return STATUS_INVALID_DEVICE_REQUEST; } VOID FspFsvolCleanupComplete( @@ -158,8 +67,6 @@ NTSTATUS FspCleanup( { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_CLEANUP == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: diff --git a/src/sys/close.c b/src/sys/close.c index 1b912117..384534b2 100644 --- a/src/sys/close.c +++ b/src/sys/close.c @@ -28,9 +28,8 @@ static NTSTATUS FspFsctlClose( { PAGED_CODE(); - NTSTATUS Result = STATUS_SUCCESS; Irp->IoStatus.Information = 0; - return Result; + return STATUS_SUCCESS; } static NTSTATUS FspFsvrtClose( @@ -38,9 +37,8 @@ static NTSTATUS FspFsvrtClose( { PAGED_CODE(); - NTSTATUS Result = STATUS_SUCCESS; Irp->IoStatus.Information = 0; - return Result; + return STATUS_SUCCESS; } static NTSTATUS FspFsvolClose( @@ -48,73 +46,7 @@ static NTSTATUS FspFsvolClose( { PAGED_CODE(); - /* is this a valid FileObject? */ - if (!FspFileContextIsValid(IrpSp->FileObject->FsContext)) - return STATUS_SUCCESS; - - NTSTATUS Result; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - PFILE_OBJECT FileObject = IrpSp->FileObject; - FSP_FILE_CONTEXT *FsContext = FileObject->FsContext; - UINT64 UserContext = FsContext->UserContext; - UINT64 UserContext2 = (UINT_PTR)FileObject->FsContext2; - - /* dereference the FsContext (and delete if no more references) */ - FspFileContextRelease(FsContext); - - PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; - if (!FspDeviceRetain(FsvrtDeviceObject)) - /* IRP_MJ_CLOSE cannot really fail :-\ */ - return STATUS_SUCCESS; - - try - { - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); - BOOLEAN FileNameRequired = 0 != FsvrtDeviceExtension->VolumeParams.FileNameRequired; - FSP_FSCTL_TRANSACT_REQ *Request; - - /* create the user-mode file system request */ - Result = FspIopCreateRequest(0, FileNameRequired ? &FsContext->FileName : 0, 0, &Request); - if (!NT_SUCCESS(Result)) - goto leak_exit; - - /* - * The new request is associated with our IRP and will be deleted during its completion. - */ - - /* populate the Close request */ - Request->Kind = FspFsctlTransactCloseKind; - Request->Req.Close.UserContext = UserContext; - Request->Req.Close.UserContext2 = UserContext2; - - /* post as a work request; this allows us to complete our own IRP and return immediately! */ - if (!FspIopPostWorkRequest(DeviceObject, Request)) - /* no need to delete the request here as FspIopPostWorkRequest() will do so in all cases */ - goto leak_exit; - - Result = STATUS_SUCCESS; - - goto exit; - - leak_exit:; -#if DBG - DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%llx: " - "error: the user-mode file system handle will be leaked!", - IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, - UserContext, UserContext2); -#endif - - /* IRP_MJ_CLOSE cannot really fail :-\ */ - Result = STATUS_SUCCESS; - - exit:; - } - finally - { - FspDeviceRelease(FsvrtDeviceObject); - } - - return Result; + return STATUS_INVALID_DEVICE_REQUEST; } VOID FspFsvolCloseComplete( @@ -130,8 +62,6 @@ NTSTATUS FspClose( { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_CLOSE == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: diff --git a/src/sys/create.c b/src/sys/create.c index 052558fe..fc1fdfbd 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -14,9 +14,7 @@ static NTSTATUS FspFsvolCreate( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_IOPREP_DISPATCH FspFsvolCreatePrepare; FSP_IOCMPL_DISPATCH FspFsvolCreateComplete; -static VOID FspFsvolCreateCleanupClose( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); -FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini; +static FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini; FSP_DRIVER_DISPATCH FspCreate; #ifdef ALLOC_PRAGMA @@ -25,25 +23,17 @@ FSP_DRIVER_DISPATCH FspCreate; #pragma alloc_text(PAGE, FspFsvolCreate) #pragma alloc_text(PAGE, FspFsvolCreatePrepare) #pragma alloc_text(PAGE, FspFsvolCreateComplete) -#pragma alloc_text(PAGE, FspFsvolCreateCleanupClose) #pragma alloc_text(PAGE, FspFsvolCreateRequestFini) #pragma alloc_text(PAGE, FspCreate) #endif -enum -{ - RequestFsContext = 0, - RequestAccessToken, -}; - static NTSTATUS FspFsctlCreate( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); - NTSTATUS Result = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; - return Result; + return STATUS_SUCCESS; } static NTSTATUS FspFsvrtCreate( @@ -51,9 +41,8 @@ static NTSTATUS FspFsvrtCreate( { PAGED_CODE(); - NTSTATUS Result = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; - return Result; + return STATUS_SUCCESS; } static NTSTATUS FspFsvolCreate( @@ -61,280 +50,7 @@ static NTSTATUS FspFsvolCreate( { PAGED_CODE(); - /* open the volume object? */ - if (0 == IrpSp->FileObject->FileName.Length && - (0 == IrpSp->FileObject->RelatedFileObject || - 0 == IrpSp->FileObject->RelatedFileObject->FsContext)) - { - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; - - IrpSp->FileObject->Vpb = FsvrtDeviceObject->Vpb; - Irp->IoStatus.Information = FILE_OPENED; - return STATUS_SUCCESS; - } - - NTSTATUS Result; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - - PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; - if (!FspDeviceRetain(FsvrtDeviceObject)) - return STATUS_CANCELLED; - - try - { - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); - PFILE_OBJECT FileObject = IrpSp->FileObject; - PFILE_OBJECT RelatedFileObject = FileObject->RelatedFileObject; - UNICODE_STRING FileName = FileObject->FileName; - PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; - ULONG CreateOptions = IrpSp->Parameters.Create.Options; - USHORT FileAttributes = IrpSp->Parameters.Create.FileAttributes; - PSECURITY_DESCRIPTOR SecurityDescriptor = AccessState->SecurityDescriptor; - ULONG SecurityDescriptorSize = 0; - LARGE_INTEGER AllocationSize = Irp->Overlay.AllocationSize; - ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; - USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; - PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer; - //ULONG EaLength = IrpSp->Parameters.Create.EaLength; - ULONG Flags = IrpSp->Flags; - KPROCESSOR_MODE RequestorMode = - FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode; - BOOLEAN HasTraversePrivilege = - BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE); - BOOLEAN IsAbsoluteSecurityDescriptor = FALSE; - BOOLEAN IsSelfRelativeSecurityDescriptor = FALSE; - BOOLEAN HasTrailingBackslash = FALSE; - FSP_FILE_CONTEXT *FsContext = 0; - FSP_FSCTL_TRANSACT_REQ *Request; - - /* cannot open a paging file */ - if (FlagOn(Flags, SL_OPEN_PAGING_FILE)) - { - Result = STATUS_ACCESS_DENIED; - goto exit; - } - - /* cannot open files by fileid */ - if (FlagOn(CreateOptions, FILE_OPEN_BY_FILE_ID)) - { - Result = STATUS_NOT_IMPLEMENTED; - goto exit; - } - - /* do we support EA? */ - if (0 != EaBuffer && !FsvrtDeviceExtension->VolumeParams.EaSupported) - { - Result = STATUS_EAS_NOT_SUPPORTED; - goto exit; - } - - /* check create options */ - if (FlagOn(CreateOptions, FILE_NON_DIRECTORY_FILE) && - FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) - { - Result = STATUS_INVALID_PARAMETER; - goto exit; - } - - /* check security descriptor validity */ - if (0 != SecurityDescriptor) - { - IsAbsoluteSecurityDescriptor = RtlValidSecurityDescriptor(SecurityDescriptor); - if (IsAbsoluteSecurityDescriptor) - { - Result = RtlAbsoluteToSelfRelativeSD(SecurityDescriptor, 0, &SecurityDescriptorSize); - if (STATUS_BUFFER_TOO_SMALL != Result) - { - Result = STATUS_INVALID_PARAMETER; - goto exit; - } - } - else - { - SecurityDescriptorSize = RtlLengthSecurityDescriptor(SecurityDescriptor); - IsSelfRelativeSecurityDescriptor = RtlValidRelativeSecurityDescriptor( - SecurityDescriptor, SecurityDescriptorSize, 0); - if (!IsSelfRelativeSecurityDescriptor) - { - Result = STATUS_INVALID_PARAMETER; - goto exit; - } - } - } - - /* according to fastfat, filenames that begin with two backslashes are ok */ - if (sizeof(WCHAR) * 2 <= FileName.Length && - L'\\' == FileName.Buffer[1] && L'\\' == FileName.Buffer[0]) - { - FileName.Length -= sizeof(WCHAR); - FileName.MaximumLength -= sizeof(WCHAR); - FileName.Buffer++; - - if (sizeof(WCHAR) * 2 <= FileName.Length && - L'\\' == FileName.Buffer[1] && L'\\' == FileName.Buffer[0]) - { - Result = STATUS_OBJECT_NAME_INVALID; - goto exit; - } - } - - /* check for trailing backslash */ - if (sizeof(WCHAR) * 2/* not empty or root */ <= 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]) - { - Result = STATUS_OBJECT_NAME_INVALID; - goto exit; - } - } - if (HasTrailingBackslash && !FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) - { - Result = STATUS_OBJECT_NAME_INVALID; - goto exit; - } - - /* is this a relative or absolute open? */ - if (0 != RelatedFileObject) - { - FSP_FILE_CONTEXT *RelatedFsContext = RelatedFileObject->FsContext; - - /* is this a valid RelatedFileObject? */ - if (!FspFileContextIsValid(RelatedFsContext)) - { - Result = STATUS_OBJECT_PATH_NOT_FOUND; - goto exit; - } - - /* must be a relative path */ - if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0]) - { - Result = STATUS_OBJECT_NAME_INVALID; - goto exit; - } - - /* cannot FILE_DELETE_ON_CLOSE on the root directory */ - if (sizeof(WCHAR) == RelatedFsContext->FileName.Length && - 0 == FileName.Length && - FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) - { - Result = STATUS_CANNOT_DELETE; - goto exit; - } - - /* - * 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. - */ - BOOLEAN AppendBackslash = - sizeof(WCHAR) * 2/* not empty or root */ <= RelatedFsContext->FileName.Length && - sizeof(WCHAR) <= FileName.Length && L':' != FileName.Buffer[0]; - Result = FspFileContextCreate(DeviceObject, - RelatedFsContext->FileName.Length + AppendBackslash * sizeof(WCHAR) + FileName.Length, - &FsContext); - if (!NT_SUCCESS(Result)) - goto exit; - - Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &RelatedFsContext->FileName); - ASSERT(NT_SUCCESS(Result)); - if (AppendBackslash) - { - Result = RtlAppendUnicodeToString(&FsContext->FileName, L"\\"); - ASSERT(NT_SUCCESS(Result)); - } - } - else - { - /* must be an absolute path */ - if (sizeof(WCHAR) <= FileName.Length && L'\\' != FileName.Buffer[0]) - { - Result = STATUS_OBJECT_NAME_INVALID; - goto exit; - } - - /* cannot FILE_DELETE_ON_CLOSE on the root directory */ - if (sizeof(WCHAR) == FileName.Length && - FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) - { - Result = STATUS_CANNOT_DELETE; - goto exit; - } - - Result = FspFileContextCreate(DeviceObject, - FileName.Length, - &FsContext); - if (!NT_SUCCESS(Result)) - goto exit; - } - - Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &FileName); - ASSERT(NT_SUCCESS(Result)); - - /* create the user-mode file system request */ - Result = FspIopCreateRequestEx(Irp, &FsContext->FileName, SecurityDescriptorSize, - FspFsvolCreateRequestFini, &Request); - if (!NT_SUCCESS(Result)) - { - FspFileContextRelease(FsContext); - goto exit; - } - - /* - * The new request is associated with our IRP and will be deleted during its completion. - * Go ahead and associate our FsContext with the Request as well. - */ - FspIopRequestContext(Request, RequestFsContext) = FsContext; - - /* populate the Create request */ - Request->Kind = FspFsctlTransactCreateKind; - Request->Req.Create.CreateOptions = CreateOptions; - Request->Req.Create.FileAttributes = FileAttributes; - Request->Req.Create.SecurityDescriptor.Offset = 0 == SecurityDescriptorSize ? 0 : - FSP_FSCTL_DEFAULT_ALIGN_UP(Request->FileName.Size); - Request->Req.Create.SecurityDescriptor.Size = (UINT16)SecurityDescriptorSize; - Request->Req.Create.AllocationSize = AllocationSize.QuadPart; - Request->Req.Create.AccessToken = 0; - Request->Req.Create.DesiredAccess = DesiredAccess; - Request->Req.Create.ShareAccess = ShareAccess; - Request->Req.Create.Ea.Offset = 0; - Request->Req.Create.Ea.Size = 0; - Request->Req.Create.UserMode = UserMode == RequestorMode; - Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege; - Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY); - Request->Req.Create.CaseSensitive = BooleanFlagOn(Flags, SL_CASE_SENSITIVE); - - /* copy the security descriptor into the request */ - if (IsAbsoluteSecurityDescriptor) - { - Result = RtlAbsoluteToSelfRelativeSD(SecurityDescriptor, - Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, &SecurityDescriptorSize); - if (!NT_SUCCESS(Result)) - { - if (STATUS_BAD_DESCRIPTOR_FORMAT == Result || STATUS_BUFFER_TOO_SMALL == Result) - Result = STATUS_INVALID_PARAMETER; /* should not happen */ - goto exit; - } - } - else if (IsSelfRelativeSecurityDescriptor) - RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, - SecurityDescriptor, SecurityDescriptorSize); - - Result = STATUS_PENDING; - - exit:; - } - finally - { - FspDeviceRelease(FsvrtDeviceObject); - } - - return Result; + return STATUS_INVALID_DEVICE_REQUEST; } NTSTATUS FspFsvolCreatePrepare( @@ -342,30 +58,6 @@ NTSTATUS FspFsvolCreatePrepare( { FSP_ENTER_IOP(PAGED_CODE()); - PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = - FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject); - - /* is the user-mode file system doing access checks? */ - if (!FsvrtDeviceExtension->VolumeParams.NoSystemAccessCheck) - { - ASSERT(0 == Request->Req.Create.AccessToken); - FSP_RETURN(Result = STATUS_SUCCESS); - } - - /* get a user-mode handle to the access token */ - PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; - HANDLE UserModeAccessToken; - Result = ObOpenObjectByPointer(SeQuerySubjectContextToken(&AccessState->SubjectSecurityContext), - 0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken); - if (!NT_SUCCESS(Result)) - FSP_RETURN(); - - /* send the user-mode handle to the user-mode file system */ - FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken; - Request->Req.Create.AccessToken = (UINT_PTR)UserModeAccessToken; - FSP_LEAVE_IOP(); } @@ -374,358 +66,14 @@ VOID FspFsvolCreateComplete( { FSP_ENTER_IOC(PAGED_CODE()); - /* - * NOTE: - * In the following we may have to close the just opened file object. But we must - * never close a file we just created, because this will leave an orphan file on - * the disk. - * - * Files may have to be closed if a security access or share access check fails. In - * both those cases we were opening an existing file and so it is safe to close it. - * - * Because of how IRP_MJ_CREATE works in Windows, it is difficult to improve on this - * scheme without introducing a 2-phase Create protocol, which is undesirable as it - * means two trips into user-mode for a single Create request. - */ - - PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); - FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); - PFILE_OBJECT FileObject = IrpSp->FileObject; - PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; - ULONG CreateOptions = IrpSp->Parameters.Create.Options; - BOOLEAN FileCreated = FILE_CREATED == Response->IoStatus.Information; - UINT32 ResponseFileAttributes = Response->Rsp.Create.Opened.FileAttributes; - PSECURITY_DESCRIPTOR SecurityDescriptor; - ULONG SecurityDescriptorSize; - UNICODE_STRING ReparseFileName; - ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; - PPRIVILEGE_SET Privileges = 0; - USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; - ULONG Flags = IrpSp->Flags; - KPROCESSOR_MODE RequestorMode = - FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode; - FSP_FILE_CONTEXT *FsContext = FspIopRequestContext(Request, RequestFsContext); - ACCESS_MASK GrantedAccess; - BOOLEAN Inserted = FALSE; - - /* did the user-mode file system sent us a failure code? */ - if (!NT_SUCCESS(Response->IoStatus.Status)) - { - Irp->IoStatus.Information = Response->IoStatus.Information; - Result = Response->IoStatus.Status; - FSP_RETURN(); - } - - /* special case STATUS_REPARSE */ - if (STATUS_REPARSE == Result) - { - 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 (0 == ReparseFileName.Length || - (PUINT8)ReparseFileName.Buffer + ReparseFileName.Length > - (PUINT8)Response + Response->Size) - FSP_RETURN(); - - if (ReparseFileName.Length > FileObject->FileName.MaximumLength) - { - PVOID Buffer = FspAllocExternal(ReparseFileName.Length); - if (0 == Buffer) - FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES); - FspFreeExternal(FileObject->FileName.Buffer); - FileObject->FileName.MaximumLength = ReparseFileName.Length; - FileObject->FileName.Buffer = Buffer; - } - FileObject->FileName.Length = 0; - RtlCopyUnicodeString(&FileObject->FileName, &ReparseFileName); - } - else - if (IO_REMOUNT == Response->IoStatus.Information) - { - if (0 != ReparseFileName.Length) - FSP_RETURN(); - } - else - FSP_RETURN(); - - Irp->IoStatus.Information = Response->IoStatus.Information; - Result = Response->IoStatus.Status; - FSP_RETURN(); - } - - /* are we doing access checks? */ - if (!FsvrtDeviceExtension->VolumeParams.NoSystemAccessCheck) - { - /* read-only attribute check */ - if (!FileCreated && FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_READONLY)) - { - /* from fastfat: allowed accesses when read-only */ - ACCESS_MASK Allowed = - DELETE | READ_CONTROL | WRITE_OWNER | WRITE_DAC | - SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | - FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA | - FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | - FILE_EXECUTE | FILE_TRAVERSE | FILE_LIST_DIRECTORY | - FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD; - - if (FlagOn(DesiredAccess, ~Allowed)) - { - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(Result = STATUS_ACCESS_DENIED); - } - else - if (!FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_DIRECTORY) && - FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) - { - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(Result = STATUS_CANNOT_DELETE); - } - } - - /* security descriptor check */ - SecurityDescriptor = - (PVOID)(Response->Buffer + Response->Rsp.Create.Opened.SecurityDescriptor.Offset); - SecurityDescriptorSize = Response->Rsp.Create.Opened.SecurityDescriptor.Size; - if (0 != SecurityDescriptorSize) - { - if ((PUINT8)SecurityDescriptor + SecurityDescriptorSize > - (PUINT8)Response + Response->Size || - !FspValidRelativeSecurityDescriptor(SecurityDescriptor, SecurityDescriptorSize, 0)) - { - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(Result = STATUS_ACCESS_DENIED); - } - - /* access check */ - if (!SeAccessCheck(SecurityDescriptor, - &AccessState->SubjectSecurityContext, - FALSE, - DesiredAccess, - AccessState->PreviouslyGrantedAccess, - &Privileges, - IoGetFileObjectGenericMapping(), - RequestorMode, - &GrantedAccess, - &Result)) - { - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(); - } - - if (0 != Privileges) - { - Result = SeAppendPrivileges(AccessState, Privileges); - SeFreePrivileges(Privileges); - if (!NT_SUCCESS(Result)) - { - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(); - } - } - - SetFlag(AccessState->PreviouslyGrantedAccess, GrantedAccess); - ClearFlag(AccessState->RemainingDesiredAccess, GrantedAccess); - } - } - - /* were we asked to open a directory or non-directory? */ - if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE) && - !FileCreated && !FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) - { - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(Result = STATUS_NOT_A_DIRECTORY); - } - if (FlagOn(CreateOptions, FILE_NON_DIRECTORY_FILE) && - !FileCreated && FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) - { - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(Result = STATUS_FILE_IS_A_DIRECTORY); - } - - /* - * The following must be done under the file system volume device Resource, - * because we are manipulating its GenericTable and accessing foreign FsContext's. - */ - ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->Base.Resource, TRUE); - try - { - /* insert the newly created FsContext into our generic table */ - FsContext = FspFsvolDeviceInsertContext(DeviceObject, - FsContext->UserContext, FsContext, &FsContext->ElementStorage, &Inserted); - ASSERT(0 != FsContext); - - /* share access check */ - if (Inserted) - { - /* - * This is a newly created FsContext. Set its share access and - * increment its open count. There is no need to acquire the - * FsContext's Resource (because it is newly created). - */ - IoSetShareAccess(AccessState->PreviouslyGrantedAccess, - ShareAccess, FileObject, &FsContext->ShareAccess); - FspFileContextOpen(FsContext); - if (FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) - FsContext->DeleteOnClose = TRUE; - Result = STATUS_SUCCESS; - } - else - { - /* - * This is an existing FsContext. We must acquire its Resource and - * check if there is a delete pending and the share access. Only if - * both tests succeed we increment the open count and report success. - */ - ExAcquireResourceExclusiveLite(FsContext->Header.Resource, TRUE); - if (FsContext->DeletePending) - Result = STATUS_DELETE_PENDING; - else - Result = IoCheckShareAccess(AccessState->PreviouslyGrantedAccess, - ShareAccess, FileObject, &FsContext->ShareAccess, TRUE); - if (NT_SUCCESS(Result)) - { - FspFileContextRetain(FsContext); - FspFileContextOpen(FsContext); - if (FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) - FsContext->DeleteOnClose = TRUE; - } - ExReleaseResourceLite(FsContext->Header.Resource); - } - } - finally - { - ExReleaseResourceLite(&FsvolDeviceExtension->Base.Resource); - } - - /* did we fail our share access checks? */ - if (!NT_SUCCESS(Result)) - { - ASSERT(!Inserted); - FspFsvolCreateCleanupClose(Irp, Response); - FSP_RETURN(); - } - - /* - * Looks like SUCCESS! - */ - - /* did an FsContext with the same UserContext already exist? */ - if (!Inserted) - /* delete the newly created FsContext as it is not being used */ - FspFileContextRelease(FspIopRequestContext(Request, RequestFsContext)); - - /* disassociate our FsContext from the Request */ - FspIopRequestContext(Request, RequestFsContext) = 0; - - /* record the user-mode file system contexts */ - FsContext->UserContext = Response->Rsp.Create.Opened.UserContext; - FileObject->FsContext = FsContext; - FileObject->FsContext2 = (PVOID)(UINT_PTR)Response->Rsp.Create.Opened.UserContext2; - - /* finish seting up the FileObject */ - FileObject->Vpb = FsvrtDeviceObject->Vpb; - - /* SUCCESS! */ - Irp->IoStatus.Information = Response->IoStatus.Information; - Result = Response->IoStatus.Status; - FSP_LEAVE_IOC( "FileObject=%p[%p:\"%wZ\"]", IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName); } -static VOID FspFsvolCreateCleanupClose( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +static VOID FspFsvolCreateRequestFini(PVOID Context[3]) { PAGED_CODE(); - - /* - * This routine handles the case where we must close an open file, - * because of a failure during Create completion. We simply create - * a CreateClose request and we post it as a work item. - * - * Ideally there would be no failure modes for this routine. Reality is - * different. - * - * The more serious (but perhaps non-existent in practice) failure is a - * memory allocation failure. In this case we will leak the user-mode - * file system handle! - * - * This routine may also fail if we cannot post a work item, which means that - * the virtual volume device and the file system volume device are being - * deleted. Because it is assumed that only the user-mode file system would - * initiate a device deletion, this case is more benign (presumably the file - * system knows to close off all its handles when tearing down its devices). - */ - - NTSTATUS Result; - PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject; - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = - FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject); - FSP_FSCTL_TRANSACT_REQ *OriginalRequest = FspIrpRequest(Irp); - FSP_FILE_CONTEXT *FsContext = FspIopRequestContext(OriginalRequest, RequestFsContext); - UINT64 UserContext = Response->Rsp.Create.Opened.UserContext; - UINT64 UserContext2 = Response->Rsp.Create.Opened.UserContext2; - BOOLEAN FileNameRequired = 0 != FsvrtDeviceExtension->VolumeParams.FileNameRequired; - FSP_FSCTL_TRANSACT_REQ *Request; - - /* create the user-mode file system request */ - Result = FspIopCreateRequest(0, FileNameRequired ? &FsContext->FileName : 0, 0, &Request); - if (!NT_SUCCESS(Result)) - goto leak_exit; - - /* populate the CreateCleanupClose request */ - Request->Kind = FspFsctlTransactCreateCleanupCloseKind; - Request->Req.Cleanup.UserContext = UserContext; - Request->Req.Cleanup.UserContext2 = UserContext2; - Request->Req.Cleanup.Delete = FILE_CREATED == Response->IoStatus.Information; - - /* post as a work request */ - if (!FspIopPostWorkRequest(DeviceObject, Request)) - /* no need to delete the request here as FspIopPostWorkRequest() will do so in all cases */ - goto leak_exit; - - goto exit; - -leak_exit:; -#if DBG - DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%llx: " - "error: the user-mode file system handle will be leaked!", - IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, - UserContext, UserContext2); -#endif - -exit:; -} - -VOID FspFsvolCreateRequestFini(PVOID Context[3]) -{ - PAGED_CODE(); - - if (0 != Context[RequestFsContext]) - FspFileContextRelease(Context[RequestFsContext]); - - if (0 != Context[RequestAccessToken]) - { -#if DBG - NTSTATUS Result0; - Result0 = ObCloseHandle(Context[RequestAccessToken], KernelMode); - if (!NT_SUCCESS(Result0)) - DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result0)); -#else - ObCloseHandle(Context[RequestAccessToken], KernelMode); -#endif - } } NTSTATUS FspCreate( @@ -733,8 +81,6 @@ NTSTATUS FspCreate( { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_CREATE == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: diff --git a/src/sys/debug.c b/src/sys/debug.c index 2e5e4dff..583a2730 100644 --- a/src/sys/debug.c +++ b/src/sys/debug.c @@ -166,7 +166,6 @@ const char *IoctlCodeSym(ULONG ControlCode) switch (ControlCode) { SYM(FSP_FSCTL_CREATE) - SYM(FSP_FSCTL_DELETE) SYM(FSP_FSCTL_TRANSACT) SYM(FSP_FSCTL_WORK) default: diff --git a/src/sys/devctl.c b/src/sys/devctl.c index 9b892362..56214417 100644 --- a/src/sys/devctl.c +++ b/src/sys/devctl.c @@ -8,13 +8,13 @@ static NTSTATUS FspFsvolDeviceControl( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete; FSP_DRIVER_DISPATCH FspDeviceControl; -FSP_IOCMPL_DISPATCH FspDeviceControlComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolDeviceControl) +#pragma alloc_text(PAGE, FspFsvolDeviceControlComplete) #pragma alloc_text(PAGE, FspDeviceControl) -#pragma alloc_text(PAGE, FspDeviceControlComplete) #endif static NTSTATUS FspFsvolDeviceControl( @@ -25,13 +25,19 @@ static NTSTATUS FspFsvolDeviceControl( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolDeviceControlComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspDeviceControl( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_DEVICE_CONTROL == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -42,11 +48,3 @@ NTSTATUS FspDeviceControl( FSP_LEAVE_MJ("%s", ""); } - -VOID FspDeviceControlComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/device.c b/src/sys/device.c index 62205799..e4339bb4 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -15,29 +15,21 @@ NTSTATUS FspDeviceCreate(UINT32 Kind, ULONG ExtraSize, PDEVICE_OBJECT *PDeviceObject); VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject); VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject); -static NTSTATUS FspFsctlDeviceInit(PDEVICE_OBJECT DeviceObject); -static VOID FspFsctlDeviceInitComplete(PDEVICE_OBJECT DeviceObject); -static VOID FspFsctlDeviceFini(PDEVICE_OBJECT DeviceObject); -static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject); -static VOID FspFsvrtDeviceInitComplete(PDEVICE_OBJECT DeviceObject); -static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject); +BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject); +VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject); +PVOID FspDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier); +PVOID FspDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PVOID Context, + FSP_DEVICE_GENERIC_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); +VOID FspDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, + PBOOLEAN PDeleted); +static RTL_AVL_COMPARE_ROUTINE FspDeviceCompareElement; +static RTL_AVL_ALLOCATE_ROUTINE FspDeviceAllocateElement; +static RTL_AVL_FREE_ROUTINE FspDeviceFreeElement; static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject); static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject); static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject); -BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject); -VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject); -VOID FspFsctlDeviceVolumeCreated(PDEVICE_OBJECT DeviceObject); -VOID FspFsctlDeviceVolumeDeleted(PDEVICE_OBJECT DeviceObject); -static IO_TIMER_ROUTINE FspFsvrtDeviceTimerRoutine; -static WORKER_THREAD_ROUTINE FspFsvrtDeviceExpirationRoutine; -PVOID FspFsvolDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier); -PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PVOID Context, - FSP_DEVICE_GENERIC_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); -VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, - PBOOLEAN PDeleted); -static RTL_AVL_COMPARE_ROUTINE FspFsvolDeviceCompareElement; -static RTL_AVL_ALLOCATE_ROUTINE FspFsvolDeviceAllocateElement; -static RTL_AVL_FREE_ROUTINE FspFsvolDeviceFreeElement; +static IO_TIMER_ROUTINE FspFsvolDeviceTimerRoutine; +static WORKER_THREAD_ROUTINE FspFsvolDeviceExpirationRoutine; NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount); VOID FspDeviceDeleteList( @@ -49,23 +41,15 @@ VOID FspDeviceDeleteAll(VOID); #pragma alloc_text(PAGE, FspDeviceCreate) #pragma alloc_text(PAGE, FspDeviceInitComplete) #pragma alloc_text(PAGE, FspDeviceDelete) -#pragma alloc_text(PAGE, FspFsctlDeviceInit) -#pragma alloc_text(PAGE, FspFsctlDeviceInitComplete) -#pragma alloc_text(PAGE, FspFsctlDeviceFini) -#pragma alloc_text(PAGE, FspFsvrtDeviceInit) -#pragma alloc_text(PAGE, FspFsvrtDeviceInitComplete) -#pragma alloc_text(PAGE, FspFsvrtDeviceFini) +#pragma alloc_text(PAGE, FspDeviceLookupContext) +#pragma alloc_text(PAGE, FspDeviceInsertContext) +#pragma alloc_text(PAGE, FspDeviceDeleteContext) +#pragma alloc_text(PAGE, FspDeviceCompareElement) +#pragma alloc_text(PAGE, FspDeviceAllocateElement) +#pragma alloc_text(PAGE, FspDeviceFreeElement) #pragma alloc_text(PAGE, FspFsvolDeviceInit) #pragma alloc_text(PAGE, FspFsvolDeviceInitComplete) #pragma alloc_text(PAGE, FspFsvolDeviceFini) -#pragma alloc_text(PAGE, FspFsctlDeviceVolumeCreated) -#pragma alloc_text(PAGE, FspFsctlDeviceVolumeDeleted) -#pragma alloc_text(PAGE, FspFsvolDeviceLookupContext) -#pragma alloc_text(PAGE, FspFsvolDeviceInsertContext) -#pragma alloc_text(PAGE, FspFsvolDeviceDeleteContext) -#pragma alloc_text(PAGE, FspFsvolDeviceCompareElement) -#pragma alloc_text(PAGE, FspFsvolDeviceAllocateElement) -#pragma alloc_text(PAGE, FspFsvolDeviceFreeElement) #pragma alloc_text(PAGE, FspDeviceCopyList) #pragma alloc_text(PAGE, FspDeviceDeleteList) #pragma alloc_text(PAGE, FspDeviceDeleteAll) @@ -89,10 +73,10 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize, DeviceExtensionSize = sizeof(FSP_FSVOL_DEVICE_EXTENSION); break; case FspFsvrtDeviceExtensionKind: - DeviceExtensionSize = sizeof(FSP_FSVRT_DEVICE_EXTENSION); + DeviceExtensionSize = 0; break; case FspFsctlDeviceExtensionKind: - DeviceExtensionSize = sizeof(FSP_FSCTL_DEVICE_EXTENSION); + DeviceExtensionSize = 0; break; default: ASSERT(0); @@ -117,6 +101,8 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize, KeInitializeSpinLock(&DeviceExtension->SpinLock); DeviceExtension->RefCount = 1; ExInitializeResourceLite(&DeviceExtension->Resource); + RtlInitializeGenericTableAvl(&DeviceExtension->GenericTable, + FspDeviceCompareElement, FspDeviceAllocateElement, FspDeviceFreeElement, 0); DeviceExtension->Kind = Kind; switch (Kind) @@ -125,15 +111,24 @@ NTSTATUS FspDeviceCreateSecure(UINT32 Kind, ULONG ExtraSize, Result = FspFsvolDeviceInit(DeviceObject); break; case FspFsvrtDeviceExtensionKind: - Result = FspFsvrtDeviceInit(DeviceObject); break; case FspFsctlDeviceExtensionKind: - Result = FspFsctlDeviceInit(DeviceObject); break; } if (!NT_SUCCESS(Result)) { +#if 0 + /* FspDeviceFreeElement is now a no-op, so this is no longer necessary */ + /* + * Enumerate and delete all entries in the GenericTable. + * There is no need to protect accesses to the table as we are in the device destructor. + */ + FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Element; + while (0 != (Element = RtlGetElementGenericTableAvl(&DeviceExtension->GenericTable, 0))) + RtlDeleteElementGenericTableAvl(&DeviceExtension->GenericTable, &Element->Identifier); +#endif + ExDeleteResourceLite(&DeviceExtension->Resource); IoDeleteDevice(DeviceObject); } @@ -164,10 +159,8 @@ VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject) FspFsvolDeviceInitComplete(DeviceObject); break; case FspFsvrtDeviceExtensionKind: - FspFsvrtDeviceInitComplete(DeviceObject); break; case FspFsctlDeviceExtensionKind: - FspFsctlDeviceInitComplete(DeviceObject); break; default: ASSERT(0); @@ -189,128 +182,27 @@ VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject) FspFsvolDeviceFini(DeviceObject); break; case FspFsvrtDeviceExtensionKind: - FspFsvrtDeviceFini(DeviceObject); break; case FspFsctlDeviceExtensionKind: - FspFsctlDeviceFini(DeviceObject); break; default: ASSERT(0); return; } - ExDeleteResourceLite(&DeviceExtension->Resource); - - IoDeleteDevice(DeviceObject); -} - -static NTSTATUS FspFsctlDeviceInit(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); - - return STATUS_SUCCESS; -} - -static VOID FspFsctlDeviceInitComplete(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); -} - -static VOID FspFsctlDeviceFini(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); -} - -static NTSTATUS FspFsvrtDeviceInit(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); - - NTSTATUS Result; - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); - - /* initialize our timer routine */ - Result = IoInitializeTimer(DeviceObject, FspFsvrtDeviceTimerRoutine, 0); - if (!NT_SUCCESS(Result)) - return Result; - - FspIoqInitialize(&FsvrtDeviceExtension->Ioq); - KeInitializeSpinLock(&FsvrtDeviceExtension->ExpirationLock); - ExInitializeWorkItem(&FsvrtDeviceExtension->ExpirationWorkItem, - FspFsvrtDeviceExpirationRoutine, DeviceObject); - - FsvrtDeviceExtension->SwapVpb = FspAllocNonPagedExternal(sizeof *FsvrtDeviceExtension->SwapVpb); - if (0 == FsvrtDeviceExtension->SwapVpb) - return STATUS_INSUFFICIENT_RESOURCES; - RtlZeroMemory(FsvrtDeviceExtension->SwapVpb, sizeof *FsvrtDeviceExtension->SwapVpb); - - return STATUS_SUCCESS; -} - -static VOID FspFsvrtDeviceInitComplete(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); - - IoStartTimer(DeviceObject); -} - -static VOID FspFsvrtDeviceFini(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); - - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); - - /* - * First things first: stop our timer. - * - * Our IoTimer routine will NOT be called again after IoStopTimer() returns. - * However a work item may be in flight. For this reason our IoTimer routine - * does an ObReferenceObject() on our DeviceObject before queueing work items. - */ - IoStopTimer(DeviceObject); - - if (0 != FsvrtDeviceExtension->SwapVpb) - FspFreeExternal(FsvrtDeviceExtension->SwapVpb); -} - -static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); - - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - - RtlInitializeGenericTableAvl(&FsvolDeviceExtension->GenericTable, - FspFsvolDeviceCompareElement, FspFsvolDeviceAllocateElement, FspFsvolDeviceFreeElement, 0); - - return STATUS_SUCCESS; -} - -static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); -} - -static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); - - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - #if 0 - /* FspFsvolDeviceFreeElement is now a no-op, so this is no longer necessary */ + /* FspDeviceFreeElement is now a no-op, so this is no longer necessary */ /* * Enumerate and delete all entries in the GenericTable. * There is no need to protect accesses to the table as we are in the device destructor. */ FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Element; - while (0 != (Element = RtlGetElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, 0))) - RtlDeleteElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, &Element->Identifier); + while (0 != (Element = RtlGetElementGenericTableAvl(&DeviceExtension->GenericTable, 0))) + RtlDeleteElementGenericTableAvl(&DeviceExtension->GenericTable, &Element->Identifier); #endif - /* - * Dereference the virtual volume device so that it can now go away. - */ - if (0 != FsvolDeviceExtension->FsvrtDeviceObject) - ObDereferenceObject(FsvolDeviceExtension->FsvrtDeviceObject); + ExDeleteResourceLite(&DeviceExtension->Resource); + IoDeleteDevice(DeviceObject); } BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject) @@ -352,144 +244,60 @@ VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject) FspDeviceDelete(DeviceObject); } -VOID FspFsctlDeviceVolumeCreated(PDEVICE_OBJECT DeviceObject) +PVOID FspDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier) { PAGED_CODE(); - ASSERT(FspFsctlDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind); - ASSERT(ExIsResourceAcquiredExclusiveLite(&FspDeviceExtension(DeviceObject)->Resource)); - -#if 1 - FspFsctlDeviceExtension(DeviceObject)->FsvrtDeviceObjectCount++; -#else - ULONG FsvrtDeviceObjectCount = FspFsctlDeviceExtension(DeviceObject)->FsvrtDeviceObjectCount++; - if (0 == FsvrtDeviceObjectCount) - IoRegisterFileSystem(DeviceObject); -#endif -} - -VOID FspFsctlDeviceVolumeDeleted(PDEVICE_OBJECT DeviceObject) -{ - PAGED_CODE(); - - ASSERT(FspFsctlDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind); - ASSERT(ExIsResourceAcquiredExclusiveLite(&FspDeviceExtension(DeviceObject)->Resource)); - -#if 1 - --FspFsctlDeviceExtension(DeviceObject)->FsvrtDeviceObjectCount; -#else - ULONG FsvrtDeviceObjectCount = --FspFsctlDeviceExtension(DeviceObject)->FsvrtDeviceObjectCount; - if (0 == FsvrtDeviceObjectCount) - IoUnregisterFileSystem(DeviceObject); -#endif -} - -static VOID FspFsvrtDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context) -{ - // !PAGED_CODE(); - - /* - * This routine runs at DPC level. Reference our DeviceObject and queue a work item - * so that we can do our processing at Passive level. Only do so if the work item - * is not already in flight (otherwise we could requeue the same work item). - */ - - ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); - - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); - - KeAcquireSpinLockAtDpcLevel(&FsvrtDeviceExtension->ExpirationLock); - if (!FsvrtDeviceExtension->ExpirationInProgress) - { - FsvrtDeviceExtension->ExpirationInProgress = TRUE; - ObReferenceObject(DeviceObject); - ExQueueWorkItem(&FsvrtDeviceExtension->ExpirationWorkItem, DelayedWorkQueue); - } - KeReleaseSpinLockFromDpcLevel(&FsvrtDeviceExtension->ExpirationLock); -} - -static VOID FspFsvrtDeviceExpirationRoutine(PVOID Context) -{ - // !PAGED_CODE(); - - PDEVICE_OBJECT DeviceObject = Context; - if (FspDeviceRetain(DeviceObject)) - try - { - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); - LARGE_INTEGER Timeout; - KIRQL Irql; - - Timeout.QuadPart = FsvrtDeviceExtension->VolumeParams.IrpTimeout * 10000; - /* convert millis to nanos */ - FspIoqRemoveExpired(&FsvrtDeviceExtension->Ioq, &Timeout); - - KeAcquireSpinLock(&FsvrtDeviceExtension->ExpirationLock, &Irql); - FsvrtDeviceExtension->ExpirationInProgress = FALSE; - KeReleaseSpinLock(&FsvrtDeviceExtension->ExpirationLock, Irql); - } - finally - { - FspDeviceRelease(DeviceObject); - } - - ObDereferenceObject(DeviceObject); -} - -PVOID FspFsvolDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier) -{ - PAGED_CODE(); - - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - ASSERT(FspFsvolDeviceExtensionKind == FsvolDeviceExtension->Base.Kind); - ASSERT(ExIsResourceAcquiredExclusiveLite(&FsvolDeviceExtension->Base.Resource)); + FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); + ASSERT(ExIsResourceAcquiredExclusiveLite(&DeviceExtension->Resource)); FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Result; - Result = RtlLookupElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, &Identifier); + Result = RtlLookupElementGenericTableAvl(&DeviceExtension->GenericTable, &Identifier); return 0 != Result ? Result->Context : 0; } -PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PVOID Context, +PVOID FspDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PVOID Context, FSP_DEVICE_GENERIC_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted) { PAGED_CODE(); - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - ASSERT(FspFsvolDeviceExtensionKind == FsvolDeviceExtension->Base.Kind); - ASSERT(ExIsResourceAcquiredExclusiveLite(&FsvolDeviceExtension->Base.Resource)); + FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); + ASSERT(ExIsResourceAcquiredExclusiveLite(&DeviceExtension->Resource)); + ASSERT(0 != ElementStorage); FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA *Result, Element = { 0 }; Element.Identifier = Identifier; Element.Context = Context; - FsvolDeviceExtension->GenericTableElementStorage = ElementStorage; - Result = RtlInsertElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, + DeviceExtension->GenericTableElementStorage = ElementStorage; + Result = RtlInsertElementGenericTableAvl(&DeviceExtension->GenericTable, &Element, sizeof Element, PInserted); - FsvolDeviceExtension->GenericTableElementStorage = 0; + DeviceExtension->GenericTableElementStorage = 0; - return 0 != Result ? Result->Context : 0; + ASSERT(0 != Result); + + return Result->Context; } -VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, +VOID FspDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PBOOLEAN PDeleted) { PAGED_CODE(); - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - ASSERT(FspFsvolDeviceExtensionKind == FsvolDeviceExtension->Base.Kind); - ASSERT(ExIsResourceAcquiredExclusiveLite(&FsvolDeviceExtension->Base.Resource)); + FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); + ASSERT(ExIsResourceAcquiredExclusiveLite(&DeviceExtension->Resource)); BOOLEAN Deleted; - Deleted = RtlDeleteElementGenericTableAvl(&FsvolDeviceExtension->GenericTable, &Identifier); + Deleted = RtlDeleteElementGenericTableAvl(&DeviceExtension->GenericTable, &Identifier); if (0 != PDeleted) *PDeleted = Deleted; } -static RTL_GENERIC_COMPARE_RESULTS NTAPI FspFsvolDeviceCompareElement( +static RTL_GENERIC_COMPARE_RESULTS NTAPI FspDeviceCompareElement( PRTL_AVL_TABLE Table, PVOID FirstElement, PVOID SecondElement) { PAGED_CODE(); @@ -503,25 +311,149 @@ static RTL_GENERIC_COMPARE_RESULTS NTAPI FspFsvolDeviceCompareElement( return GenericEqual; } -static PVOID NTAPI FspFsvolDeviceAllocateElement( +static PVOID NTAPI FspDeviceAllocateElement( PRTL_AVL_TABLE Table, CLONG ByteSize) { PAGED_CODE(); - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = - CONTAINING_RECORD(Table, FSP_FSVOL_DEVICE_EXTENSION, GenericTable); + FSP_DEVICE_EXTENSION *DeviceExtension = + CONTAINING_RECORD(Table, FSP_DEVICE_EXTENSION, GenericTable); ASSERT(sizeof(FSP_DEVICE_GENERIC_TABLE_ELEMENT) == ByteSize); - return FsvolDeviceExtension->GenericTableElementStorage; + return DeviceExtension->GenericTableElementStorage; } -static VOID NTAPI FspFsvolDeviceFreeElement( +static VOID NTAPI FspDeviceFreeElement( PRTL_AVL_TABLE Table, PVOID Buffer) { PAGED_CODE(); } +static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + + /* allocate a spare VPB in case we are mounted on an fsvrt */ + if (FILE_DEVICE_DISK_FILE_SYSTEM == DeviceObject->DeviceType) + { + FsvolDeviceExtension->SwapVpb = FspAllocNonPagedExternal(sizeof *FsvolDeviceExtension->SwapVpb); + if (0 == FsvolDeviceExtension->SwapVpb) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(FsvolDeviceExtension->SwapVpb, sizeof *FsvolDeviceExtension->SwapVpb); + } + + /* setup our Ioq and expiration fields */ + FspIoqInitialize(&FsvolDeviceExtension->Ioq, FspIopCompleteCanceledIrp); + KeInitializeSpinLock(&FsvolDeviceExtension->ExpirationLock); + ExInitializeWorkItem(&FsvolDeviceExtension->ExpirationWorkItem, + FspFsvolDeviceExpirationRoutine, DeviceObject); + + /* initialize our timer routine */ + Result = IoInitializeTimer(DeviceObject, FspFsvolDeviceTimerRoutine, 0); + if (!NT_SUCCESS(Result)) + return Result; + + return STATUS_SUCCESS; +} + +static VOID FspFsvolDeviceInitComplete(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + + /* + * Reference the virtual volume device so that it will not go away while we are using it. + */ + if (0 != FsvolDeviceExtension->FsvrtDeviceObject) + ObReferenceObject(FsvolDeviceExtension->FsvrtDeviceObject); + + /* start our expiration timer */ + IoStartTimer(DeviceObject); +} + +static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + + /* + * First things first: stop our timer. + * + * Our IoTimer routine will NOT be called again after IoStopTimer() returns. + * However a work item may be in flight. For this reason our IoTimer routine + * does an ObReferenceObject() on our DeviceObject before queueing work items. + */ + IoStopTimer(DeviceObject); + + /* + * Dereference the virtual volume device so that it can now go away. + */ + if (0 != FsvolDeviceExtension->FsvrtDeviceObject) + ObDereferenceObject(FsvolDeviceExtension->FsvrtDeviceObject); + + /* free the spare VPB if we still have it */ + if (0 != FsvolDeviceExtension->SwapVpb) + FspFreeExternal(FsvolDeviceExtension->SwapVpb); +} + +static VOID FspFsvolDeviceTimerRoutine(PDEVICE_OBJECT DeviceObject, PVOID Context) +{ + // !PAGED_CODE(); + + /* + * This routine runs at DPC level. Reference our DeviceObject and queue a work item + * so that we can do our processing at Passive level. Only do so if the work item + * is not already in flight (otherwise we could requeue the same work item). + */ + + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + + KeAcquireSpinLockAtDpcLevel(&FsvolDeviceExtension->ExpirationLock); + if (!FsvolDeviceExtension->ExpirationInProgress) + { + FsvolDeviceExtension->ExpirationInProgress = TRUE; + ObReferenceObject(DeviceObject); + ExQueueWorkItem(&FsvolDeviceExtension->ExpirationWorkItem, DelayedWorkQueue); + } + KeReleaseSpinLockFromDpcLevel(&FsvolDeviceExtension->ExpirationLock); +} + +static VOID FspFsvolDeviceExpirationRoutine(PVOID Context) +{ + // !PAGED_CODE(); + + PDEVICE_OBJECT DeviceObject = Context; + if (FspDeviceRetain(DeviceObject)) + try + { + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + LARGE_INTEGER Timeout; + KIRQL Irql; + + Timeout.QuadPart = FsvolDeviceExtension->VolumeParams.IrpTimeout * 10000; + /* convert millis to nanos */ + FspIoqRemoveExpired(&FsvolDeviceExtension->Ioq, &Timeout); + + KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql); + FsvolDeviceExtension->ExpirationInProgress = FALSE; + KeReleaseSpinLock(&FsvolDeviceExtension->ExpirationLock, Irql); + } + finally + { + FspDeviceRelease(DeviceObject); + } + + ObDereferenceObject(DeviceObject); +} + NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount) { diff --git a/src/sys/dirctl.c b/src/sys/dirctl.c index c0e7772c..43f281e6 100644 --- a/src/sys/dirctl.c +++ b/src/sys/dirctl.c @@ -8,13 +8,13 @@ static NTSTATUS FspFsvolDirectoryControl( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolDirectoryControlComplete; FSP_DRIVER_DISPATCH FspDirectoryControl; -FSP_IOCMPL_DISPATCH FspDirectoryControlComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolDirectoryControl) +#pragma alloc_text(PAGE, FspFsvolDirectoryControlComplete) #pragma alloc_text(PAGE, FspDirectoryControl) -#pragma alloc_text(PAGE, FspDirectoryControlComplete) #endif static NTSTATUS FspFsvolDirectoryControl( @@ -25,13 +25,19 @@ static NTSTATUS FspFsvolDirectoryControl( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolDirectoryControlComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspDirectoryControl( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_DIRECTORY_CONTROL == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -42,11 +48,3 @@ NTSTATUS FspDirectoryControl( FSP_LEAVE_MJ("%s", ""); } - -VOID FspDirectoryControlComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/driver.c b/src/sys/driver.c index cb7a0e7f..ce382ba9 100644 --- a/src/sys/driver.c +++ b/src/sys/driver.c @@ -58,7 +58,6 @@ NTSTATUS DriverEntry( DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = FspDirectoryControl; DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFileSystemControl; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FspDeviceControl; - DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = FspInternalDeviceControl; DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = FspShutdown; DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = FspLockControl; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FspCleanup; @@ -71,24 +70,23 @@ NTSTATUS DriverEntry( /* setup the I/O completion functions */ FspIopCompleteFunction[IRP_MJ_CREATE] = FspFsvolCreateComplete; FspIopCompleteFunction[IRP_MJ_CLOSE] = FspFsvolCloseComplete; - FspIopCompleteFunction[IRP_MJ_READ] = FspReadComplete; - FspIopCompleteFunction[IRP_MJ_WRITE] = FspWriteComplete; - FspIopCompleteFunction[IRP_MJ_QUERY_INFORMATION] = FspQueryInformationComplete; - FspIopCompleteFunction[IRP_MJ_SET_INFORMATION] = FspSetInformationComplete; - FspIopCompleteFunction[IRP_MJ_QUERY_EA] = FspQueryEaComplete; - FspIopCompleteFunction[IRP_MJ_SET_EA] = FspSetEaComplete; - FspIopCompleteFunction[IRP_MJ_FLUSH_BUFFERS] = FspFlushBuffersComplete; - FspIopCompleteFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = FspQueryVolumeInformationComplete; - FspIopCompleteFunction[IRP_MJ_SET_VOLUME_INFORMATION] = FspSetVolumeInformationComplete; - FspIopCompleteFunction[IRP_MJ_DIRECTORY_CONTROL] = FspDirectoryControlComplete; - FspIopCompleteFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFileSystemControlComplete; - FspIopCompleteFunction[IRP_MJ_DEVICE_CONTROL] = FspDeviceControlComplete; - FspIopCompleteFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = FspFsvolInternalDeviceControlComplete; - FspIopCompleteFunction[IRP_MJ_SHUTDOWN] = FspShutdownComplete; - FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspLockControlComplete; + FspIopCompleteFunction[IRP_MJ_READ] = FspFsvolReadComplete; + FspIopCompleteFunction[IRP_MJ_WRITE] = FspFsvolWriteComplete; + FspIopCompleteFunction[IRP_MJ_QUERY_INFORMATION] = FspFsvolQueryInformationComplete; + FspIopCompleteFunction[IRP_MJ_SET_INFORMATION] = FspFsvolSetInformationComplete; + FspIopCompleteFunction[IRP_MJ_QUERY_EA] = FspFsvolQueryEaComplete; + FspIopCompleteFunction[IRP_MJ_SET_EA] = FspFsvolSetEaComplete; + FspIopCompleteFunction[IRP_MJ_FLUSH_BUFFERS] = FspFsvolFlushBuffersComplete; + FspIopCompleteFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = FspFsvolQueryVolumeInformationComplete; + FspIopCompleteFunction[IRP_MJ_SET_VOLUME_INFORMATION] = FspFsvolSetVolumeInformationComplete; + FspIopCompleteFunction[IRP_MJ_DIRECTORY_CONTROL] = FspFsvolDirectoryControlComplete; + FspIopCompleteFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFsvolFileSystemControlComplete; + FspIopCompleteFunction[IRP_MJ_DEVICE_CONTROL] = FspFsvolDeviceControlComplete; + FspIopCompleteFunction[IRP_MJ_SHUTDOWN] = FspFsvolShutdownComplete; + FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete; FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete; - FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspQuerySecurityComplete; - FspIopCompleteFunction[IRP_MJ_SET_SECURITY] = FspSetSecurityComplete; + FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete; + FspIopCompleteFunction[IRP_MJ_SET_SECURITY] = FspFsvolSetSecurityComplete; /* setup fast I/O and resource acquisition */ static FAST_IO_DISPATCH FspFastIoDispatch = { 0 }; @@ -124,18 +122,15 @@ NTSTATUS DriverEntry( DriverObject->FastIoDispatch = &FspFastIoDispatch; /* - * Register our devices as file systems. We do this here to simplify file system - * registration/unregistration, although this makes our driver unloadable from the - * get go. + * Register our "disk" device as a file system. We do not register our "net" device + * as a file system, but we register with the MUP instead at a later time. * - * Unfortunately a call to IoRegisterFileSystem(), even if followed by a call to - * IoUnregistreFileSystem(), makes the driver unloadable. We attempted to move - * the register/unregister calls to FspFsctlDeviceVolume{Created,Deleted}, but it - * did not make any difference with regards to making the driver unloadable. Hence - * we stick to the simpler scheme of doing registration here. + * Please note that the call below makes our driver unloadable. In fact the driver + * remains unloadable even if we issue an IoUnregisterFileSystem() call immediately + * after our IoRegisterFileSystem() call! Some system component appears to keep an + * extra reference to our device somewhere. */ IoRegisterFileSystem(FspFsctlDiskDeviceObject); - IoRegisterFileSystem(FspFsctlNetDeviceObject); #pragma prefast(suppress:28175, "We are in DriverEntry: ok to access DriverName") FSP_LEAVE("DriverName=\"%wZ\", RegistryPath=\"%wZ\"", diff --git a/src/sys/driver.h b/src/sys/driver.h index 0b9df793..9184a8de 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -13,6 +13,10 @@ #include #include +/* disable warnings */ +#pragma warning(disable:4100) /* unreferenced formal parameter */ +#pragma warning(disable:4200) /* zero-sized array in struct/union */ + #define DRIVER_NAME "WinFsp" /* IoCreateDeviceSecure default SDDL's */ @@ -21,6 +25,11 @@ #define FSP_FSVRT_DEVICE_SDDL "D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GR;;;WD)" /* System:GENERIC_ALL, Administrators:GENERIC_ALL, World:GENERIC_READ */ +/* misc macros */ +#define FSP_ALLOC_INTERNAL_TAG 'IpsF' +#define FSP_ALLOC_EXTERNAL_TAG 'XpsF' +#define FSP_IO_INCREMENT IO_NETWORK_INCREMENT + /* DEBUGLOG */ #if DBG #define DEBUGLOG(fmt, ...) \ @@ -111,15 +120,12 @@ if (0 == (IrpSp->Control & SL_PENDING_RETURNED))\ { \ /* if the IRP has not been marked pending already */\ - ASSERT(FspFsvolDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind);\ FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =\ FspFsvolDeviceExtension(DeviceObject);\ - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension =\ - FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject);\ - if (!FspIoqPostIrp(&FsvrtDeviceExtension->Ioq, Irp))\ + if (!FspIoqPostIrp(&FsvolDeviceExtension->Ioq, Irp))\ { \ /* this can only happen if the Ioq was stopped */\ - ASSERT(FspIoqStopped(&FsvrtDeviceExtension->Ioq));\ + ASSERT(FspIoqStopped(&FsvolDeviceExtension->Ioq));\ FspIopCompleteIrp(Irp, Result = STATUS_CANCELLED);\ } \ } \ @@ -166,15 +172,6 @@ goto fsp_leave_label; \ } while (0,0) -/* misc macros */ -#define FSP_ALLOC_INTERNAL_TAG 'IpsF' -#define FSP_ALLOC_EXTERNAL_TAG 'XpsF' -#define FSP_IO_INCREMENT IO_NETWORK_INCREMENT - -/* disable warnings */ -#pragma warning(disable:4100) /* unreferenced formal parameter */ -#pragma warning(disable:4200) /* zero-sized array in struct/union */ - /* driver major functions */ _Function_class_(DRIVER_DISPATCH) _IRQL_requires_max_(APC_LEVEL) @@ -189,7 +186,6 @@ _Dispatch_type_(IRP_MJ_DEVICE_CONTROL) FSP_DRIVER_DISPATCH FspDeviceControl; _Dispatch_type_(IRP_MJ_DIRECTORY_CONTROL) FSP_DRIVER_DISPATCH FspDirectoryControl; _Dispatch_type_(IRP_MJ_FILE_SYSTEM_CONTROL) FSP_DRIVER_DISPATCH FspFileSystemControl; _Dispatch_type_(IRP_MJ_FLUSH_BUFFERS) FSP_DRIVER_DISPATCH FspFlushBuffers; -_Dispatch_type_(IRP_MJ_INTERNAL_DEVICE_CONTROL) FSP_DRIVER_DISPATCH FspInternalDeviceControl; _Dispatch_type_(IRP_MJ_LOCK_CONTROL) FSP_DRIVER_DISPATCH FspLockControl; _Dispatch_type_(IRP_MJ_QUERY_EA) FSP_DRIVER_DISPATCH FspQueryEa; _Dispatch_type_(IRP_MJ_QUERY_INFORMATION) FSP_DRIVER_DISPATCH FspQueryInformation; @@ -216,28 +212,25 @@ FSP_IOPREP_DISPATCH FspFsvolCreatePrepare; FSP_IOCMPL_DISPATCH FspFsvolCleanupComplete; FSP_IOCMPL_DISPATCH FspFsvolCloseComplete; FSP_IOCMPL_DISPATCH FspFsvolCreateComplete; -FSP_IOCMPL_DISPATCH FspDeviceControlComplete; -FSP_IOCMPL_DISPATCH FspDirectoryControlComplete; -FSP_IOCMPL_DISPATCH FspFileSystemControlComplete; -FSP_IOCMPL_DISPATCH FspFlushBuffersComplete; -FSP_IOCMPL_DISPATCH FspFsvolInternalDeviceControlComplete; -FSP_IOCMPL_DISPATCH FspLockControlComplete; -FSP_IOCMPL_DISPATCH FspQueryEaComplete; -FSP_IOCMPL_DISPATCH FspQueryInformationComplete; -FSP_IOCMPL_DISPATCH FspQuerySecurityComplete; -FSP_IOCMPL_DISPATCH FspQueryVolumeInformationComplete; -FSP_IOCMPL_DISPATCH FspReadComplete; -FSP_IOCMPL_DISPATCH FspSetEaComplete; -FSP_IOCMPL_DISPATCH FspSetInformationComplete; -FSP_IOCMPL_DISPATCH FspSetSecurityComplete; -FSP_IOCMPL_DISPATCH FspSetVolumeInformationComplete; -FSP_IOCMPL_DISPATCH FspShutdownComplete; -FSP_IOCMPL_DISPATCH FspWriteComplete; +FSP_IOCMPL_DISPATCH FspFsvolDeviceControlComplete; +FSP_IOCMPL_DISPATCH FspFsvolDirectoryControlComplete; +FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete; +FSP_IOCMPL_DISPATCH FspFsvolFlushBuffersComplete; +FSP_IOCMPL_DISPATCH FspFsvolLockControlComplete; +FSP_IOCMPL_DISPATCH FspFsvolQueryEaComplete; +FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete; +FSP_IOCMPL_DISPATCH FspFsvolQuerySecurityComplete; +FSP_IOCMPL_DISPATCH FspFsvolQueryVolumeInformationComplete; +FSP_IOCMPL_DISPATCH FspFsvolReadComplete; +FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete; +FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete; +FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete; +FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete; +FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete; +FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; -/* fast I/O */ +/* fast I/O and resource acquisition */ FAST_IO_CHECK_IF_POSSIBLE FspFastIoCheckIfPossible; - -/* resource acquisition */ FAST_IO_ACQUIRE_FILE FspAcquireFileForNtCreateSection; FAST_IO_RELEASE_FILE FspReleaseFileForNtCreateSection; FAST_IO_ACQUIRE_FOR_MOD_WRITE FspAcquireForModWrite; @@ -245,6 +238,52 @@ FAST_IO_RELEASE_FOR_MOD_WRITE FspReleaseForModWrite; FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush; FAST_IO_RELEASE_FOR_CCFLUSH FspReleaseForCcFlush; +/* memory allocation */ +static inline +PVOID FspAlloc(SIZE_T Size) +{ + return ExAllocatePoolWithTag(PagedPool, Size, FSP_ALLOC_INTERNAL_TAG); +} +static inline +PVOID FspAllocNonPaged(SIZE_T Size) +{ + return ExAllocatePoolWithTag(NonPagedPool, Size, FSP_ALLOC_INTERNAL_TAG); +} +static inline +VOID FspFree(PVOID Pointer) +{ + ExFreePoolWithTag(Pointer, FSP_ALLOC_INTERNAL_TAG); +} +static inline +PVOID FspAllocExternal(SIZE_T Size) +{ + return ExAllocatePoolWithTag(PagedPool, Size, FSP_ALLOC_EXTERNAL_TAG); +} +static inline +PVOID FspAllocNonPagedExternal(SIZE_T Size) +{ + return ExAllocatePoolWithTag(NonPagedPool, Size, FSP_ALLOC_EXTERNAL_TAG); +} +static inline +VOID FspFreeExternal(PVOID Pointer) +{ + ExFreePool(Pointer); +} + +/* utility: GUIDs */ +NTSTATUS FspCreateGuid(GUID *Guid); + +/* utility: delayed work queue */ +typedef struct +{ + KTIMER Timer; + KDPC Dpc; + WORK_QUEUE_ITEM WorkQueueItem; +} FSP_WORK_ITEM_WITH_DELAY; +VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, + PWORKER_THREAD_ROUTINE Routine, PVOID Context); +VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout); + /* IRP context */ #define FspIrpTimestamp(Irp) \ (*(ULONGLONG *)&(Irp)->Tail.Overlay.DriverContext[0]) @@ -261,8 +300,9 @@ typedef struct KEVENT PendingIrpEvent; LIST_ENTRY PendingIrpList, ProcessIrpList; IO_CSQ PendingIoCsq, ProcessIoCsq; + VOID (*CompleteCanceledIrp)(PIRP Irp); } FSP_IOQ; -VOID FspIoqInitialize(FSP_IOQ *Ioq); +VOID FspIoqInitialize(FSP_IOQ *Ioq, VOID (*CompleteCanceledIrp)(PIRP Irp)); VOID FspIoqStop(FSP_IOQ *Ioq); BOOLEAN FspIoqStopped(FSP_IOQ *Ioq); VOID FspIoqRemoveExpired(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout); @@ -289,10 +329,21 @@ VOID FspIopCompleteIrp(PIRP Irp, NTSTATUS Result) { FspIopCompleteIrpEx(Irp, Result, TRUE); } +VOID FspIopCompleteCanceledIrp(PIRP Irp); NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request); VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); /* device management */ +typedef struct +{ + UINT64 Identifier; + PVOID Context; +} FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA; +typedef struct +{ + RTL_BALANCED_LINKS Header; + FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA Data; +} FSP_DEVICE_GENERIC_TABLE_ELEMENT; enum { FspFsctlDeviceExtensionKind = '\0ltC', /* file system control device (e.g. \Device\WinFsp.Disk) */ @@ -304,62 +355,32 @@ typedef struct KSPIN_LOCK SpinLock; LONG RefCount; ERESOURCE Resource; + RTL_AVL_TABLE GenericTable; + PVOID GenericTableElementStorage; UINT32 Kind; } FSP_DEVICE_EXTENSION; typedef struct -{ - FSP_DEVICE_EXTENSION Base; - ULONG FsvrtDeviceObjectCount; -} FSP_FSCTL_DEVICE_EXTENSION; -typedef struct { FSP_DEVICE_EXTENSION Base; PDEVICE_OBJECT FsctlDeviceObject; - PDEVICE_OBJECT FsvolDeviceObject; + PDEVICE_OBJECT FsvrtDeviceObject; + HANDLE MupHandle; + BOOLEAN DeletePending; + FSP_WORK_ITEM_WITH_DELAY DeleteVolumeWorkItem; + FSP_DEVICE_GENERIC_TABLE_ELEMENT ElementStorage; FSP_FSCTL_VOLUME_PARAMS VolumeParams; + PVPB SwapVpb; FSP_IOQ Ioq; KSPIN_LOCK ExpirationLock; WORK_QUEUE_ITEM ExpirationWorkItem; BOOLEAN ExpirationInProgress; - PVPB SwapVpb; - BOOLEAN Deleted; - FSP_FSCTL_DECLSPEC_ALIGN UINT8 SecurityDescriptorBuf[]; -} FSP_FSVRT_DEVICE_EXTENSION; -typedef struct -{ - FSP_DEVICE_EXTENSION Base; - PDEVICE_OBJECT FsvrtDeviceObject; - RTL_AVL_TABLE GenericTable; - PVOID GenericTableElementStorage; } FSP_FSVOL_DEVICE_EXTENSION; -typedef struct -{ - UINT64 Identifier; - PVOID Context; -} FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA; -typedef struct -{ - RTL_BALANCED_LINKS Header; - FSP_DEVICE_GENERIC_TABLE_ELEMENT_DATA Data; -} FSP_DEVICE_GENERIC_TABLE_ELEMENT; static inline FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject) { return DeviceObject->DeviceExtension; } static inline -FSP_FSCTL_DEVICE_EXTENSION *FspFsctlDeviceExtension(PDEVICE_OBJECT DeviceObject) -{ - ASSERT(FspFsctlDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind); - return DeviceObject->DeviceExtension; -} -static inline -FSP_FSVRT_DEVICE_EXTENSION *FspFsvrtDeviceExtension(PDEVICE_OBJECT DeviceObject) -{ - ASSERT(FspFsvrtDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind); - return DeviceObject->DeviceExtension; -} -static inline FSP_FSVOL_DEVICE_EXTENSION *FspFsvolDeviceExtension(PDEVICE_OBJECT DeviceObject) { ASSERT(FspFsvolDeviceExtensionKind == ((FSP_DEVICE_EXTENSION *)DeviceObject->DeviceExtension)->Kind); @@ -376,12 +397,10 @@ VOID FspDeviceInitComplete(PDEVICE_OBJECT DeviceObject); VOID FspDeviceDelete(PDEVICE_OBJECT DeviceObject); BOOLEAN FspDeviceRetain(PDEVICE_OBJECT DeviceObject); VOID FspDeviceRelease(PDEVICE_OBJECT DeviceObject); -VOID FspFsctlDeviceVolumeCreated(PDEVICE_OBJECT DeviceObject); -VOID FspFsctlDeviceVolumeDeleted(PDEVICE_OBJECT DeviceObject); -PVOID FspFsvolDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier); -PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PVOID Context, +PVOID FspDeviceLookupContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier); +PVOID FspDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PVOID Context, FSP_DEVICE_GENERIC_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); -VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, +VOID FspDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PBOOLEAN PDeleted); NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount); @@ -389,6 +408,23 @@ VOID FspDeviceDeleteList( PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount); VOID FspDeviceDeleteAll(VOID); +/* debug */ +#if DBG +BOOLEAN HasDbgBreakPoint(const char *Function); +const char *NtStatusSym(NTSTATUS Status); +const char *IrpMajorFunctionSym(UCHAR MajorFunction); +const char *IrpMinorFunctionSym(UCHAR MajorFunction, UCHAR MinorFunction); +const char *IoctlCodeSym(ULONG ControlCode); +#endif + +/* extern */ +extern PDRIVER_OBJECT FspDriverObject; +extern PDEVICE_OBJECT FspFsctlDiskDeviceObject; +extern PDEVICE_OBJECT FspFsctlNetDeviceObject; +extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; +extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; + +#if 0 /* file objects */ #define FspFileContextKind(FsContext) \ (((FSP_FILE_CONTEXT *)FsContext)->Header.NodeTypeCode) @@ -451,69 +487,6 @@ VOID FspFileContextRelease(FSP_FILE_CONTEXT *Context) FspFileContextDelete(Context); } -/* misc */ -static inline -PVOID FspAlloc(SIZE_T Size) -{ - return ExAllocatePoolWithTag(PagedPool, Size, FSP_ALLOC_INTERNAL_TAG); -} -static inline -PVOID FspAllocNonPaged(SIZE_T Size) -{ - return ExAllocatePoolWithTag(NonPagedPool, Size, FSP_ALLOC_INTERNAL_TAG); -} -static inline -VOID FspFree(PVOID Pointer) -{ - ExFreePoolWithTag(Pointer, FSP_ALLOC_INTERNAL_TAG); -} -static inline -PVOID FspAllocExternal(SIZE_T Size) -{ - return ExAllocatePoolWithTag(PagedPool, Size, FSP_ALLOC_EXTERNAL_TAG); -} -static inline -PVOID FspAllocNonPagedExternal(SIZE_T Size) -{ - return ExAllocatePoolWithTag(NonPagedPool, Size, FSP_ALLOC_EXTERNAL_TAG); -} -static inline -VOID FspFreeExternal(PVOID Pointer) -{ - ExFreePool(Pointer); -} -NTSTATUS FspCreateGuid(GUID *Guid); -BOOLEAN FspValidRelativeSecurityDescriptor( - PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG SecurityDescriptorLength, - SECURITY_INFORMATION RequiredInformation); -NTSTATUS FspSecuritySubjectContextAccessCheck( - PSECURITY_DESCRIPTOR SecurityDescriptor, ACCESS_MASK DesiredAccess, KPROCESSOR_MODE AccessMode); - -/* delayed work queue */ -typedef struct -{ - KTIMER Timer; - KDPC Dpc; - WORK_QUEUE_ITEM WorkQueueItem; -} FSP_WORK_ITEM_WITH_DELAY; -VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, - PWORKER_THREAD_ROUTINE Routine, PVOID Context); -VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout); - -/* debug */ -#if DBG -BOOLEAN HasDbgBreakPoint(const char *Function); -const char *NtStatusSym(NTSTATUS Status); -const char *IrpMajorFunctionSym(UCHAR MajorFunction); -const char *IrpMinorFunctionSym(UCHAR MajorFunction, UCHAR MinorFunction); -const char *IoctlCodeSym(ULONG ControlCode); #endif -/* extern */ -extern PDRIVER_OBJECT FspDriverObject; -extern PDEVICE_OBJECT FspFsctlDiskDeviceObject; -extern PDEVICE_OBJECT FspFsctlNetDeviceObject; -extern FSP_IOPREP_DISPATCH *FspIopPrepareFunction[]; -extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; - #endif diff --git a/src/sys/ea.c b/src/sys/ea.c index d1511cc0..4c65d9c3 100644 --- a/src/sys/ea.c +++ b/src/sys/ea.c @@ -8,20 +8,20 @@ static NTSTATUS FspFsvolQueryEa( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolQueryEaComplete; static NTSTATUS FspFsvolSetEa( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete; FSP_DRIVER_DISPATCH FspQueryEa; FSP_DRIVER_DISPATCH FspSetEa; -FSP_IOCMPL_DISPATCH FspQueryEaComplete; -FSP_IOCMPL_DISPATCH FspSetEaComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolQueryEa) +#pragma alloc_text(PAGE, FspFsvolQueryEaComplete) #pragma alloc_text(PAGE, FspFsvolSetEa) +#pragma alloc_text(PAGE, FspFsvolSetEaComplete) #pragma alloc_text(PAGE, FspQueryEa) #pragma alloc_text(PAGE, FspSetEa) -#pragma alloc_text(PAGE, FspQueryEaComplete) -#pragma alloc_text(PAGE, FspSetEaComplete) #endif static NTSTATUS FspFsvolQueryEa( @@ -32,6 +32,14 @@ static NTSTATUS FspFsvolQueryEa( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolQueryEaComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + static NTSTATUS FspFsvolSetEa( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -40,13 +48,19 @@ static NTSTATUS FspFsvolSetEa( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolSetEaComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspQueryEa( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_QUERY_EA == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -63,8 +77,6 @@ NTSTATUS FspSetEa( { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_SET_EA == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -75,19 +87,3 @@ NTSTATUS FspSetEa( FSP_LEAVE_MJ("%s", ""); } - -VOID FspQueryEaComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} - -VOID FspSetEaComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/fastio.c b/src/sys/fastio.c index a32bf2dd..a46821e4 100644 --- a/src/sys/fastio.c +++ b/src/sys/fastio.c @@ -7,9 +7,21 @@ #include FAST_IO_CHECK_IF_POSSIBLE FspFastIoCheckIfPossible; +FAST_IO_ACQUIRE_FILE FspAcquireFileForNtCreateSection; +FAST_IO_RELEASE_FILE FspReleaseFileForNtCreateSection; +FAST_IO_ACQUIRE_FOR_MOD_WRITE FspAcquireForModWrite; +FAST_IO_RELEASE_FOR_MOD_WRITE FspReleaseForModWrite; +FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush; +FAST_IO_RELEASE_FOR_CCFLUSH FspReleaseForCcFlush; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFastIoCheckIfPossible) +#pragma alloc_text(PAGE, FspAcquireFileForNtCreateSection) +#pragma alloc_text(PAGE, FspReleaseFileForNtCreateSection) +#pragma alloc_text(PAGE, FspAcquireForModWrite) +#pragma alloc_text(PAGE, FspReleaseForModWrite) +#pragma alloc_text(PAGE, FspAcquireForCcFlush) +#pragma alloc_text(PAGE, FspReleaseForCcFlush) #endif BOOLEAN FspFastIoCheckIfPossible( @@ -28,3 +40,66 @@ BOOLEAN FspFastIoCheckIfPossible( FSP_LEAVE_BOOL("%s", ""); } + +VOID FspAcquireFileForNtCreateSection( + PFILE_OBJECT FileObject) +{ + FSP_ENTER_VOID(PAGED_CODE()); + + FSP_LEAVE_VOID("%s", ""); +} + +VOID FspReleaseFileForNtCreateSection( + PFILE_OBJECT FileObject) +{ + FSP_ENTER_VOID(PAGED_CODE()); + + FSP_LEAVE_VOID("%s", ""); +} + +NTSTATUS FspAcquireForModWrite( + PFILE_OBJECT FileObject, + PLARGE_INTEGER EndingOffset, + PERESOURCE *ResourceToRelease, + PDEVICE_OBJECT DeviceObject) +{ + FSP_ENTER(PAGED_CODE()); + + Result = STATUS_NOT_IMPLEMENTED; + + FSP_LEAVE("%s", ""); +} + +NTSTATUS FspReleaseForModWrite( + PFILE_OBJECT FileObject, + PERESOURCE ResourceToRelease, + PDEVICE_OBJECT DeviceObject) +{ + FSP_ENTER(PAGED_CODE()); + + Result = STATUS_NOT_IMPLEMENTED; + + FSP_LEAVE("%s", ""); +} + +NTSTATUS FspAcquireForCcFlush( + PFILE_OBJECT FileObject, + PDEVICE_OBJECT DeviceObject) +{ + FSP_ENTER(PAGED_CODE()); + + Result = STATUS_NOT_IMPLEMENTED; + + FSP_LEAVE("%s", ""); +} + +NTSTATUS FspReleaseForCcFlush( + PFILE_OBJECT FileObject, + PDEVICE_OBJECT DeviceObject) +{ + FSP_ENTER(PAGED_CODE()); + + Result = STATUS_NOT_IMPLEMENTED; + + FSP_LEAVE("%s", ""); +} diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index 72d0385d..01242977 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -8,20 +8,20 @@ static NTSTATUS FspFsvolQueryInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolQueryInformationComplete; static NTSTATUS FspFsvolSetInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolSetInformationComplete; FSP_DRIVER_DISPATCH FspQueryInformation; FSP_DRIVER_DISPATCH FspSetInformation; -FSP_IOCMPL_DISPATCH FspQueryInformationComplete; -FSP_IOCMPL_DISPATCH FspSetInformationComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolQueryInformation) +#pragma alloc_text(PAGE, FspFsvolQueryInformationComplete) #pragma alloc_text(PAGE, FspFsvolSetInformation) +#pragma alloc_text(PAGE, FspFsvolSetInformationComplete) #pragma alloc_text(PAGE, FspQueryInformation) #pragma alloc_text(PAGE, FspSetInformation) -#pragma alloc_text(PAGE, FspQueryInformationComplete) -#pragma alloc_text(PAGE, FspSetInformationComplete) #endif static NTSTATUS FspFsvolQueryInformation( @@ -32,6 +32,14 @@ static NTSTATUS FspFsvolQueryInformation( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolQueryInformationComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + static NTSTATUS FspFsvolSetInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -40,13 +48,19 @@ static NTSTATUS FspFsvolSetInformation( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolSetInformationComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspQueryInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_QUERY_INFORMATION == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -63,8 +77,6 @@ NTSTATUS FspSetInformation( { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_SET_INFORMATION == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -75,19 +87,3 @@ NTSTATUS FspSetInformation( FSP_LEAVE_MJ("%s", ""); } - -VOID FspQueryInformationComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} - -VOID FspSetInformationComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/flush.c b/src/sys/flush.c index 181b7153..72e60658 100644 --- a/src/sys/flush.c +++ b/src/sys/flush.c @@ -8,13 +8,13 @@ static NTSTATUS FspFsvolFlushBuffers( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolFlushBuffersComplete; FSP_DRIVER_DISPATCH FspFlushBuffers; -FSP_IOCMPL_DISPATCH FspFlushBuffersComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolFlushBuffers) +#pragma alloc_text(PAGE, FspFsvolFlushBuffersComplete) #pragma alloc_text(PAGE, FspFlushBuffers) -#pragma alloc_text(PAGE, FspFlushBuffersComplete) #endif static NTSTATUS FspFsvolFlushBuffers( @@ -25,13 +25,19 @@ static NTSTATUS FspFsvolFlushBuffers( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolFlushBuffersComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspFlushBuffers( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_FLUSH_BUFFERS == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -42,11 +48,3 @@ NTSTATUS FspFlushBuffers( FSP_LEAVE_MJ("%s", ""); } - -VOID FspFlushBuffersComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index 9b97c926..b77c6a19 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -6,99 +6,64 @@ #include -/* - * Overview - * - * The fsctl module provides the IOCTL interface to interact with the - * user-mode file system. The user-mode file system can use the IOCTL's - * to create new volumes, delete them (while they are live!) and transact - * with them. - * - * - * Volume Creation - * - * The creation of a new volume is performed using an FSP_FSCTL_CREATE - * IOCTL code. Creation is simple: a new device \Device\Volume{GUID} is - * created and its path is returned to the user-mode file system. The - * user-mode file system also passes a security descriptor to associate - * with the new virtual volume device so that only the creating user-mode - * file system can control the new volume. - * - * - * Volume Deletion - * - * Deletion of an existing volume is performed using FSP_FSCTL_DELETE and - * is quite a bit more involved. We must protect against the following two - * eventualities: (1) that the volume is currently in use and cannot simply - * go away, and (2) that a simultaneous mount operation is taking place - * while we are deleting the volume. - * - * To protect against the first eventuality we maintain a reference count - * on all our device extensions. Every time an MJ function is entered, - * the reference count is incremented (FspDeviceRetain). Every time - * an IRP is completed, the reference count is decremented (FspDeviceRelease). - * When the reference count reaches 0 the device is deleted using - * IoDeleteDevice. This ensures that a device will not go away while an - * IRP is being pending/processed. - * - * To protect against the second eventuality we use the lock (ERESOURCE) - * on the root Fsctl device to wrap volume deletion and attempts from the - * system to mount the same volume. We also mark the virtual volume device - * as Deleted in case we attempt to delete it (FspDeviceRelease) but we - * cannot because it is currently in use. - * - * A sticky point is our use of the Windows VPB. It is not well documented - * how one should handle this structure during forcible dismount. The fastfat - * and cdfs samples use a technique where they keep a spare VPB and they swap - * it with the volume one during forcible dismount. We do something similar. - * The issue is what to do with the old VPB, because we can delete a volume - * that is not currently being used. We check the VPB's ReferenceCount and - * we free the VPB in this case. - * - * - * Volume Transact - * - * The user-mode file system's primary interaction with the kernel-mode driver - * is by using the FSP_FSCTL_TRANSACT IOCTL code. Every virtual volume device - * maintains an FSP_IOQ (refer to ioq.c for more). When an FSP_FSCTL_TRANSACT - * arrives it first processes any responses (FSP_FSCTL_TRANSACT_RSP) that the - * user-mode file system has sent to handle requests sent to it using a prior - * FSP_FSCTL_TRANSACT. It then proceeds to handle any pending IRP requests by - * sending the corresponding requests (FSP_FSCTL_TRANSACT_REQ) to the user- - * mode file system. - */ - +static NTSTATUS FspFsctlFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspFsctlCreateVolume( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspFsctlMountVolume( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); -static NTSTATUS FspFsvrtDeleteVolume( +VOID FspFsctlDeleteVolume( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); -static WORKER_THREAD_ROUTINE FspFsvrtDeleteVolumeDelayed; -static NTSTATUS FspFsvrtTransact( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); -static NTSTATUS FspFsctlFileSystemControl( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); -static NTSTATUS FspFsvrtFileSystemControl( +static WORKER_THREAD_ROUTINE FspFsctlDeleteVolumeDelayed; +static NTSTATUS FspFsctlTransact( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspFsvolFileSystemControl( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete; FSP_DRIVER_DISPATCH FspFileSystemControl; -FSP_IOCMPL_DISPATCH FspFileSystemControlComplete; #ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFsctlFileSystemControl) #pragma alloc_text(PAGE, FspFsctlCreateVolume) #pragma alloc_text(PAGE, FspFsctlMountVolume) -#pragma alloc_text(PAGE, FspFsvrtDeleteVolume) -#pragma alloc_text(PAGE, FspFsvrtDeleteVolumeDelayed) -#pragma alloc_text(PAGE, FspFsvrtTransact) -#pragma alloc_text(PAGE, FspFsctlFileSystemControl) -#pragma alloc_text(PAGE, FspFsvrtFileSystemControl) +#pragma alloc_text(PAGE, FspFsctlDeleteVolume) +#pragma alloc_text(PAGE, FspFsctlDeleteVolumeDelayed) +#pragma alloc_text(PAGE, FspFsctlTransact) #pragma alloc_text(PAGE, FspFsvolFileSystemControl) +#pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete) #pragma alloc_text(PAGE, FspFileSystemControl) -#pragma alloc_text(PAGE, FspFileSystemControlComplete) #endif +static NTSTATUS FspFsctlFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST; + switch (IrpSp->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + switch (IrpSp->Parameters.FileSystemControl.FsControlCode) + { + case FSP_FSCTL_CREATE: + Result = FspFsctlCreateVolume(DeviceObject, Irp, IrpSp); + break; + case FSP_FSCTL_TRANSACT: + Result = FspFsctlTransact(DeviceObject, Irp, IrpSp); + break; + } + break; + case IRP_MN_MOUNT_VOLUME: + Result = FspFsctlMountVolume(DeviceObject, Irp, IrpSp); + break; +#if 0 + case IRP_MN_VERIFY_VOLUME: + break; +#endif + } + return Result; +} + static NTSTATUS FspFsctlCreateVolume( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -108,29 +73,24 @@ static NTSTATUS FspFsctlCreateVolume( ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer; - PSECURITY_DESCRIPTOR SecurityDescriptor = - (PVOID)((PUINT8)SystemBuffer + FSP_FSCTL_VOLUME_PARAMS_SIZE); - DWORD SecurityDescriptorSize = InputBufferLength - FSP_FSCTL_VOLUME_PARAMS_SIZE; - if (FSP_FSCTL_VOLUME_PARAMS_SIZE >= InputBufferLength || 0 == SystemBuffer || - !FspValidRelativeSecurityDescriptor(SecurityDescriptor, SecurityDescriptorSize, - DACL_SECURITY_INFORMATION)) + if (sizeof(FSP_FSCTL_VOLUME_PARAMS) > InputBufferLength || 0 == SystemBuffer) return STATUS_INVALID_PARAMETER; if (FSP_FSCTL_CREATE_BUFFER_SIZEMIN > OutputBufferLength) return STATUS_BUFFER_TOO_SMALL; NTSTATUS Result; FSP_FSCTL_VOLUME_PARAMS VolumeParams = *(FSP_FSCTL_VOLUME_PARAMS *)SystemBuffer; - PVOID SecurityDescriptorBuf = 0; - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension; /* check the passed in VolumeParams */ if (FspFsctlIrpTimeoutMinimum > VolumeParams.IrpTimeout || VolumeParams.IrpTimeout > FspFsctlIrpTimeoutMaximum) + { #if DBG /* allow the debug timeout value on debug builds */ if (FspFsctlIrpTimeoutDebug != VolumeParams.IrpTimeout) #endif VolumeParams.IrpTimeout = FspFsctlIrpTimeoutDefault; + } if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout || VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum) VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault; @@ -141,14 +101,7 @@ static NTSTATUS FspFsctlCreateVolume( if (!NT_SUCCESS(Result)) return Result; - /* copy the security descriptor from the system buffer to a temporary one */ - SecurityDescriptorBuf = FspAlloc(SecurityDescriptorSize); - if (0 == SecurityDescriptorBuf) - return STATUS_INSUFFICIENT_RESOURCES; - RtlCopyMemory(SecurityDescriptorBuf, SecurityDescriptor, SecurityDescriptorSize); - /* prepare the device name and SDDL */ - PDEVICE_OBJECT FsvrtDeviceObject; UNICODE_STRING DeviceSddl; UNICODE_STRING DeviceName; RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSVRT_DEVICE_SDDL); @@ -160,38 +113,81 @@ static NTSTATUS FspFsctlCreateVolume( Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]); ASSERT(NT_SUCCESS(Result)); - /* create the virtual volume device */ - FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension = FspFsctlDeviceExtension(DeviceObject); - ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE); + FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); + ExAcquireResourceExclusiveLite(&DeviceExtension->Resource, TRUE); try { - Result = FspDeviceCreateSecure(FspFsvrtDeviceExtensionKind, SecurityDescriptorSize, - &DeviceName, FILE_DEVICE_VIRTUAL_DISK, - &DeviceSddl, &FspFsvrtDeviceClassGuid, - &FsvrtDeviceObject); - if (NT_SUCCESS(Result)) + HANDLE MupHandle = 0; + PDEVICE_OBJECT FsvrtDeviceObject = 0; + PDEVICE_OBJECT FsvolDeviceObject; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; + BOOLEAN Inserted; + + /* quick check to see if we already have a volume */ + FsvolDeviceObject = FspDeviceLookupContext(DeviceObject, (UINT_PTR)IrpSp->FileObject); + if (0 != FsvolDeviceObject) { + Result = STATUS_ACCESS_DENIED; + goto exit; + } + + /* create the volume (and virtual disk) device(s) */ + Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0, + DeviceObject->DeviceType, + &FsvolDeviceObject); + if (!NT_SUCCESS(Result)) + goto exit; + if (FILE_DEVICE_DISK_FILE_SYSTEM == DeviceObject->DeviceType) + { + Result = FspDeviceCreateSecure(FspFsvrtDeviceExtensionKind, 0, + &DeviceName, FILE_DEVICE_VIRTUAL_DISK, + &DeviceSddl, &FspFsvrtDeviceClassGuid, + &FsvrtDeviceObject); + if (!NT_SUCCESS(Result)) + { + FspDeviceRelease(FsvolDeviceObject); + goto exit; + } #pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize") FsvrtDeviceObject->SectorSize = VolumeParams.SectorSize; - FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); - FsvrtDeviceExtension->FsctlDeviceObject = DeviceObject; - FsvrtDeviceExtension->VolumeParams = VolumeParams; - RtlCopyMemory(FsvrtDeviceExtension->SecurityDescriptorBuf, - SecurityDescriptorBuf, SecurityDescriptorSize); - FspDeviceInitComplete(FsvrtDeviceObject); - Irp->IoStatus.Information = DeviceName.Length + sizeof(WCHAR); - FspFsctlDeviceVolumeCreated(DeviceObject); } +#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize") + FsvolDeviceObject->SectorSize = VolumeParams.SectorSize; + FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + FsvolDeviceExtension->FsctlDeviceObject = DeviceObject; + FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject; + FsvolDeviceExtension->MupHandle = MupHandle; + FsvolDeviceExtension->VolumeParams = VolumeParams; + if (0 != FsvrtDeviceObject) + FspDeviceInitComplete(FsvrtDeviceObject); + FspDeviceInitComplete(FsvolDeviceObject); + + /* do we need to register with MUP? */ + if (0 == FsvrtDeviceObject) + { + Result = FsRtlRegisterUncProviderEx(&MupHandle, &DeviceName, FsvolDeviceObject, 0); + if (!NT_SUCCESS(Result)) + { + FspDeviceRelease(FsvolDeviceObject); + goto exit; + } + } + + /* associate the new volume device with our file object */ + FspDeviceInsertContext(DeviceObject, (UINT_PTR)IrpSp->FileObject, FsvolDeviceObject, + &FsvolDeviceExtension->ElementStorage, &Inserted); + ASSERT(Inserted); + + Irp->IoStatus.Information = DeviceName.Length + sizeof(WCHAR); + Result = STATUS_SUCCESS; + + exit:; } finally { - ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource); + ExReleaseResourceLite(&DeviceExtension->Resource); } - /* free the temporary security descriptor */ - if (0 != SecurityDescriptorBuf) - FspFree(SecurityDescriptorBuf); - return Result; } @@ -201,222 +197,182 @@ static NTSTATUS FspFsctlMountVolume( PAGED_CODE(); NTSTATUS Result; - FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension = FspFsctlDeviceExtension(DeviceObject); - ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE); + FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); + ExAcquireResourceExclusiveLite(&DeviceExtension->Resource, TRUE); try { - PDEVICE_OBJECT *DeviceObjects = 0; - ULONG DeviceObjectCount = 0; PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb; PDEVICE_OBJECT FsvrtDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject; PDEVICE_OBJECT FsvolDeviceObject; - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = - FspFsvrtDeviceExtension(FsvrtDeviceObject); FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; - /* check the passed in volume object; it must be one of our own and not marked Deleted */ - Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount); - if (NT_SUCCESS(Result)) + /* quick check to see if we already have a volume */ + FsvolDeviceObject = FspDeviceLookupContext(DeviceObject, (UINT_PTR)IrpSp->FileObject); + if (0 != FsvolDeviceObject) { Result = STATUS_UNRECOGNIZED_VOLUME; - for (ULONG i = 0; DeviceObjectCount > i; i++) - if (DeviceObjects[i] == FsvrtDeviceObject) - { - if (FspDeviceRetain(FsvrtDeviceObject)) - { - if (!FsvrtDeviceExtension->Deleted && - FILE_DEVICE_VIRTUAL_DISK == FsvrtDeviceObject->DeviceType) - Result = STATUS_SUCCESS; - else - FspDeviceRelease(FsvrtDeviceObject); - } - break; - } - FspDeviceDeleteList(DeviceObjects, DeviceObjectCount); - } - if (!NT_SUCCESS(Result)) goto exit; - - /* create the file system device object */ - Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0, - DeviceObject->DeviceType, - &FsvolDeviceObject); - if (NT_SUCCESS(Result)) - { - /* - * Reference the virtual volume device so that it will not go away while the - * file system device object is alive! - */ - ObReferenceObject(FsvrtDeviceObject); - -#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize") - FsvolDeviceObject->SectorSize = FsvrtDeviceExtension->VolumeParams.SectorSize; - FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); - FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject; - FsvrtDeviceExtension->FsvolDeviceObject = FsvolDeviceObject; - FspDeviceInitComplete(FsvolDeviceObject); - Vpb->DeviceObject = FsvolDeviceObject; - Vpb->SerialNumber = FsvrtDeviceExtension->VolumeParams.SerialNumber; - Irp->IoStatus.Information = 0; } - FspDeviceRelease(FsvrtDeviceObject); + FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + if (FsvolDeviceExtension->DeletePending || + FsvolDeviceExtension->FsvrtDeviceObject != FsvrtDeviceObject) + { + Result = STATUS_UNRECOGNIZED_VOLUME; + goto exit; + } + + Vpb->DeviceObject = FsvolDeviceObject; + Vpb->SerialNumber = FsvolDeviceExtension->VolumeParams.SerialNumber; + + Irp->IoStatus.Information = 0; + Result = STATUS_SUCCESS; exit:; } finally { - ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource); + ExReleaseResourceLite(&DeviceExtension->Resource); } return Result; } -typedef struct -{ - PDEVICE_OBJECT FsvolDeviceObject; - PVPB OldVpb; - FSP_WORK_ITEM_WITH_DELAY WorkItemWithDelay; -} FSP_FSVRT_DELETE_VOLUME_WORK_ITEM; - -static NTSTATUS FspFsvrtDeleteVolume( +VOID FspFsctlDeleteVolume( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { + /* performed during IRP_MJ_CLEANUP! */ PAGED_CODE(); - NTSTATUS Result; - FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); - FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension = - FspFsctlDeviceExtension(FsvrtDeviceExtension->FsctlDeviceObject); + PDEVICE_OBJECT FsvolDeviceObject = 0; - ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE); + FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); + ExAcquireResourceExclusiveLite(&DeviceExtension->Resource, TRUE); try { - PDEVICE_OBJECT FsctlDeviceObject = FsvrtDeviceExtension->FsctlDeviceObject; - PDEVICE_OBJECT FsvolDeviceObject = FsvrtDeviceExtension->FsvolDeviceObject; - PVPB OldVpb; - BOOLEAN DeleteVpb = FALSE; - BOOLEAN DeleteDelayed = FALSE; - LARGE_INTEGER DelayTimeout; - FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = 0; - KIRQL Irql; - - /* access check */ - Result = FspSecuritySubjectContextAccessCheck( - FsvrtDeviceExtension->SecurityDescriptorBuf, FILE_WRITE_DATA, Irp->RequestorMode); - if (!NT_SUCCESS(Result)) - goto exit; - - /* pre-allocate a work item in case we need it for delayed delete */ - WorkItem = FspAllocNonPaged(sizeof *WorkItem); - if (0 == WorkItem) - { - Result = STATUS_INSUFFICIENT_RESOURCES; - goto exit; - } - - /* mark the virtual volume device as deleted */ - FsvrtDeviceExtension->Deleted = TRUE; - - /* stop the I/O queue */ - FspIoqStop(&FsvrtDeviceExtension->Ioq); - - /* swap the preallocated VPB */ -#pragma prefast(push) -#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb") - IoAcquireVpbSpinLock(&Irql); - OldVpb = DeviceObject->Vpb; - if (0 != OldVpb && 0 != FsvrtDeviceExtension->SwapVpb) - { - DeviceObject->Vpb = FsvrtDeviceExtension->SwapVpb; - DeviceObject->Vpb->Size = sizeof *DeviceObject->Vpb; - DeviceObject->Vpb->Type = IO_TYPE_VPB; - DeviceObject->Vpb->Flags = FlagOn(OldVpb->Flags, VPB_REMOVE_PENDING); - DeviceObject->Vpb->RealDevice = OldVpb->RealDevice; - DeviceObject->Vpb->RealDevice->Vpb = DeviceObject->Vpb; - FsvrtDeviceExtension->SwapVpb = 0; - DeleteVpb = 0 == OldVpb->ReferenceCount; - DeleteDelayed = !DeleteVpb && 0 != FsvolDeviceObject; - if (DeleteDelayed) - /* keep VPB around for delayed delete */ - OldVpb->ReferenceCount++; - } - IoReleaseVpbSpinLock(Irql); - if (DeleteDelayed) - /* keep fsvol around for delayed delete */ - FspDeviceRetain(FsvolDeviceObject); - else if (DeleteVpb) - FspFreeExternal(OldVpb); -#pragma prefast(pop) - - /* release the file system device and virtual volume objects */ - FsvrtDeviceExtension->FsvolDeviceObject = 0; + FsvolDeviceObject = FspDeviceLookupContext(DeviceObject, (UINT_PTR)IrpSp->FileObject); if (0 != FsvolDeviceObject) - FspDeviceRelease(FsvolDeviceObject); - FspDeviceRelease(DeviceObject); - - FspFsctlDeviceVolumeDeleted(FsctlDeviceObject); - - /* are we doing delayed delete of VPB and fsvol? */ - if (DeleteDelayed) - { - DelayTimeout.QuadPart = 300/*ms*/ * -10000; - WorkItem->FsvolDeviceObject = FsvolDeviceObject; - WorkItem->OldVpb = OldVpb; - FspInitializeWorkItemWithDelay(&WorkItem->WorkItemWithDelay, - FspFsvrtDeleteVolumeDelayed, WorkItem); - FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout); - WorkItem = 0; - } - - Result = STATUS_SUCCESS; - - exit: - if (0 != WorkItem) - FspFree(WorkItem); + FspDeviceDeleteContext(DeviceObject, (UINT_PTR)IrpSp->FileObject, 0); } finally { - ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource); + ExReleaseResourceLite(&DeviceExtension->Resource); } - return Result; + if (0 != FsvolDeviceObject) + { + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + + /* mark the volume device as pending delete */ + FsvolDeviceExtension->DeletePending = TRUE; + + /* stop the I/O queue */ + FspIoqStop(&FsvolDeviceExtension->Ioq); + + /* do we have a virtual disk device or a MUP handle? */ + if (0 != FsvolDeviceExtension->FsvrtDeviceObject) + { + PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; + PVPB OldVpb; + KIRQL Irql; + BOOLEAN DeleteVpb = FALSE; + BOOLEAN DeleteDelayed = FALSE; + LARGE_INTEGER DelayTimeout; + + /* swap the virtual disk device VPB with the preallocated one */ +#pragma prefast(push) +#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb") + IoAcquireVpbSpinLock(&Irql); + OldVpb = FsvrtDeviceObject->Vpb; + if (0 != OldVpb) + { + FsvrtDeviceObject->Vpb = FsvolDeviceExtension->SwapVpb; + FsvrtDeviceObject->Vpb->Size = sizeof *FsvrtDeviceObject->Vpb; + FsvrtDeviceObject->Vpb->Type = IO_TYPE_VPB; + FsvrtDeviceObject->Vpb->Flags = FlagOn(OldVpb->Flags, VPB_REMOVE_PENDING); + FsvrtDeviceObject->Vpb->RealDevice = OldVpb->RealDevice; + FsvrtDeviceObject->Vpb->RealDevice->Vpb = FsvrtDeviceObject->Vpb; + DeleteVpb = 0 == OldVpb->ReferenceCount; + DeleteDelayed = !DeleteVpb; + if (DeleteDelayed) + { + /* keep VPB around for delayed delete */ + OldVpb->ReferenceCount++; + FsvolDeviceExtension->SwapVpb = OldVpb; + } + else + FsvolDeviceExtension->SwapVpb = 0; + } + IoReleaseVpbSpinLock(Irql); + if (DeleteDelayed) + /* keep volume device object around for delayed delete */ + FspDeviceRetain(FsvolDeviceObject); + else if (DeleteVpb) + /* no more references to the old VPB; delete now! */ + FspFreeExternal(OldVpb); +#pragma prefast(pop) + + /* release the virtual disk and volume device objects */ + FspDeviceRelease(FsvrtDeviceObject); + FspDeviceRelease(FsvolDeviceObject); + + /* are we doing delayed delete of VPB and volume device object? */ + if (DeleteDelayed) + { + DelayTimeout.QuadPart = 300/*ms*/ * -10000; + FspInitializeWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem, + FspFsctlDeleteVolumeDelayed, FsvolDeviceObject); + FspQueueWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem, DelayTimeout); + } + } + else if (0 != FsvolDeviceExtension->MupHandle) + { + HANDLE MupHandle = FsvolDeviceExtension->MupHandle; + + FsRtlDeregisterUncProvider(MupHandle); + + /* release the volume device object */ + FspDeviceRelease(FsvolDeviceObject); + } + } } -static VOID FspFsvrtDeleteVolumeDelayed(PVOID Context) +static VOID FspFsctlDeleteVolumeDelayed(PVOID Context) { PAGED_CODE(); - FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = Context; + PDEVICE_OBJECT FsvolDeviceObject = Context; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + KIRQL Irql; BOOLEAN DeleteVpb = FALSE; LARGE_INTEGER DelayTimeout; - KIRQL Irql; IoAcquireVpbSpinLock(&Irql); - ASSERT(0 != WorkItem->OldVpb->ReferenceCount); - DeleteVpb = 1 == WorkItem->OldVpb->ReferenceCount; + ASSERT(0 != FsvolDeviceExtension->SwapVpb->ReferenceCount); + DeleteVpb = 1 == FsvolDeviceExtension->SwapVpb->ReferenceCount; if (DeleteVpb) - WorkItem->OldVpb->ReferenceCount = 0; + FsvolDeviceExtension->SwapVpb->ReferenceCount = 0; IoReleaseVpbSpinLock(Irql); if (DeleteVpb) { - FspFreeExternal(WorkItem->OldVpb); - FspDeviceRelease(WorkItem->FsvolDeviceObject); - FspFree(WorkItem); + FspFreeExternal(FsvolDeviceExtension->SwapVpb); + FsvolDeviceExtension->SwapVpb = 0; + FspDeviceRelease(FsvolDeviceObject); } else { DelayTimeout.QuadPart = 300/*ms*/ * -10000; - FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout); + FspQueueWorkItemWithDelay(&FsvolDeviceExtension->DeleteVolumeWorkItem, DelayTimeout); } } -static NTSTATUS FspFsvrtTransact( +static NTSTATUS FspFsctlTransact( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); +#if 0 /* check parameters */ ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; @@ -518,56 +474,10 @@ static NTSTATUS FspFsvrtTransact( Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)SystemBuffer; return STATUS_SUCCESS; -} -static NTSTATUS FspFsctlFileSystemControl( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) -{ - PAGED_CODE(); - - NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST; - switch (IrpSp->MinorFunction) - { - case IRP_MN_USER_FS_REQUEST: - switch (IrpSp->Parameters.FileSystemControl.FsControlCode) - { - case FSP_FSCTL_CREATE: - Result = FspFsctlCreateVolume(DeviceObject, Irp, IrpSp); - break; - } - break; - case IRP_MN_MOUNT_VOLUME: - Result = FspFsctlMountVolume(DeviceObject, Irp, IrpSp); - break; -#if 0 - case IRP_MN_VERIFY_VOLUME: - break; +#else + return STATUS_INVALID_DEVICE_REQUEST; #endif - } - return Result; -} - -static NTSTATUS FspFsvrtFileSystemControl( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) -{ - PAGED_CODE(); - - NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST; - switch (IrpSp->MinorFunction) - { - case IRP_MN_USER_FS_REQUEST: - switch (IrpSp->Parameters.FileSystemControl.FsControlCode) - { - case FSP_FSCTL_DELETE: - Result = FspFsvrtDeleteVolume(DeviceObject, Irp, IrpSp); - break; - case FSP_FSCTL_TRANSACT: - Result = FspFsvrtTransact(DeviceObject, Irp, IrpSp); - break; - } - break; - } - return Result; } static NTSTATUS FspFsvolFileSystemControl( @@ -584,19 +494,28 @@ static NTSTATUS FspFsvolFileSystemControl( return Result; } +VOID FspFsvolFileSystemControlComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC( + "FileObject=%p%s%s", + IrpSp->FileObject, + IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? ", " : "", + IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? + IoctlCodeSym(IrpSp->Parameters.FileSystemControl.FsControlCode) : ""); +} + NTSTATUS FspFileSystemControl( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: FSP_RETURN(Result = FspFsvolFileSystemControl(DeviceObject, Irp, IrpSp)); - case FspFsvrtDeviceExtensionKind: - FSP_RETURN(Result = FspFsvrtFileSystemControl(DeviceObject, Irp, IrpSp)); case FspFsctlDeviceExtensionKind: FSP_RETURN(Result = FspFsctlFileSystemControl(DeviceObject, Irp, IrpSp)); default: @@ -610,16 +529,3 @@ NTSTATUS FspFileSystemControl( IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? IoctlCodeSym(IrpSp->Parameters.FileSystemControl.FsControlCode) : ""); } - -VOID FspFileSystemControlComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC( - "FileObject=%p%s%s", - IrpSp->FileObject, - IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? ", " : "", - IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? - IoctlCodeSym(IrpSp->Parameters.FileSystemControl.FsControlCode) : ""); -} diff --git a/src/sys/iop.c b/src/sys/iop.c index bd9f691c..3776e27b 100644 --- a/src/sys/iop.c +++ b/src/sys/iop.c @@ -113,10 +113,12 @@ NTSTATUS FspIopPostWorkRequest(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_TRANSACT_R } PIO_STACK_LOCATION IrpSp = IoGetNextIrpStackLocation(Irp); - IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; - IrpSp->Parameters.DeviceIoControl.IoControlCode = FSP_FSCTL_WORK; - IrpSp->Parameters.DeviceIoControl.InputBufferLength = Request->Size; - IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = Request; + Irp->RequestorMode = KernelMode; + IrpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; + IrpSp->MinorFunction = IRP_MN_USER_FS_REQUEST; + IrpSp->Parameters.FileSystemControl.FsControlCode = FSP_FSCTL_WORK; + IrpSp->Parameters.FileSystemControl.InputBufferLength = Request->Size; + IrpSp->Parameters.FileSystemControl.Type3InputBuffer = Request; ASSERT(METHOD_NEITHER == (IrpSp->Parameters.DeviceIoControl.IoControlCode & 3)); @@ -170,6 +172,11 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceRelease) FspDeviceRelease(DeviceObject); } +VOID FspIopCompleteCanceledIrp(PIRP Irp) +{ + FspIopCompleteIrpEx(Irp, STATUS_CANCELLED, TRUE); +} + NTSTATUS FspIopDispatchPrepare(PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request) { PAGED_CODE(); diff --git a/src/sys/ioq.c b/src/sys/ioq.c index b0a5ad6b..cc527e86 100644 --- a/src/sys/ioq.c +++ b/src/sys/ioq.c @@ -120,7 +120,8 @@ static VOID FspIoqPendingReleaseLock(PIO_CSQ IoCsq, _IRQL_restores_ KIRQL Irql) static VOID FspIoqPendingCompleteCanceledIrp(PIO_CSQ IoCsq, PIRP Irp) { - FspIopCompleteIrp(Irp, STATUS_CANCELLED); + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, PendingIoCsq); + Ioq->CompleteCanceledIrp(Irp); } static NTSTATUS FspIoqProcessInsertIrpEx(PIO_CSQ IoCsq, PIRP Irp, PVOID InsertContext) @@ -183,11 +184,14 @@ static VOID FspIoqProcessReleaseLock(PIO_CSQ IoCsq, _IRQL_restores_ KIRQL Irql) static VOID FspIoqProcessCompleteCanceledIrp(PIO_CSQ IoCsq, PIRP Irp) { - FspIopCompleteIrp(Irp, STATUS_CANCELLED); + FSP_IOQ *Ioq = CONTAINING_RECORD(IoCsq, FSP_IOQ, ProcessIoCsq); + Ioq->CompleteCanceledIrp(Irp); } -VOID FspIoqInitialize(FSP_IOQ *Ioq) +VOID FspIoqInitialize(FSP_IOQ *Ioq, VOID (*CompleteCanceledIrp)(PIRP Irp)) { + ASSERT(0 != CompleteCanceledIrp); + RtlZeroMemory(Ioq, sizeof *Ioq); KeInitializeSpinLock(&Ioq->SpinLock); KeInitializeEvent(&Ioq->PendingIrpEvent, NotificationEvent, FALSE); @@ -207,6 +211,7 @@ VOID FspIoqInitialize(FSP_IOQ *Ioq) FspIoqProcessAcquireLock, FspIoqProcessReleaseLock, FspIoqProcessCompleteCanceledIrp); + Ioq->CompleteCanceledIrp = CompleteCanceledIrp; } VOID FspIoqStop(FSP_IOQ *Ioq) @@ -219,9 +224,9 @@ VOID FspIoqStop(FSP_IOQ *Ioq) KeReleaseSpinLock(&Ioq->SpinLock, Irql); PIRP Irp; while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, 0))) - FspIoqPendingCompleteCanceledIrp(&Ioq->PendingIoCsq, Irp); + Ioq->CompleteCanceledIrp(Irp); while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->ProcessIoCsq, 0))) - FspIoqProcessCompleteCanceledIrp(&Ioq->ProcessIoCsq, Irp); + Ioq->CompleteCanceledIrp(Irp); } BOOLEAN FspIoqStopped(FSP_IOQ *Ioq) @@ -245,9 +250,9 @@ VOID FspIoqRemoveExpired(FSP_IOQ *Ioq, PLARGE_INTEGER Timeout) PeekContext.ExpirationTime = 0; PIRP Irp; while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->PendingIoCsq, &PeekContext))) - FspIoqPendingCompleteCanceledIrp(&Ioq->PendingIoCsq, Irp); + Ioq->CompleteCanceledIrp(Irp); while (0 != (Irp = IoCsqRemoveNextIrp(&Ioq->ProcessIoCsq, &PeekContext))) - FspIoqProcessCompleteCanceledIrp(&Ioq->ProcessIoCsq, Irp); + Ioq->CompleteCanceledIrp(Irp); } BOOLEAN FspIoqPostIrp(FSP_IOQ *Ioq, PIRP Irp) diff --git a/src/sys/lockctl.c b/src/sys/lockctl.c index bf1f03b9..8da709bf 100644 --- a/src/sys/lockctl.c +++ b/src/sys/lockctl.c @@ -8,13 +8,13 @@ static NTSTATUS FspFsvolLockControl( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolLockControlComplete; FSP_DRIVER_DISPATCH FspLockControl; -FSP_IOCMPL_DISPATCH FspLockControlComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolLockControl) +#pragma alloc_text(PAGE, FspFsvolLockControlComplete) #pragma alloc_text(PAGE, FspLockControl) -#pragma alloc_text(PAGE, FspLockControlComplete) #endif static NTSTATUS FspFsvolLockControl( @@ -25,13 +25,19 @@ static NTSTATUS FspFsvolLockControl( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolLockControlComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspLockControl( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_LOCK_CONTROL == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -42,11 +48,3 @@ NTSTATUS FspLockControl( FSP_LEAVE_MJ("%s", ""); } - -VOID FspLockControlComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/read.c b/src/sys/read.c index f6bc6976..cd42b7e6 100644 --- a/src/sys/read.c +++ b/src/sys/read.c @@ -8,13 +8,13 @@ static NTSTATUS FspFsvolRead( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolReadComplete; FSP_DRIVER_DISPATCH FspRead; -FSP_IOCMPL_DISPATCH FspReadComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolRead) +#pragma alloc_text(PAGE, FspFsvolReadComplete) #pragma alloc_text(PAGE, FspRead) -#pragma alloc_text(PAGE, FspReadComplete) #endif static NTSTATUS FspFsvolRead( @@ -25,13 +25,19 @@ static NTSTATUS FspFsvolRead( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolReadComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspRead( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_READ == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -42,11 +48,3 @@ NTSTATUS FspRead( FSP_LEAVE_MJ("%s", ""); } - -VOID FspReadComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/resource.c b/src/sys/resource.c deleted file mode 100644 index 638af5c1..00000000 --- a/src/sys/resource.c +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file sys/resource.c - * - * @copyright 2015 Bill Zissimopoulos - */ - -#include - -FAST_IO_ACQUIRE_FILE FspAcquireFileForNtCreateSection; -FAST_IO_RELEASE_FILE FspReleaseFileForNtCreateSection; -FAST_IO_ACQUIRE_FOR_MOD_WRITE FspAcquireForModWrite; -FAST_IO_RELEASE_FOR_MOD_WRITE FspReleaseForModWrite; -FAST_IO_ACQUIRE_FOR_CCFLUSH FspAcquireForCcFlush; -FAST_IO_RELEASE_FOR_CCFLUSH FspReleaseForCcFlush; - -#ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, FspAcquireFileForNtCreateSection) -#pragma alloc_text(PAGE, FspReleaseFileForNtCreateSection) -#pragma alloc_text(PAGE, FspAcquireForModWrite) -#pragma alloc_text(PAGE, FspReleaseForModWrite) -#pragma alloc_text(PAGE, FspAcquireForCcFlush) -#pragma alloc_text(PAGE, FspReleaseForCcFlush) -#endif - -VOID FspAcquireFileForNtCreateSection( - PFILE_OBJECT FileObject) -{ - FSP_ENTER_VOID(PAGED_CODE()); - - FSP_LEAVE_VOID("%s", ""); -} - -VOID FspReleaseFileForNtCreateSection( - PFILE_OBJECT FileObject) -{ - FSP_ENTER_VOID(PAGED_CODE()); - - FSP_LEAVE_VOID("%s", ""); -} - -NTSTATUS FspAcquireForModWrite( - PFILE_OBJECT FileObject, - PLARGE_INTEGER EndingOffset, - PERESOURCE *ResourceToRelease, - PDEVICE_OBJECT DeviceObject) -{ - FSP_ENTER(PAGED_CODE()); - - Result = STATUS_NOT_IMPLEMENTED; - - FSP_LEAVE("%s", ""); -} - -NTSTATUS FspReleaseForModWrite( - PFILE_OBJECT FileObject, - PERESOURCE ResourceToRelease, - PDEVICE_OBJECT DeviceObject) -{ - FSP_ENTER(PAGED_CODE()); - - Result = STATUS_NOT_IMPLEMENTED; - - FSP_LEAVE("%s", ""); -} - -NTSTATUS FspAcquireForCcFlush( - PFILE_OBJECT FileObject, - PDEVICE_OBJECT DeviceObject) -{ - FSP_ENTER(PAGED_CODE()); - - Result = STATUS_NOT_IMPLEMENTED; - - FSP_LEAVE("%s", ""); -} - -NTSTATUS FspReleaseForCcFlush( - PFILE_OBJECT FileObject, - PDEVICE_OBJECT DeviceObject) -{ - FSP_ENTER(PAGED_CODE()); - - Result = STATUS_NOT_IMPLEMENTED; - - FSP_LEAVE("%s", ""); -} diff --git a/src/sys/security.c b/src/sys/security.c index 117e1f7c..f9920818 100644 --- a/src/sys/security.c +++ b/src/sys/security.c @@ -8,20 +8,20 @@ static NTSTATUS FspFsvolQuerySecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolQuerySecurityComplete; static NTSTATUS FspFsvolSetSecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolSetSecurityComplete; FSP_DRIVER_DISPATCH FspQuerySecurity; FSP_DRIVER_DISPATCH FspSetSecurity; -FSP_IOCMPL_DISPATCH FspQuerySecurityComplete; -FSP_IOCMPL_DISPATCH FspSetSecurityComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolQuerySecurity) +#pragma alloc_text(PAGE, FspFsvolQuerySecurityComplete) #pragma alloc_text(PAGE, FspFsvolSetSecurity) +#pragma alloc_text(PAGE, FspFsvolSetSecurityComplete) #pragma alloc_text(PAGE, FspQuerySecurity) #pragma alloc_text(PAGE, FspSetSecurity) -#pragma alloc_text(PAGE, FspQuerySecurityComplete) -#pragma alloc_text(PAGE, FspSetSecurityComplete) #endif static NTSTATUS FspFsvolQuerySecurity( @@ -32,6 +32,14 @@ static NTSTATUS FspFsvolQuerySecurity( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolQuerySecurityComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + static NTSTATUS FspFsvolSetSecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -40,13 +48,19 @@ static NTSTATUS FspFsvolSetSecurity( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolSetSecurityComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspQuerySecurity( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_QUERY_SECURITY == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -63,8 +77,6 @@ NTSTATUS FspSetSecurity( { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_SET_SECURITY == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -75,19 +87,3 @@ NTSTATUS FspSetSecurity( FSP_LEAVE_MJ("%s", ""); } - -VOID FspQuerySecurityComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} - -VOID FspSetSecurityComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/shutdown.c b/src/sys/shutdown.c index c9d117dd..57e33f8f 100644 --- a/src/sys/shutdown.c +++ b/src/sys/shutdown.c @@ -9,12 +9,12 @@ static NTSTATUS FspFsvolShutdown( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_DRIVER_DISPATCH FspShutdown; -FSP_IOCMPL_DISPATCH FspShutdownComplete; +FSP_IOCMPL_DISPATCH FspFsvolShutdownComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolShutdown) +#pragma alloc_text(PAGE, FspFsvolShutdownComplete) #pragma alloc_text(PAGE, FspShutdown) -#pragma alloc_text(PAGE, FspShutdownComplete) #endif static NTSTATUS FspFsvolShutdown( @@ -25,13 +25,19 @@ static NTSTATUS FspFsvolShutdown( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolShutdownComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspShutdown( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_SHUTDOWN == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -42,11 +48,3 @@ NTSTATUS FspShutdown( FSP_LEAVE_MJ("%s", ""); } - -VOID FspShutdownComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/util.c b/src/sys/util.c new file mode 100644 index 00000000..2fd7b922 --- /dev/null +++ b/src/sys/util.c @@ -0,0 +1,61 @@ +/** + * @file sys/util.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +NTSTATUS FspCreateGuid(GUID *Guid); +VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, + PWORKER_THREAD_ROUTINE Routine, PVOID Context); +VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout); +static KDEFERRED_ROUTINE FspQueueWorkItemWithDelayDPC; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspCreateGuid) +#pragma alloc_text(PAGE, FspInitializeWorkItemWithDelay) +#pragma alloc_text(PAGE, FspQueueWorkItemWithDelay) +#endif + +NTSTATUS FspCreateGuid(GUID *Guid) +{ + PAGED_CODE(); + + NTSTATUS Result; + + int Retries = 3; + do + { + Result = ExUuidCreate(Guid); + } while (!NT_SUCCESS(Result) && 0 < --Retries); + + return Result; +} + +VOID FspInitializeWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, + PWORKER_THREAD_ROUTINE Routine, PVOID Context) +{ + PAGED_CODE(); + + KeInitializeTimer(&WorkItem->Timer); + KeInitializeDpc(&WorkItem->Dpc, FspQueueWorkItemWithDelayDPC, WorkItem); + ExInitializeWorkItem(&WorkItem->WorkQueueItem, Routine, Context); +} + +VOID FspQueueWorkItemWithDelay(FSP_WORK_ITEM_WITH_DELAY *WorkItem, LARGE_INTEGER Timeout) +{ + PAGED_CODE(); + + KeSetTimer(&WorkItem->Timer, Timeout, &WorkItem->Dpc); +} + +static VOID FspQueueWorkItemWithDelayDPC(PKDPC Dpc, + PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2) +{ + // !PAGED_CODE(); + + FSP_WORK_ITEM_WITH_DELAY *WorkItem = DeferredContext; + + ExQueueWorkItem(&WorkItem->WorkQueueItem, DelayedWorkQueue); +} diff --git a/src/sys/volinfo.c b/src/sys/volinfo.c index 2f0e2b7c..89da6a51 100644 --- a/src/sys/volinfo.c +++ b/src/sys/volinfo.c @@ -8,20 +8,20 @@ static NTSTATUS FspFsvolQueryVolumeInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolQueryVolumeInformationComplete; static NTSTATUS FspFsvolSetVolumeInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete; FSP_DRIVER_DISPATCH FspQueryVolumeInformation; FSP_DRIVER_DISPATCH FspSetVolumeInformation; -FSP_IOCMPL_DISPATCH FspQueryVolumeInformationComplete; -FSP_IOCMPL_DISPATCH FspSetVolumeInformationComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolQueryVolumeInformation) +#pragma alloc_text(PAGE, FspFsvolQueryVolumeInformationComplete) #pragma alloc_text(PAGE, FspFsvolSetVolumeInformation) +#pragma alloc_text(PAGE, FspFsvolSetVolumeInformationComplete) #pragma alloc_text(PAGE, FspQueryVolumeInformation) #pragma alloc_text(PAGE, FspSetVolumeInformation) -#pragma alloc_text(PAGE, FspQueryVolumeInformationComplete) -#pragma alloc_text(PAGE, FspSetVolumeInformationComplete) #endif static NTSTATUS FspFsvolQueryVolumeInformation( @@ -32,6 +32,14 @@ static NTSTATUS FspFsvolQueryVolumeInformation( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolQueryVolumeInformationComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + static NTSTATUS FspFsvolSetVolumeInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -40,13 +48,19 @@ static NTSTATUS FspFsvolSetVolumeInformation( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolSetVolumeInformationComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspQueryVolumeInformation( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_QUERY_VOLUME_INFORMATION == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -63,8 +77,6 @@ NTSTATUS FspSetVolumeInformation( { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_SET_VOLUME_INFORMATION == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -75,19 +87,3 @@ NTSTATUS FspSetVolumeInformation( FSP_LEAVE_MJ("%s", ""); } - -VOID FspQueryVolumeInformationComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} - -VOID FspSetVolumeInformationComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/sys/write.c b/src/sys/write.c index 947247ce..6fb5a942 100644 --- a/src/sys/write.c +++ b/src/sys/write.c @@ -8,13 +8,13 @@ static NTSTATUS FspFsvolWrite( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolWriteComplete; FSP_DRIVER_DISPATCH FspWrite; -FSP_IOCMPL_DISPATCH FspWriteComplete; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFsvolWrite) +#pragma alloc_text(PAGE, FspFsvolWriteComplete) #pragma alloc_text(PAGE, FspWrite) -#pragma alloc_text(PAGE, FspWriteComplete) #endif static NTSTATUS FspFsvolWrite( @@ -25,13 +25,19 @@ static NTSTATUS FspFsvolWrite( return STATUS_INVALID_DEVICE_REQUEST; } +VOID FspFsvolWriteComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("%s", ""); +} + NTSTATUS FspWrite( PDEVICE_OBJECT DeviceObject, PIRP Irp) { FSP_ENTER_MJ(PAGED_CODE()); - ASSERT(IRP_MJ_WRITE == IrpSp->MajorFunction); - switch (FspDeviceExtension(DeviceObject)->Kind) { case FspFsvolDeviceExtensionKind: @@ -42,11 +48,3 @@ NTSTATUS FspWrite( FSP_LEAVE_MJ("%s", ""); } - -VOID FspWriteComplete( - PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) -{ - FSP_ENTER_IOC(PAGED_CODE()); - - FSP_LEAVE_IOC("%s", ""); -} diff --git a/src/dll/debug.c b/src0/dll/debug.c similarity index 100% rename from src/dll/debug.c rename to src0/dll/debug.c diff --git a/src/dll/fsctl.c b/src0/dll/fsctl.c similarity index 100% rename from src/dll/fsctl.c rename to src0/dll/fsctl.c diff --git a/src/dll/library.c b/src0/dll/library.c similarity index 100% rename from src/dll/library.c rename to src0/dll/library.c diff --git a/src/dll/library.h b/src0/dll/library.h similarity index 100% rename from src/dll/library.h rename to src0/dll/library.h diff --git a/src/dll/loop.c b/src0/dll/loop.c similarity index 100% rename from src/dll/loop.c rename to src0/dll/loop.c diff --git a/src/dll/ntstatus.c b/src0/dll/ntstatus.c similarity index 100% rename from src/dll/ntstatus.c rename to src0/dll/ntstatus.c diff --git a/src/dll/ntstatus.i b/src0/dll/ntstatus.i similarity index 100% rename from src/dll/ntstatus.i rename to src0/dll/ntstatus.i diff --git a/src0/sys/cleanup.c b/src0/sys/cleanup.c new file mode 100644 index 00000000..4aea9e75 --- /dev/null +++ b/src0/sys/cleanup.c @@ -0,0 +1,176 @@ +/** + * @file sys/cleanup.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +static NTSTATUS FspFsctlCleanup( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvrtCleanup( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvolCleanup( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolCleanupComplete; +FSP_DRIVER_DISPATCH FspCleanup; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFsctlCleanup) +#pragma alloc_text(PAGE, FspFsvrtCleanup) +#pragma alloc_text(PAGE, FspFsvolCleanup) +#pragma alloc_text(PAGE, FspFsvolCleanupComplete) +#pragma alloc_text(PAGE, FspCleanup) +#endif + +static NTSTATUS FspFsctlCleanup( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + return Result; +} + +static NTSTATUS FspFsvrtCleanup( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + return Result; +} + +static NTSTATUS FspFsvolCleanup( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + /* is this a valid FileObject? */ + if (!FspFileContextIsValid(IrpSp->FileObject->FsContext)) + return STATUS_SUCCESS; + + NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + PFILE_OBJECT FileObject = IrpSp->FileObject; + FSP_FILE_CONTEXT *FsContext = FileObject->FsContext; + UINT64 UserContext = FsContext->UserContext; + UINT64 UserContext2 = (UINT_PTR)FileObject->FsContext2; + BOOLEAN DeletePending; + LONG OpenCount; + + /* lock the FsContext */ + ExAcquireResourceExclusiveLite(FsContext->Header.Resource, TRUE); + + /* propagate the FsContext DeleteOnClose to DeletePending */ + if (FsContext->DeleteOnClose) + FsContext->DeletePending = TRUE; + DeletePending = FsContext->DeletePending; + + /* all handles on this FileObject are gone; decrement its FsContext->OpenCount */ + OpenCount = FspFileContextClose(FsContext); + + /* unlock the FsContext */ + ExReleaseResourceLite(FsContext->Header.Resource); + + /* is the FsContext going away as well? */ + if (0 == OpenCount) + { + /* + * The following must be done under the file system volume device Resource, + * because we are manipulating its GenericTable. + */ + ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->Base.Resource, TRUE); + try + { + /* remove the FsContext from the file system volume device generic table */ + FspFsvolDeviceDeleteContext(DeviceObject, FsContext->UserContext, 0); + } + finally + { + ExReleaseResourceLite(&FsvolDeviceExtension->Base.Resource); + } + } + + PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; + if (!FspDeviceRetain(FsvrtDeviceObject)) + /* IRP_MJ_CLEANUP cannot really fail :-\ */ + return STATUS_SUCCESS; + + try + { + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + BOOLEAN FileNameRequired = 0 != FsvrtDeviceExtension->VolumeParams.FileNameRequired; + FSP_FSCTL_TRANSACT_REQ *Request; + + /* create the user-mode file system request */ + Result = FspIopCreateRequest(Irp, FileNameRequired ? &FsContext->FileName : 0, 0, &Request); + if (!NT_SUCCESS(Result)) + goto leak_exit; + + /* + * The new request is associated with our IRP and will be deleted during its completion. + */ + + /* populate the Cleanup request */ + Request->Kind = FspFsctlTransactCleanupKind; + Request->Req.Cleanup.UserContext = UserContext; + Request->Req.Cleanup.UserContext2 = UserContext2; + Request->Req.Cleanup.Delete = DeletePending && 0 == OpenCount; + + Result = STATUS_PENDING; + + goto exit; + + leak_exit:; +#if DBG + DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%llx: " + "error: the user-mode file system handle will be leaked!", + IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, + UserContext, UserContext2); +#endif + + /* IRP_MJ_CLEANUP cannot really fail :-\ */ + Result = STATUS_SUCCESS; + + exit:; + } + finally + { + FspDeviceRelease(FsvrtDeviceObject); + } + + return Result; +} + +VOID FspFsvolCleanupComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("FileObject=%p", IrpSp->FileObject); +} + +NTSTATUS FspCleanup( + PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + FSP_ENTER_MJ(PAGED_CODE()); + + ASSERT(IRP_MJ_CLEANUP == IrpSp->MajorFunction); + + switch (FspDeviceExtension(DeviceObject)->Kind) + { + case FspFsvolDeviceExtensionKind: + FSP_RETURN(Result = FspFsvolCleanup(DeviceObject, Irp, IrpSp)); + case FspFsvrtDeviceExtensionKind: + FSP_RETURN(Result = FspFsvrtCleanup(DeviceObject, Irp, IrpSp)); + case FspFsctlDeviceExtensionKind: + FSP_RETURN(Result = FspFsctlCleanup(DeviceObject, Irp, IrpSp)); + default: + FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); + } + + FSP_LEAVE_MJ("FileObject=%p", IrpSp->FileObject); +} diff --git a/src0/sys/close.c b/src0/sys/close.c new file mode 100644 index 00000000..1b912117 --- /dev/null +++ b/src0/sys/close.c @@ -0,0 +1,148 @@ +/** + * @file sys/close.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +static NTSTATUS FspFsctlClose( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvrtClose( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvolClose( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOCMPL_DISPATCH FspFsvolCloseComplete; +FSP_DRIVER_DISPATCH FspClose; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFsctlClose) +#pragma alloc_text(PAGE, FspFsvrtClose) +#pragma alloc_text(PAGE, FspFsvolClose) +#pragma alloc_text(PAGE, FspFsvolCloseComplete) +#pragma alloc_text(PAGE, FspClose) +#endif + +static NTSTATUS FspFsctlClose( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + return Result; +} + +static NTSTATUS FspFsvrtClose( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + return Result; +} + +static NTSTATUS FspFsvolClose( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + /* is this a valid FileObject? */ + if (!FspFileContextIsValid(IrpSp->FileObject->FsContext)) + return STATUS_SUCCESS; + + NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + PFILE_OBJECT FileObject = IrpSp->FileObject; + FSP_FILE_CONTEXT *FsContext = FileObject->FsContext; + UINT64 UserContext = FsContext->UserContext; + UINT64 UserContext2 = (UINT_PTR)FileObject->FsContext2; + + /* dereference the FsContext (and delete if no more references) */ + FspFileContextRelease(FsContext); + + PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; + if (!FspDeviceRetain(FsvrtDeviceObject)) + /* IRP_MJ_CLOSE cannot really fail :-\ */ + return STATUS_SUCCESS; + + try + { + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + BOOLEAN FileNameRequired = 0 != FsvrtDeviceExtension->VolumeParams.FileNameRequired; + FSP_FSCTL_TRANSACT_REQ *Request; + + /* create the user-mode file system request */ + Result = FspIopCreateRequest(0, FileNameRequired ? &FsContext->FileName : 0, 0, &Request); + if (!NT_SUCCESS(Result)) + goto leak_exit; + + /* + * The new request is associated with our IRP and will be deleted during its completion. + */ + + /* populate the Close request */ + Request->Kind = FspFsctlTransactCloseKind; + Request->Req.Close.UserContext = UserContext; + Request->Req.Close.UserContext2 = UserContext2; + + /* post as a work request; this allows us to complete our own IRP and return immediately! */ + if (!FspIopPostWorkRequest(DeviceObject, Request)) + /* no need to delete the request here as FspIopPostWorkRequest() will do so in all cases */ + goto leak_exit; + + Result = STATUS_SUCCESS; + + goto exit; + + leak_exit:; +#if DBG + DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%llx: " + "error: the user-mode file system handle will be leaked!", + IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, + UserContext, UserContext2); +#endif + + /* IRP_MJ_CLOSE cannot really fail :-\ */ + Result = STATUS_SUCCESS; + + exit:; + } + finally + { + FspDeviceRelease(FsvrtDeviceObject); + } + + return Result; +} + +VOID FspFsvolCloseComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC("FileObject=%p", IrpSp->FileObject); +} + +NTSTATUS FspClose( + PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + FSP_ENTER_MJ(PAGED_CODE()); + + ASSERT(IRP_MJ_CLOSE == IrpSp->MajorFunction); + + switch (FspDeviceExtension(DeviceObject)->Kind) + { + case FspFsvolDeviceExtensionKind: + FSP_RETURN(Result = FspFsvolClose(DeviceObject, Irp, IrpSp)); + case FspFsvrtDeviceExtensionKind: + FSP_RETURN(Result = FspFsvrtClose(DeviceObject, Irp, IrpSp)); + case FspFsctlDeviceExtensionKind: + FSP_RETURN(Result = FspFsctlClose(DeviceObject, Irp, IrpSp)); + default: + FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); + } + + FSP_LEAVE_MJ("FileObject=%p", IrpSp->FileObject); +} diff --git a/src0/sys/create.c b/src0/sys/create.c new file mode 100644 index 00000000..052558fe --- /dev/null +++ b/src0/sys/create.c @@ -0,0 +1,767 @@ +/** + * @file sys/create.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +static NTSTATUS FspFsctlCreate( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvrtCreate( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvolCreate( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_IOPREP_DISPATCH FspFsvolCreatePrepare; +FSP_IOCMPL_DISPATCH FspFsvolCreateComplete; +static VOID FspFsvolCreateCleanupClose( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); +FSP_IOP_REQUEST_FINI FspFsvolCreateRequestFini; +FSP_DRIVER_DISPATCH FspCreate; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFsctlCreate) +#pragma alloc_text(PAGE, FspFsvrtCreate) +#pragma alloc_text(PAGE, FspFsvolCreate) +#pragma alloc_text(PAGE, FspFsvolCreatePrepare) +#pragma alloc_text(PAGE, FspFsvolCreateComplete) +#pragma alloc_text(PAGE, FspFsvolCreateCleanupClose) +#pragma alloc_text(PAGE, FspFsvolCreateRequestFini) +#pragma alloc_text(PAGE, FspCreate) +#endif + +enum +{ + RequestFsContext = 0, + RequestAccessToken, +}; + +static NTSTATUS FspFsctlCreate( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_SUCCESS; + Irp->IoStatus.Information = FILE_OPENED; + return Result; +} + +static NTSTATUS FspFsvrtCreate( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_SUCCESS; + Irp->IoStatus.Information = FILE_OPENED; + return Result; +} + +static NTSTATUS FspFsvolCreate( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + /* open the volume object? */ + if (0 == IrpSp->FileObject->FileName.Length && + (0 == IrpSp->FileObject->RelatedFileObject || + 0 == IrpSp->FileObject->RelatedFileObject->FsContext)) + { + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; + + IrpSp->FileObject->Vpb = FsvrtDeviceObject->Vpb; + Irp->IoStatus.Information = FILE_OPENED; + return STATUS_SUCCESS; + } + + NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + + PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; + if (!FspDeviceRetain(FsvrtDeviceObject)) + return STATUS_CANCELLED; + + try + { + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + PFILE_OBJECT FileObject = IrpSp->FileObject; + PFILE_OBJECT RelatedFileObject = FileObject->RelatedFileObject; + UNICODE_STRING FileName = FileObject->FileName; + PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; + ULONG CreateOptions = IrpSp->Parameters.Create.Options; + USHORT FileAttributes = IrpSp->Parameters.Create.FileAttributes; + PSECURITY_DESCRIPTOR SecurityDescriptor = AccessState->SecurityDescriptor; + ULONG SecurityDescriptorSize = 0; + LARGE_INTEGER AllocationSize = Irp->Overlay.AllocationSize; + ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; + USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; + PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer; + //ULONG EaLength = IrpSp->Parameters.Create.EaLength; + ULONG Flags = IrpSp->Flags; + KPROCESSOR_MODE RequestorMode = + FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode; + BOOLEAN HasTraversePrivilege = + BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE); + BOOLEAN IsAbsoluteSecurityDescriptor = FALSE; + BOOLEAN IsSelfRelativeSecurityDescriptor = FALSE; + BOOLEAN HasTrailingBackslash = FALSE; + FSP_FILE_CONTEXT *FsContext = 0; + FSP_FSCTL_TRANSACT_REQ *Request; + + /* cannot open a paging file */ + if (FlagOn(Flags, SL_OPEN_PAGING_FILE)) + { + Result = STATUS_ACCESS_DENIED; + goto exit; + } + + /* cannot open files by fileid */ + if (FlagOn(CreateOptions, FILE_OPEN_BY_FILE_ID)) + { + Result = STATUS_NOT_IMPLEMENTED; + goto exit; + } + + /* do we support EA? */ + if (0 != EaBuffer && !FsvrtDeviceExtension->VolumeParams.EaSupported) + { + Result = STATUS_EAS_NOT_SUPPORTED; + goto exit; + } + + /* check create options */ + if (FlagOn(CreateOptions, FILE_NON_DIRECTORY_FILE) && + FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) + { + Result = STATUS_INVALID_PARAMETER; + goto exit; + } + + /* check security descriptor validity */ + if (0 != SecurityDescriptor) + { + IsAbsoluteSecurityDescriptor = RtlValidSecurityDescriptor(SecurityDescriptor); + if (IsAbsoluteSecurityDescriptor) + { + Result = RtlAbsoluteToSelfRelativeSD(SecurityDescriptor, 0, &SecurityDescriptorSize); + if (STATUS_BUFFER_TOO_SMALL != Result) + { + Result = STATUS_INVALID_PARAMETER; + goto exit; + } + } + else + { + SecurityDescriptorSize = RtlLengthSecurityDescriptor(SecurityDescriptor); + IsSelfRelativeSecurityDescriptor = RtlValidRelativeSecurityDescriptor( + SecurityDescriptor, SecurityDescriptorSize, 0); + if (!IsSelfRelativeSecurityDescriptor) + { + Result = STATUS_INVALID_PARAMETER; + goto exit; + } + } + } + + /* according to fastfat, filenames that begin with two backslashes are ok */ + if (sizeof(WCHAR) * 2 <= FileName.Length && + L'\\' == FileName.Buffer[1] && L'\\' == FileName.Buffer[0]) + { + FileName.Length -= sizeof(WCHAR); + FileName.MaximumLength -= sizeof(WCHAR); + FileName.Buffer++; + + if (sizeof(WCHAR) * 2 <= FileName.Length && + L'\\' == FileName.Buffer[1] && L'\\' == FileName.Buffer[0]) + { + Result = STATUS_OBJECT_NAME_INVALID; + goto exit; + } + } + + /* check for trailing backslash */ + if (sizeof(WCHAR) * 2/* not empty or root */ <= 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]) + { + Result = STATUS_OBJECT_NAME_INVALID; + goto exit; + } + } + if (HasTrailingBackslash && !FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) + { + Result = STATUS_OBJECT_NAME_INVALID; + goto exit; + } + + /* is this a relative or absolute open? */ + if (0 != RelatedFileObject) + { + FSP_FILE_CONTEXT *RelatedFsContext = RelatedFileObject->FsContext; + + /* is this a valid RelatedFileObject? */ + if (!FspFileContextIsValid(RelatedFsContext)) + { + Result = STATUS_OBJECT_PATH_NOT_FOUND; + goto exit; + } + + /* must be a relative path */ + if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0]) + { + Result = STATUS_OBJECT_NAME_INVALID; + goto exit; + } + + /* cannot FILE_DELETE_ON_CLOSE on the root directory */ + if (sizeof(WCHAR) == RelatedFsContext->FileName.Length && + 0 == FileName.Length && + FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) + { + Result = STATUS_CANNOT_DELETE; + goto exit; + } + + /* + * 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. + */ + BOOLEAN AppendBackslash = + sizeof(WCHAR) * 2/* not empty or root */ <= RelatedFsContext->FileName.Length && + sizeof(WCHAR) <= FileName.Length && L':' != FileName.Buffer[0]; + Result = FspFileContextCreate(DeviceObject, + RelatedFsContext->FileName.Length + AppendBackslash * sizeof(WCHAR) + FileName.Length, + &FsContext); + if (!NT_SUCCESS(Result)) + goto exit; + + Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &RelatedFsContext->FileName); + ASSERT(NT_SUCCESS(Result)); + if (AppendBackslash) + { + Result = RtlAppendUnicodeToString(&FsContext->FileName, L"\\"); + ASSERT(NT_SUCCESS(Result)); + } + } + else + { + /* must be an absolute path */ + if (sizeof(WCHAR) <= FileName.Length && L'\\' != FileName.Buffer[0]) + { + Result = STATUS_OBJECT_NAME_INVALID; + goto exit; + } + + /* cannot FILE_DELETE_ON_CLOSE on the root directory */ + if (sizeof(WCHAR) == FileName.Length && + FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) + { + Result = STATUS_CANNOT_DELETE; + goto exit; + } + + Result = FspFileContextCreate(DeviceObject, + FileName.Length, + &FsContext); + if (!NT_SUCCESS(Result)) + goto exit; + } + + Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &FileName); + ASSERT(NT_SUCCESS(Result)); + + /* create the user-mode file system request */ + Result = FspIopCreateRequestEx(Irp, &FsContext->FileName, SecurityDescriptorSize, + FspFsvolCreateRequestFini, &Request); + if (!NT_SUCCESS(Result)) + { + FspFileContextRelease(FsContext); + goto exit; + } + + /* + * The new request is associated with our IRP and will be deleted during its completion. + * Go ahead and associate our FsContext with the Request as well. + */ + FspIopRequestContext(Request, RequestFsContext) = FsContext; + + /* populate the Create request */ + Request->Kind = FspFsctlTransactCreateKind; + Request->Req.Create.CreateOptions = CreateOptions; + Request->Req.Create.FileAttributes = FileAttributes; + Request->Req.Create.SecurityDescriptor.Offset = 0 == SecurityDescriptorSize ? 0 : + FSP_FSCTL_DEFAULT_ALIGN_UP(Request->FileName.Size); + Request->Req.Create.SecurityDescriptor.Size = (UINT16)SecurityDescriptorSize; + Request->Req.Create.AllocationSize = AllocationSize.QuadPart; + Request->Req.Create.AccessToken = 0; + Request->Req.Create.DesiredAccess = DesiredAccess; + Request->Req.Create.ShareAccess = ShareAccess; + Request->Req.Create.Ea.Offset = 0; + Request->Req.Create.Ea.Size = 0; + Request->Req.Create.UserMode = UserMode == RequestorMode; + Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege; + Request->Req.Create.OpenTargetDirectory = BooleanFlagOn(Flags, SL_OPEN_TARGET_DIRECTORY); + Request->Req.Create.CaseSensitive = BooleanFlagOn(Flags, SL_CASE_SENSITIVE); + + /* copy the security descriptor into the request */ + if (IsAbsoluteSecurityDescriptor) + { + Result = RtlAbsoluteToSelfRelativeSD(SecurityDescriptor, + Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, &SecurityDescriptorSize); + if (!NT_SUCCESS(Result)) + { + if (STATUS_BAD_DESCRIPTOR_FORMAT == Result || STATUS_BUFFER_TOO_SMALL == Result) + Result = STATUS_INVALID_PARAMETER; /* should not happen */ + goto exit; + } + } + else if (IsSelfRelativeSecurityDescriptor) + RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, + SecurityDescriptor, SecurityDescriptorSize); + + Result = STATUS_PENDING; + + exit:; + } + finally + { + FspDeviceRelease(FsvrtDeviceObject); + } + + return Result; +} + +NTSTATUS FspFsvolCreatePrepare( + PIRP Irp, FSP_FSCTL_TRANSACT_REQ *Request) +{ + FSP_ENTER_IOP(PAGED_CODE()); + + PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = + FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject); + + /* is the user-mode file system doing access checks? */ + if (!FsvrtDeviceExtension->VolumeParams.NoSystemAccessCheck) + { + ASSERT(0 == Request->Req.Create.AccessToken); + FSP_RETURN(Result = STATUS_SUCCESS); + } + + /* get a user-mode handle to the access token */ + PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; + HANDLE UserModeAccessToken; + Result = ObOpenObjectByPointer(SeQuerySubjectContextToken(&AccessState->SubjectSecurityContext), + 0, 0, TOKEN_QUERY, *SeTokenObjectType, UserMode, &UserModeAccessToken); + if (!NT_SUCCESS(Result)) + FSP_RETURN(); + + /* send the user-mode handle to the user-mode file system */ + FspIopRequestContext(Request, RequestAccessToken) = UserModeAccessToken; + Request->Req.Create.AccessToken = (UINT_PTR)UserModeAccessToken; + + FSP_LEAVE_IOP(); +} + +VOID FspFsvolCreateComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + /* + * NOTE: + * In the following we may have to close the just opened file object. But we must + * never close a file we just created, because this will leave an orphan file on + * the disk. + * + * Files may have to be closed if a security access or share access check fails. In + * both those cases we were opening an existing file and so it is safe to close it. + * + * Because of how IRP_MJ_CREATE works in Windows, it is difficult to improve on this + * scheme without introducing a 2-phase Create protocol, which is undesirable as it + * means two trips into user-mode for a single Create request. + */ + + PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + PDEVICE_OBJECT FsvrtDeviceObject = FsvolDeviceExtension->FsvrtDeviceObject; + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); + PFILE_OBJECT FileObject = IrpSp->FileObject; + PACCESS_STATE AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; + ULONG CreateOptions = IrpSp->Parameters.Create.Options; + BOOLEAN FileCreated = FILE_CREATED == Response->IoStatus.Information; + UINT32 ResponseFileAttributes = Response->Rsp.Create.Opened.FileAttributes; + PSECURITY_DESCRIPTOR SecurityDescriptor; + ULONG SecurityDescriptorSize; + UNICODE_STRING ReparseFileName; + ACCESS_MASK DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; + PPRIVILEGE_SET Privileges = 0; + USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; + ULONG Flags = IrpSp->Flags; + KPROCESSOR_MODE RequestorMode = + FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode; + FSP_FILE_CONTEXT *FsContext = FspIopRequestContext(Request, RequestFsContext); + ACCESS_MASK GrantedAccess; + BOOLEAN Inserted = FALSE; + + /* did the user-mode file system sent us a failure code? */ + if (!NT_SUCCESS(Response->IoStatus.Status)) + { + Irp->IoStatus.Information = Response->IoStatus.Information; + Result = Response->IoStatus.Status; + FSP_RETURN(); + } + + /* special case STATUS_REPARSE */ + if (STATUS_REPARSE == Result) + { + 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 (0 == ReparseFileName.Length || + (PUINT8)ReparseFileName.Buffer + ReparseFileName.Length > + (PUINT8)Response + Response->Size) + FSP_RETURN(); + + if (ReparseFileName.Length > FileObject->FileName.MaximumLength) + { + PVOID Buffer = FspAllocExternal(ReparseFileName.Length); + if (0 == Buffer) + FSP_RETURN(Result = STATUS_INSUFFICIENT_RESOURCES); + FspFreeExternal(FileObject->FileName.Buffer); + FileObject->FileName.MaximumLength = ReparseFileName.Length; + FileObject->FileName.Buffer = Buffer; + } + FileObject->FileName.Length = 0; + RtlCopyUnicodeString(&FileObject->FileName, &ReparseFileName); + } + else + if (IO_REMOUNT == Response->IoStatus.Information) + { + if (0 != ReparseFileName.Length) + FSP_RETURN(); + } + else + FSP_RETURN(); + + Irp->IoStatus.Information = Response->IoStatus.Information; + Result = Response->IoStatus.Status; + FSP_RETURN(); + } + + /* are we doing access checks? */ + if (!FsvrtDeviceExtension->VolumeParams.NoSystemAccessCheck) + { + /* read-only attribute check */ + if (!FileCreated && FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_READONLY)) + { + /* from fastfat: allowed accesses when read-only */ + ACCESS_MASK Allowed = + DELETE | READ_CONTROL | WRITE_OWNER | WRITE_DAC | + SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | + FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA | + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | + FILE_EXECUTE | FILE_TRAVERSE | FILE_LIST_DIRECTORY | + FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD; + + if (FlagOn(DesiredAccess, ~Allowed)) + { + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(Result = STATUS_ACCESS_DENIED); + } + else + if (!FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_DIRECTORY) && + FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) + { + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(Result = STATUS_CANNOT_DELETE); + } + } + + /* security descriptor check */ + SecurityDescriptor = + (PVOID)(Response->Buffer + Response->Rsp.Create.Opened.SecurityDescriptor.Offset); + SecurityDescriptorSize = Response->Rsp.Create.Opened.SecurityDescriptor.Size; + if (0 != SecurityDescriptorSize) + { + if ((PUINT8)SecurityDescriptor + SecurityDescriptorSize > + (PUINT8)Response + Response->Size || + !FspValidRelativeSecurityDescriptor(SecurityDescriptor, SecurityDescriptorSize, 0)) + { + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(Result = STATUS_ACCESS_DENIED); + } + + /* access check */ + if (!SeAccessCheck(SecurityDescriptor, + &AccessState->SubjectSecurityContext, + FALSE, + DesiredAccess, + AccessState->PreviouslyGrantedAccess, + &Privileges, + IoGetFileObjectGenericMapping(), + RequestorMode, + &GrantedAccess, + &Result)) + { + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(); + } + + if (0 != Privileges) + { + Result = SeAppendPrivileges(AccessState, Privileges); + SeFreePrivileges(Privileges); + if (!NT_SUCCESS(Result)) + { + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(); + } + } + + SetFlag(AccessState->PreviouslyGrantedAccess, GrantedAccess); + ClearFlag(AccessState->RemainingDesiredAccess, GrantedAccess); + } + } + + /* were we asked to open a directory or non-directory? */ + if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE) && + !FileCreated && !FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(Result = STATUS_NOT_A_DIRECTORY); + } + if (FlagOn(CreateOptions, FILE_NON_DIRECTORY_FILE) && + !FileCreated && FlagOn(ResponseFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(Result = STATUS_FILE_IS_A_DIRECTORY); + } + + /* + * The following must be done under the file system volume device Resource, + * because we are manipulating its GenericTable and accessing foreign FsContext's. + */ + ExAcquireResourceExclusiveLite(&FsvolDeviceExtension->Base.Resource, TRUE); + try + { + /* insert the newly created FsContext into our generic table */ + FsContext = FspFsvolDeviceInsertContext(DeviceObject, + FsContext->UserContext, FsContext, &FsContext->ElementStorage, &Inserted); + ASSERT(0 != FsContext); + + /* share access check */ + if (Inserted) + { + /* + * This is a newly created FsContext. Set its share access and + * increment its open count. There is no need to acquire the + * FsContext's Resource (because it is newly created). + */ + IoSetShareAccess(AccessState->PreviouslyGrantedAccess, + ShareAccess, FileObject, &FsContext->ShareAccess); + FspFileContextOpen(FsContext); + if (FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) + FsContext->DeleteOnClose = TRUE; + Result = STATUS_SUCCESS; + } + else + { + /* + * This is an existing FsContext. We must acquire its Resource and + * check if there is a delete pending and the share access. Only if + * both tests succeed we increment the open count and report success. + */ + ExAcquireResourceExclusiveLite(FsContext->Header.Resource, TRUE); + if (FsContext->DeletePending) + Result = STATUS_DELETE_PENDING; + else + Result = IoCheckShareAccess(AccessState->PreviouslyGrantedAccess, + ShareAccess, FileObject, &FsContext->ShareAccess, TRUE); + if (NT_SUCCESS(Result)) + { + FspFileContextRetain(FsContext); + FspFileContextOpen(FsContext); + if (FlagOn(CreateOptions, FILE_DELETE_ON_CLOSE)) + FsContext->DeleteOnClose = TRUE; + } + ExReleaseResourceLite(FsContext->Header.Resource); + } + } + finally + { + ExReleaseResourceLite(&FsvolDeviceExtension->Base.Resource); + } + + /* did we fail our share access checks? */ + if (!NT_SUCCESS(Result)) + { + ASSERT(!Inserted); + FspFsvolCreateCleanupClose(Irp, Response); + FSP_RETURN(); + } + + /* + * Looks like SUCCESS! + */ + + /* did an FsContext with the same UserContext already exist? */ + if (!Inserted) + /* delete the newly created FsContext as it is not being used */ + FspFileContextRelease(FspIopRequestContext(Request, RequestFsContext)); + + /* disassociate our FsContext from the Request */ + FspIopRequestContext(Request, RequestFsContext) = 0; + + /* record the user-mode file system contexts */ + FsContext->UserContext = Response->Rsp.Create.Opened.UserContext; + FileObject->FsContext = FsContext; + FileObject->FsContext2 = (PVOID)(UINT_PTR)Response->Rsp.Create.Opened.UserContext2; + + /* finish seting up the FileObject */ + FileObject->Vpb = FsvrtDeviceObject->Vpb; + + /* SUCCESS! */ + Irp->IoStatus.Information = Response->IoStatus.Information; + Result = Response->IoStatus.Status; + + FSP_LEAVE_IOC( + "FileObject=%p[%p:\"%wZ\"]", + IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName); +} + +static VOID FspFsvolCreateCleanupClose( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + PAGED_CODE(); + + /* + * This routine handles the case where we must close an open file, + * because of a failure during Create completion. We simply create + * a CreateClose request and we post it as a work item. + * + * Ideally there would be no failure modes for this routine. Reality is + * different. + * + * The more serious (but perhaps non-existent in practice) failure is a + * memory allocation failure. In this case we will leak the user-mode + * file system handle! + * + * This routine may also fail if we cannot post a work item, which means that + * the virtual volume device and the file system volume device are being + * deleted. Because it is assumed that only the user-mode file system would + * initiate a device deletion, this case is more benign (presumably the file + * system knows to close off all its handles when tearing down its devices). + */ + + NTSTATUS Result; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = + FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject); + FSP_FSCTL_TRANSACT_REQ *OriginalRequest = FspIrpRequest(Irp); + FSP_FILE_CONTEXT *FsContext = FspIopRequestContext(OriginalRequest, RequestFsContext); + UINT64 UserContext = Response->Rsp.Create.Opened.UserContext; + UINT64 UserContext2 = Response->Rsp.Create.Opened.UserContext2; + BOOLEAN FileNameRequired = 0 != FsvrtDeviceExtension->VolumeParams.FileNameRequired; + FSP_FSCTL_TRANSACT_REQ *Request; + + /* create the user-mode file system request */ + Result = FspIopCreateRequest(0, FileNameRequired ? &FsContext->FileName : 0, 0, &Request); + if (!NT_SUCCESS(Result)) + goto leak_exit; + + /* populate the CreateCleanupClose request */ + Request->Kind = FspFsctlTransactCreateCleanupCloseKind; + Request->Req.Cleanup.UserContext = UserContext; + Request->Req.Cleanup.UserContext2 = UserContext2; + Request->Req.Cleanup.Delete = FILE_CREATED == Response->IoStatus.Information; + + /* post as a work request */ + if (!FspIopPostWorkRequest(DeviceObject, Request)) + /* no need to delete the request here as FspIopPostWorkRequest() will do so in all cases */ + goto leak_exit; + + goto exit; + +leak_exit:; +#if DBG + DEBUGLOG("FileObject=%p[%p:\"%wZ\"], UserContext=%llx, UserContext2=%llx: " + "error: the user-mode file system handle will be leaked!", + IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, + UserContext, UserContext2); +#endif + +exit:; +} + +VOID FspFsvolCreateRequestFini(PVOID Context[3]) +{ + PAGED_CODE(); + + if (0 != Context[RequestFsContext]) + FspFileContextRelease(Context[RequestFsContext]); + + if (0 != Context[RequestAccessToken]) + { +#if DBG + NTSTATUS Result0; + Result0 = ObCloseHandle(Context[RequestAccessToken], KernelMode); + if (!NT_SUCCESS(Result0)) + DEBUGLOG("ObCloseHandle() = %s", NtStatusSym(Result0)); +#else + ObCloseHandle(Context[RequestAccessToken], KernelMode); +#endif + } +} + +NTSTATUS FspCreate( + PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + FSP_ENTER_MJ(PAGED_CODE()); + + ASSERT(IRP_MJ_CREATE == IrpSp->MajorFunction); + + switch (FspDeviceExtension(DeviceObject)->Kind) + { + case FspFsvolDeviceExtensionKind: + FSP_RETURN(Result = FspFsvolCreate(DeviceObject, Irp, IrpSp)); + case FspFsvrtDeviceExtensionKind: + FSP_RETURN(Result = FspFsvrtCreate(DeviceObject, Irp, IrpSp)); + case FspFsctlDeviceExtensionKind: + FSP_RETURN(Result = FspFsctlCreate(DeviceObject, Irp, IrpSp)); + default: + FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); + } + + FSP_LEAVE_MJ( + "FileObject=%p[%p:\"%wZ\"], " + "Flags=%x, " + "DesiredAccess=%#lx, " + "ShareAccess=%#x, " + "Options=%#lx, " + "FileAttributes=%#x, " + "AllocationSize=%#lx:%#lx, " + "Ea=%p, EaLength=%ld", + IrpSp->FileObject, IrpSp->FileObject->RelatedFileObject, IrpSp->FileObject->FileName, + IrpSp->Flags, + IrpSp->Parameters.Create.SecurityContext->DesiredAccess, + IrpSp->Parameters.Create.ShareAccess, + IrpSp->Parameters.Create.Options, + IrpSp->Parameters.Create.FileAttributes, + Irp->Overlay.AllocationSize.HighPart, Irp->Overlay.AllocationSize.LowPart, + Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength); +} diff --git a/src/sys/fileobj.c b/src0/sys/fileobj.c similarity index 100% rename from src/sys/fileobj.c rename to src0/sys/fileobj.c diff --git a/src0/sys/fsctl.c b/src0/sys/fsctl.c new file mode 100644 index 00000000..9b97c926 --- /dev/null +++ b/src0/sys/fsctl.c @@ -0,0 +1,625 @@ +/** + * @file sys/fsctl.c + * + * @copyright 2015 Bill Zissimopoulos + */ + +#include + +/* + * Overview + * + * The fsctl module provides the IOCTL interface to interact with the + * user-mode file system. The user-mode file system can use the IOCTL's + * to create new volumes, delete them (while they are live!) and transact + * with them. + * + * + * Volume Creation + * + * The creation of a new volume is performed using an FSP_FSCTL_CREATE + * IOCTL code. Creation is simple: a new device \Device\Volume{GUID} is + * created and its path is returned to the user-mode file system. The + * user-mode file system also passes a security descriptor to associate + * with the new virtual volume device so that only the creating user-mode + * file system can control the new volume. + * + * + * Volume Deletion + * + * Deletion of an existing volume is performed using FSP_FSCTL_DELETE and + * is quite a bit more involved. We must protect against the following two + * eventualities: (1) that the volume is currently in use and cannot simply + * go away, and (2) that a simultaneous mount operation is taking place + * while we are deleting the volume. + * + * To protect against the first eventuality we maintain a reference count + * on all our device extensions. Every time an MJ function is entered, + * the reference count is incremented (FspDeviceRetain). Every time + * an IRP is completed, the reference count is decremented (FspDeviceRelease). + * When the reference count reaches 0 the device is deleted using + * IoDeleteDevice. This ensures that a device will not go away while an + * IRP is being pending/processed. + * + * To protect against the second eventuality we use the lock (ERESOURCE) + * on the root Fsctl device to wrap volume deletion and attempts from the + * system to mount the same volume. We also mark the virtual volume device + * as Deleted in case we attempt to delete it (FspDeviceRelease) but we + * cannot because it is currently in use. + * + * A sticky point is our use of the Windows VPB. It is not well documented + * how one should handle this structure during forcible dismount. The fastfat + * and cdfs samples use a technique where they keep a spare VPB and they swap + * it with the volume one during forcible dismount. We do something similar. + * The issue is what to do with the old VPB, because we can delete a volume + * that is not currently being used. We check the VPB's ReferenceCount and + * we free the VPB in this case. + * + * + * Volume Transact + * + * The user-mode file system's primary interaction with the kernel-mode driver + * is by using the FSP_FSCTL_TRANSACT IOCTL code. Every virtual volume device + * maintains an FSP_IOQ (refer to ioq.c for more). When an FSP_FSCTL_TRANSACT + * arrives it first processes any responses (FSP_FSCTL_TRANSACT_RSP) that the + * user-mode file system has sent to handle requests sent to it using a prior + * FSP_FSCTL_TRANSACT. It then proceeds to handle any pending IRP requests by + * sending the corresponding requests (FSP_FSCTL_TRANSACT_REQ) to the user- + * mode file system. + */ + +static NTSTATUS FspFsctlCreateVolume( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsctlMountVolume( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvrtDeleteVolume( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static WORKER_THREAD_ROUTINE FspFsvrtDeleteVolumeDelayed; +static NTSTATUS FspFsvrtTransact( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsctlFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvrtFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvolFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +FSP_DRIVER_DISPATCH FspFileSystemControl; +FSP_IOCMPL_DISPATCH FspFileSystemControlComplete; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFsctlCreateVolume) +#pragma alloc_text(PAGE, FspFsctlMountVolume) +#pragma alloc_text(PAGE, FspFsvrtDeleteVolume) +#pragma alloc_text(PAGE, FspFsvrtDeleteVolumeDelayed) +#pragma alloc_text(PAGE, FspFsvrtTransact) +#pragma alloc_text(PAGE, FspFsctlFileSystemControl) +#pragma alloc_text(PAGE, FspFsvrtFileSystemControl) +#pragma alloc_text(PAGE, FspFsvolFileSystemControl) +#pragma alloc_text(PAGE, FspFileSystemControl) +#pragma alloc_text(PAGE, FspFileSystemControlComplete) +#endif + +static NTSTATUS FspFsctlCreateVolume( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + /* check parameters */ + ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; + ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer; + PSECURITY_DESCRIPTOR SecurityDescriptor = + (PVOID)((PUINT8)SystemBuffer + FSP_FSCTL_VOLUME_PARAMS_SIZE); + DWORD SecurityDescriptorSize = InputBufferLength - FSP_FSCTL_VOLUME_PARAMS_SIZE; + if (FSP_FSCTL_VOLUME_PARAMS_SIZE >= InputBufferLength || 0 == SystemBuffer || + !FspValidRelativeSecurityDescriptor(SecurityDescriptor, SecurityDescriptorSize, + DACL_SECURITY_INFORMATION)) + return STATUS_INVALID_PARAMETER; + if (FSP_FSCTL_CREATE_BUFFER_SIZEMIN > OutputBufferLength) + return STATUS_BUFFER_TOO_SMALL; + + NTSTATUS Result; + FSP_FSCTL_VOLUME_PARAMS VolumeParams = *(FSP_FSCTL_VOLUME_PARAMS *)SystemBuffer; + PVOID SecurityDescriptorBuf = 0; + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension; + + /* check the passed in VolumeParams */ + if (FspFsctlIrpTimeoutMinimum > VolumeParams.IrpTimeout || + VolumeParams.IrpTimeout > FspFsctlIrpTimeoutMaximum) +#if DBG + /* allow the debug timeout value on debug builds */ + if (FspFsctlIrpTimeoutDebug != VolumeParams.IrpTimeout) +#endif + VolumeParams.IrpTimeout = FspFsctlIrpTimeoutDefault; + if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout || + VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum) + VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault; + + /* create volume guid */ + GUID Guid; + Result = FspCreateGuid(&Guid); + if (!NT_SUCCESS(Result)) + return Result; + + /* copy the security descriptor from the system buffer to a temporary one */ + SecurityDescriptorBuf = FspAlloc(SecurityDescriptorSize); + if (0 == SecurityDescriptorBuf) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(SecurityDescriptorBuf, SecurityDescriptor, SecurityDescriptorSize); + + /* prepare the device name and SDDL */ + PDEVICE_OBJECT FsvrtDeviceObject; + UNICODE_STRING DeviceSddl; + UNICODE_STRING DeviceName; + RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSVRT_DEVICE_SDDL); + RtlInitEmptyUnicodeString(&DeviceName, SystemBuffer, FSP_FSCTL_CREATE_BUFFER_SIZEMIN); + Result = RtlUnicodeStringPrintf(&DeviceName, + L"\\Device\\Volume{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + Guid.Data1, Guid.Data2, Guid.Data3, + Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3], + Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]); + ASSERT(NT_SUCCESS(Result)); + + /* create the virtual volume device */ + FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension = FspFsctlDeviceExtension(DeviceObject); + ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE); + try + { + Result = FspDeviceCreateSecure(FspFsvrtDeviceExtensionKind, SecurityDescriptorSize, + &DeviceName, FILE_DEVICE_VIRTUAL_DISK, + &DeviceSddl, &FspFsvrtDeviceClassGuid, + &FsvrtDeviceObject); + if (NT_SUCCESS(Result)) + { +#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize") + FsvrtDeviceObject->SectorSize = VolumeParams.SectorSize; + FsvrtDeviceExtension = FspFsvrtDeviceExtension(FsvrtDeviceObject); + FsvrtDeviceExtension->FsctlDeviceObject = DeviceObject; + FsvrtDeviceExtension->VolumeParams = VolumeParams; + RtlCopyMemory(FsvrtDeviceExtension->SecurityDescriptorBuf, + SecurityDescriptorBuf, SecurityDescriptorSize); + FspDeviceInitComplete(FsvrtDeviceObject); + Irp->IoStatus.Information = DeviceName.Length + sizeof(WCHAR); + FspFsctlDeviceVolumeCreated(DeviceObject); + } + } + finally + { + ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource); + } + + /* free the temporary security descriptor */ + if (0 != SecurityDescriptorBuf) + FspFree(SecurityDescriptorBuf); + + return Result; +} + +static NTSTATUS FspFsctlMountVolume( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result; + FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension = FspFsctlDeviceExtension(DeviceObject); + + ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE); + try + { + PDEVICE_OBJECT *DeviceObjects = 0; + ULONG DeviceObjectCount = 0; + PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb; + PDEVICE_OBJECT FsvrtDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject; + PDEVICE_OBJECT FsvolDeviceObject; + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = + FspFsvrtDeviceExtension(FsvrtDeviceObject); + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; + + /* check the passed in volume object; it must be one of our own and not marked Deleted */ + Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount); + if (NT_SUCCESS(Result)) + { + Result = STATUS_UNRECOGNIZED_VOLUME; + for (ULONG i = 0; DeviceObjectCount > i; i++) + if (DeviceObjects[i] == FsvrtDeviceObject) + { + if (FspDeviceRetain(FsvrtDeviceObject)) + { + if (!FsvrtDeviceExtension->Deleted && + FILE_DEVICE_VIRTUAL_DISK == FsvrtDeviceObject->DeviceType) + Result = STATUS_SUCCESS; + else + FspDeviceRelease(FsvrtDeviceObject); + } + break; + } + FspDeviceDeleteList(DeviceObjects, DeviceObjectCount); + } + if (!NT_SUCCESS(Result)) + goto exit; + + /* create the file system device object */ + Result = FspDeviceCreate(FspFsvolDeviceExtensionKind, 0, + DeviceObject->DeviceType, + &FsvolDeviceObject); + if (NT_SUCCESS(Result)) + { + /* + * Reference the virtual volume device so that it will not go away while the + * file system device object is alive! + */ + ObReferenceObject(FsvrtDeviceObject); + +#pragma prefast(suppress:28175, "We are a filesystem: ok to access SectorSize") + FsvolDeviceObject->SectorSize = FsvrtDeviceExtension->VolumeParams.SectorSize; + FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + FsvolDeviceExtension->FsvrtDeviceObject = FsvrtDeviceObject; + FsvrtDeviceExtension->FsvolDeviceObject = FsvolDeviceObject; + FspDeviceInitComplete(FsvolDeviceObject); + Vpb->DeviceObject = FsvolDeviceObject; + Vpb->SerialNumber = FsvrtDeviceExtension->VolumeParams.SerialNumber; + Irp->IoStatus.Information = 0; + } + + FspDeviceRelease(FsvrtDeviceObject); + + exit:; + } + finally + { + ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource); + } + + return Result; +} + +typedef struct +{ + PDEVICE_OBJECT FsvolDeviceObject; + PVPB OldVpb; + FSP_WORK_ITEM_WITH_DELAY WorkItemWithDelay; +} FSP_FSVRT_DELETE_VOLUME_WORK_ITEM; + +static NTSTATUS FspFsvrtDeleteVolume( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result; + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); + FSP_FSCTL_DEVICE_EXTENSION *FsctlDeviceExtension = + FspFsctlDeviceExtension(FsvrtDeviceExtension->FsctlDeviceObject); + + ExAcquireResourceExclusiveLite(&FsctlDeviceExtension->Base.Resource, TRUE); + try + { + PDEVICE_OBJECT FsctlDeviceObject = FsvrtDeviceExtension->FsctlDeviceObject; + PDEVICE_OBJECT FsvolDeviceObject = FsvrtDeviceExtension->FsvolDeviceObject; + PVPB OldVpb; + BOOLEAN DeleteVpb = FALSE; + BOOLEAN DeleteDelayed = FALSE; + LARGE_INTEGER DelayTimeout; + FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = 0; + KIRQL Irql; + + /* access check */ + Result = FspSecuritySubjectContextAccessCheck( + FsvrtDeviceExtension->SecurityDescriptorBuf, FILE_WRITE_DATA, Irp->RequestorMode); + if (!NT_SUCCESS(Result)) + goto exit; + + /* pre-allocate a work item in case we need it for delayed delete */ + WorkItem = FspAllocNonPaged(sizeof *WorkItem); + if (0 == WorkItem) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + /* mark the virtual volume device as deleted */ + FsvrtDeviceExtension->Deleted = TRUE; + + /* stop the I/O queue */ + FspIoqStop(&FsvrtDeviceExtension->Ioq); + + /* swap the preallocated VPB */ +#pragma prefast(push) +#pragma prefast(disable:28175, "We are a filesystem: ok to access Vpb") + IoAcquireVpbSpinLock(&Irql); + OldVpb = DeviceObject->Vpb; + if (0 != OldVpb && 0 != FsvrtDeviceExtension->SwapVpb) + { + DeviceObject->Vpb = FsvrtDeviceExtension->SwapVpb; + DeviceObject->Vpb->Size = sizeof *DeviceObject->Vpb; + DeviceObject->Vpb->Type = IO_TYPE_VPB; + DeviceObject->Vpb->Flags = FlagOn(OldVpb->Flags, VPB_REMOVE_PENDING); + DeviceObject->Vpb->RealDevice = OldVpb->RealDevice; + DeviceObject->Vpb->RealDevice->Vpb = DeviceObject->Vpb; + FsvrtDeviceExtension->SwapVpb = 0; + DeleteVpb = 0 == OldVpb->ReferenceCount; + DeleteDelayed = !DeleteVpb && 0 != FsvolDeviceObject; + if (DeleteDelayed) + /* keep VPB around for delayed delete */ + OldVpb->ReferenceCount++; + } + IoReleaseVpbSpinLock(Irql); + if (DeleteDelayed) + /* keep fsvol around for delayed delete */ + FspDeviceRetain(FsvolDeviceObject); + else if (DeleteVpb) + FspFreeExternal(OldVpb); +#pragma prefast(pop) + + /* release the file system device and virtual volume objects */ + FsvrtDeviceExtension->FsvolDeviceObject = 0; + if (0 != FsvolDeviceObject) + FspDeviceRelease(FsvolDeviceObject); + FspDeviceRelease(DeviceObject); + + FspFsctlDeviceVolumeDeleted(FsctlDeviceObject); + + /* are we doing delayed delete of VPB and fsvol? */ + if (DeleteDelayed) + { + DelayTimeout.QuadPart = 300/*ms*/ * -10000; + WorkItem->FsvolDeviceObject = FsvolDeviceObject; + WorkItem->OldVpb = OldVpb; + FspInitializeWorkItemWithDelay(&WorkItem->WorkItemWithDelay, + FspFsvrtDeleteVolumeDelayed, WorkItem); + FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout); + WorkItem = 0; + } + + Result = STATUS_SUCCESS; + + exit: + if (0 != WorkItem) + FspFree(WorkItem); + } + finally + { + ExReleaseResourceLite(&FsctlDeviceExtension->Base.Resource); + } + + return Result; +} + +static VOID FspFsvrtDeleteVolumeDelayed(PVOID Context) +{ + PAGED_CODE(); + + FSP_FSVRT_DELETE_VOLUME_WORK_ITEM *WorkItem = Context; + BOOLEAN DeleteVpb = FALSE; + LARGE_INTEGER DelayTimeout; + KIRQL Irql; + + IoAcquireVpbSpinLock(&Irql); + ASSERT(0 != WorkItem->OldVpb->ReferenceCount); + DeleteVpb = 1 == WorkItem->OldVpb->ReferenceCount; + if (DeleteVpb) + WorkItem->OldVpb->ReferenceCount = 0; + IoReleaseVpbSpinLock(Irql); + if (DeleteVpb) + { + FspFreeExternal(WorkItem->OldVpb); + FspDeviceRelease(WorkItem->FsvolDeviceObject); + FspFree(WorkItem); + } + else + { + DelayTimeout.QuadPart = 300/*ms*/ * -10000; + FspQueueWorkItemWithDelay(&WorkItem->WorkItemWithDelay, DelayTimeout); + } +} + +static NTSTATUS FspFsvrtTransact( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + /* check parameters */ + ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; + ULONG OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + PVOID SystemBuffer = Irp->AssociatedIrp.SystemBuffer; + if (0 == SystemBuffer || + (0 != InputBufferLength && + FSP_FSCTL_DEFAULT_ALIGN_UP(sizeof(FSP_FSCTL_TRANSACT_RSP)) > InputBufferLength)) + return STATUS_INVALID_PARAMETER; + if (FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMIN > OutputBufferLength) + return STATUS_BUFFER_TOO_SMALL; + + NTSTATUS Result; + FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension = FspFsvrtDeviceExtension(DeviceObject); + PUINT8 SystemBufferEnd; + FSP_FSCTL_TRANSACT_RSP *Response, *NextResponse; + FSP_FSCTL_TRANSACT_REQ *Request, *PendingIrpRequest; + PIRP ProcessIrp, PendingIrp; + LARGE_INTEGER Timeout; + + /* access check */ + Result = FspSecuritySubjectContextAccessCheck( + FsvrtDeviceExtension->SecurityDescriptorBuf, FILE_WRITE_DATA, Irp->RequestorMode); + if (!NT_SUCCESS(Result)) + return Result; + + /* process any user-mode file system responses */ + Response = SystemBuffer; + SystemBufferEnd = (PUINT8)SystemBuffer + InputBufferLength; + for (;;) + { + NextResponse = FspFsctlTransactConsumeResponse(Response, SystemBufferEnd); + if (0 == NextResponse) + break; + + ProcessIrp = FspIoqEndProcessingIrp(&FsvrtDeviceExtension->Ioq, (UINT_PTR)Response->Hint); + if (0 == ProcessIrp) + /* either IRP was canceled or a bogus Hint was provided */ + continue; + + FspIopDispatchComplete(ProcessIrp, Response); + + Response = NextResponse; + } + + /* wait for an IRP to arrive */ + KeQuerySystemTime(&Timeout); + Timeout.QuadPart += FsvrtDeviceExtension->VolumeParams.TransactTimeout * 10000; + /* convert millis to nanos and add to absolute time */ + while (0 == (PendingIrp = FspIoqNextPendingIrp(&FsvrtDeviceExtension->Ioq, &Timeout))) + { + if (FspIoqStopped(&FsvrtDeviceExtension->Ioq)) + return STATUS_CANCELLED; + } + if (FspIoqTimeout == PendingIrp) + { + Irp->IoStatus.Information = 0; + return STATUS_SUCCESS; + } + + /* send any pending IRP's to the user-mode file system */ + Request = SystemBuffer; + SystemBufferEnd = (PUINT8)SystemBuffer + OutputBufferLength; + ASSERT(FspFsctlTransactCanProduceRequest(Request, SystemBufferEnd)); + for (;;) + { + PendingIrpRequest = FspIrpRequest(PendingIrp); + + Result = FspIopDispatchPrepare(PendingIrp, PendingIrpRequest); + if (!NT_SUCCESS(Result)) + FspIopCompleteIrp(PendingIrp, Result); + else + { + RtlCopyMemory(Request, PendingIrpRequest, PendingIrpRequest->Size); + Request = FspFsctlTransactProduceRequest(Request, PendingIrpRequest->Size); + + if (!FspIoqStartProcessingIrp(&FsvrtDeviceExtension->Ioq, PendingIrp)) + { + /* + * This can only happen if the Ioq was stopped. Abandon everything + * and return STATUS_CANCELLED. Any IRP's in the Pending and Process + * queues of the Ioq will be cancelled during FspIoqStop(). We must + * also cancel the PendingIrp we have in our hands. + */ + ASSERT(FspIoqStopped(&FsvrtDeviceExtension->Ioq)); + FspIopCompleteIrp(PendingIrp, STATUS_CANCELLED); + return STATUS_CANCELLED; + } + + /* check that we have enough space before pulling the next pending IRP off the queue */ + if (!FspFsctlTransactCanProduceRequest(Request, SystemBufferEnd)) + break; + } + + PendingIrp = FspIoqNextPendingIrp(&FsvrtDeviceExtension->Ioq, 0); + if (0 == PendingIrp) + break; + + } + Irp->IoStatus.Information = (PUINT8)Request - (PUINT8)SystemBuffer; + + return STATUS_SUCCESS; +} + +static NTSTATUS FspFsctlFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST; + switch (IrpSp->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + switch (IrpSp->Parameters.FileSystemControl.FsControlCode) + { + case FSP_FSCTL_CREATE: + Result = FspFsctlCreateVolume(DeviceObject, Irp, IrpSp); + break; + } + break; + case IRP_MN_MOUNT_VOLUME: + Result = FspFsctlMountVolume(DeviceObject, Irp, IrpSp); + break; +#if 0 + case IRP_MN_VERIFY_VOLUME: + break; +#endif + } + return Result; +} + +static NTSTATUS FspFsvrtFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST; + switch (IrpSp->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + switch (IrpSp->Parameters.FileSystemControl.FsControlCode) + { + case FSP_FSCTL_DELETE: + Result = FspFsvrtDeleteVolume(DeviceObject, Irp, IrpSp); + break; + case FSP_FSCTL_TRANSACT: + Result = FspFsvrtTransact(DeviceObject, Irp, IrpSp); + break; + } + break; + } + return Result; +} + +static NTSTATUS FspFsvolFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST; + switch (IrpSp->MinorFunction) + { + case IRP_MN_USER_FS_REQUEST: + break; + } + return Result; +} + +NTSTATUS FspFileSystemControl( + PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + FSP_ENTER_MJ(PAGED_CODE()); + + ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction); + + switch (FspDeviceExtension(DeviceObject)->Kind) + { + case FspFsvolDeviceExtensionKind: + FSP_RETURN(Result = FspFsvolFileSystemControl(DeviceObject, Irp, IrpSp)); + case FspFsvrtDeviceExtensionKind: + FSP_RETURN(Result = FspFsvrtFileSystemControl(DeviceObject, Irp, IrpSp)); + case FspFsctlDeviceExtensionKind: + FSP_RETURN(Result = FspFsctlFileSystemControl(DeviceObject, Irp, IrpSp)); + default: + FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST); + } + + FSP_LEAVE_MJ( + "FileObject=%p%s%s", + IrpSp->FileObject, + IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? ", " : "", + IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? + IoctlCodeSym(IrpSp->Parameters.FileSystemControl.FsControlCode) : ""); +} + +VOID FspFileSystemControlComplete( + PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response) +{ + FSP_ENTER_IOC(PAGED_CODE()); + + FSP_LEAVE_IOC( + "FileObject=%p%s%s", + IrpSp->FileObject, + IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? ", " : "", + IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction ? + IoctlCodeSym(IrpSp->Parameters.FileSystemControl.FsControlCode) : ""); +} diff --git a/src/sys/idevctl.c b/src0/sys/idevctl.c similarity index 100% rename from src/sys/idevctl.c rename to src0/sys/idevctl.c diff --git a/src/sys/misc.c b/src0/sys/misc.c similarity index 100% rename from src/sys/misc.c rename to src0/sys/misc.c