diff --git a/src/sys/device.c b/src/sys/device.c index 4ea50ccd..92b3acab 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -40,6 +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; +NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject, + PVOID **PContexts, PULONG PContextCount); +VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount); PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, BOOLEAN SubpathOnly, PVOID *PRestartKey); PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName); @@ -79,6 +82,8 @@ VOID FspDeviceDeleteAll(VOID); #pragma alloc_text(PAGE, FspFsvolDeviceCompareContext) #pragma alloc_text(PAGE, FspFsvolDeviceAllocateContext) #pragma alloc_text(PAGE, FspFsvolDeviceFreeContext) +#pragma alloc_text(PAGE, FspFsvolDeviceCopyContextByNameList) +#pragma alloc_text(PAGE, FspFsvolDeviceDeleteContextByNameList) #pragma alloc_text(PAGE, FspFsvolDeviceEnumerateContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceLookupContextByName) #pragma alloc_text(PAGE, FspFsvolDeviceInsertContextByName) @@ -653,6 +658,45 @@ static VOID NTAPI FspFsvolDeviceFreeContext( PAGED_CODE(); } +NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject, + PVOID **PContexts, PULONG PContextCount) +{ + PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + FSP_DEVICE_CONTEXT_BY_NAME_TABLE_ELEMENT_DATA *Data; + PVOID *Contexts; + ULONG ContextCount, Index; + + *PContexts = 0; + *PContextCount = 0; + + ContextCount = RtlNumberGenericTableElementsAvl(&FsvolDeviceExtension->ContextByNameTable); + Contexts = FspAlloc(sizeof(PVOID) * ContextCount); + if (0 == Contexts) + return STATUS_INSUFFICIENT_RESOURCES; + + Index = 0; + Data = RtlEnumerateGenericTableAvl(&FsvolDeviceExtension->ContextByNameTable, TRUE); + while (Index < ContextCount && 0 != Data) + { + Contexts[Index++] = Data->Context; + Data = RtlEnumerateGenericTableAvl(&FsvolDeviceExtension->ContextByNameTable, FALSE); + } + + *PContexts = Contexts; + *PContextCount = Index; + + return STATUS_SUCCESS; +} + +VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount) +{ + PAGED_CODE(); + + FspFree(Contexts); +} + PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, BOOLEAN SubpathOnly, PVOID *PRestartKey) { @@ -668,7 +712,7 @@ PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE Result = RtlEnumerateGenericTableLikeADirectory(&FsvolDeviceExtension->ContextByNameTable, 0, 0, SubpathOnly, PRestartKey, &DeleteCount, &FileName); - + if (0 != Result && RtlPrefixUnicodeString(FileName, Result->FileName, CaseInsensitive) && FileName->Length < Result->FileName->Length && diff --git a/src/sys/driver.h b/src/sys/driver.h index 122dc04b..c09b4b9b 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -764,6 +764,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); +NTSTATUS FspFsvolDeviceCopyContextByNameList(PDEVICE_OBJECT DeviceObject, + PVOID **PContexts, PULONG PContextCount); +VOID FspFsvolDeviceDeleteContextByNameList(PVOID *Contexts, ULONG ContextCount); PVOID FspFsvolDeviceEnumerateContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName, BOOLEAN SubpathOnly, PVOID *PRestartKey); PVOID FspFsvolDeviceLookupContextByName(PDEVICE_OBJECT DeviceObject, PUNICODE_STRING FileName); @@ -881,6 +884,9 @@ typedef struct UINT64 DirInfo; ULONG DirInfoCacheHint; } FSP_FILE_DESC; +NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject, + FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount); +VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount); NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject, ULONG ExtraSize, FSP_FILE_NODE **PFileNode); VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode); diff --git a/src/sys/file.c b/src/sys/file.c index fd782bdc..da27ca9a 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -6,6 +6,9 @@ #include +NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject, + FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount); +VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount); NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject, ULONG ExtraSize, FSP_FILE_NODE **PFileNode); VOID FspFileNodeDelete(FSP_FILE_NODE *FileNode); @@ -51,6 +54,8 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, PUNICODE_STRING FileName, BOOLEAN Reset); #ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspFileNodeCopyList) +#pragma alloc_text(PAGE, FspFileNodeDeleteList) #pragma alloc_text(PAGE, FspFileNodeCreate) #pragma alloc_text(PAGE, FspFileNodeDelete) #pragma alloc_text(PAGE, FspFileNodeAcquireSharedF) @@ -102,6 +107,38 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, if (IrpValid) \ FspIrpSetFlags(Irp, FspIrpFlags(Irp) & (~Flags & 3)) +NTSTATUS FspFileNodeCopyList(PDEVICE_OBJECT DeviceObject, + FSP_FILE_NODE ***PFileNodes, PULONG PFileNodeCount) +{ + PAGED_CODE(); + + NTSTATUS Result; + ULONG Index; + + FspFsvolDeviceLockContextTable(DeviceObject); + Result = FspFsvolDeviceCopyContextByNameList(DeviceObject, PFileNodes, PFileNodeCount); + if (NT_SUCCESS(Result)) + { + for (Index = 0; *PFileNodeCount > Index; Index++) + FspFileNodeReference((*PFileNodes)[Index]); + } + FspFsvolDeviceUnlockContextTable(DeviceObject); + + return Result; +} + +VOID FspFileNodeDeleteList(FSP_FILE_NODE **FileNodes, ULONG FileNodeCount) +{ + PAGED_CODE(); + + ULONG Index; + + for (Index = 0; FileNodeCount > Index; Index++) + FspFileNodeDereference(FileNodes[Index]); + + FspFsvolDeviceDeleteContextByNameList(FileNodes, FileNodeCount); +} + NTSTATUS FspFileNodeCreate(PDEVICE_OBJECT DeviceObject, ULONG ExtraSize, FSP_FILE_NODE **PFileNode) { diff --git a/src/sys/flush.c b/src/sys/flush.c index 267176b4..407110c4 100644 --- a/src/sys/flush.c +++ b/src/sys/flush.c @@ -7,7 +7,7 @@ #include static NTSTATUS FspFsvolFlushBuffers( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_IOCMPL_DISPATCH FspFsvolFlushBuffersComplete; static FSP_IOP_REQUEST_FINI FspFsvolFlushBuffersRequestFini; FSP_DRIVER_DISPATCH FspFlushBuffers; @@ -23,60 +23,98 @@ enum { /* FlushBuffers */ RequestFileNode = 0, + RequestFlushResult = 1, }; static NTSTATUS FspFsvolFlushBuffers( - PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { PAGED_CODE(); - NTSTATUS Result; + NTSTATUS Result, FlushResult; + PFILE_OBJECT FileObject = IrpSp->FileObject; + FSP_FILE_NODE *FileNode = FileObject->FsContext; + FSP_FILE_DESC *FileDesc = FileObject->FsContext2; + FSP_FILE_NODE **FileNodes; + ULONG FileNodeCount, Index; + IO_STATUS_BLOCK IoStatus; FSP_FSCTL_TRANSACT_REQ *Request; - /* is this a valid FileObject? */ - if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext)) + /* + * A flush request on the volume (or the root directory according to FastFat) + * is a request to flush the whole volume. + */ + if (!FspFileNodeIsValid(FileNode) || FileNode->IsRootDirectory) { - /* indicate that we are flushing the whole volume! */ + Result = FspFileNodeCopyList(FsvolDeviceObject, &FileNodes, &FileNodeCount); + if (!NT_SUCCESS(Result)) + return Result; + + /* + * Enumerate in reverse order so that files are flushed before containing directories. + * This would be useful if we ever started flushing directories, but since we do not + * it is not as important now. + */ + FlushResult = STATUS_SUCCESS; + for (Index = FileNodeCount - 1; FileNodeCount > Index; Index--) + if (!FileNodes[Index]->IsDirectory) + { + Result = FspCcFlushCache(&FileNodes[Index]->NonPaged->SectionObjectPointers, + 0, 0, &IoStatus); + if (!NT_SUCCESS(Result) && NT_SUCCESS(FlushResult)) + FlushResult = Result; + } + + FspFileNodeDeleteList(FileNodes, FileNodeCount); + Result = FspIopCreateRequest(Irp, 0, 0, &Request); if (!NT_SUCCESS(Result)) return Result; + /* a NULL UserContext indicates to user-mode to flush the whole volume! */ Request->Kind = FspFsctlTransactFlushBuffersKind; + //Request->Req.FlushBuffers.UserContext = 0; + //Request->Req.FlushBuffers.UserContext2 = 0; + + FspIopRequestContext(Request, RequestFileNode) = 0; + FspIopRequestContext(Request, RequestFlushResult) = (PVOID)(UINT_PTR)FlushResult; return FSP_STATUS_IOQ_POST; } - - PFILE_OBJECT FileObject = IrpSp->FileObject; - FSP_FILE_NODE *FileNode = FileObject->FsContext; - FSP_FILE_DESC *FileDesc = FileObject->FsContext2; - IO_STATUS_BLOCK IoStatus; - - ASSERT(FileNode == FileDesc->FileNode); - - FspFileNodeAcquireExclusive(FileNode, Full); - - Result = FspCcFlushCache(FileObject->SectionObjectPointer, 0, 0, &IoStatus); - if (!NT_SUCCESS(Result)) + else { - FspFileNodeRelease(FileNode, Full); - return Result; + ASSERT(FileNode == FileDesc->FileNode); + + /* cannot really flush directories but we will say we did it! */ + if (FileNode->IsDirectory) + return STATUS_SUCCESS; + + FspFileNodeAcquireExclusive(FileNode, Full); + + Result = FspCcFlushCache(FileObject->SectionObjectPointer, 0, 0, &IoStatus); + if (!NT_SUCCESS(Result)) + { + FspFileNodeRelease(FileNode, Full); + return Result; + } + + Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolFlushBuffersRequestFini, &Request); + if (!NT_SUCCESS(Result)) + { + FspFileNodeRelease(FileNode, Full); + return Result; + } + + Request->Kind = FspFsctlTransactFlushBuffersKind; + Request->Req.FlushBuffers.UserContext = FileNode->UserContext; + Request->Req.FlushBuffers.UserContext2 = FileDesc->UserContext2; + + FspFileNodeSetOwner(FileNode, Full, Request); + FspIopRequestContext(Request, RequestFileNode) = FileNode; + FspIopRequestContext(Request, RequestFlushResult) = 0; + + return FSP_STATUS_IOQ_POST; } - - Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolFlushBuffersRequestFini, &Request); - if (!NT_SUCCESS(Result)) - { - FspFileNodeRelease(FileNode, Full); - return Result; - } - - Request->Kind = FspFsctlTransactFlushBuffersKind; - Request->Req.FlushBuffers.UserContext = FileNode->UserContext; - Request->Req.FlushBuffers.UserContext2 = FileDesc->UserContext2; - - FspFileNodeSetOwner(FileNode, Full, Request); - FspIopRequestContext(Request, RequestFileNode) = FileNode; - - return FSP_STATUS_IOQ_POST; } NTSTATUS FspFsvolFlushBuffersComplete( @@ -84,6 +122,17 @@ NTSTATUS FspFsvolFlushBuffersComplete( { FSP_ENTER_IOC(PAGED_CODE()); + FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); + NTSTATUS FlushResult = (NTSTATUS)(UINT_PTR)FspIopRequestContext(Request, RequestFlushResult); + + Irp->IoStatus.Information = 0; + if (!NT_SUCCESS(Response->IoStatus.Status)) + Result = Response->IoStatus.Status; + else if (!NT_SUCCESS(FlushResult)) + Result = FlushResult; + else + Result = STATUS_SUCCESS; + FSP_LEAVE_IOC("FileObject=%p", IrpSp->FileObject); }