From bd413b9c9be87a5e1e8e158b00223a1d145a5b6f Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 15 Mar 2016 15:09:47 -0700 Subject: [PATCH] sys: FSP_FILE_NODE: add HandleCount field and refactor cleanup/close/rename --- src/sys/cleanup.c | 100 +++---------------------------------- src/sys/close.c | 1 + src/sys/create.c | 6 +-- src/sys/device.c | 52 ++++++++++--------- src/sys/driver.h | 13 +++-- src/sys/file.c | 121 ++++++++++++++++++++++++++++++++++++++------- src/sys/fileinfo.c | 6 +-- 7 files changed, 151 insertions(+), 148 deletions(-) diff --git a/src/sys/cleanup.c b/src/sys/cleanup.c index cf3d8cd9..8b05a1c5 100644 --- a/src/sys/cleanup.c +++ b/src/sys/cleanup.c @@ -14,7 +14,6 @@ static NTSTATUS FspFsvolCleanup( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_IOCMPL_DISPATCH FspFsvolCleanupComplete; static FSP_IOP_REQUEST_FINI FspFsvolCleanupRequestFini; -static VOID FspFsvolCleanupUninitialize(PVOID Context); FSP_DRIVER_DISPATCH FspCleanup; #ifdef ALLOC_PRAGMA @@ -23,7 +22,6 @@ FSP_DRIVER_DISPATCH FspCleanup; #pragma alloc_text(PAGE, FspFsvolCleanup) #pragma alloc_text(PAGE, FspFsvolCleanupComplete) #pragma alloc_text(PAGE, FspFsvolCleanupRequestFini) -#pragma alloc_text(PAGE, FspFsvolCleanupUninitialize) #pragma alloc_text(PAGE, FspCleanup) #endif @@ -33,13 +31,6 @@ enum RequestIrp = 0, }; -typedef struct -{ - PFILE_OBJECT FileObject; - LARGE_INTEGER TruncateSize, *PTruncateSize; - WORK_QUEUE_ITEM WorkQueueItem; -} FSP_FSVOL_CLEANUP_UNINITIALIZE_WORK_ITEM; - static NTSTATUS FspFsctlCleanup( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -78,11 +69,9 @@ static NTSTATUS FspFsvolCleanup( ASSERT(FileNode == FileDesc->FileNode); + FspFileNodeAcquireExclusive(FileNode, Main); + FspFileNodeCleanup(FileNode, FileObject, &DeletePending); - if (DeletePending) - FspFileNodeAcquireExclusive(FileNode, Full); - else - FspFileNodeAcquireShared(FileNode, Full); /* create the user-mode file system request; MustSucceed because IRP_MJ_CLEANUP cannot fail */ FspIopCreateRequestMustSucceedEx(Irp, DeletePending ? &FileNode->FileName : 0, 0, @@ -92,6 +81,8 @@ static NTSTATUS FspFsvolCleanup( Request->Req.Cleanup.UserContext2 = FileDesc->UserContext2; Request->Req.Cleanup.Delete = DeletePending; + FspFileNodeAcquireExclusive(FileNode, Pgio); + FspFileNodeSetOwner(FileNode, Full, Request); FspIopRequestContext(Request, RequestIrp) = Irp; @@ -129,93 +120,14 @@ static VOID FspFsvolCleanupRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Co PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PFILE_OBJECT FileObject = IrpSp->FileObject; FSP_FILE_NODE *FileNode = FileObject->FsContext; - FSP_FSCTL_FILE_INFO FileInfo; - LARGE_INTEGER TruncateSize = { 0 }, *PTruncateSize = 0; - BOOLEAN DeletePending = 0 != Request->Req.Cleanup.Delete; - BOOLEAN DeletedFromContextTable; - BOOLEAN Success; - FspFileNodeClose(FileNode, FileObject, &DeletedFromContextTable); - if (DeletedFromContextTable) - { - if (DeletePending) - PTruncateSize = &TruncateSize; - else if (FileNode->TruncateOnClose) - { - /* - * Even when FileInfoTimeout != Infinity, - * this is the last size that the cache manager knows. - */ - FspFileNodeGetFileInfo(FileNode, &FileInfo); + FspFileNodeReleaseOwner(FileNode, Pgio, Request); - TruncateSize.QuadPart = FileInfo.FileSize; - PTruncateSize = &TruncateSize; - } - } + FspFileNodeCleanupComplete(FileNode, FileObject); - if (DeletePending) - { - /* FileNode is Exclusive Full; release Pgio */ - FspFileNodeReleaseOwner(FileNode, Pgio, Request); - - /* FileNode is now Exclusive Main; owner is Request */ - } - else - { - /* FileNode is Shared Full; reacquire as Exclusive Main for CcUninitializeCacheMap */ - FspFileNodeReleaseOwner(FileNode, Full, Request); - - Success = DEBUGTEST(90, TRUE) && FspFileNodeTryAcquireExclusive(FileNode, Main); - if (!Success) - { - /* oh, maaan! we now have to do delayed uninitialize! */ - - FSP_FSVOL_CLEANUP_UNINITIALIZE_WORK_ITEM *WorkItem; - - WorkItem = FspAllocatePoolMustSucceed( - NonPagedPool, sizeof *WorkItem, FSP_ALLOC_INTERNAL_TAG); - WorkItem->FileObject = FileObject; - WorkItem->TruncateSize = TruncateSize; - WorkItem->PTruncateSize = 0 != PTruncateSize ? &WorkItem->TruncateSize : 0; - ExInitializeWorkItem(&WorkItem->WorkQueueItem, FspFsvolCleanupUninitialize, WorkItem); - - /* make sure that the file object (and corresponding device object) stay around! */ - ObReferenceObject(FileObject); - - ExQueueWorkItem(&WorkItem->WorkQueueItem, CriticalWorkQueue); - - return; - } - - /* FileNode is now Exclusive Main; owner is current thread */ - } - - CcUninitializeCacheMap(FileObject, PTruncateSize, 0); - - /* this works correctly even if owner is current thread */ FspFileNodeReleaseOwner(FileNode, Main, Request); } -static VOID FspFsvolCleanupUninitialize(PVOID Context) -{ - PAGED_CODE(); - - FSP_FSVOL_CLEANUP_UNINITIALIZE_WORK_ITEM *WorkItem = Context; - PFILE_OBJECT FileObject = WorkItem->FileObject; - FSP_FILE_NODE *FileNode = FileObject->FsContext; - LARGE_INTEGER *PTruncateSize = WorkItem->PTruncateSize; - - FspFileNodeAcquireExclusive(FileNode, Main); - - CcUninitializeCacheMap(FileObject, PTruncateSize, 0); - - FspFileNodeRelease(FileNode, Main); - - ObDereferenceObject(FileObject); - - FspFree(WorkItem); -} - NTSTATUS FspCleanup( PDEVICE_OBJECT DeviceObject, PIRP Irp) { diff --git a/src/sys/close.c b/src/sys/close.c index a21bb21a..54186089 100644 --- a/src/sys/close.c +++ b/src/sys/close.c @@ -63,6 +63,7 @@ static NTSTATUS FspFsvolClose( Request->Req.Close.UserContext = FileNode->UserContext; Request->Req.Close.UserContext2 = FileDesc->UserContext2; + FspFileNodeClose(FileNode, FileObject); FspFileNodeDereference(FileNode); FspFileDescDelete(FileDesc); diff --git a/src/sys/create.c b/src/sys/create.c index d2796fd5..8dc1a81c 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -742,7 +742,7 @@ static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Re if (0 == Request) { FspFsvolCreatePostClose(FileDesc); - FspFileNodeClose(FileNode, FileObject, 0); + FspFileNodeClose(FileNode, FileObject); } return DeleteOnClose ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; @@ -843,7 +843,7 @@ static VOID FspFsvolCreateTryOpenRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PV ASSERT(0 != FileObject); FspFsvolCreatePostClose(FileDesc); - FspFileNodeClose(FileDesc->FileNode, FileObject, 0); + FspFileNodeClose(FileDesc->FileNode, FileObject); FspFileNodeDereference(FileDesc->FileNode); FspFileDescDelete(FileDesc); } @@ -870,7 +870,7 @@ static VOID FspFsvolCreateOverwriteRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, else if (RequestProcessing == State) FspFileNodeReleaseOwner(FileDesc->FileNode, Full, Request); - FspFileNodeClose(FileDesc->FileNode, FileObject, 0); + FspFileNodeClose(FileDesc->FileNode, FileObject); FspFileNodeDereference(FileDesc->FileNode); FspFileDescDelete(FileDesc); } diff --git a/src/sys/device.c b/src/sys/device.c index b0275d6c..0db3ff11 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -40,9 +40,9 @@ VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, static RTL_AVL_COMPARE_ROUTINE FspFsvolDeviceCompareContext; static RTL_AVL_ALLOCATE_ROUTINE FspFsvolDeviceAllocateContext; static RTL_AVL_FREE_ROUTINE FspFsvolDeviceFreeContext; +PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, + BOOLEAN SubpathOnly, PVOID *PRestartKey); PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName); -PVOID FspFsvolDeviceLookupDescendantContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, - BOOLEAN ChildOnly); PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); VOID FspFsvolDeviceDeleteContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, @@ -79,8 +79,8 @@ VOID FspDeviceDeleteAll(VOID); #pragma alloc_text(PAGE, FspFsvolDeviceCompareContext) #pragma alloc_text(PAGE, FspFsvolDeviceAllocateContext) #pragma alloc_text(PAGE, FspFsvolDeviceFreeContext) +#pragma alloc_text(PAGE, FspFsvolDeviceEnumerateContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceLookupContextByName) -#pragma alloc_text(PAGE, FspFsvolDeviceLookupDescendantContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceInsertContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceDeleteContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceCompareContextByName) @@ -623,6 +623,31 @@ static VOID NTAPI FspFsvolDeviceFreeContext( PAGED_CODE(); } +PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, + BOOLEAN SubpathOnly, PVOID *PRestartKey) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + BOOLEAN CaseInsensitive = 0 == FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch; + FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Result; + ULONG DeleteCount = 0; + + if (0 != *PRestartKey) + SubpathOnly = FALSE; + + Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable, + 0, 0, SubpathOnly, PRestartKey, &DeleteCount, &FileName); + + if (0 != Result && + RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) && + FileName->Length < Result->FileName->Length && + '\\' == Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)]) + return Result->Context; + else + return 0; +} + PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName) { PAGED_CODE(); @@ -635,27 +660,6 @@ PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_ST return 0 != Result ? Result->Context : 0; } -PVOID FspFsvolDeviceLookupDescendantContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, - BOOLEAN ChildOnly) -{ - PAGED_CODE(); - - FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); - BOOLEAN CaseInsensitive = 0 == FsvolDeviceExtension->VolumeParams.CaseSensitiveSearch; - FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Result; - PVOID RestartKey = 0; - ULONG DeleteCount = 0; - - Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable, - 0, 0, ChildOnly, &RestartKey, &DeleteCount, &FileName); - if (0 == Result || - !RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) || - (FileName->Length < Result->FileName->Length && - '\\' != Result->FileName->Buffer[FileName->Length / sizeof(WCHAR)])) - return 0; - return Result->Context; -} - PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted) { diff --git a/src/sys/driver.h b/src/sys/driver.h index 37aae1e1..a74d9087 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -707,9 +707,9 @@ PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier FSP_DEVICE_CONTEXT_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PBOOLEAN PDeleted); +PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, + BOOLEAN SubpathOnly, PVOID *PRestartKey); PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName); -PVOID FspFsvolDeviceLookupDescendantContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, - BOOLEAN ChildOnly); PVOID FspFsvolDeviceInsertContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, PVOID Context, FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); VOID FspFsvolDeviceDeleteContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, @@ -775,7 +775,8 @@ typedef struct LONG RefCount; UINT32 DeletePending; /* locked under FSP_FSVOL_DEVICE_EXTENSION::ContextTableResource */ - LONG OpenCount; + LONG OpenCount; /* ContextTable ref count */ + LONG HandleCount; /* HANDLE count (CREATE/CLEANUP) */ SHARE_ACCESS ShareAccess; FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT ContextByNameElementStorage; /* locked under FSP_FSVOL_DEVICE_EXTENSION::FileRenameResource or Header.Resource */ @@ -838,9 +839,11 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult); VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PBOOLEAN PDeletePending); -VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, - PBOOLEAN PDeletedFromContextTable); +VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject); +VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); +BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject, + PUNICODE_STRING FileName, BOOLEAN SubpathOnly); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, diff --git a/src/sys/file.c b/src/sys/file.c index 5709c5a6..0500d256 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -20,9 +20,11 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, UINT32 GrantedAccess, UINT32 ShareAccess, NTSTATUS *PResult); VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PBOOLEAN PDeletePending); -VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, - PBOOLEAN PDeletedFromContextTable); +VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject); +VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject); VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName); +BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject, + PUNICODE_STRING FileName, BOOLEAN SubpathOnly); VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo); VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject, @@ -48,8 +50,10 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); #pragma alloc_text(PAGE, FspFileNodeReleaseOwnerF) #pragma alloc_text(PAGE, FspFileNodeOpen) #pragma alloc_text(PAGE, FspFileNodeCleanup) +#pragma alloc_text(PAGE, FspFileNodeCleanupComplete) #pragma alloc_text(PAGE, FspFileNodeClose) #pragma alloc_text(PAGE, FspFileNodeRename) +#pragma alloc_text(PAGE, FspFileNodeHasOpenHandles) #pragma alloc_text(PAGE, FspFileNodeGetFileInfo) #pragma alloc_text(PAGE, FspFileNodeTryGetFileInfo) #pragma alloc_text(PAGE, FspFileNodeSetFileInfo) @@ -308,6 +312,8 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, * Attempt to insert our FileNode into the volume device's generic table. * If an FileNode with the same UserContext already exists, then use that * FileNode instead. + * + * There is no FileNode that can be acquired when calling this function. */ PAGED_CODE(); @@ -386,6 +392,7 @@ FSP_FILE_NODE *FspFileNodeOpen(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, { FspFileNodeReference(OpenedFileNode); OpenedFileNode->OpenCount++; + OpenedFileNode->HandleCount++; } FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); @@ -397,16 +404,18 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, PBOOLEAN PDeletePending) { /* - * Determine whether a FileNode should be deleted. Note that when - * FileNode->DeletePending is set, the OpenCount cannot be changed - * because FspFileNodeOpen() will return STATUS_DELETE_PENDING. + * Determine whether a FileNode should be deleted. Note that when FileNode->DeletePending + * is set, the OpenCount/HandleCount cannot be increased because FspFileNodeOpen() will + * return STATUS_DELETE_PENDING. + * + * The FileNode must be acquired exclusive (Main) when calling this function. */ PAGED_CODE(); PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; FSP_FILE_DESC *FileDesc = FileObject->FsContext2; - BOOLEAN DeletePending, SingleOpen; + BOOLEAN DeletePending, SingleHandle; FspFsvolDeviceLockContextTable(FsvolDeviceObject); @@ -415,40 +424,91 @@ VOID FspFileNodeCleanup(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, DeletePending = 0 != FileNode->DeletePending; MemoryBarrier(); - SingleOpen = 1 == FileNode->OpenCount; + SingleHandle = 1 == FileNode->HandleCount; FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); if (0 != PDeletePending) - *PDeletePending = SingleOpen && DeletePending; + *PDeletePending = SingleHandle && DeletePending; } -VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject, - PBOOLEAN PDeletedFromContextTable) +VOID FspFileNodeCleanupComplete(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject) { /* - * Close the FileNode. If the OpenCount becomes zero remove it - * from the Context table. + * Complete the cleanup of a FileNode. Remove its share access and + * finalize its cache. + * + * NOTE: If the FileNode is not being deleted (!FileNode->DeletePending) + * the FileNode REMAINS in the Context table until Close time! + * This is so that if there are mapped views or write behind's pending + * when a file gets reopened the FileNode will be correctly reused. + * + * The FileNode must be acquired exclusive (Main) when calling this function. */ PAGED_CODE(); PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; - BOOLEAN Deleted = FALSE; + LARGE_INTEGER TruncateSize = { 0 }, *PTruncateSize = 0; + BOOLEAN DeletePending; + BOOLEAN DeletedFromContextTable = FALSE; FspFsvolDeviceLockContextTable(FsvolDeviceObject); IoRemoveShareAccess(FileObject, &FileNode->ShareAccess); - if (0 == --FileNode->OpenCount) - FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName, &Deleted); + + if (0 == --FileNode->HandleCount) + { + DeletePending = 0 != FileNode->DeletePending; + MemoryBarrier(); + + if (DeletePending) + { + PTruncateSize = &TruncateSize; + + if (0 == --FileNode->OpenCount) + FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName, + &DeletedFromContextTable); + } + else if (FileNode->TruncateOnClose && FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) + { + TruncateSize = FileNode->Header.FileSize; + PTruncateSize = &TruncateSize; + } + } FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); - if (Deleted) - FspFileNodeDereference(FileNode); + CcUninitializeCacheMap(FileObject, PTruncateSize, 0); - if (0 != PDeletedFromContextTable) - *PDeletedFromContextTable = Deleted; + if (DeletedFromContextTable) + FspFileNodeDereference(FileNode); +} + +VOID FspFileNodeClose(FSP_FILE_NODE *FileNode, PFILE_OBJECT FileObject) +{ + /* + * Close the FileNode. If the OpenCount becomes zero remove it + * from the Context table. + * + * The FileNode may or may not be acquired when calling this function. + */ + + PAGED_CODE(); + + PDEVICE_OBJECT FsvolDeviceObject = FileNode->FsvolDeviceObject; + BOOLEAN DeletedFromContextTable = FALSE; + + FspFsvolDeviceLockContextTable(FsvolDeviceObject); + + if (0 < FileNode->OpenCount && 0 == --FileNode->OpenCount) + FspFsvolDeviceDeleteContextByName(FsvolDeviceObject, &FileNode->FileName, + &DeletedFromContextTable); + + FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); + + if (DeletedFromContextTable) + FspFileNodeDereference(FileNode); } VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) @@ -475,6 +535,29 @@ VOID FspFileNodeRename(FSP_FILE_NODE *FileNode, PUNICODE_STRING NewFileName) FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); } +BOOLEAN FspFileNodeHasOpenHandles(PDEVICE_OBJECT FsvolDeviceObject, + PUNICODE_STRING FileName, BOOLEAN SubpathOnly) +{ + /* + * The ContextByNameTable must be already locked. + */ + + PAGED_CODE(); + + FSP_FILE_NODE *FileNode; + PVOID RestartKey = 0; + + for (;;) + { + FileNode = FspFsvolDeviceEnumerateContextByName(FsvolDeviceObject, FileName, SubpathOnly, + &RestartKey); + if (0 == FileNode) + return FALSE; + if (0 < FileNode->HandleCount) + return TRUE; + } +} + VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo) { PAGED_CODE(); diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index c6407827..68f1ba23 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -879,10 +879,10 @@ static NTSTATUS FspFsvolSetRenameInformation( Result = STATUS_SUCCESS; FspFsvolDeviceLockContextTable(FsvolDeviceObject); - if (1 < FileNode->OpenCount || + if (1 < FileNode->HandleCount || (FileNode->IsDirectory && - 0 != FspFsvolDeviceLookupDescendantContextByName(FsvolDeviceObject, &FileNode->FileName, TRUE)) || - 0 != FspFsvolDeviceLookupDescendantContextByName(FsvolDeviceObject, &NewFileName, FALSE)) + FspFileNodeHasOpenHandles(FsvolDeviceObject, &FileNode->FileName, TRUE)) || + FspFileNodeHasOpenHandles(FsvolDeviceObject, &NewFileName, FALSE)) Result = STATUS_ACCESS_DENIED; FspFsvolDeviceUnlockContextTable(FsvolDeviceObject); if (!NT_SUCCESS(Result))