diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 1aa5f931..32583295 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -131,12 +131,7 @@ typedef struct { UINT64 UserContext; UINT64 UserContext2; - UINT32 ReadAccess:1; /* file was open for read access */ - UINT32 WriteAccess:1; /* file was open for write access */ - UINT32 DeleteAccess:1; /* file was open for delete access */ - UINT32 SharedRead:1; /* file was open for shared read access */ - UINT32 SharedWrite:1; /* file was open for shared write access */ - UINT32 SharedDelete:1; /* file was open for shared delete access */ + UINT32 Delete:1; /* file must be deleted */ } Cleanup; struct { diff --git a/src/dll/cleanup.c b/src/dll/cleanup.c index 2a8f565c..93411bd8 100644 --- a/src/dll/cleanup.c +++ b/src/dll/cleanup.c @@ -6,6 +6,7 @@ #include +#if 0 FSP_API VOID FspShareAccessRemove(FSP_FILE_SYSTEM *FileSystem, FSP_FSCTL_TRANSACT_REQ *Request, FSP_FILE_NODE *FileNode) { @@ -65,3 +66,4 @@ FSP_API NTSTATUS FspFileSystemSendCleanupResponse(FSP_FILE_SYSTEM *FileSystem, Response.IoStatus.Information = 0; return FspFileSystemSendResponse(FileSystem, &Response); } +#endif diff --git a/src/sys/cleanup.c b/src/sys/cleanup.c index 215a153c..00efb255 100644 --- a/src/sys/cleanup.c +++ b/src/sys/cleanup.c @@ -60,8 +60,9 @@ static NTSTATUS FspFsvolCleanup( UINT64 UserContext = FsContext->UserContext; UINT64 UserContext2 = (UINT_PTR)FileObject->FsContext2; FSP_FSCTL_TRANSACT_REQ *Request; + BOOLEAN DeletePending; - FspFileContextClose(FsContext, FileObject); + FspFileContextClose(FsContext, FileObject, &DeletePending); /* create the user-mode file system request; MustSucceed because IRP_MJ_CLEANUP cannot fail */ FspIopCreateRequestMustSucceed(Irp, FileNameRequired ? &FsContext->FileName : 0, 0, &Request); @@ -70,12 +71,7 @@ static NTSTATUS FspFsvolCleanup( Request->Kind = FspFsctlTransactCleanupKind; Request->Req.Cleanup.UserContext = UserContext; Request->Req.Cleanup.UserContext2 = UserContext2; - Request->Req.Cleanup.ReadAccess = !!FileObject->ReadAccess; - Request->Req.Cleanup.WriteAccess = !!FileObject->WriteAccess; - Request->Req.Cleanup.DeleteAccess = !!FileObject->DeleteAccess; - Request->Req.Cleanup.SharedRead = !!FileObject->SharedRead; - Request->Req.Cleanup.SharedWrite = !!FileObject->SharedWrite; - Request->Req.Cleanup.SharedDelete = !!FileObject->SharedDelete; + Request->Req.Cleanup.Delete = DeletePending; /* * Note that it is still possible for this request to not be delivered, diff --git a/src/sys/create.c b/src/sys/create.c index 1c0ce99c..4ae84d73 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -359,7 +359,7 @@ NTSTATUS FspFsvolCreatePrepare( FspFileContextPgioUnlock(FsContext); FspFsvolCreatePostClose(FsContext, (UINT_PTR)FileObject->FsContext2); - FspFileContextClose(FsContext, FileObject); + FspFileContextClose(FsContext, FileObject, 0); return STATUS_USER_MAPPED_FILE; } @@ -468,6 +468,7 @@ VOID FspFsvolCreateComplete( /* open the FsContext */ OpenedFsContext = FspFileContextOpen(FsContext, FileObject, Response->Rsp.Create.Opened.GrantedAccess, IrpSp->Parameters.Create.ShareAccess, + DeleteOnClose, &Result); if (0 == OpenedFsContext) { @@ -508,7 +509,7 @@ VOID FspFsvolCreateComplete( { FspFsvolCreatePostClose(FsContext, Response->Rsp.Create.Opened.UserContext2); - FspFileContextClose(FsContext, FileObject); + FspFileContextClose(FsContext, FileObject, 0); Result = DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; FSP_RETURN(); @@ -576,7 +577,7 @@ VOID FspFsvolCreateComplete( { FspFileContextPgioUnlock(FsContext); - FspFileContextClose(FsContext, FileObject); + FspFileContextClose(FsContext, FileObject, 0); Irp->IoStatus.Information = 0; Result = Response->IoStatus.Status; @@ -686,7 +687,7 @@ static VOID FspFsvolCreateOverwriteRequestFini(PVOID Context[3]) if (0 != FileObject) { FspFsvolCreatePostClose(FsContext, (UINT_PTR)FileObject->FsContext2); - FspFileContextClose(FsContext, FileObject); + FspFileContextClose(FsContext, FileObject, 0); } FspFileContextRelease(FsContext); diff --git a/src/sys/driver.h b/src/sys/driver.h index 1da1db3e..667f5d86 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -513,10 +513,15 @@ typedef struct FSP_FILE_CONTEXT_NONPAGED *NonPaged; /* interlocked access */ LONG RefCount; - /* locked access */ + /* locked access (ContextTable lock) */ LONG OpenCount; SHARE_ACCESS ShareAccess; - /* read-only after creation (and insertion in the GenericTable) */ + struct + { + UINT32 DeleteOnClose:1; + UINT32 DeletePending:1; + } Flags; + /* read-only after creation (and insertion in the ContextTable) */ PDEVICE_OBJECT FsvolDeviceObject; UINT64 UserContext; FSP_DEVICE_GENERIC_TABLE_ELEMENT ElementStorage; @@ -527,8 +532,9 @@ NTSTATUS FspFileContextCreate(PDEVICE_OBJECT DeviceObject, ULONG ExtraSize, FSP_FILE_CONTEXT **PFsContext); VOID FspFileContextDelete(FSP_FILE_CONTEXT *FsContext); FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject, - DWORD GrantedAccess, DWORD ShareAccess, NTSTATUS *PResult); -VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject); + DWORD GrantedAccess, DWORD ShareAccess, BOOLEAN DeleteOnClose, NTSTATUS *PResult); +VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject, + PBOOLEAN PDeletePending); static inline VOID FspFileContextRetain(FSP_FILE_CONTEXT *FsContext) { diff --git a/src/sys/filectx.c b/src/sys/filectx.c index 6ffc1081..a5c358f6 100644 --- a/src/sys/filectx.c +++ b/src/sys/filectx.c @@ -9,10 +9,16 @@ NTSTATUS FspFileContextCreate(PDEVICE_OBJECT DeviceObject, ULONG ExtraSize, FSP_FILE_CONTEXT **PFsContext); VOID FspFileContextDelete(FSP_FILE_CONTEXT *Context); +FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject, + DWORD GrantedAccess, DWORD ShareAccess, BOOLEAN DeleteOnClose, NTSTATUS *PResult); +VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject, + PBOOLEAN PDeletePending); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, FspFileContextCreate) #pragma alloc_text(PAGE, FspFileContextDelete) +#pragma alloc_text(PAGE, FspFileContextOpen) +#pragma alloc_text(PAGE, FspFileContextClose) #endif NTSTATUS FspFileContextCreate(PDEVICE_OBJECT DeviceObject, @@ -74,7 +80,7 @@ VOID FspFileContextDelete(FSP_FILE_CONTEXT *FsContext) } FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject, - DWORD GrantedAccess, DWORD ShareAccess, NTSTATUS *PResult) + DWORD GrantedAccess, DWORD ShareAccess, BOOLEAN DeleteOnClose, NTSTATUS *PResult) { /* * Attempt to insert our FsContext into the volume device's generic table. @@ -82,9 +88,12 @@ FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT F * FsContext instead. */ + PAGED_CODE(); + PDEVICE_OBJECT FsvolDeviceObject = FsContext->FsvolDeviceObject; FSP_FILE_CONTEXT *OpenedFsContext; BOOLEAN Inserted; + NTSTATUS Result; FspFsvolDeviceLockContextTable(FsvolDeviceObject); @@ -102,20 +111,21 @@ FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT F ASSERT(OpenedFsContext == FsContext); IoSetShareAccess(GrantedAccess, ShareAccess, FileObject, &FsContext->ShareAccess); - FspFileContextRetain(OpenedFsContext); - OpenedFsContext->OpenCount++; } else { /* * The new FsContext was NOT inserted into the Context table. Instead we are * opening a prior FsContext that we found in the table. - * - * First check and update the share access. If successful then retain the - * opened FsContext for our caller. */ ASSERT(OpenedFsContext != FsContext); + if (OpenedFsContext->Flags.DeletePending) + { + Result = STATUS_DELETE_PENDING; + goto exit; + } + /* * FastFat says to do the following on Vista and above. * @@ -124,22 +134,20 @@ FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT F * write sharing - this is neccessary since a section may exist with no handles * open to the file its based against. */ - NTSTATUS Result = STATUS_SUCCESS; if (!FlagOn(ShareAccess, FILE_SHARE_WRITE) && FlagOn(GrantedAccess, FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE) && MmDoesFileHaveUserWritableReferences(&FsContext->NonPaged->SectionObjectPointers)) + { Result = STATUS_SHARING_VIOLATION; + goto exit; + } /* share access check */ - if (NT_SUCCESS(Result)) - Result = IoCheckShareAccess(GrantedAccess, ShareAccess, FileObject, &FsContext->ShareAccess, TRUE); - if (NT_SUCCESS(Result)) - { - FspFileContextRetain(OpenedFsContext); - OpenedFsContext->OpenCount++; - } - else + Result = IoCheckShareAccess(GrantedAccess, ShareAccess, FileObject, &FsContext->ShareAccess, TRUE); + + exit: + if (!NT_SUCCESS(Result)) { if (0 != PResult) *PResult = Result; @@ -148,23 +156,39 @@ FSP_FILE_CONTEXT *FspFileContextOpen(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT F } } + if (0 != OpenedFsContext) + { + FspFileContextRetain(OpenedFsContext); + OpenedFsContext->OpenCount++; + + if (DeleteOnClose) + OpenedFsContext->Flags.DeleteOnClose = TRUE; + } + FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); return OpenedFsContext; } -VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject) +VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject, + PBOOLEAN PDeletePending) { /* * Close the FsContext. If the OpenCount becomes zero remove it * from the Context table. */ + PAGED_CODE(); + PDEVICE_OBJECT FsvolDeviceObject = FsContext->FsvolDeviceObject; - BOOLEAN Deleted = FALSE; + BOOLEAN Deleted = FALSE, DeletePending; FspFsvolDeviceLockContextTable(FsvolDeviceObject); + if (FsContext->Flags.DeleteOnClose) + FsContext->Flags.DeletePending = TRUE; + DeletePending = 0 != FsContext->Flags.DeletePending; + IoRemoveShareAccess(FileObject, &FsContext->ShareAccess); if (0 == --FsContext->OpenCount) FspFsvolDeviceDeleteContext(FsvolDeviceObject, FsContext->UserContext, &Deleted); @@ -173,4 +197,7 @@ VOID FspFileContextClose(FSP_FILE_CONTEXT *FsContext, PFILE_OBJECT FileObject) if (Deleted) FspFileContextRelease(FsContext); + + if (0 != PDeletePending) + *PDeletePending = Deleted && DeletePending; }