mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 11:38:39 -05:00 
			
		
		
		
	sys: FSP_FILE_NODE: add HandleCount field and refactor cleanup/close/rename
This commit is contained in:
		| @@ -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) | ||||
| { | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
|   | ||||
| @@ -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) | ||||
| { | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
							
								
								
									
										121
									
								
								src/sys/file.c
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								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(); | ||||
|   | ||||
| @@ -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)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user