From cffe655cef17faa700e627e74e593b186cab11a5 Mon Sep 17 00:00:00 2001 From: Gleb Lamm Date: Tue, 3 Feb 2026 01:26:59 +0400 Subject: [PATCH 1/5] refactoring --- drivers/filesystems/udfs/CMakeLists.txt | 1 + drivers/filesystems/udfs/Include/phys_lib.cpp | 3 +- drivers/filesystems/udfs/cleanup.cpp | 185 +--- drivers/filesystems/udfs/close.cpp | 240 +----- drivers/filesystems/udfs/create.cpp | 798 +++++++++++------- drivers/filesystems/udfs/dircntrl.cpp | 17 +- drivers/filesystems/udfs/fastio.cpp | 99 +-- drivers/filesystems/udfs/fileinfo.cpp | 168 ++-- drivers/filesystems/udfs/flush.cpp | 23 +- drivers/filesystems/udfs/fscntrl.cpp | 208 ++--- drivers/filesystems/udfs/lockctrl.cpp | 35 +- drivers/filesystems/udfs/misc.cpp | 18 +- drivers/filesystems/udfs/nodetype.h | 1 + drivers/filesystems/udfs/protos.h | 108 ++- drivers/filesystems/udfs/read.cpp | 88 +- drivers/filesystems/udfs/strucsup.cpp | 506 ++++++++--- drivers/filesystems/udfs/struct.h | 66 +- drivers/filesystems/udfs/udf_info/dirtree.cpp | 45 + .../filesystems/udfs/udf_info/udf_info.cpp | 186 +++- drivers/filesystems/udfs/udf_info/udf_info.h | 17 + drivers/filesystems/udfs/udf_info/udf_rel.h | 12 + drivers/filesystems/udfs/udffs.h | 4 +- drivers/filesystems/udfs/udfinit.cpp | 2 +- drivers/filesystems/udfs/volinfo.cpp | 4 - drivers/filesystems/udfs/write.cpp | 673 +++++++-------- 25 files changed, 1981 insertions(+), 1526 deletions(-) diff --git a/drivers/filesystems/udfs/CMakeLists.txt b/drivers/filesystems/udfs/CMakeLists.txt index 53ce00f1bd62f..1ae3d50d9b070 100644 --- a/drivers/filesystems/udfs/CMakeLists.txt +++ b/drivers/filesystems/udfs/CMakeLists.txt @@ -24,6 +24,7 @@ list(APPEND SOURCE mem.cpp misc.cpp namesup.cpp + prefxsup.cpp pnp.cpp read.cpp secursup.cpp diff --git a/drivers/filesystems/udfs/Include/phys_lib.cpp b/drivers/filesystems/udfs/Include/phys_lib.cpp index 656441f1790dc..bba91e86d1c06 100644 --- a/drivers/filesystems/udfs/Include/phys_lib.cpp +++ b/drivers/filesystems/udfs/Include/phys_lib.cpp @@ -845,7 +845,8 @@ UDFGetBlockSize( ASSERT(FALSE); } } else { - ASSERT(FALSE); + + try_return(RC = STATUS_UNRECOGNIZED_VOLUME); } Vcb->LastPossibleLBA = Vcb->LastLBA; } diff --git a/drivers/filesystems/udfs/cleanup.cpp b/drivers/filesystems/udfs/cleanup.cpp index 22788214d386c..355a7e22bbb53 100644 --- a/drivers/filesystems/udfs/cleanup.cpp +++ b/drivers/filesystems/udfs/cleanup.cpp @@ -50,7 +50,6 @@ UDFCommonCleanup( { IO_STATUS_BLOCK IoStatus; NTSTATUS RC = STATUS_SUCCESS; - NTSTATUS RC2; PFILE_OBJECT FileObject = NULL; PFCB Fcb = NULL; PCCB Ccb = NULL; @@ -78,13 +77,13 @@ UDFCommonCleanup( return STATUS_SUCCESS; } - // Get the file object out of the Irp and decode the type of open. + // Get the file object out of the Irp and decode the type of open. FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject; TypeOfOpen = UDFDecodeFileObject(FileObject, &Fcb, &Ccb); - // No work here for either an UnopenedFile object or a StreamFileObject. + // No work here for either an UnopenedFile object or a StreamFileObject. if (TypeOfOpen <= StreamFileOpen) { @@ -174,15 +173,8 @@ UDFCommonCleanup( AcquiredVcb = TRUE; } - // Acquire parent object - if (Fcb->FileInfo->ParentFile) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); - UDFAcquireResourceExclusive(&(Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource), TRUE); - } else { - UDFAcquireResourceShared(&(Vcb->VcbResource), TRUE); - } - AcquiredParentFCB = TRUE; - // Acquire current object + // Acquire current object only + // Parent is acquired later only for delete operations (Child → Parent order) UDF_CHECK_PAGING_IO_RESOURCE(Fcb); UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); AcquiredFCB = TRUE; @@ -242,40 +234,12 @@ UDFCommonCleanup( !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) { RC = UDFMarkStreamsForDeletion(IrpContext, Vcb, Fcb, TRUE); // Delete } - // we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE - // flag is already set & the file can't be opened - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); - AcquiredFCB = FALSE; - if (Fcb->FileInfo->ParentFile) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); - UDFReleaseResource(&Fcb->ParentFcb->FcbNonpaged->FcbResource); - } else { - UDFReleaseResource(&Vcb->VcbResource); - } - AcquiredParentFCB = FALSE; - UDFReleaseResource(&(Vcb->VcbResource)); - AcquiredVcb = FALSE; - - // Make system to issue last Close request - // for our Target ... - -#ifdef UDF_DELAYED_CLOSE - UDFFspClose(Fcb->Vcb); -#endif //UDF_DELAYED_CLOSE - - UDFAcquireResourceShared(&Vcb->VcbResource, TRUE); - AcquiredVcb = TRUE; + // Acquire parent for delete operation (after current - child first order) if (Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); UDFAcquireResourceExclusive(&(Fcb->ParentFcb->FcbNonpaged->FcbResource), TRUE); - } else { - UDFAcquireResourceShared(&Vcb->VcbResource, TRUE); + AcquiredParentFCB = TRUE; } - AcquiredParentFCB = TRUE; - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); - AcquiredFCB = TRUE; // we should set file sizes to zero if there are no more // links to this file @@ -292,14 +256,6 @@ UDFCommonCleanup( } } -#ifdef UDF_DELAYED_CLOSE - if ((Fcb->FcbReference == 1) && - /*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above - (!(Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE)) ) { - Fcb->FcbState |= UDF_FCB_DELAY_CLOSE; - } -#endif //UDF_DELAYED_CLOSE - NextFileInfo = Fcb->FileInfo; // do we need to delete it now ? @@ -460,7 +416,7 @@ UDFCommonCleanup( /* MmPrint((" CcPurgeCacheSection()\n")); CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);*/ } - // we needn't Flush here. It will be done in UDFCloseFileInfoChain() + // we needn't Flush here. It will be done in UDFCloseFile__ } // Update FileTimes & Attrs @@ -501,11 +457,28 @@ UDFCommonCleanup( ASize = UDFGetFileAllocationSize(Vcb, NextFileInfo); // Fcb->CommonFCBHeader.AllocationSize.QuadPart; UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); - } else - if (FileObject->Flags & FO_FILE_SIZE_CHANGED) { + + } else if (FileObject->Flags & FO_FILE_SIZE_CHANGED) { + ASize = //UDFGetFileAllocationSize(Vcb, NextFileInfo); Fcb->Header.AllocationSize.QuadPart; UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize); + + if (UDFIsAStream(Fcb->FileInfo)) { + + UDFNotifyFullReportChange(Vcb, + Fcb, + FILE_NOTIFY_CHANGE_STREAM_SIZE, + FILE_ACTION_MODIFIED_STREAM); + } + else { + + UDFNotifyFullReportChange(Vcb, + Fcb, + FILE_NOTIFY_CHANGE_SIZE, + FILE_ACTION_MODIFIED); + } + } } // AccessTime @@ -539,23 +512,22 @@ UDFCommonCleanup( } // release resources now. - // they'll be acquired in UDFCloseFileInfoChain() UDF_CHECK_PAGING_IO_RESOURCE(Fcb); UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); AcquiredFCB = FALSE; - if (Fcb->FileInfo->ParentFile) { + if (AcquiredParentFCB && Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); UDFReleaseResource(&Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource); - } else { - UDFReleaseResource(&Vcb->VcbResource); + AcquiredParentFCB = FALSE; } - AcquiredParentFCB = FALSE; - // close the chain + + // Close the target file's FileInfo - this decrements FileInfo->RefCount + // Parent FileInfo references are now handled by LCB mechanism in UDFTeardownStructures ASSERT(AcquiredVcb); - RC2 = UDFCloseFileInfoChain(IrpContext, Vcb, NextFileInfo, Ccb->TreeLength, TRUE); - if (NT_SUCCESS(RC)) - RC = RC2; + if (NextFileInfo) { + UDFCloseFile__(IrpContext, Vcb, NextFileInfo); + } Ccb->Flags |= UDF_CCB_CLEANED; @@ -577,13 +549,9 @@ try_exit: NOTHING; UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); } - if (AcquiredParentFCB) { - if (Fcb->FileInfo->ParentFile) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); - UDFReleaseResource(&Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource); - } else { - UDFReleaseResource(&Vcb->VcbResource); - } + if (AcquiredParentFCB && Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); + UDFReleaseResource(&Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource); } if (AcquiredVcb) { @@ -605,85 +573,6 @@ try_exit: NOTHING; return(RC); } // end UDFCommonCleanup() -/* - This routine walks through the tree to RootDir & - calls UDFCloseFile__() for each file instance - imho, Useful feature - */ -NTSTATUS -UDFCloseFileInfoChain( - IN PIRP_CONTEXT IrpContext, - IN PVCB Vcb, - IN PUDF_FILE_INFO fi, - IN ULONG TreeLength, - IN BOOLEAN VcbAcquired - ) -{ - PUDF_FILE_INFO ParentFI; - PFCB Fcb; - PFCB ParentFcb = NULL; - NTSTATUS RC = STATUS_SUCCESS; - NTSTATUS RC2; - - // we can't process Tree until we can acquire Vcb - if (!VcbAcquired) - UDFAcquireResourceShared(&(Vcb->VcbResource),TRUE); - - AdPrint(("UDFCloseFileInfoChain\n")); - for(; TreeLength && fi; TreeLength--) { - - // close parent chain (if any) - // if we started path parsing not from RootDir on Create, - // we would never get RootDir here - ValidateFileInfo(fi); - - // acquire parent - if ((ParentFI = fi->ParentFile)) { - ParentFcb = fi->Fcb->ParentFcb; - ASSERT(ParentFcb); - UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb); - UDFAcquireResourceExclusive(&ParentFcb->FcbNonpaged->FcbResource, TRUE); - ASSERT_FCB(ParentFcb); - } else { - AdPrint(("Acquiring VCB...\n")); - UDFAcquireResourceShared(&Vcb->VcbResource, TRUE); - AdPrint(("Done\n")); - } - // acquire current file/dir - // we must assure that no more threads try to reuse this object - if ((Fcb = fi->Fcb)) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); - ASSERT(Fcb->FcbReference >= fi->RefCount); - RC2 = UDFCloseFile__(IrpContext, Vcb, fi); - if (!NT_SUCCESS(RC2)) - RC = RC2; - ASSERT(Fcb->FcbReference > fi->RefCount); - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); - } else { - BrutePoint(); - RC2 = UDFCloseFile__(IrpContext, Vcb, fi); - if (!NT_SUCCESS(RC2)) - RC = RC2; - } - - if (ParentFI) { - UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb); - UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); - } else { - UDFReleaseResource(&Vcb->VcbResource); - } - fi = ParentFI; - } - - if (!VcbAcquired) - UDFReleaseResource(&Vcb->VcbResource); - - return RC; - -} // end UDFCloseFileInfoChain() - VOID UDFAutoUnlock ( IN PVCB Vcb diff --git a/drivers/filesystems/udfs/close.cpp b/drivers/filesystems/udfs/close.cpp index 664f54f599dbf..8b99cc498ff61 100644 --- a/drivers/filesystems/udfs/close.cpp +++ b/drivers/filesystems/udfs/close.cpp @@ -78,7 +78,6 @@ UDFCommonClose( PFCB Fcb = NULL; PCCB Ccb = NULL; PVCB Vcb = NULL; - ULONG i = 0; TYPE_OF_OPEN TypeOfOpen; ULONG UserReference = 0; BOOLEAN PotentialVcbTeardown = FALSE; @@ -121,8 +120,7 @@ UDFCommonClose( if (Irp) { UserReference = 1; - IrpContext->TreeLength = - i = Ccb->TreeLength; + // TreeLength no longer used - LCB model handles parent tracking // remember the number of incomplete Close requests InterlockedIncrement((PLONG)&(Fcb->CcbCount)); // we can release CCB in any case @@ -159,7 +157,7 @@ UDFCommonClose( InterlockedDecrement((PLONG)&Vcb->VcbReference); - if (!i || (Fcb == Fcb->Vcb->VolumeDasdFcb)) { + if (Fcb == Vcb->VolumeDasdFcb) { AdPrint(("UDF: Closing volume\n")); AdPrint(("UDF: ReferenceCount: %x\n",Fcb->FcbReference)); @@ -209,7 +207,16 @@ UDFCommonClose( } // try to clean up as long chain as it is possible - UDFTeardownStructures(IrpContext, Fcb, i, NULL); + // TODO: refactor to use UDFCommonClosePrivate + { + BOOLEAN RemovedFcb = FALSE; + UDFAcquireFcbExclusive(IrpContext, Fcb, FALSE); + // LCB-based teardown: walks ParentLcbQueue to find and remove LCBs + UDFTeardownStructures(IrpContext, Fcb, FALSE, &RemovedFcb); + if (!RemovedFcb) { + UDFReleaseFcb(IrpContext, Fcb); + } + } } try_exit: NOTHING; @@ -232,224 +239,6 @@ try_exit: NOTHING; return STATUS_SUCCESS; } // end UDFCommonClose() -/* - This routine walks through the tree to RootDir & kills all unreferenced - structures.... - imho, Useful feature - */ -_Requires_lock_held_(_Global_critical_region_) -VOID -UDFTeardownStructures( - _In_ PIRP_CONTEXT IrpContext, - _Inout_ PFCB StartingFcb, - _In_ ULONG TreeLength, - _Out_ PBOOLEAN RemovedStartingFcb - ) -{ - PVCB Vcb = StartingFcb->Vcb; - PFCB CurrentFcb = StartingFcb; - PFCB ParentFcb = NULL; - - LONG RefCount; - BOOLEAN Delete = FALSE; - - ValidateFileInfo(CurrentFcb->FileInfo); - AdPrint(("UDFCleanUpFcbChain\n")); - - ASSERT(TreeLength); - //TODO: - //ASSERT_EXCLUSIVE_FCB(StartingFcb); - //ASSERT_SHARED_VCB(Vcb); - - if (RemovedStartingFcb) { - *RemovedStartingFcb = FALSE; - } - - // Use a try-finally to safely clear the top-level field. - - _SEH2_TRY { - - // Loop until we find an Fcb we can't remove. - do { - - // If the reference count is non-zero then break. - - if (CurrentFcb->FcbReference != 0) { - - break; - } - - ParentFcb = CurrentFcb->ParentFcb; - - // acquire parent - if (ParentFcb != NULL) { - - UDFAcquireFcbExclusive(IrpContext, ParentFcb, FALSE); - } - - // acquire current file/dir - // we must assure that no more threads try to re-use this object - #ifdef UDF_DBG - _SEH2_TRY { - #endif // UDF_DBG - UDFAcquireResourceExclusive(&CurrentFcb->FcbNonpaged->FcbResource,TRUE); - #ifdef UDF_DBG - } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - BrutePoint(); - if (ParentFcb) { - UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); - } - break; - } _SEH2_END; - #endif // UDF_DBG - ASSERT((CurrentFcb->FcbReference > CurrentFcb->FileInfo->RefCount) || !TreeLength); - // If we haven't pass through all files opened - // in UDFCommonCreate before target file (TreeLength specfies - // the number of such files) dereference them. - // Otherwise we'll just check if the file has no references. - #ifdef UDF_DBG - if (CurrentFcb) { - if (TreeLength) { - ASSERT(CurrentFcb->FcbReference); - RefCount = InterlockedDecrement((PLONG)&CurrentFcb->FcbReference); - } - } else { - BrutePoint(); - } - if (TreeLength) - TreeLength--; - ASSERT(CurrentFcb->FcbCleanup <= CurrentFcb->FcbReference); - #else - if (TreeLength) { - RefCount = InterlockedDecrement((PLONG)&CurrentFcb->FcbReference); - TreeLength--; - } - #endif - - // ...and delete if it has gone - - if (!RefCount && !CurrentFcb->FcbCleanup) { - - // no more references... current file/dir MUST DIE!!! - if (Delete) { - /* if (!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { - // set file size to zero (for UdfInfo package) - // we should not do this for directories - UDFResizeFile__(Vcb, fi, 0); - }*/ - UDFReferenceFile__(CurrentFcb->FileInfo); - ASSERT(CurrentFcb->FcbReference < CurrentFcb->FileInfo->RefCount); - UDFFlushFile__(IrpContext, Vcb, CurrentFcb->FileInfo); - UDFUnlinkFile__(IrpContext, Vcb, CurrentFcb->FileInfo, TRUE); - UDFCloseFile__(IrpContext, Vcb, CurrentFcb->FileInfo); - ASSERT(CurrentFcb->FcbReference == CurrentFcb->FileInfo->RefCount); - CurrentFcb->FcbState |= UDF_FCB_DELETED; - Delete = FALSE; - } - else if (!(CurrentFcb->FcbState & UDF_FCB_DELETED)) { - UDFFlushFile__(IrpContext, Vcb, CurrentFcb->FileInfo); - } else { - // BrutePoint(); - } - - // check if we should try to delete Parent for the next time - if (CurrentFcb->FcbState & UDF_FCB_DELETE_PARENT) - Delete = TRUE; - - // remove references to OS-specific structures - // to let UDF_INFO release FI & Co - CurrentFcb->FileInfo->Fcb = NULL; - CurrentFcb->FileInfo->Dloc->CommonFcb = NULL; - - if (UDFCleanUpFile__(Vcb, CurrentFcb->FileInfo) == (UDF_FREE_FILEINFO | UDF_FREE_DLOC)) { - // Check, if we can uninitialize & deallocate CommonFcb part - // kill some cross links - // release allocated resources - // Obviously, it is a good time & place to release - // CommonFcb structure - - // NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID; - // Unitialize byte-range locks support structure - if (CurrentFcb->FileLock != NULL) { - - FsRtlFreeFileLock(CurrentFcb->FileLock); - } - - FsRtlTeardownPerStreamContexts(&CurrentFcb->Header); - - // Remove resources - UDF_CHECK_PAGING_IO_RESOURCE(CurrentFcb); - UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); - if (CurrentFcb->Header.Resource) { - UDFDeleteResource(&CurrentFcb->FcbNonpaged->FcbResource); - UDFDeleteResource(&CurrentFcb->FcbNonpaged->FcbPagingIoResource); - } - - CurrentFcb->Header.Resource = - CurrentFcb->Header.PagingIoResource = NULL; - - UDFPrint(("UDFRelease Fcb: %x\n", CurrentFcb)); - - // remove some references & free Fcb structure - CurrentFcb->ParentFcb = NULL; - UDFCleanUpFCB(CurrentFcb); - MyFreePool__(CurrentFcb->FileInfo); - CurrentFcb->FileInfo = NULL; - - // get pointer to parent FCB - CurrentFcb = ParentFcb; - // free old parent's resource... - if (CurrentFcb) { - UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); - } - } else { - // Stop cleaning up - - // Restore pointers - CurrentFcb->FileInfo->Fcb = CurrentFcb; - CurrentFcb->FileInfo->Dloc->CommonFcb = CurrentFcb; - // free all acquired resources - UDF_CHECK_PAGING_IO_RESOURCE(CurrentFcb); - UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); - CurrentFcb = ParentFcb; - if (CurrentFcb) { - UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb); - UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); - } - // If we have dereferenced all parents 'associated' - // with input file & current file is still in use - // then it isn't worth walking down the tree - // 'cause in this case all the rest files are also used - if (!TreeLength) - break; - // AdPrint(("Stop on referenced File/Dir\n")); - } - } else { - // we get to referenced file/dir. Stop search & release resource - - UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); - if (ParentFcb) { - - UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); - } - Delete = FALSE; - if (!TreeLength) - break; - CurrentFcb = ParentFcb; - } - - } while (CurrentFcb != NULL); - - } _SEH2_FINALLY { - - } _SEH2_END; - - if (RemovedStartingFcb) { - *RemovedStartingFcb = (CurrentFcb != StartingFcb); - } - -} // end UDFCleanUpFcbChain() - PIRP_CONTEXT UDFRemoveClose( _In_opt_ PVCB Vcb @@ -620,7 +409,6 @@ Return Value: // Copy RealDevice for workque algorithms. - IrpContext->TreeLength = IrpContextLite->TreeLength; IrpContext->RealDevice = IrpContextLite->RealDevice; // The Vcb is found in the Fcb. @@ -722,8 +510,9 @@ Return Value: // Call our teardown routine to see if this object can go away. // If we don't remove the Fcb then release it. + // LCB-based teardown: walks ParentLcbQueue to find and remove LCBs - UDFTeardownStructures(IrpContext, Fcb, IrpContext->TreeLength, &RemovedFcb); + UDFTeardownStructures(IrpContext, Fcb, FALSE, &RemovedFcb); if (!RemovedFcb) { @@ -990,7 +779,6 @@ UDFQueueClose( IrpContextLite->NodeIdentifier.NodeTypeCode = UDF_NODE_TYPE_IRP_CONTEXT_LITE; IrpContextLite->NodeIdentifier.NodeByteSize = sizeof(IRP_CONTEXT_LITE); IrpContextLite->Fcb = Fcb; - IrpContextLite->TreeLength = IrpContext->TreeLength; IrpContextLite->UserReference = UserReference; IrpContextLite->RealDevice = IrpContext->RealDevice; diff --git a/drivers/filesystems/udfs/create.cpp b/drivers/filesystems/udfs/create.cpp index a72893b61512f..27d68fb7a8b14 100644 --- a/drivers/filesystems/udfs/create.cpp +++ b/drivers/filesystems/udfs/create.cpp @@ -41,54 +41,132 @@ UDFNormalizeFileNames( _Inout_ PUNICODE_STRING RemainingName ); -/* - */ -VOID -__fastcall -UDFReleaseResFromCreate( - IN PERESOURCE* PagingIoRes, - IN PERESOURCE* Res1, - IN PERESOURCE* Res2 +NTSTATUS +UDFSupersedeOrOverwriteFile( + IN PIRP_CONTEXT IrpContext, + IN PFILE_OBJECT FileObject, + IN PVCB Vcb, + IN PFCB Fcb, + IN PUDF_FILE_INFO FileInfo, + IN LONGLONG AllocationSize, + IN ULONG FileAttributes, + IN BOOLEAN Supersede ) { - if (*PagingIoRes) { - UDFReleaseResource(*PagingIoRes); - (*PagingIoRes) = NULL; - } - if (*Res1) { - UDFReleaseResource(*Res1); - (*Res1) = NULL; - } - if (*Res2) { - UDFReleaseResource(*Res2); - (*Res2) = NULL; - } -} // end UDFReleaseResFromCreate() + NTSTATUS RC; + ULONG NewFileAttributes; -/* - */ -VOID -__fastcall -UDFAcquireParent( - IN PUDF_FILE_INFO RelatedFileInfo, - IN PERESOURCE* Res1, - IN PERESOURCE* Res2 + UDFAcquirePagingIoExclusive(IrpContext, Fcb); + + _SEH2_TRY { + + if (!MmCanFileBeTruncated(&Fcb->FcbNonpaged->SegmentObject, &UdfData.UDFLargeZero)) { + + AdPrint((" Can't truncate. File is mapped\n")); + try_return(RC = STATUS_USER_MAPPED_FILE); + } + + // Truncate file to zero + RC = UDFResizeFile__(IrpContext, Vcb, FileInfo, 0); + + if (!NT_SUCCESS(RC)) { + + AdPrint((" Error during resize operation\n")); + try_return(RC); + } + + // Set file sizes + Fcb->Header.AllocationSize.QuadPart = UDFSysGetAllocSize(Vcb, AllocationSize); + Fcb->Header.FileSize.QuadPart = 0; + Fcb->Header.ValidDataLength.QuadPart = 0; + Fcb->FcbState &= ~UDF_FCB_DELAY_CLOSE; + + MmPrint((" CcSetFileSizes()\n")); + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); + Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + + // Set attributes + NewFileAttributes = FileAttributes | FILE_ATTRIBUTE_ARCHIVE; + if (!Supersede) { + // For Overwrite, combine with current attributes (get from FileInfo) + NewFileAttributes |= UDFAttributesToNT( + UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index), + FileInfo->Dloc->FileEntry); + } + UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index), + FileInfo->Dloc->FileEntry, NewFileAttributes); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + + UDFReleasePagingIo(IrpContext, Fcb); + } _SEH2_END; + + return RC; +} // end UDFSupersedeOrOverwriteFile() + + +/************************************************************************* +* +* Function: UDFOpenExistingFcb() +* +* Description: +* Open an existing FCB. Determines the type of open, sets CCB flags, +* and calls UDFCompleteFcbOpen. +* +* Opens an existing FCB with proper type detection. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: STATUS_SUCCESS/Error +* +*************************************************************************/ +NTSTATUS +UDFOpenExistingFcb( + IN PIRP_CONTEXT IrpContext, + IN PIO_STACK_LOCATION IrpSp, + IN PVCB Vcb, + IN OUT PFCB *CurrentFcb, + IN BOOLEAN IgnoreCase, + IN BOOLEAN OpenByFileId, + IN ULONG CreateDisposition ) { - if (RelatedFileInfo->Fcb && - RelatedFileInfo->Fcb->ParentFcb) { + ULONG CcbFlags = 0; + TYPE_OF_OPEN TypeOfOpen; + + ASSERT_FCB(*CurrentFcb); - UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->ParentFcb); - UDFAcquireResourceExclusive((*Res2) = &RelatedFileInfo->Fcb->ParentFcb->FcbNonpaged->FcbResource, TRUE); + // Determine type of open based on FCB type + if (UDFIsADirectory((*CurrentFcb)->FileInfo)) { + TypeOfOpen = UserDirectoryOpen; + } else { + TypeOfOpen = UserFileOpen; + } + + // Set CCB flags + if (IgnoreCase) { + SetFlag(CcbFlags, CCB_FLAG_IGNORE_CASE); } - UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb); - UDFAcquireResourceExclusive((*Res1) = &RelatedFileInfo->Fcb->FcbNonpaged->FcbResource, TRUE); + if (OpenByFileId) { + SetFlag(CcbFlags, CCB_FLAG_OPEN_BY_ID); + } + + // Complete the open + return UDFCompleteFcbOpen(IrpContext, + IrpSp, + Vcb, + CurrentFcb, + TypeOfOpen, + CcbFlags, + CreateDisposition); + +} // end UDFOpenExistingFcb() - InterlockedIncrement((PLONG)&RelatedFileInfo->Fcb->FcbReference); - UDFReferenceFile__(RelatedFileInfo); - ASSERT(RelatedFileInfo->Fcb->FcbReference >= RelatedFileInfo->RefCount); -} // end UDFAcquireParent() /************************************************************************* * @@ -128,9 +206,10 @@ UDFCommonCreate( PVCB Vcb = NULL; BOOLEAN OpenExisting = FALSE; - PERESOURCE Res1 = NULL; - PERESOURCE Res2 = NULL; - PERESOURCE PagingIoRes = NULL; + // Hold two locks during tree traversal (child + parent) + // CurrentFcb = current node lock, PreviousFcb = parent node lock (released after operations) + PFCB CurrentFcb = NULL; + PFCB PreviousFcb = NULL; BOOLEAN DeleteOnClose; BOOLEAN OpenByFileId; @@ -173,16 +252,17 @@ UDFCommonCreate( PUDF_FILE_INFO NewFileInfo = NULL; PUDF_FILE_INFO LastGoodFileInfo = NULL; PWCHAR TmpBuffer; - ULONG TreeLength = 0; BOOLEAN VolumeOpen = FALSE; BOOLEAN StreamOpen = FALSE; BOOLEAN StreamTargetOpen = FALSE; BOOLEAN StreamExists = FALSE; BOOLEAN RestoreShareAccess = FALSE; + BOOLEAN SkipPathTraversal = FALSE; PWCHAR TailNameBuffer = NULL; ULONG SNameIndex = 0; DECLARE_CONST_UNICODE_STRING(StreamSuffix, L":$DATA"); + DIR_ENUM_CONTEXT DirContext; PAGED_CODE(); @@ -545,33 +625,31 @@ UDFCommonCreate( RC = UDFCompleteFcbOpen(IrpContext, IrpSp, Vcb, &PtrNewFcb, UserVolumeOpen, 0, CreateDisposition); - if (!NT_SUCCESS(RC)) - goto op_vol_accs_dnd; - - PtrNewCcb = UDFDecodeFileObjectCcb(FileObject); + if (NT_SUCCESS(RC)) { + PtrNewCcb = UDFDecodeFileObjectCcb(FileObject); - // Check _Security_ - RC = UDFCheckAccessRights(NULL, AccessState, Vcb->RootIndexFcb, PtrNewCcb, DesiredAccess, ShareAccess); - if (!NT_SUCCESS(RC)) { - AdPrint((" Access violation (Volume)\n")); - goto op_vol_accs_dnd; - } - // Check _ShareAccess_ - RC = UDFCheckAccessRights(FileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); - if (!NT_SUCCESS(RC)) { - AdPrint((" Sharing violation (Volume)\n")); -op_vol_accs_dnd: - if (UndoLock) { - Vcb->VcbState &= ~VCB_STATE_LOCKED; - Vcb->VolumeLockFileObject = NULL; + // Check _Security_ + RC = UDFCheckAccessRights(NULL, AccessState, Vcb->RootIndexFcb, PtrNewCcb, DesiredAccess, ShareAccess); + if (NT_SUCCESS(RC)) { + // Check _ShareAccess_ + RC = UDFCheckAccessRights(FileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); + if (NT_SUCCESS(RC)) { + Options |= FILE_NO_INTERMEDIATE_BUFFERING; + ReturnedInformation = FILE_OPENED; + try_return(RC); + } else { + AdPrint((" Sharing violation (Volume)\n")); + } + } else { + AdPrint((" Access violation (Volume)\n")); } - try_return(RC); } - Options |= FILE_NO_INTERMEDIATE_BUFFERING; - - ReturnedInformation = FILE_OPENED; - + // Error cleanup + if (UndoLock) { + Vcb->VcbState &= ~VCB_STATE_LOCKED; + Vcb->VolumeLockFileObject = NULL; + } try_return(RC); } @@ -798,10 +876,9 @@ UDFCommonCreate( PtrNewFcb = Vcb->RootIndexFcb; RC = UDFCompleteFcbOpen(IrpContext, IrpSp, Vcb, &PtrNewFcb, UserDirectoryOpen, 0, CreateDisposition); if (!NT_SUCCESS(RC)) try_return(RC); -// DbgPrint("UDF: Open/Create RootDir : ReferenceCount %x\n",PtrNewFcb->ReferenceCount); + // Reference root's FileInfo (root has no parent, so no LCB) UDFReferenceFile__(PtrNewFcb->FileInfo); PtrNewCcb = UDFDecodeFileObjectCcb(FileObject); - TreeLength = 1; RC = UDFCheckAccessRights(FileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); if (!NT_SUCCESS(RC)) { @@ -846,25 +923,30 @@ UDFCommonCreate( RelatedFileInfo = OldRelatedFileInfo = RelatedFileInfo->ParentFile; NextFcb = NextFcb->ParentFcb; - // prevent releasing parent structures - UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); - TreeLength++; + // Parent references are now handled by LCB in UDFCompleteFcbOpen - if (Res1) UDFReleaseResource(Res1); - if (Res2) UDFReleaseResource(Res2); - - UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb); - UDFAcquireResourceExclusive(Res2 = &RelatedFileInfo->Fcb->FcbNonpaged->FcbResource, TRUE); + // Acquire FCB lock for tree traversal + // Skip if same FCB to avoid recursive acquire leading to lock leak PtrNewFcb = NewFileInfo->Fcb; + if (PtrNewFcb != CurrentFcb) { + UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb); + UDFAcquireFcbExclusive(IrpContext, PtrNewFcb, FALSE); + // Release grandparent lock from previous iteration + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } + PreviousFcb = CurrentFcb; + CurrentFcb = PtrNewFcb; + } - UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb); - UDFAcquireResourceExclusive(Res1 = &PtrNewFcb->FcbNonpaged->FcbResource, TRUE); + // Reference target file's FileInfo (balanced by cleanup) UDFReferenceFile__(NewFileInfo); - TreeLength++; - goto AlreadyOpened; + SkipPathTraversal = TRUE; } + if (!SkipPathTraversal) { + //AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject)); if (AbsolutePathName.Length > UDF_X_PATH_LEN*sizeof(WCHAR)) { @@ -925,8 +1007,13 @@ UDFCommonCreate( LastGoodName.Length = 0; LastGoodFileInfo = RelatedFileInfo; // reference RelatedObject to prevent releasing parent structures - UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); - TreeLength++; + // Acquire only CurrentFcb (= LastGoodFileInfo->Fcb) + CurrentFcb = RelatedFileInfo->Fcb; + UDF_CHECK_PAGING_IO_RESOURCE(CurrentFcb); + UDFAcquireFcbExclusive(IrpContext, CurrentFcb, FALSE); + + // Parent references are now handled by LCB in UDFCompleteFcbOpen + // when child files are opened through this directory. // go into a loop parsing the supplied name @@ -984,11 +1071,11 @@ UDFCommonCreate( try_return(RC); } - ASSERT(RelatedFileInfo->Fcb->FcbReference >= RelatedFileInfo->RefCount); + // Note: FcbReference may be 0 for intermediate directories during path traversal; + // it will be incremented when CCB is created in UDFCompleteFcbOpen - if (RelatedFileInfo && (TreeLength>1)) { - // it was an internal Open operation. Thus, assume - // RelatedFileInfo's Fcb to be valid + // Mark intermediate directory FCB as valid (internal open) + if (RelatedFileInfo && RelatedFileInfo->ParentFile) { RelatedFileInfo->Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; RelatedFileInfo->Fcb->FcbState |= UDF_FCB_VALID; } @@ -997,100 +1084,97 @@ UDFCommonCreate( AdPrint((" Path component is too long\n")); try_return(RC = STATUS_OBJECT_NAME_INVALID); } - // ...and now release previously acquired objects, - if (Res1) UDFReleaseResource(Res1); - if (Res2) { - UDFReleaseResource(Res2); - Res2 = NULL; + // Acquire FCB lock for tree traversal + // Skip if same FCB to avoid recursive acquire leading to lock leak + { + PFCB NewFcb = RelatedFileInfo->Fcb; + if (NewFcb != CurrentFcb) { + UDF_CHECK_PAGING_IO_RESOURCE(NewFcb); + UDFAcquireFcbExclusive(IrpContext, NewFcb, FALSE); + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } + PreviousFcb = CurrentFcb; + CurrentFcb = NewFcb; + } } - // acquire new _parent_ directory & try to open what - // we want. - UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb); - UDFAcquireResourceExclusive(Res1 = &RelatedFileInfo->Fcb->FcbNonpaged->FcbResource, TRUE); - - // check traverse rights + // check traverse rights (uses RelatedFileInfo->Fcb which is now locked as PreviousFcb) RC = UDFCheckAccessRights(NULL, NULL, RelatedFileInfo->Fcb, RelatedCcb, FILE_TRAVERSE, 0); if (!NT_SUCCESS(RC)) { NewFileInfo = NULL; AdPrint((" Traverse check failed\n")); - goto Skip_open_attempt; - } - // check if we should open normal File/Dir or SDir - if (CurName.Buffer[0] != ':') { - // standard open, nothing interesting.... - RC = UDFOpenFile__(IrpContext, - Vcb, - IgnoreCase,TRUE,&CurName, - RelatedFileInfo,&NewFileInfo,NULL); - if (RC == STATUS_FILE_DELETED) { - // file has gone, but system still remembers it... - NewFileInfo = NULL; - AdPrint((" File deleted\n")); - RC = STATUS_ACCESS_DENIED; + } else if (CurName.Buffer[0] != ':') { + // standard open: first find, then open + RC = UDFFindDirEntry(Vcb, RelatedFileInfo, &CurName, IgnoreCase, TRUE, &DirContext); + if (NT_SUCCESS(RC)) { + // Check if intermediate path component is a directory + if (TailName.Length && + !(DirContext.DirNdx->FileCharacteristics & FILE_DIRECTORY)) { + AdPrint((" Not a directory\n")); + RC = STATUS_NOT_A_DIRECTORY; + } else { + RC = UDFOpenObjectFromDirContext(IrpContext, Vcb, &DirContext, TRUE, &NewFileInfo); + if (RC == STATUS_FILE_DELETED) { + // file has gone, but system still remembers it... + NewFileInfo = NULL; + AdPrint((" File deleted\n")); + RC = STATUS_ACCESS_DENIED; + } else + if (RC == STATUS_SHARING_PAUSED) { + AdPrint((" Dloc is being initialized\n")); + BrutePoint(); + RC = STATUS_SHARING_VIOLATION; + } + } + } #ifdef UDF_DBG - } else - if (RC == STATUS_NOT_A_DIRECTORY) { + else if (RC == STATUS_NOT_A_DIRECTORY) { AdPrint((" Not a directory\n")); -#endif // UDF_DBG - } else - if (RC == STATUS_SHARING_PAUSED) { - AdPrint((" Dloc is being initialized\n")); - BrutePoint(); - RC = STATUS_SHARING_VIOLATION; } +#endif // UDF_DBG } else { - // And here we should open Stream Dir (if any, of cource) + // And here we should open Stream Dir (if any, of course) RC = UDFOpenStreamDir__(IrpContext, Vcb, RelatedFileInfo, &NewFileInfo); if (NT_SUCCESS(RC)) { -SuccessOpen_SDir: // this indicates that we needn't Stream Dir creation StreamExists = TRUE; StreamName.Buffer++; - StreamName.Length-=sizeof(WCHAR); + StreamName.Length -= sizeof(WCHAR); // update TailName TailName = StreamName; } else if (RC == STATUS_NOT_FOUND) { - // Stream Dir doesn't exist, but caller wants it to be // created. Lets try to help him... if ((CreateDisposition == FILE_CREATE) || (CreateDisposition == FILE_OPEN_IF) || (CreateDisposition == FILE_OVERWRITE_IF) || - OpenTargetDirectory ) { + OpenTargetDirectory) { RC = UDFCreateStreamDir__(IrpContext, Vcb, RelatedFileInfo, &NewFileInfo); - if (NT_SUCCESS(RC)) - goto SuccessOpen_SDir; + if (NT_SUCCESS(RC)) { + StreamExists = TRUE; + StreamName.Buffer++; + StreamName.Length -= sizeof(WCHAR); + TailName = StreamName; + } } } -/* } else { - AdPrint((" File deleted (2)\n")); - RC = STATUS_ACCESS_DENIED;*/ } -Skip_open_attempt: - // check if we have successfully opened path component if (NT_SUCCESS(RC)) { - // Yesss !!! + // Get or create FCB for the opened FileInfo if (!(PtrNewFcb = NewFileInfo->Fcb)) { - // It is a first open operation - // Allocate new FCB - // Here we set FileObject pointer to NULL to avoid - // new CCB allocation - RC = UDFFirstOpenFile(IrpContext, - IrpSp, - Vcb, + // First open - create FCB + RC = UDFFirstOpenFile(IrpContext, IrpSp, Vcb, NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, &LocalPath, &CurName, CreateDisposition); - if (!NT_SUCCESS(RC)) { BrutePoint(); AdPrint((" Can't perform FirstOpen\n")); UDFCloseFile__(IrpContext, Vcb, NewFileInfo); - if (PtrNewFcb) UDFCleanUpFCB(PtrNewFcb); - PtrNewFcb = NULL; + if (PtrNewFcb) UDFDeleteFcb(IrpContext, PtrNewFcb); NewFileInfo->Fcb = NULL; if (UDFCleanUpFile__(Vcb, NewFileInfo)) { MyFreePool__(NewFileInfo); @@ -1099,14 +1183,11 @@ UDFCommonCreate( try_return(RC); } } else { - // It is not a first open operation - // Validate Fcb. It is possible to get - // not completly initialized Fcb here. + // Validate existing FCB if (!(PtrNewFcb->FcbState & UDF_FCB_VALID)) { BrutePoint(); AdPrint((" Fcb not valid\n")); UDFCloseFile__(IrpContext, Vcb, NewFileInfo); - PtrNewFcb = NULL; if (UDFCleanUpFile__(Vcb, NewFileInfo)) { MyFreePool__(NewFileInfo); NewFileInfo = NULL; @@ -1114,23 +1195,54 @@ UDFCommonCreate( try_return(RC = STATUS_ACCESS_DENIED); } } - // Acquire newly opened File... - Res2 = Res1; - UDF_CHECK_PAGING_IO_RESOURCE(NewFileInfo->Fcb); - UDFAcquireResourceExclusive(Res1 = &NewFileInfo->Fcb->FcbNonpaged->FcbResource, TRUE); - // ...and reference it - InterlockedIncrement((PLONG)&PtrNewFcb->FcbReference); - - ASSERT(PtrNewFcb->FcbReference >= NewFileInfo->RefCount); - // update unwind information + + // Acquire FCB lock for tree traversal (try-lock to prevent deadlock) + { + PFCB NewFcb = NewFileInfo->Fcb; + if (NewFcb != CurrentFcb) { + UDF_CHECK_PAGING_IO_RESOURCE(NewFcb); + if (!UDFAcquireFcbExclusive(IrpContext, NewFcb, TRUE)) { + // Try-lock failed - rollback and reacquire in order + UDFLockVcb(IrpContext, Vcb); + NewFcb->FcbCleanup++; + UDFUnlockVcb(IrpContext, Vcb); + + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } + PFCB OldCurrentFcb = CurrentFcb; + UDF_CHECK_PAGING_IO_RESOURCE(OldCurrentFcb); + UDFReleaseResource(&OldCurrentFcb->FcbNonpaged->FcbResource); + + UDFAcquireFcbExclusive(IrpContext, NewFcb, FALSE); + UDFAcquireFcbExclusive(IrpContext, OldCurrentFcb, FALSE); + PreviousFcb = OldCurrentFcb; + + UDFLockVcb(IrpContext, Vcb); + NewFcb->FcbCleanup--; + UDFUnlockVcb(IrpContext, Vcb); + } else { + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } + PreviousFcb = CurrentFcb; + } + CurrentFcb = NewFcb; + } + } + + // FCB references are handled by LCB in UDFCompleteFcbOpen + // Note: FcbReference may be 0 here during path traversal; + // it will be incremented when CCB is created + + // Update state LastGoodFileInfo = NewFileInfo; LastGoodName = CurName; - TreeLength++; - // update current path + + // Update current path if (!StreamOpen || ((CurName.Buffer[0] != L':') && (!LocalPath.Length || (LocalPath.Buffer[LocalPath.Length/sizeof(WCHAR)-1] != L':'))) ) { - // we should not insert '\' before or after ':' ASSERT(!LocalPath.Length || (LocalPath.Buffer[LocalPath.Length/2-1] != L'\\')); RC = MyAppendUnicodeToString(&LocalPath, L"\\"); @@ -1139,7 +1251,6 @@ UDFCommonCreate( RC = MyAppendUnicodeStringToStringTag(&LocalPath, &CurName, MEM_USLOC_TAG); if (!NT_SUCCESS(RC)) try_return(RC); -// DbgPrint("UDF: Open/Create File %ws : ReferenceCount %x\n",CurName.Buffer,PtrNewFcb->ReferenceCount); } else { AdPrint((" Can't open file\n")); // We have failed durring last Open attempt @@ -1148,11 +1259,11 @@ UDFCommonCreate( // Cleanup FileInfo if any if (NewFileInfo) { PtrNewFcb = NewFileInfo->Fcb; - // acquire appropriate resource if possible + // Temporarily acquire NewFcb for cleanup, + // but keep CurrentFcb unchanged (= LastGoodFileInfo->Fcb) if (PtrNewFcb) { - Res2 = Res1; UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb); - UDFAcquireResourceExclusive(Res1 = &PtrNewFcb->FcbNonpaged->FcbResource, TRUE); + UDFAcquireFcbExclusive(IrpContext, PtrNewFcb, FALSE); } // cleanup pointer to Fcb in FileInfo to allow // UDF_INFO package release FileInfo if there are @@ -1175,7 +1286,7 @@ UDFCommonCreate( ASSERT(!PtrNewFcb); if (PtrNewFcb) { BrutePoint(); - UDFCleanUpFCB(PtrNewFcb); + UDFDeleteFcb(IrpContext, PtrNewFcb); } MyFreePool__(NewFileInfo); } else { @@ -1186,6 +1297,10 @@ UDFCommonCreate( if (PtrNewFcb) NewFileInfo->Dloc->CommonFcb = PtrNewFcb; } + // Release NewFcb lock after cleanup + if (PtrNewFcb) { + UDFReleaseResource(&PtrNewFcb->FcbNonpaged->FcbResource); + } // forget about last FileInfo & Fcb, // further unwind staff needs only last good // structures @@ -1227,8 +1342,8 @@ UDFCommonCreate( // ... and exit with error try_return(RC); } - // discard changes for last successfully opened file - InterlockedDecrement((PLONG)&PtrNewFcb->FcbReference); + // Note: With LCB model, FcbReference is not incremented during path traversal, + // so no decrement is needed here (removed the old InterlockedDecrement). RC = STATUS_SUCCESS; ASSERT(!OpenTargetDirectory); // break open loop and continue with Open @@ -1292,18 +1407,18 @@ UDFCommonCreate( // to reflect the fact that the parent directory of the // target has been opened PtrNewFcb = NewFileInfo->Fcb; - InterlockedDecrement((PLONG)&PtrNewFcb->FcbReference); + // Note: Removed FcbReference decrement - no longer needed with LCB model. + // The old TreeLength model incremented parent FcbReference during path traversal, + // but LCB model handles parent references differently (via UDFAcquirePrefix). RC = UDFCompleteFcbOpen(IrpContext, IrpSp, Vcb, &PtrNewFcb, UserDirectoryOpen, 0, CreateDisposition); - - ASSERT(PtrNewFcb->FcbReference >= NewFileInfo->RefCount); if (!NT_SUCCESS(RC)) { AdPrint((" Can't perform OpenFile operation for target\n")); try_return(RC); } PtrNewCcb = UDFDecodeFileObjectCcb(FileObject); - ASSERT(Res1); + ASSERT(CurrentFcb); RC = UDFCheckAccessRights(FileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); if (!NT_SUCCESS(RC)) { AdPrint((" Access/Share access check failed (Open Target)\n")); @@ -1367,7 +1482,7 @@ UDFCommonCreate( try_return(RC = STATUS_INVALID_PARAMETER); } // check access rights - ASSERT(Res1); + ASSERT(CurrentFcb); RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, RelatedCcb, DirectoryFile ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0); if (!NT_SUCCESS(RC)) { AdPrint((" Creation of File/Dir not permitted\n")); @@ -1385,30 +1500,6 @@ UDFCommonCreate( (CreateDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo); if (!NT_SUCCESS(RC)) { AdPrint((" Creation error\n")); -Creation_Err_1: - if (NewFileInfo) { - PtrNewFcb = NewFileInfo->Fcb; - ASSERT(!PtrNewFcb); - if (PtrNewFcb && - !PtrNewFcb->FcbReference && - !PtrNewFcb->FcbCleanup) { - NewFileInfo->Fcb = NULL; - } - if (NewFileInfo->Dloc && - !NewFileInfo->Dloc->LinkRefCount) { - NewFileInfo->Dloc->CommonFcb = NULL; - } - if (UDFCleanUpFile__(Vcb, NewFileInfo)) { - if (PtrNewFcb) { - BrutePoint(); - UDFCleanUpFCB(PtrNewFcb); - } - MyFreePool__(NewFileInfo); - } else { - NewFileInfo->Fcb = PtrNewFcb; - } - PtrNewFcb = NULL; - } try_return(RC); } // Update parent object @@ -1423,8 +1514,8 @@ UDFCommonCreate( // user wants the directory to be created RC = UDFRecordDirectory__(IrpContext, Vcb, NewFileInfo); if (!NT_SUCCESS(RC)) { - AdPrint((" Can't transform to directory\n")); -Undo_Create_1: + AdPrint((" Can't transform to directory\n")); + // Undo create - flush and unlink from disk if ((RC != STATUS_FILE_IS_A_DIRECTORY) && (RC != STATUS_NOT_A_DIRECTORY) && (RC != STATUS_ACCESS_DENIED)) { @@ -1432,16 +1523,8 @@ UDFCommonCreate( UDFUnlinkFile__(IrpContext, Vcb, NewFileInfo, TRUE); } UDFCloseFile__(IrpContext, Vcb, NewFileInfo); - BrutePoint(); - goto Creation_Err_1; + try_return(RC); } - - } else if (AllocationSize) { - // set initial file size -/* if (!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { - AdPrint((" Can't set initial file size\n")); - goto Undo_Create_1; - };*/ } if (StreamOpen && !StreamExists) { @@ -1462,25 +1545,42 @@ UDFCommonCreate( if (!NT_SUCCESS(RC)) { AdPrint((" Can't perform FirstOpenFile operation for file to contain stream\n")); BrutePoint(); - UDFCleanUpFCB(NewFileInfo->Fcb); + if (PtrNewFcb) { + UDFDeleteFcb(IrpContext, PtrNewFcb); + PtrNewFcb = NULL; + } NewFileInfo->Fcb = NULL; - goto Creation_Err_1; + try_return(RC); } } else { BrutePoint(); } - // Update unwind information - TreeLength++; + // Update state + // FCB references are now handled by LCB in UDFCompleteFcbOpen LastGoodFileInfo = NewFileInfo; + // Acquire FCB lock for tree traversal + // Skip if same FCB to avoid recursive acquire leading to lock leak + { + PFCB NewFcb = NewFileInfo->Fcb; + if (NewFcb != CurrentFcb) { + UDF_CHECK_PAGING_IO_RESOURCE(NewFcb); + UDFAcquireFcbExclusive(IrpContext, NewFcb, FALSE); + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } + PreviousFcb = CurrentFcb; + CurrentFcb = NewFcb; + } + } // update FCB tree RC = MyAppendUnicodeToString(&LocalPath, L"\\"); if (!NT_SUCCESS(RC)) try_return(RC); RC = MyAppendUnicodeStringToStringTag(&LocalPath, &LastGoodTail, MEM_USLOC_TAG); - if (!NT_SUCCESS(RC)) - goto Creation_Err_1; - InterlockedIncrement((PLONG)&PtrNewFcb->FcbReference); - ASSERT(PtrNewFcb->FcbReference >= NewFileInfo->RefCount); + if (!NT_SUCCESS(RC)) { + try_return(RC); + } + // Note: FcbReference will be set when CCB is created in UDFCompleteFcbOpen PtrNewFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; PtrNewFcb->FcbState |= UDF_FCB_VALID; @@ -1496,7 +1596,7 @@ UDFCommonCreate( if (!NT_SUCCESS(RC)) { AdPrint((" Can't create SDir\n")); BrutePoint(); - goto Creation_Err_1; + try_return(RC); } // normalize stream name @@ -1519,21 +1619,34 @@ UDFCommonCreate( if (!NT_SUCCESS(RC)) { AdPrint((" Can't perform OpenFile operation for SDir\n")); BrutePoint(); - goto Creation_Err_1; + try_return(RC); } - // Update unwind information - TreeLength++; + // Update state + // FCB references are now handled by LCB in UDFCompleteFcbOpen LastGoodFileInfo = NewFileInfo; + // Acquire FCB lock for tree traversal + // Skip if same FCB to avoid recursive acquire leading to lock leak + { + PFCB NewFcb = NewFileInfo->Fcb; + if (NewFcb != CurrentFcb) { + UDF_CHECK_PAGING_IO_RESOURCE(NewFcb); + UDFAcquireFcbExclusive(IrpContext, NewFcb, FALSE); + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } + PreviousFcb = CurrentFcb; + CurrentFcb = NewFcb; + } + } // update FCB tree RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(UdfData.UnicodeStrSDir), MEM_USLOC_TAG); if (!NT_SUCCESS(RC)) { AdPrint((" Can't append UNC str\n")); BrutePoint(); - goto Creation_Err_1; + try_return(RC); } - InterlockedIncrement((PLONG)&PtrNewFcb->FcbReference); - ASSERT(PtrNewFcb->FcbReference >= NewFileInfo->RefCount); + // Note: FcbReference will be set when CCB is created in UDFCompleteFcbOpen PtrNewFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; PtrNewFcb->FcbState |= UDF_FCB_VALID; @@ -1547,7 +1660,7 @@ UDFCommonCreate( if (!NT_SUCCESS(RC)) { AdPrint((" Can't create Stream\n")); BrutePoint(); - goto Creation_Err_1; + try_return(RC); } // Update unwind information @@ -1579,7 +1692,15 @@ UDFCommonCreate( if (!NT_SUCCESS(RC)) { AdPrint((" Can't perform OpenFile operation for file or stream\n")); BrutePoint(); - goto Undo_Create_1; + // Undo create - flush and unlink from disk + if ((RC != STATUS_FILE_IS_A_DIRECTORY) && + (RC != STATUS_NOT_A_DIRECTORY) && + (RC != STATUS_ACCESS_DENIED)) { + UDFFlushFile__(IrpContext, Vcb, NewFileInfo); + UDFUnlinkFile__(IrpContext, Vcb, NewFileInfo, TRUE); + } + UDFCloseFile__(IrpContext, Vcb, NewFileInfo); + try_return(RC); } PtrNewFcb->Header.FileSize.QuadPart = @@ -1596,9 +1717,23 @@ UDFCommonCreate( } } - // Update unwind information - TreeLength++; + // Update state + // FCB references are now handled by LCB in UDFCompleteFcbOpen LastGoodFileInfo = NewFileInfo; + // Acquire FCB lock for tree traversal + // Skip if same FCB to avoid recursive acquire leading to lock leak + { + PFCB NewFcb = NewFileInfo->Fcb; + if (NewFcb != CurrentFcb) { + UDF_CHECK_PAGING_IO_RESOURCE(NewFcb); + UDFAcquireFcbExclusive(IrpContext, NewFcb, FALSE); + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } + PreviousFcb = CurrentFcb; + CurrentFcb = NewFcb; + } + } // Set the Share Access for the file stream. // The FCBShareAccess field will be set by the I/O Manager. @@ -1608,8 +1743,10 @@ UDFCommonCreate( if (!NT_SUCCESS(RC)) { AdPrint((" Can't set Access Rights on Create\n")); BrutePoint(); + // Undo create - flush, unlink and close UDFFlushFile__(IrpContext, Vcb, NewFileInfo); UDFUnlinkFile__(IrpContext, Vcb, NewFileInfo, TRUE); + UDFCloseFile__(IrpContext, Vcb, NewFileInfo); try_return(RC); } @@ -1650,26 +1787,14 @@ UDFCommonCreate( try_return(RC); } -AlreadyOpened: + } // end if (!SkipPathTraversal) // **************** // we have always STATUS_SUCCESS here // **************** - ASSERT(NewFileInfo != OldRelatedFileInfo); - // A new CCB will be allocated. - // Assume that this structure named PtrNewCcb - - TYPE_OF_OPEN TypeOfOpen; - - if (UDFIsADirectory(PtrNewFcb->FileInfo)) { - TypeOfOpen = UserDirectoryOpen; - } else { - TypeOfOpen = UserFileOpen; - } - - RC = UDFCompleteFcbOpen(IrpContext, IrpSp, Vcb, &PtrNewFcb, TypeOfOpen, 0, DesiredAccess); + RC = UDFOpenExistingFcb(IrpContext, IrpSp, Vcb, &PtrNewFcb, IgnoreCase, OpenByFileId, CreateDisposition); if (!NT_SUCCESS(RC)) try_return(RC); PtrNewCcb = UDFDecodeFileObjectCcb(FileObject); @@ -1709,8 +1834,7 @@ UDFCommonCreate( } // Check share access and fail if the share conflicts with an existing // open. - ASSERT(Res1 != NULL); - ASSERT(Res2 != NULL); + ASSERT(CurrentFcb); RC = UDFCheckAccessRights(FileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); if (!NT_SUCCESS(RC)) { AdPrint((" Access/Share access check failed\n")); @@ -1766,8 +1890,7 @@ UDFCommonCreate( if (DeleteOnClose && (TmpFileAttributes & FILE_ATTRIBUTE_READONLY)) { - ASSERT(Res1 != NULL); - ASSERT(Res2 != NULL); + ASSERT(CurrentFcb); RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, RelatedCcb, FILE_DELETE_CHILD, 0); if (!NT_SUCCESS(RC)) { AdPrint((" Read-only. DeleteOnClose attempt failed\n")); @@ -1786,8 +1909,7 @@ UDFCommonCreate( if (CreateDisposition == FILE_SUPERSEDE) { BOOLEAN RestoreRO = FALSE; - ASSERT(Res1 != NULL); - ASSERT(Res2 != NULL); + ASSERT(CurrentFcb); // NT wants us to allow Supersede on RO files if (PtrNewFcb->FcbState & UDF_FCB_READ_ONLY) { // Imagine, that file is not RO and check other permissions @@ -1804,8 +1926,7 @@ UDFCommonCreate( try_return (RC); } } else { - ASSERT(Res1 != NULL); - ASSERT(Res2 != NULL); + ASSERT(CurrentFcb); RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES, 0); if (!NT_SUCCESS(RC)) { @@ -1820,58 +1941,24 @@ UDFCommonCreate( try_return(RC = STATUS_ACCESS_DENIED); } - // Before we actually truncate, check to see if the purge - // is going to fail. - MmPrint((" MmCanFileBeTruncated()\n")); - if (!MmCanFileBeTruncated(&PtrNewFcb->FcbNonpaged->SegmentObject, - &UdfData.UDFLargeZero)) { - AdPrint((" Can't truncate. File is mapped\n")); - try_return(RC = STATUS_USER_MAPPED_FILE); - } + ASSERT(CurrentFcb); - ASSERT(Res1 != NULL); - ASSERT(Res2 != NULL); - - // Synchronize with PagingIo - UDFAcquireResourceExclusive(PagingIoRes = &PtrNewFcb->FcbNonpaged->FcbPagingIoResource, TRUE); - // Set file sizes - if (!NT_SUCCESS(RC = UDFResizeFile__(IrpContext, Vcb, NewFileInfo, 0))) { - AdPrint((" Error during resize operation\n")); + // Truncate file and set attributes (acquires PagingIoResource internally, checks MmCanFileBeTruncated) + RC = UDFSupersedeOrOverwriteFile( + IrpContext, + FileObject, + Vcb, + PtrNewFcb, + NewFileInfo, + AllocationSize, + FileAttributes, + (BOOLEAN)(CreateDisposition == FILE_SUPERSEDE) + ); + if (!NT_SUCCESS(RC)) { try_return(RC); } -/* if (AllocationSize) { - if (!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { - AdPrint((" Error during resize operation (2)\n")); - try_return(RC); - } - }*/ - PtrNewFcb->Header.AllocationSize.QuadPart = UDFSysGetAllocSize(Vcb, AllocationSize); - PtrNewFcb->Header.FileSize.QuadPart = - PtrNewFcb->Header.ValidDataLength.QuadPart = 0 /*AllocationSize*/; - PtrNewFcb->FcbState &= ~UDF_FCB_DELAY_CLOSE; - MmPrint((" CcSetFileSizes()\n")); - CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&PtrNewFcb->Header.AllocationSize); - PtrNewFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; - // Release PagingIoResource - UDFReleaseResource(PagingIoRes); - PagingIoRes = NULL; - if (NT_SUCCESS(RC)) { - FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; - if (CreateDisposition == FILE_SUPERSEDE) { - // Set attributes for the file ... - UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), - NewFileInfo->Dloc->FileEntry, FileAttributes); - ReturnedInformation = FILE_SUPERSEDED; - } else { - // Get attributes for the file ... - FileAttributes |= TmpFileAttributes; - // Set attributes for the file ... - UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), - NewFileInfo->Dloc->FileEntry, FileAttributes); - ReturnedInformation = FILE_OVERWRITTEN; - } - } + ReturnedInformation = (CreateDisposition == FILE_SUPERSEDE) ? FILE_SUPERSEDED : FILE_OVERWRITTEN; // notify changes UDFNotifyFullReportChange( Vcb, NewFileInfo->Fcb, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE, @@ -1966,14 +2053,9 @@ try_exit: NOTHING; UDFUnlockVcb(IrpContext, Vcb); - - if (FileObject->Flags & FO_CACHE_SUPPORTED) - InterlockedIncrement((PLONG)&PtrNewFcb->CachedOpenHandleCount); // Store some flags in CCB if (PtrNewCcb) { - PtrNewCcb->TreeLength = TreeLength; // delete on close - if (DeleteOnClose) { ASSERT(!(PtrNewFcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); PtrNewCcb->Flags |= UDF_CCB_DELETE_ON_CLOSE; @@ -1996,16 +2078,10 @@ try_exit: NOTHING; InterlockedIncrement((PLONG)&Vcb->VcbReference); PtrNewFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; PtrNewFcb->FcbState |= UDF_FCB_VALID; -#ifdef UDF_DBG - // We have no FileInfo for Volume - if (PtrNewFcb->FileInfo) { - ASSERT(PtrNewFcb->FcbReference >= PtrNewFcb->FileInfo->RefCount); - } -#endif // UDF_DBG + // Note: With LCB model, FcbReference may not always be >= RefCount + // for intermediate files (e.g., parent of a stream) AdPrint((" FCB %x, CCB %x, FO %x, Flags %x\n", PtrNewFcb, PtrNewCcb, FileObject, PtrNewFcb->FcbState)); - UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); - } else if (!NT_SUCCESS(RC)) { // Perform failure related post-processing now if (RestoreShareAccess && PtrNewFcb && FileObject) { @@ -2027,30 +2103,76 @@ try_exit: NOTHING; LastGoodFileInfo->Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; } } - // Release resources... - UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); - // close the chain - UDFCloseFileInfoChain(IrpContext, Vcb, LastGoodFileInfo, TreeLength, TRUE); // cleanup FCBs (if any) + // Note: UDFTeardownStructures calls UDFCloseFile__ when CallCloseFile=TRUE + // (CloseFileInfoChain is NOT called in Create finally) + // Note: UDFTeardownStructures releases lock when FCB is removed + ASSERT(!LastGoodFileInfo || !LastGoodFileInfo->Fcb || CurrentFcb == LastGoodFileInfo->Fcb); if ( Vcb && (PtrNewFcb != Vcb->RootIndexFcb) && LastGoodFileInfo ) { - UDFTeardownStructures(IrpContext, LastGoodFileInfo->Fcb, TreeLength, NULL); + // + // LOCK LEAK FIX: + // TeardownStructures walks up the FCB tree and acquires parent locks. + // If we hold PreviousFcb (= CurrentFcb->ParentFcb), TeardownStructures will: + // - Recursively acquire it (OwnerCount: 1->2) + // - Process and release (OwnerCount: 2->1) + // Our original lock is still held (count=1). + // + // Old bug: Code set PreviousFcb=NULL when RemovedFcb=TRUE, leaking our lock. + // + // Fix: Protect PreviousFcb from deletion via FcbReference++. + // Using FcbReference (not FcbCleanup) because TeardownStructures + // may decrement parent FcbReferences via LCB removal. + // If we used FcbCleanup++, ASSERT(FcbCleanup <= FcbReference) would fail + // when FcbReference is decremented to 0 but FcbCleanup is still 1. + // After TeardownStructures, decrement FcbReference. + // Let finally block release our lock normally. + // DON'T set PreviousFcb=NULL! + // + BOOLEAN ProtectedPreviousFcb = FALSE; + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFLockVcb(IrpContext, Vcb); + PreviousFcb->FcbReference++; + UDFUnlockVcb(IrpContext, Vcb); + ProtectedPreviousFcb = TRUE; + } + + BOOLEAN RemovedFcb = FALSE; + // LCB-based teardown: walks ParentLcbQueue to find and remove LCBs + UDFTeardownStructures(IrpContext, LastGoodFileInfo->Fcb, FALSE, &RemovedFcb); + // If FCB was removed, lock is already released by TeardownStructures + if (RemovedFcb) { + CurrentFcb = NULL; + } + + // Unprotect PreviousFcb + if (ProtectedPreviousFcb) { + UDFLockVcb(IrpContext, Vcb); + PreviousFcb->FcbReference--; + UDFUnlockVcb(IrpContext, Vcb); + } + // PreviousFcb lock will be released by finally block below } else { ASSERT(!LastGoodFileInfo); } - } else { - UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); } - // As long as this unwinding is not being performed as a result of - // an exception condition, complete the IRP ... - if (!_SEH2_AbnormalTermination()) { + } - Irp->IoStatus.Information = ReturnedInformation; + // Release parent lock first (PreviousFcb before CurrentFcb) + if (PreviousFcb && PreviousFcb != CurrentFcb) { + UDFReleaseResource(&PreviousFcb->FcbNonpaged->FcbResource); + } - UDFCompleteRequest(IrpContext, Irp, RC); - } - } else { - UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); + // Release current lock + if (CurrentFcb) { + UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); + } + + if (RC != STATUS_PENDING && !_SEH2_AbnormalTermination()) { + + Irp->IoStatus.Information = ReturnedInformation; + + UDFCompleteRequest(IrpContext, Irp, RC); } // free allocated tmp buffers (if any) @@ -2211,6 +2333,11 @@ UDFFirstOpenFile( UDFUnlockVcb(IrpContext, Vcb); return RC; } + // Set embedded data flag if file data is stored in ICB + if (!UDFIsADirectory(NewFileInfo) && + (((PFILE_ENTRY)(NewFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { + (*PtrNewFcb)->FcbState |= UDF_FCB_EMBEDDED_DATA; + } // set Read-only attribute if (!UDFIsAStreamDir(NewFileInfo)) { hDirIndex = UDFGetDirIndexByFileInfo(NewFileInfo); @@ -2254,6 +2381,14 @@ UDFFirstOpenFile( } } + // Insert FCB into table only on success (matching MS pattern where + // UdfInsertFcbTable is called at the END of initialization after + // everything succeeds). This ensures FCB is not in table if error + // occurs and UDFDeleteFcb is called from error path. + if (NT_SUCCESS(RC)) { + UDFInsertFcbIntoTable(IrpContext, *PtrNewFcb); + } + UDFUnlockVcb(IrpContext, Vcb); // end transaction @@ -2440,6 +2575,17 @@ UDFCompleteFcbOpen( // initialize the CCB to point to the file object Ccb->FileObject = IrpSp->FileObject; + // Acquire or create LCB to link parent directory FCB to this file FCB + // Skip for root directory (no parent) + // UDFAcquirePrefix will find existing LCB and increment Reference, + // or create new LCB and increment parent's FcbReference + if (Fcb->ParentFcb) { + Ccb->Lcb = UDFAcquirePrefix(IrpContext, + Fcb->ParentFcb, + Fcb, + Fcb->FileInfo ? Fcb->FileInfo->Index : 0); + } + // Set the file object type. UDFSetFileObject(IrpSp->FileObject, TypeOfOpen, Fcb, Ccb); @@ -2476,8 +2622,12 @@ try_exit: NOTHING; } _SEH2_FINALLY { if (Ccb) { - // TODO: fix NextCCB list - //UDFDeleteCcb(Ccb); + // CCB was allocated but create failed - clean up + if (Ccb->Lcb) { + UDFRemovePrefix(IrpContext, Ccb->Lcb); + Ccb->Lcb = NULL; + } + UDFReleaseCCB(Ccb); } } _SEH2_END; diff --git a/drivers/filesystems/udfs/dircntrl.cpp b/drivers/filesystems/udfs/dircntrl.cpp index 772b7a53a4446..bd46beecc851b 100644 --- a/drivers/filesystems/udfs/dircntrl.cpp +++ b/drivers/filesystems/udfs/dircntrl.cpp @@ -413,16 +413,21 @@ UDFQueryDirectory( DirInformation->FileIndex = NextMatch; FileNameBytes = DirInformation->FileNameLength; + // If this won't fit and we have returned a previous entry then just + // return STATUS_SUCCESS. + if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) { - // If this won't fit and we have returned a previous entry then just - // return STATUS_SUCCESS. Otherwise - // use a status code of STATUS_BUFFER_OVERFLOW. - if (CurrentOffset) { + + // If we already found an entry then just exit. + + if (CurrentOffset != 0) { try_return(RC = STATUS_SUCCESS); } - // strange policy... + + // Reduce the FileNameBytes to just fit in the buffer. + + FileNameBytes = BytesRemainingInBuffer - BaseLength; ReturnSingleEntry = TRUE; - FileNameBytes = BaseLength + FileNameBytes - BytesRemainingInBuffer; RC = STATUS_BUFFER_OVERFLOW; } // Now we have an entry to return to our caller. diff --git a/drivers/filesystems/udfs/fastio.cpp b/drivers/filesystems/udfs/fastio.cpp index 3709db14a7745..31b3bfac4c051 100644 --- a/drivers/filesystems/udfs/fastio.cpp +++ b/drivers/filesystems/udfs/fastio.cpp @@ -399,12 +399,17 @@ BOOLEAN NTAPI UDFAcqLazyWrite( MmPrint((" UDFAcqLazyWrite()\n")); - // Acquire the MainResource in the NT_REQ_FCB exclusively. Then, set the - // lazy-writer thread id in the NT_REQ_FCB structure for identification - // when an actual write request is received by the FSD. + // Acquire the MainResource in the NT_REQ_FCB. For embedded data files + // (data stored in ICB), acquire exclusively since data shares sector with + // metadata. For normal files, acquire shared to allow concurrent access. // Note: The lazy-writer typically always supplies WAIT set to TRUE. - if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, Wait)) - return FALSE; + if (Fcb->FcbState & UDF_FCB_EMBEDDED_DATA) { + if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, Wait)) + return FALSE; + } else { + if (!UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, Wait)) + return FALSE; + } // Now, set the lazy-writer thread id. ASSERT(!(Fcb->LazyWriteThread)); @@ -869,14 +874,10 @@ UDFFastIoAcqModWrite( OUT PERESOURCE *ResourceToRelease, IN PDEVICE_OBJECT DeviceObject) { - NTSTATUS RC = STATUS_SUCCESS; - - FsRtlEnterFileSystem(); - - MmPrint((" AcqModW %I64x\n", EndingOffset->QuadPart)); - PFCB Fcb = (PFCB)FileObject->FsContext; + *ResourceToRelease = NULL; + // We must determine which resource(s) we would like to // acquire at this time. We know that a write is imminent; // we will probably therefore acquire appropriate resources @@ -897,63 +898,23 @@ UDFFastIoAcqModWrite( // the resource that we acquired (single return value). This pointer // will be returned back to we in the release call (below). - if (UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbPagingIoResource, FALSE)) { - - if (EndingOffset->QuadPart <= Fcb->Header.ValidDataLength.QuadPart) { - - UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); - RC = STATUS_CANT_WAIT; - } else { - - *ResourceToRelease = &Fcb->FcbNonpaged->FcbPagingIoResource; - MmPrint((" AcqModW OK\n")); - } - + // For embedded data files, acquire exclusive since data shares sector with metadata + // For normal files, shared is enough + BOOLEAN Acquired; + if (Fcb->FcbState & UDF_FCB_EMBEDDED_DATA) { + Acquired = UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, FALSE); } else { - RC = STATUS_CANT_WAIT; + Acquired = UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, FALSE); } - return RC; -} // end UDFFastIoAcqModWrite() - - -/************************************************************************* -* -* Function: UDFFastIoRelModWrite() -* -* Description: -* Not really a fast-io operation. Used by the VMM to release FSD resources -* after processing a modified page/block write operation. -* -* Expected Interrupt Level (for execution) : -* -* IRQL_PASSIVE_LEVEL -* -* Return Value: STATUS_SUCCESS/Error (an error returned here is really not expected!) -* -*************************************************************************/ -NTSTATUS -NTAPI -UDFFastIoRelModWrite( - IN PFILE_OBJECT FileObject, - IN PERESOURCE ResourceToRelease, - IN PDEVICE_OBJECT DeviceObject) -{ - MmPrint((" RelModW\n")); - - PFCB Fcb = (PFCB)FileObject->FsContext; - - // The MPW has complete the write for modified pages and therefore - // wants us to release pre-acquired resource(s). - - // We must undo here whatever it is that we did in the - // UDFFastIoAcqModWrite() call above. + if (!Acquired) { + return STATUS_CANT_WAIT; + } - ASSERT(ResourceToRelease == &Fcb->FcbNonpaged->FcbPagingIoResource); - UDFReleaseResource(ResourceToRelease); + *ResourceToRelease = &Fcb->FcbNonpaged->FcbResource; - return(STATUS_SUCCESS); -} // end UDFFastIoRelModWrite() + return STATUS_SUCCESS; +} // end UDFFastIoAcqModWrite() /************************************************************************* @@ -999,8 +960,13 @@ UDFFastIoAcqCcFlush( PFCB Fcb = (PFCB)FileObject->FsContext; - UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); - UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbPagingIoResource, TRUE); + // For embedded data files, acquire exclusive since data shares sector with metadata + // For normal files, shared is enough + if (Fcb->FcbState & UDF_FCB_EMBEDDED_DATA) { + UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); + } else { + UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, TRUE); + } return STATUS_SUCCESS; @@ -1036,10 +1002,9 @@ UDFFastIoRelCcFlush( IoSetTopLevelIrp(NULL); } - // Release resources acquired in UDFFastIoAcqCcFlush() above. + // Release resource acquired in UDFFastIoAcqCcFlush() above. PFCB Fcb = (PFCB)FileObject->FsContext; - UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); return STATUS_SUCCESS; diff --git a/drivers/filesystems/udfs/fileinfo.cpp b/drivers/filesystems/udfs/fileinfo.cpp index d527a8902ac7c..82fe4faf266ef 100644 --- a/drivers/filesystems/udfs/fileinfo.cpp +++ b/drivers/filesystems/udfs/fileinfo.cpp @@ -311,7 +311,15 @@ UDFCommonSetInfo( if ((FunctionalityRequested != FilePositionInformation) && (FunctionalityRequested != FileRenameInformation) && (FunctionalityRequested != FileLinkInformation)) { - // Acquire the Parent & Main Resources exclusive. + // Child-first lock ordering + // Acquire Main (child) resource first + if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, CanWait)) { + PostRequest = TRUE; + try_return(Status = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + + // Acquire Parent resource second if (Fcb->FileInfo->ParentFile) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); if (!UDFAcquireResourceExclusive(&Fcb->ParentFcb->FcbNonpaged->FcbResource, CanWait)) { @@ -321,12 +329,6 @@ UDFCommonSetInfo( ParentResourceAcquired = TRUE; } - if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, CanWait)) { - PostRequest = TRUE; - try_return(Status = STATUS_PENDING); - } - MainResourceAcquired = TRUE; - if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbPagingIoResource, CanWait)) { PostRequest = TRUE; try_return(Status = STATUS_PENDING); @@ -426,22 +428,23 @@ try_exit: NOTHING; } _SEH2_FINALLY { + // Release in reverse order of acquisition if (PagingIoResourceAcquired) { UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); PagingIoResourceAcquired = FALSE; } - if (MainResourceAcquired) { - UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); - MainResourceAcquired = FALSE; - } - if (ParentResourceAcquired) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); UDFReleaseResource(&(Fcb->ParentFcb->FcbNonpaged->FcbResource)); ParentResourceAcquired = FALSE; } + if (MainResourceAcquired) { + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); + MainResourceAcquired = FALSE; + } + if (VcbAcquired) { UDFReleaseVcb(IrpContext, Vcb); @@ -1908,7 +1911,7 @@ UDFPrepareForRenameMoveLink( // There is a pair of objects among input dirs & // one of them is a parent of another. Sequential resource // acquisition may lead to deadlock due to concurrent - // CleanUpFcbChain() or UDFCloseFileInfoChain() + // cleanup operations or UDFTeardownStructures() InterlockedIncrement((PLONG)&Vcb->VcbReference); @@ -1920,13 +1923,15 @@ UDFPrepareForRenameMoveLink( } else { InterlockedDecrement((PLONG)&Vcb->VcbReference); - UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb); - UDFAcquireResourceExclusive(&Dir1->Fcb->FcbNonpaged->FcbResource, TRUE); - (*AcquiredDir1) = TRUE; - + // Child-first lock ordering + // File1 (child) first, Dir1 (parent) second UDF_CHECK_PAGING_IO_RESOURCE(File1->Fcb); UDFAcquireResourceExclusive(&File1->Fcb->FcbNonpaged->FcbResource, TRUE); (*AcquiredFcb1) = TRUE; + + UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb); + UDFAcquireResourceExclusive(&Dir1->Fcb->FcbNonpaged->FcbResource, TRUE); + (*AcquiredDir1) = TRUE; } return STATUS_SUCCESS; } // end UDFPrepareForRenameMoveLink() @@ -1958,19 +1963,16 @@ UDFSetRenameInfo( BOOLEAN TargetParentFcbAcquired = FALSE; BOOLEAN SingleDir = TRUE; BOOLEAN UseClose; + BOOLEAN IsStreamRename; PUDF_FILE_INFO FileInfo; PUDF_FILE_INFO DirInfo; PUDF_FILE_INFO TargetDirInfo; - PUDF_FILE_INFO NextFileInfo, fi; UNICODE_STRING NewName; UNICODE_STRING LocalPath; PCCB CurCcb = NULL; PLIST_ENTRY Link; - ULONG i; - ULONG DirRefCount; - ULONG FileInfoRefCount; ULONG Attr; PDIR_INDEX_ITEM DirNdx; @@ -2005,6 +2007,8 @@ UDFSetRenameInfo( if (!TargetFileObject) { TargetDirInfo = FileInfo->ParentFile; + // For streams or same-dir rename, target FCB is the parent + TargetFcb = TargetDirInfo->Fcb; } else { @@ -2087,6 +2091,13 @@ UDFSetRenameInfo( IgnoreCase = FlagOn(Ccb->Flags, CCB_FLAG_IGNORE_CASE); + // Check if renaming to stream name - only allowed for streams + if (!TargetFileObject && NewName.Length >= sizeof(WCHAR) && NewName.Buffer[0] == L':') { + if (!UDFIsAStream(FileInfo)) { + try_return(RC = STATUS_OBJECT_NAME_INVALID); + } + } + if (UDFIsDirOpened__(FileInfo)) { // We can't rename file because of unclean references. // UDF_INFO package can safely do it, but NT side cannot. @@ -2106,9 +2117,8 @@ UDFSetRenameInfo( } } - ASSERT(Fcb->FcbReference >= FileInfo->RefCount); - ASSERT(DirInfo->Fcb->FcbReference >= DirInfo->RefCount); - ASSERT(TargetDirInfo->Fcb->FcbReference >= TargetDirInfo->RefCount); + // Note: With LCB model, FcbReference may not always be >= RefCount + // for directories opened internally during path traversal RC = UDFRenameMoveFile__(IrpContext, Vcb, IgnoreCase, &ReplaceIfExists, &NewName, DirInfo, TargetDirInfo, FileInfo); } @@ -2123,7 +2133,9 @@ UDFSetRenameInfo( if (!NT_SUCCESS(RC)) try_return (RC); // RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName)); // if (!NT_SUCCESS(RC)) try_return (RC); - if (TargetDirInfo->ParentFile) { + // Don't append '\\' for streams (names starting with ':') + IsStreamRename = (NewName.Length >= sizeof(WCHAR) && NewName.Buffer[0] == L':'); + if (TargetDirInfo->ParentFile && !IsStreamRename) { RC = MyAppendUnicodeToString(&LocalPath, L"\\"); if (!NT_SUCCESS(RC)) try_return (RC); } @@ -2203,71 +2215,51 @@ UDFSetRenameInfo( } } - // this will prevent structutre release before call to - // UDFCleanUpFcbChain() + // this will prevent structure release before cleanup InterlockedIncrement((PLONG)&DirInfo->Fcb->FcbReference); - ASSERT(DirInfo->Fcb->FcbReference >= DirInfo->RefCount); - // Look through Ccb list & decrement OpenHandleCounter(s) - // acquire CcbList + // Switch LCBs from old parent to new parent for each CCB + // With LCB model, each CCB has one LCB linking to its immediate parent. + // When renaming across directories, we release the old LCB and acquire + // a new one from the target directory. if (!SingleDir) { UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->CcbListResource, TRUE); Link = Fcb->NextCCB.Flink; - DirRefCount = 0; - FileInfoRefCount = 0; ASSERT(Link != &Fcb->NextCCB); while (Link != &Fcb->NextCCB) { - NextFileInfo = DirInfo; CurCcb = CONTAINING_RECORD(Link, CCB, NextCCB); - ASSERT(CurCcb->TreeLength); - i = (CurCcb->TreeLength) ? (CurCcb->TreeLength - 1) : 0; Link = Link->Flink; UseClose = (CurCcb->Flags & UDF_CCB_CLEANED) ? FALSE : TRUE; - AdPrint((" Ccb:%x:%s:i:%x\n", CurCcb, UseClose ? "Close" : "",i)); - // cleanup old parent chain - for(; i && NextFileInfo; i--) { - // remember parent file now - // it will prevent us from data losses - // due to eventual structure release - fi = NextFileInfo->ParentFile; - if (UseClose) { - ASSERT(NextFileInfo->Fcb->FcbReference >= NextFileInfo->RefCount); - UDFCloseFile__(IrpContext, Vcb, NextFileInfo); - } - ASSERT(NextFileInfo->Fcb->FcbReference > NextFileInfo->RefCount); - ASSERT(NextFileInfo->Fcb->FcbReference); - InterlockedDecrement((PLONG)&NextFileInfo->Fcb->FcbReference); - ASSERT(NextFileInfo->Fcb->FcbReference >= NextFileInfo->RefCount); - NextFileInfo = fi; + AdPrint((" Ccb:%x:%s\n", CurCcb, UseClose ? "Close" : "")); + + // + // Release old LCB and acquire new one from TargetDir + // UDFReleasePrefixImmediate will decrement old parent's refs + // when the last CCB releases (LCB->Reference becomes 0). + // UDFAcquirePrefix will increment new parent's refs when + // creating a new LCB (or just increment LCB->Reference if exists). + // + if (CurCcb->Lcb) { + UDFReleasePrefixImmediate(IrpContext, CurCcb->Lcb, UseClose); + CurCcb->Lcb = NULL; } - if (CurCcb->TreeLength > 1) { - DirRefCount++; - if (UseClose) - FileInfoRefCount++; - CurCcb->TreeLength = 2; -#ifdef UDF_DBG - } else { - BrutePoint(); -#endif // UDF_DBG + // Acquire new LCB from TargetDir + CurCcb->Lcb = UDFAcquirePrefix(IrpContext, TargetDirInfo->Fcb, Fcb, + FileInfo->Index); + if (!CurCcb->Lcb) { + // Allocation failure - continue, but log error + AdPrint((" Failed to allocate LCB for CCB %x\n", CurCcb)); } } UDFReleaseResource(&Fcb->FcbNonpaged->CcbListResource); - ASSERT(DirRefCount >= FileInfoRefCount); - // update counters & pointers + // Update parent pointer Fcb->ParentFcb = TargetDirInfo->Fcb; - // move references to TargetDir - InterlockedExchangeAdd((PLONG)&TargetDirInfo->Fcb->FcbReference, DirRefCount); - ASSERT(TargetDirInfo->Fcb->FcbReference > TargetDirInfo->RefCount); - UDFReferenceFileEx__(TargetDirInfo, FileInfoRefCount); - ASSERT(TargetDirInfo->Fcb->FcbReference >= TargetDirInfo->RefCount); } - ASSERT(TargetDirInfo->Fcb->FcbReference >= TargetDirInfo->RefCount); ASSERT(TargetDirInfo->RefCount); - ASSERT(DirInfo->Fcb->FcbReference >= DirInfo->RefCount); // Modify name in Fcb1 if (Fcb->FCBName) { if (Fcb->FCBName->ObjectName.Buffer) { @@ -2290,7 +2282,15 @@ UDFSetRenameInfo( UDFReleaseResource(&DirInfo->Fcb->FcbNonpaged->FcbResource); ParentFcbAcquired = FALSE; } - UDFTeardownStructures(IrpContext, DirInfo->Fcb, 1, NULL); + { + BOOLEAN RemovedFcb = FALSE; + UDFAcquireFcbExclusive(IrpContext, DirInfo->Fcb, FALSE); + // LCB-based teardown: walks ParentLcbQueue to find and remove LCBs + UDFTeardownStructures(IrpContext, DirInfo->Fcb, FALSE, &RemovedFcb); + if (!RemovedFcb) { + UDFReleaseFcb(IrpContext, DirInfo->Fcb); + } + } try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } @@ -2302,7 +2302,9 @@ UDFSetRenameInfo( goto insuf_res;*/ // if Dir2 is a RootDir, we shoud not append '\\' because // uit will be the 2nd '\\' character (RootDir's name is also '\\') - if (TargetDirInfo->ParentFile) { + // Also don't append '\\' for streams (names starting with ':') + // IsStreamRename already set above + if (TargetDirInfo->ParentFile && !IsStreamRename) { RC = MyAppendUnicodeToString(&Fcb->FCBName->ObjectName, L"\\"); if (!NT_SUCCESS(RC)) goto insuf_res; @@ -2311,10 +2313,6 @@ UDFSetRenameInfo( if (!NT_SUCCESS(RC)) goto insuf_res; - ASSERT(Fcb->FcbReference >= FileInfo->RefCount); - ASSERT(DirInfo->Fcb->FcbReference >= DirInfo->RefCount); - ASSERT(TargetDirInfo->Fcb->FcbReference >= TargetDirInfo->RefCount); - RC = STATUS_SUCCESS; try_exit: NOTHING; @@ -2332,10 +2330,13 @@ try_exit: NOTHING; // perform protected structure release if (NT_SUCCESS(RC) && (RC != STATUS_PENDING)) { - - UDFTeardownStructures(IrpContext, DirInfo->Fcb, 1, NULL); - ASSERT(Fcb->FcbReference >= FileInfo->RefCount); - ASSERT(TargetDirInfo->Fcb->FcbReference >= TargetDirInfo->RefCount); + BOOLEAN RemovedFcb = FALSE; + UDFAcquireFcbExclusive(IrpContext, DirInfo->Fcb, FALSE); + // LCB-based teardown: walks ParentLcbQueue to find and remove LCBs + UDFTeardownStructures(IrpContext, DirInfo->Fcb, FALSE, &RemovedFcb); + if (!RemovedFcb) { + UDFReleaseFcb(IrpContext, DirInfo->Fcb); + } } if (LocalPath.Buffer) { @@ -2641,14 +2642,15 @@ try_exit: NOTHING; } _SEH2_FINALLY { - if (AcquiredFcb1) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb1); - UDFReleaseResource(&Fcb1->FcbNonpaged->FcbResource); - } + // Release in reverse order of acquisition (parent first, then child) if (AcquiredDir1) { UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb); UDFReleaseResource(&Dir1->Fcb->FcbNonpaged->FcbResource); } + if (AcquiredFcb1) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb1); + UDFReleaseResource(&Fcb1->FcbNonpaged->FcbResource); + } if (LocalPath.Buffer) { MyFreePool__(LocalPath.Buffer); diff --git a/drivers/filesystems/udfs/flush.cpp b/drivers/filesystems/udfs/flush.cpp index 76357b7eef143..56ab64c51c051 100644 --- a/drivers/filesystems/udfs/flush.cpp +++ b/drivers/filesystems/udfs/flush.cpp @@ -139,16 +139,18 @@ UDFCommonFlush( Vcb = Fcb->Vcb; ASSERT(Vcb); + // Child-first lock ordering + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); + AcquiredFCB = TRUE; + + // Parent second (needed for DirIndex modification in UDFSetFileSizeInDirNdx) if (Fcb->FileInfo->ParentFile && Fcb->FileInfo->ParentFile->Fcb) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); UDFAcquireResourceExclusive(&Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource, TRUE); AcquiredParentFcb = TRUE; } - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); - AcquiredFCB = TRUE; - // Request the Cache Manager to perform a flush operation. // Further, instruct the Cache Manager that we wish to flush the // entire file stream. @@ -168,18 +170,19 @@ try_exit: NOTHING; } _SEH2_FINALLY { - if (AcquiredFCB) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); - AcquiredFCB = FALSE; - } - + // Release in reverse order of acquisition (parent first, then child) if (AcquiredParentFcb) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); UDFReleaseResource(&Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource); AcquiredParentFcb = FALSE; } + if (AcquiredFCB) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); + AcquiredFCB = FALSE; + } + if (AcquiredVCB) { UDFReleaseResource(&Vcb->VcbResource); AcquiredVCB = FALSE; diff --git a/drivers/filesystems/udfs/fscntrl.cpp b/drivers/filesystems/udfs/fscntrl.cpp index c86050d2029d2..61b864ee94ada 100644 --- a/drivers/filesystems/udfs/fscntrl.cpp +++ b/drivers/filesystems/udfs/fscntrl.cpp @@ -184,7 +184,7 @@ UDFUserFsCtrlRequest( case FSCTL_GET_RETRIEVAL_POINTERS: UDFPrint(("UDFUserFsCtrlRequest: FSCTL_GET_RETRIEVAL_POINTERS\n")); - RC = UDFGetRetrievalPointers(IrpContext, Irp, 0); + RC = UDFGetRetrievalPointers(IrpContext, Irp); break; case FSCTL_MOVE_FILE: @@ -639,7 +639,15 @@ UDFCloseResidual( UDFCloseFile__(IrpContext, Vcb, Vcb->RootIndexFcb->FileInfo); if (Vcb->RootIndexFcb->FcbCleanup) Vcb->RootIndexFcb->FcbCleanup--; - UDFTeardownStructures(IrpContext, Vcb->RootIndexFcb, 1, NULL); + { + BOOLEAN RemovedFcb = FALSE; + UDFAcquireFcbExclusive(IrpContext, Vcb->RootIndexFcb, FALSE); + // LCB-based teardown: walks ParentLcbQueue to find and remove LCBs + UDFTeardownStructures(IrpContext, Vcb->RootIndexFcb, FALSE, &RemovedFcb); + if (!RemovedFcb) { + UDFReleaseFcb(IrpContext, Vcb->RootIndexFcb); + } + } // Remove root FCB reference in vcb if (Vcb->VcbReference) InterlockedDecrement((PLONG)&Vcb->VcbReference); @@ -1247,104 +1255,122 @@ UDFGetVolumeBitmap( IN PIRP Irp ) { -// NTSTATUS RC; + NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - UDFPrint(("UDFGetVolumeBitmap\n")); - - TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; PCCB Ccb; - PVCB Vcb; + PVCB Vcb = IrpContext->Vcb; ULONG BytesToCopy; ULONG TotalClusters; - ULONG DesiredClusters; ULONG StartingCluster; + ULONG DesiredClusters; ULONG InputBufferLength; ULONG OutputBufferLength; LARGE_INTEGER StartingLcn; PVOLUME_BITMAP_BUFFER OutputBuffer; ULONG i, lim; PULONG FSBM; -// PULONG Dest; + BOOLEAN VcbAcquired = FALSE; - // Decode the file object, the only type of opens we accept are - // user volume opens. + ASSERT_VCB(Vcb); - TypeOfOpen = UDFDecodeFileObject(IrpSp->FileObject, &Fcb, &Ccb); + // Make this a synchronous IRP because we need access to the input buffer and + // this Irp is marked METHOD_NEITHER. - ASSERT_CCB(Ccb); - ASSERT_FCB(Fcb); + SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); - if (!Ccb) { + InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; + OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; - UDFPrintErr((" !Ccb\n")); - UDFCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER); - return STATUS_INVALID_PARAMETER; - } + TotalClusters = Vcb->FSBM_BitCount; - Vcb = Fcb->Vcb; - ASSERT_FCB(Fcb); + _SEH2_TRY { - InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; - OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + // Decode the file object, the only type of opens we accept are + // user volume opens. - OutputBuffer = (PVOLUME_BITMAP_BUFFER)UDFMapUserBuffer(Irp); + if (UDFDecodeFileObject(IrpSp->FileObject, &Fcb, &Ccb) != UserVolumeOpen) { - if (!OutputBuffer) { + try_return(Status = STATUS_INVALID_USER_BUFFER); + } - UDFCompleteRequest(IrpContext, Irp, STATUS_INVALID_USER_BUFFER); - return STATUS_INVALID_USER_BUFFER; - } + ASSERT_CCB(Ccb); + ASSERT_FCB(Fcb); - // Check for a minimum length on the input and output buffers. - if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) || - (OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) { + // Check for a minimum length on the input and output buffers. - UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); + if ((InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER)) || + (OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))) { - UDFCompleteRequest(IrpContext, Irp, STATUS_BUFFER_TOO_SMALL); - return STATUS_BUFFER_TOO_SMALL; - } + try_return(Status = STATUS_BUFFER_TOO_SMALL); + } - // Check if a starting cluster was specified. - TotalClusters = Vcb->FSBM_BitCount; - StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn; + OutputBuffer = (PVOLUME_BITMAP_BUFFER)UDFMapUserBuffer(Irp); - if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) { + _SEH2_TRY { - UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); + if (Irp->RequestorMode != KernelMode) { - UDFCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER); - return STATUS_INVALID_PARAMETER; + ProbeForRead(IrpSp->Parameters.FileSystemControl.Type3InputBuffer, + InputBufferLength, + sizeof(UCHAR)); - } else { + ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(UCHAR)); + } + + StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn; + + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + + try_return(Status = STATUS_INVALID_USER_BUFFER); + } _SEH2_END + + if (StartingLcn.HighPart || StartingLcn.LowPart >= TotalClusters) { + + try_return(Status = STATUS_INVALID_PARAMETER); + } + + // Align starting block to 8-bit boundary StartingCluster = StartingLcn.LowPart & ~7; - } - OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer); - DesiredClusters = TotalClusters - StartingCluster; + DesiredClusters = TotalClusters - StartingCluster; - if (OutputBufferLength < (DesiredClusters + 7) / 8) { + // Fill in the fixed part of the output buffer - BytesToCopy = OutputBufferLength; -// RC = STATUS_BUFFER_OVERFLOW; + __try { - } else { + // StartingLcn in output = aligned starting block - BytesToCopy = (DesiredClusters + 7) / 8; -// RC = STATUS_SUCCESS; - } + OutputBuffer->StartingLcn.QuadPart = StartingCluster; - UDFAcquireResourceExclusive(&(Vcb->VcbResource), TRUE ); + // BitmapSize = remaining blocks from starting position - _SEH2_TRY { + OutputBuffer->BitmapSize.QuadPart = DesiredClusters; + + } __except (EXCEPTION_EXECUTE_HANDLER) { + + try_return(Status = STATUS_INVALID_USER_BUFFER); + } + + OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer); + + + if (OutputBufferLength < (DesiredClusters + 7) / 8) { + + BytesToCopy = OutputBufferLength; + Status = STATUS_BUFFER_OVERFLOW; - // Fill in the fixed part of the output buffer - OutputBuffer->StartingLcn.QuadPart = StartingCluster; - OutputBuffer->BitmapSize.QuadPart = DesiredClusters; + } else { + + BytesToCopy = (DesiredClusters + 7) / 8; + Status = STATUS_SUCCESS; + } + + UDFAcquireVcbShared(IrpContext, Vcb, FALSE); + VcbAcquired = TRUE; RtlZeroMemory( &OutputBuffer->Buffer[0], BytesToCopy ); lim = BytesToCopy * 8; @@ -1357,30 +1383,24 @@ UDFGetVolumeBitmap( UDFSetFreeBit(FSBM, i); } - } _SEH2_EXCEPT(UDFExceptionFilter(IrpContext, _SEH2_GetExceptionInformation())) { + Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + BytesToCopy; - BrutePoint(); - UDFPrintErr(("UDFGetVolumeBitmap: Exception\n")); -// UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); - BrutePoint(); -// RC = UDFExceptionHandler(IrpContext, Irp); - UDFReleaseResource(&(Vcb->VcbResource)); - UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); +try_exit: NOTHING; - Irp->IoStatus.Information = 0; - Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; - return STATUS_INVALID_USER_BUFFER; - } _SEH2_END; + } _SEH2_FINALLY { - UDFReleaseResource(&(Vcb->VcbResource)); + if (VcbAcquired) { - UDFUnlockCallersBuffer(IrpContext, Irp, OutputBuffer); - Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer) + - BytesToCopy; + UDFReleaseVcb(IrpContext, Vcb); + } + + } _SEH2_END; - UDFCompleteRequest(IrpContext, Irp, STATUS_SUCCESS); + // Complete the request - return STATUS_SUCCESS; + UDFCompleteRequest(IrpContext, Irp, Status); + + return Status; } // end UDFGetVolumeBitmap() @@ -1389,8 +1409,7 @@ UDFGetVolumeBitmap( NTSTATUS UDFGetRetrievalPointers( IN PIRP_CONTEXT IrpContext, - IN PIRP Irp, - IN ULONG Special + IN PIRP Irp ) { NTSTATUS RC; @@ -1410,6 +1429,7 @@ UDFGetRetrievalPointers( PCCB Ccb; PFCB Fcb; PVCB Vcb; + TYPE_OF_OPEN TypeOfOpen; PEXTENT_MAP SubMapping = NULL; ULONG SubExtInfoSz; @@ -1419,7 +1439,18 @@ UDFGetRetrievalPointers( UDFPrint(("UDFGetRetrievalPointers\n")); - UDFDecodeFileObject(IrpSp->FileObject, &Fcb, &Ccb); + // Make this a synchronous IRP because we need access to the input buffer and + // this Irp is marked METHOD_NEITHER. + + SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); + + TypeOfOpen = UDFDecodeFileObject(IrpSp->FileObject, &Fcb, &Ccb); + + if ((TypeOfOpen != UserFileOpen) && (TypeOfOpen != UserDirectoryOpen)) { + + UDFCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } Vcb = Fcb->Vcb; @@ -1439,12 +1470,8 @@ UDFGetRetrievalPointers( InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; - //OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)UDFGetCallersBuffer( IrpContext, Irp ); - if (Special) { - OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->AssociatedIrp.SystemBuffer; - } else { - OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)Irp->UserBuffer; - } + OutputBuffer = (PRETRIEVAL_POINTERS_BUFFER)UDFMapUserBuffer(Irp); + InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)IrpSp->Parameters.FileSystemControl.Type3InputBuffer; if (!InputBuffer) { InputBuffer = (PSTARTING_VCN_INPUT_BUFFER)OutputBuffer; @@ -1478,16 +1505,7 @@ UDFGetRetrievalPointers( try_return(RC); } _SEH2_END; - switch(Special) { - case 0: - FileInfo = Fcb->FileInfo; - break; - case 1: - FileInfo = Vcb->NonAllocFileInfo; - break; - default: - try_return( RC = STATUS_INVALID_PARAMETER ); - } + FileInfo = Fcb->FileInfo; if (!FileInfo) { try_return( RC = STATUS_OBJECT_NAME_NOT_FOUND ); diff --git a/drivers/filesystems/udfs/lockctrl.cpp b/drivers/filesystems/udfs/lockctrl.cpp index 60f52a880cf62..e0124fa1bbe0d 100644 --- a/drivers/filesystems/udfs/lockctrl.cpp +++ b/drivers/filesystems/udfs/lockctrl.cpp @@ -141,39 +141,35 @@ UDFFastLock ( IN PDEVICE_OBJECT DeviceObject ) { + BOOLEAN FcbAcquired = FALSE; BOOLEAN Results = FALSE; - -// BOOLEAN AcquiredFCB = FALSE; TYPE_OF_OPEN TypeOfOpen; - PFCB Fcb = NULL; - - UDFPrint(("UDFFastLock\n")); + PFCB Fcb = NULL; // Decode the type of file object we're being asked to process and // make sure that is is only a user file open. TypeOfOpen = UDFFastDecodeFileObject(FileObject, &Fcb); - ASSERT_FCB(Fcb); - - // Validate the sent-in FCB - if ( (Fcb == Fcb->Vcb->VolumeDasdFcb) || - (Fcb->FcbState & UDF_FCB_DIRECTORY)) { + if (TypeOfOpen != UserFileOpen) { IoStatus->Status = STATUS_INVALID_PARAMETER; - IoStatus->Information = 0; return TRUE; } - // Acquire exclusive access to the Fcb this operation can always wait + ASSERT_FCB(Fcb); FsRtlEnterFileSystem(); - // BUGBUG: kenr - // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); - _SEH2_TRY { + FcbAcquired = UDFAcquireFcbShared(NULL, Fcb, TRUE); + + if (FcbAcquired == FALSE) { + + try_return(NOTHING); + } + // If we don't have a file lock, then get one now. if ((Fcb->FileLock == NULL) && !UDFCreateFileLock(NULL, Fcb, FALSE)) { @@ -204,10 +200,13 @@ UDFFastLock ( try_exit: NOTHING; } _SEH2_FINALLY { - // Release the Fcb, and return to our caller + // Release the Fcb, and return to our caller + + if (FcbAcquired) { + + UDFReleaseFcb(NULL, Fcb); + } - // BUGBUG: kenr - // UDFReleaseResource( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); diff --git a/drivers/filesystems/udfs/misc.cpp b/drivers/filesystems/udfs/misc.cpp index c78f45461cc12..c3dbe0b321e5e 100644 --- a/drivers/filesystems/udfs/misc.cpp +++ b/drivers/filesystems/udfs/misc.cpp @@ -125,6 +125,14 @@ UDFInitializeZones(VOID) TAG_CCB, 0); + ExInitializePagedLookasideList(&UdfData.LcbLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + SIZEOF_LOOKASIDE_LCB, + TAG_LCB, + 0); + try_return(RC = STATUS_SUCCESS); try_exit: NOTHING; @@ -165,6 +173,7 @@ VOID UDFDestroyZones(VOID) ExDeleteNPagedLookasideList(&UdfData.NonPagedFcbLookasideList); ExDeletePagedLookasideList(&UdfData.CcbLookasideList); + ExDeletePagedLookasideList(&UdfData.LcbLookasideList); } /************************************************************************* @@ -626,6 +635,14 @@ UDFDeleteCcb( Ccb->DirectorySearchPattern = NULL; } + // Release LCB reference + // The LCB will be removed and parent references decremented + // by UDFTeardownStructures when the child FCB is torn down + if (Ccb->Lcb) { + UDFReleasePrefix(NULL, Ccb->Lcb); + Ccb->Lcb = NULL; + } + UDFReleaseCCB(Ccb); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { BrutePoint(); @@ -1644,7 +1661,6 @@ UDFInitializeStackIrpContextFromLite( IrpContext->MajorFunction = IRP_MJ_CLOSE; IrpContext->Vcb = IrpContextLite->Fcb->Vcb; IrpContext->Fcb = IrpContextLite->Fcb; - IrpContext->TreeLength = IrpContextLite->TreeLength; IrpContext->RealDevice = IrpContextLite->RealDevice; // Note that this is from the stack. diff --git a/drivers/filesystems/udfs/nodetype.h b/drivers/filesystems/udfs/nodetype.h index 5027a9e327fbf..c9709c170741d 100644 --- a/drivers/filesystems/udfs/nodetype.h +++ b/drivers/filesystems/udfs/nodetype.h @@ -19,6 +19,7 @@ typedef CSHORT NODE_BYTE_SIZE; #define UDF_NODE_TYPE_UDFFS_DEVOBJ ((NODE_TYPE_CODE)0x0908) #define UDF_NODE_TYPE_IRP_CONTEXT_LITE ((NODE_TYPE_CODE)0x0909) #define UDF_NODE_TYPE_UDFFS_DRVOBJ ((NODE_TYPE_CODE)0x090a) +#define UDF_NODE_TYPE_LCB ((NODE_TYPE_CODE)0x090b) // So all records start with // diff --git a/drivers/filesystems/udfs/protos.h b/drivers/filesystems/udfs/protos.h index 73fe5eeff7dcd..bf470a5a92233 100644 --- a/drivers/filesystems/udfs/protos.h +++ b/drivers/filesystems/udfs/protos.h @@ -110,6 +110,17 @@ UDFCompleteFcbOpen( _In_ ULONG CreateDisposition ); +NTSTATUS +UDFOpenExistingFcb( + _In_ PIRP_CONTEXT IrpContext, + _In_ PIO_STACK_LOCATION IrpSp, + _In_ PVCB Vcb, + _Inout_ PFCB *CurrentFcb, + _In_ BOOLEAN IgnoreCase, + _In_ BOOLEAN OpenByFileId, + _In_ ULONG CreateDisposition + ); + NTSTATUS UDFInitializeFCB( IN PFCB PtrNewFcb, // FCB structure to be initialized @@ -130,15 +141,6 @@ extern NTSTATUS UDFCommonCleanup( PIRP_CONTEXT IrpContext, PIRP Irp); -NTSTATUS -UDFCloseFileInfoChain( - IN PIRP_CONTEXT IrpContext, - IN PVCB Vcb, - IN PUDF_FILE_INFO fi, - IN ULONG TreeLength, - IN BOOLEAN VcbAcquired - ); - /************************************************************************* * Prototypes for the file close.cpp *************************************************************************/ @@ -158,7 +160,7 @@ VOID UDFTeardownStructures( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFCB StartingFcb, - _In_ ULONG TreeLength, + _In_ BOOLEAN Recursive, // TRUE if this is a recursive call (for hard links) _Out_ PBOOLEAN RemovedStartingFcb ); @@ -312,11 +314,13 @@ IN PLARGE_INTEGER FileOffset, OUT PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject); -extern NTSTATUS NTAPI UDFFastIoAcqModWrite( -IN PFILE_OBJECT FileObject, -IN PLARGE_INTEGER EndingOffset, -OUT PERESOURCE* ResourceToRelease, -IN PDEVICE_OBJECT DeviceObject); +NTSTATUS +NTAPI +UDFFastIoAcqModWrite( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT PERESOURCE* ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject); extern NTSTATUS NTAPI UDFFastIoRelModWrite( IN PFILE_OBJECT FileObject, @@ -645,8 +649,7 @@ extern NTSTATUS UDFGetVolumeBitmap(IN PIRP_CONTEXT IrpContext, IN PIRP Irp); extern NTSTATUS UDFGetRetrievalPointers(IN PIRP_CONTEXT IrpContext, - IN PIRP Irp, - IN ULONG Special); + IN PIRP Irp); extern NTSTATUS UDFInvalidateVolumes(IN PIRP_CONTEXT IrpContext, IN PIRP Irp); @@ -669,7 +672,9 @@ extern NTSTATUS NTAPI UDFCommonLockControl( IN PIRP_CONTEXT IrpContext, IN PIRP Irp); -extern BOOLEAN NTAPI UDFFastLock( +BOOLEAN +NTAPI +UDFFastLock( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, @@ -768,6 +773,49 @@ UDFDeleteCcb( PCCB Ccb ); +// prefxsup.cpp - LCB functions +PLCB +UDFInsertPrefix( + IN PIRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PFCB ChildFcb, + IN ULONG Index + ); + +VOID +UDFRemovePrefix( + IN PIRP_CONTEXT IrpContext, + IN PLCB Lcb + ); + +PLCB +UDFFindPrefix( + IN PIRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PFCB ChildFcb + ); + +PLCB +UDFAcquirePrefix( + IN PIRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PFCB ChildFcb, + IN ULONG Index + ); + +VOID +UDFReleasePrefix( + IN PIRP_CONTEXT IrpContext, + IN PLCB Lcb + ); + +BOOLEAN +UDFReleasePrefixImmediate( + IN PIRP_CONTEXT IrpContext, + IN PLCB Lcb, + IN BOOLEAN CloseParentFileInfo + ); + PFCB UDFCreateFcb ( _In_ PIRP_CONTEXT IrpContext, @@ -778,11 +826,15 @@ UDFCreateFcb ( VOID UDFDeleteFcb( - _In_ PIRP_CONTEXT IrpContext, + _In_opt_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb ); -VOID UDFCleanUpFCB(PFCB Fcb); +VOID +UDFInsertFcbIntoTable( + _In_ PIRP_CONTEXT IrpContext, + _In_ PFCB Fcb + ); _Ret_valid_ PIRP_CONTEXT UDFCreateIrpContext( @@ -1304,6 +1356,16 @@ SectorAlign( return (Length + (Vcb->SectorSize - 1)) & ~(Vcb->SectorSize - 1); } +inline +ULONGLONG +LlSectorAlign( + PVCB Vcb, + ULONGLONG Length +) { + + return (Length + (Vcb->SectorSize - 1)) & ~(ULONGLONG)(Vcb->SectorSize - 1); +} + VOID UDFSetThreadContext( _Inout_ PIRP_CONTEXT IrpContext, @@ -1344,4 +1406,10 @@ UDFWaitForIoAtEof( IN ULONG Length ); +VOID +UDFPrePostIrp( + _Inout_ PIRP_CONTEXT IrpContext, + _Inout_ PIRP Irp + ); + #endif // _UDF_PROTOS_H_ diff --git a/drivers/filesystems/udfs/read.cpp b/drivers/filesystems/udfs/read.cpp index 0f56677fb5d2d..ca1795add66de 100644 --- a/drivers/filesystems/udfs/read.cpp +++ b/drivers/filesystems/udfs/read.cpp @@ -480,7 +480,14 @@ UDFMapUserBuffer( } else { - return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority | MdlMappingNoExecute); + PVOID Address = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority | MdlMappingNoExecute); + + if (Address == NULL) { + + ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); + } + + return Address; } } // end UDFMapUserBuffer() @@ -608,27 +615,82 @@ UDFCompleteMdl( ) { PFILE_OBJECT FileObject; - PIO_STACK_LOCATION IrpSp; - - UDFPrint(("UDFCompleteMdl: \n")); + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + PFCB Fcb; - IrpSp = IoGetCurrentIrpStackLocation(Irp); + // Do completion processing. FileObject = IrpSp->FileObject; - ASSERT(FileObject); - // Not much to do here. - if (IrpContext->MajorFunction == IRP_MJ_READ) { + switch(IrpContext->MajorFunction) { + + case IRP_MJ_READ: - MmPrint((" CcMdlReadComplete() MDL=%x\n", Irp->MdlAddress)); CcMdlReadComplete(FileObject, Irp->MdlAddress); + break; - } else { + case IRP_MJ_WRITE: + + UDFFastDecodeFileObject(FileObject, &Fcb); + + ASSERT(FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); + + // Check if EOF advance is active. + + if (FlagOn(Fcb->Header.Flags, FSRTL_FLAG_EOF_ADVANCE_ACTIVE)) { + + LONGLONG ByteRange = IrpSp->Parameters.Write.ByteOffset.QuadPart; + + PMDL MdlChain = Irp->MdlAddress; + while (MdlChain != NULL) + { + ByteRange += MmGetMdlByteCount(MdlChain); + MdlChain = MdlChain->Next; + } + + // Acquire the fast mutex and check if we extended valid data. + + ExAcquireFastMutex(Fcb->Header.FastMutex); + + if (ByteRange > Fcb->Header.ValidDataLength.QuadPart) { + + // Extend valid data length to file size. + + Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart; + + // Notify cache manager of new file sizes if caching is active. + + if (CcIsFileCached(FileObject)) { + + _SEH2_TRY { + + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); + + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + + NOTHING; + + } _SEH2_END; + } + + // Complete the EOF advance operation. + + UDFFinishIoAtEof(Fcb); + } + + ExReleaseFastMutex(Fcb->Header.FastMutex); + + } - ASSERT(IrpContext->MajorFunction == IRP_MJ_WRITE); - // The Cache Manager needs the byte offset in the I/O stack location. - MmPrint((" CcMdlWriteComplete() MDL=%x\n", Irp->MdlAddress)); CcMdlWriteComplete(FileObject, &IrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress); + + Irp->IoStatus.Status = STATUS_SUCCESS; + + break; + + default: + + UDFBugCheck(IrpContext->MajorFunction, 0, 0); } // Mdl is now deallocated. diff --git a/drivers/filesystems/udfs/strucsup.cpp b/drivers/filesystems/udfs/strucsup.cpp index 6e00af7d5bd4f..a4818726c1a9a 100644 --- a/drivers/filesystems/udfs/strucsup.cpp +++ b/drivers/filesystems/udfs/strucsup.cpp @@ -29,6 +29,23 @@ typedef struct _FCB_TABLE_ELEMENT { RtlDeleteElementGenericTable( &(F)->Vcb->FcbTable, &_Key ); \ } +// +// Public wrapper for inserting FCB into FcbTable. +// Called from create.cpp after FCB is fully initialized. +// VCB must be locked by caller. +// +VOID +UDFInsertFcbIntoTable( + _In_ PIRP_CONTEXT IrpContext, + _In_ PFCB Fcb + ) +{ + UNREFERENCED_PARAMETER(IrpContext); + + UDFInsertFcbTable(IrpContext, Fcb); + SetFlag(Fcb->FcbState, FCB_STATE_IN_FCB_TABLE); +} + inline PFCB_NONPAGED UDFAllocateFcbNonpaged( @@ -173,7 +190,7 @@ Return Value: VOID UDFDeleteFcb( - _In_ PIRP_CONTEXT IrpContext, + _In_opt_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb ) @@ -185,9 +202,16 @@ Routine Description: are no references remaining. We cleanup any auxilary structures and deallocate this Fcb. + NOTE: Caller should remove FCB from FcbTable before calling this routine + (typically done by UDFTeardownStructures while holding VCB lock). + FCB should NOT be in FcbTable when this is called - either it was removed + by TeardownStructures, or it was never inserted (error path in create). + Arguments: - Fcb - This is the Fcb to deallcoate. + IrpContext - Optional IrpContext (unused but kept for API consistency). + + Fcb - This is the Fcb to deallocate. Return Value: @@ -197,101 +221,391 @@ Return Value: { PVCB Vcb = NULL; + PAGED_CODE(); - // Sanity check the counts. + UNREFERENCED_PARAMETER(IrpContext); - NT_ASSERT( Fcb->FcbCleanup == 0 ); - NT_ASSERT( Fcb->FcbReference == 0 ); + UDFPrint(("UDFDeleteFcb: %x\n", Fcb)); - // Release any Filter Context structures associated with this FCB + ASSERT_FCB(Fcb); - // FsRtlTeardownPerStreamContexts(&Fcb->Header); + // Sanity check the counts. - // Start with the common structures. + NT_ASSERT( Fcb->FcbCleanup == 0 ); + NT_ASSERT( Fcb->FcbReference == 0 ); - // CdUninitializeMcb( IrpContext, Fcb ); + // FCB must NOT be in FcbTable - either TeardownStructures removed it, + // or it was never inserted (error path before UDFInsertFcbIntoTable). + NT_ASSERT(!FlagOn(Fcb->FcbState, FCB_STATE_IN_FCB_TABLE)); - // CdDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged ); + // LCB queues must be empty - all LCBs should be removed during teardown + NT_ASSERT(IsListEmpty(&Fcb->ParentLcbQueue)); + NT_ASSERT(IsListEmpty(&Fcb->ChildLcbQueue)); - // - // Check if we need to deallocate the prefix name buffer. - // + // Deinitialize FCBName field. - // if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) Fcb->FileNamePrefix.FileNameBuffer) && - // (Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) { + if (Fcb->FCBName) { + if (Fcb->FCBName->ObjectName.Buffer) { + MyFreePool__(Fcb->FCBName->ObjectName.Buffer); + } + UDFReleaseObjectName(Fcb->FCBName); + Fcb->FCBName = NULL; + } - // CdFreePool( &Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer ); - // } + // Release any Filter Context structures associated with this FCB. + // Only if FCB was fully initialized (Header.Resource is set by + // UDFInitializeFCB). - // - // Now look at the short name prefix. - // + if (Fcb->Header.Resource) { + FsRtlTeardownPerStreamContexts(&Fcb->Header); + } - // if (Fcb->ShortNamePrefix != NULL) { + // Delete non-paged portion (resources + dealloc). - // CdFreePool( &Fcb->ShortNamePrefix ); - // } + UDFDeleteFcbNonpaged(IrpContext, Fcb->FcbNonpaged); - // - // Now do the type specific structures. - // + // Now do the type specific structures. switch (Fcb->Header.NodeTypeCode) { case UDF_NODE_TYPE_INDEX: - // NT_ASSERT( Fcb->FileObject == NULL ); - // NT_ASSERT( IsListEmpty( &Fcb->FcbQueue )); - - // if (Fcb == Fcb->Vcb->RootIndexFcb) { - - // Vcb = Fcb->Vcb; - // Vcb->RootIndexFcb = NULL; + if (Fcb == Fcb->Vcb->RootIndexFcb) { - // } else if (Fcb == Fcb->Vcb->PathTableFcb) { - - // Vcb = Fcb->Vcb; - // Vcb->PathTableFcb = NULL; - // } + Vcb = Fcb->Vcb; + Vcb->RootIndexFcb = NULL; + } UDFDeallocateFcbIndex(Fcb); break; case UDF_NODE_TYPE_DATA: - // if (Fcb->FileLock != NULL) { - - // FsRtlFreeFileLock( Fcb->FileLock ); - // } + if (Fcb->FileLock != NULL) { - // FsRtlUninitializeOplock( CdGetFcbOplock(Fcb) ); - - if (Fcb == Fcb->Vcb->VolumeDasdFcb) { + FsRtlFreeFileLock( Fcb->FileLock ); + } - __debugbreak(); + if (Fcb == Fcb->Vcb->VolumeDasdFcb) { - Vcb = Fcb->Vcb; - Vcb->VolumeDasdFcb = NULL; - } + Vcb = Fcb->Vcb; + Vcb->VolumeDasdFcb = NULL; + } UDFDeallocateFcbData(Fcb); + break; } - // - // Decrement the Vcb reference count if this is a system - // Fcb. - // + // Decrement the Vcb reference count if this is a system + // Fcb. if (Vcb != NULL) { - // InterlockedDecrement( (LONG*)&Vcb->VcbReference ); - // InterlockedDecrement( (LONG*)&Vcb->VcbUserReference ); + InterlockedDecrement( (LONG*)&Vcb->VcbReference ); + InterlockedDecrement( (LONG*)&Vcb->VcbUserReference ); } return; } +/* + This routine walks through the tree to RootDir & kills all unreferenced + structures using LCB-based parent traversal (similar to MS UdfTeardownStructures). + + StartingFcb must be acquired exclusively by caller. + This function will acquire locks for parent FCBs as needed. + + The algorithm: + 1. If FcbReference != 0, break (FCB still in use) + 2. Walk ParentLcbQueue to find LCBs with Reference == 0 + 3. For each such LCB: remove it and decrement parent's FcbReference/FileInfo->RefCount + 4. If parent's FcbReference goes to 0, recursively tear down parent + 5. Delete the FCB when all LCBs are processed + */ +_Requires_lock_held_(_Global_critical_region_) +VOID +UDFTeardownStructures( + _In_ PIRP_CONTEXT IrpContext, + _Inout_ PFCB StartingFcb, + _In_ BOOLEAN Recursive, // TRUE if this is a recursive call (for hard links) + _Out_ PBOOLEAN RemovedStartingFcb + ) +{ + PVCB Vcb = StartingFcb->Vcb; + PFCB CurrentFcb = StartingFcb; + PFCB ParentFcb = NULL; + PLCB Lcb; + PLIST_ENTRY ListLinks; + + BOOLEAN Delete = FALSE; + BOOLEAN AcquiredCurrentFcb = FALSE; + BOOLEAN Abort = FALSE; + BOOLEAN Removed; + + AdPrint(("UDFTeardownStructures, StartingFcb %p %s\n", + StartingFcb, Recursive ? "Recursive" : "Flat")); + + ASSERT_EXCLUSIVE_FCB(StartingFcb); + + *RemovedStartingFcb = FALSE; + + // + // If this is not an intentionally recursive call we need to check if this + // is a layered close and we're already in another instance of teardown. + // + if (!Recursive) { + if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN)) { + return; + } + SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN); + } + + _SEH2_TRY { + + // + // Loop until we find an Fcb we can't remove. + // + do { + + // + // If the reference count is non-zero then break. + // + if (CurrentFcb->FcbReference != 0) { + break; + } + + // + // It looks like we have a candidate for removal here. We + // will need to walk the list of prefixes (LCBs) and delete them + // from their parents. If it turns out that we have multiple + // parents of this Fcb (hard links), we are going to recursively + // teardown on each of these. + // + for (ListLinks = CurrentFcb->ParentLcbQueue.Flink; + ListLinks != &CurrentFcb->ParentLcbQueue; ) { + + Lcb = CONTAINING_RECORD(ListLinks, LCB, ChildFcbLinks); + + ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); + + // + // We advance the pointer now because we will be toasting this guy, + // invalidating whatever is here. + // + ListLinks = ListLinks->Flink; + + // + // We may have multiple parents through hard links. If the previous parent we + // dealt with is not the parent of this new Lcb, lets do some work. + // + if (ParentFcb != Lcb->ParentFcb) { + + // + // We need to deal with the previous parent. It may now be the case that + // we deleted the last child reference and it wants to go away at this point. + // + if (ParentFcb) { + // + // It should never be the case that we have to recurse more than one level on + // any teardown since no cross-linkage of directories is possible. + // + ASSERT(!Recursive); + + UDFTeardownStructures(IrpContext, ParentFcb, TRUE, &Removed); + + if (!Removed) { + UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); + } + } + + // + // Get this new parent Fcb to work on. + // + ParentFcb = Lcb->ParentFcb; + UDFAcquireResourceExclusive(&ParentFcb->FcbNonpaged->FcbResource, TRUE); + } + + // + // Lock the Vcb so we can look at references. + // + UDFLockVcb(IrpContext, Vcb); + + // + // Now check that the reference counts on the Lcb are zero. + // + if (Lcb->Reference != 0) { + // + // A create is interested in getting in here, so we should + // stop right now. + // + UDFUnlockVcb(IrpContext, Vcb); + UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); + ParentFcb = NULL; + Abort = TRUE; + break; + } + + // + // Now remove this prefix and drop the references to the parent. + // + ASSERT(Lcb->ChildFcb == CurrentFcb); + ASSERT(Lcb->ParentFcb == ParentFcb); + + AdPrint(("UDFTeardownStructures, removing Lcb %p P %p <-> C %p\n", + Lcb, ParentFcb, CurrentFcb)); + + // + // Remove LCB from queues + // + UDFRemovePrefix(IrpContext, Lcb); + + // + // Decrement parent's references + // (UDFAcquirePrefix incremented both when LCB was created) + // + if (ParentFcb->FileInfo) { + UDFCloseFile__(IrpContext, Vcb, ParentFcb->FileInfo); + } + InterlockedDecrement((PLONG)&ParentFcb->FcbReference); + + UDFUnlockVcb(IrpContext, Vcb); + } + + // + // Now really leave if we have to. + // + if (Abort) { + break; + } + + // + // Now that we have removed all of the prefixes of this Fcb we can make the final check. + // Lock the Vcb again so we can inspect the child's references. + // + UDFLockVcb(IrpContext, Vcb); + + if (CurrentFcb->FcbReference != 0) { + // + // Nope, nothing more to do. Stop right now. + // + UDFUnlockVcb(IrpContext, Vcb); + + if (ParentFcb != NULL) { + UDFReleaseResource(&ParentFcb->FcbNonpaged->FcbResource); + } + break; + } + + // + // This Fcb is toast. Remove it from the Fcb Table as appropriate and delete. + // + if (FlagOn(CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE)) { + UDFDeleteFcbTable(IrpContext, CurrentFcb); + ClearFlag(CurrentFcb->FcbState, FCB_STATE_IN_FCB_TABLE); + } + + // + // Check FcbCleanup while still holding VcbMutex + // + BOOLEAN ShouldDelete = !CurrentFcb->FcbCleanup; + UDFUnlockVcb(IrpContext, Vcb); + + if (ShouldDelete && CurrentFcb->FileInfo) { + + // no more references... current file/dir MUST DIE!!! + if (Delete) { + UDFReferenceFile__(CurrentFcb->FileInfo); + UDFFlushFile__(IrpContext, Vcb, CurrentFcb->FileInfo); + UDFUnlinkFile__(IrpContext, Vcb, CurrentFcb->FileInfo, TRUE); + UDFCloseFile__(IrpContext, Vcb, CurrentFcb->FileInfo); + CurrentFcb->FcbState |= UDF_FCB_DELETED; + Delete = FALSE; + } + else if (!(CurrentFcb->FcbState & UDF_FCB_DELETED)) { + UDFFlushFile__(IrpContext, Vcb, CurrentFcb->FileInfo); + } + + // check if we should try to delete Parent for the next time + if (CurrentFcb->FcbState & UDF_FCB_DELETE_PARENT) { + Delete = TRUE; + } + + // remove references to OS-specific structures + // to let UDF_INFO release FI & Co + CurrentFcb->FileInfo->Fcb = NULL; + if (CurrentFcb->FileInfo->Dloc) { + CurrentFcb->FileInfo->Dloc->CommonFcb = NULL; + } + + if (UDFCleanUpFile__(Vcb, CurrentFcb->FileInfo) == (UDF_FREE_FILEINFO | UDF_FREE_DLOC)) { + + AdPrint(("UDFTeardownStructures, deleting Fcb %p\n", CurrentFcb)); + + // Release the exclusive FCB lock before deleting the FCB. + UDF_CHECK_PAGING_IO_RESOURCE(CurrentFcb); + UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); + + // Save FileInfo before freeing FCB (avoid use-after-free) + PUDF_FILE_INFO FileInfoToFree = CurrentFcb->FileInfo; + CurrentFcb->ParentFcb = NULL; + UDFDeleteFcb(IrpContext, CurrentFcb); + MyFreePool__(FileInfoToFree); + + // Move to the parent Fcb. + CurrentFcb = ParentFcb; + ParentFcb = NULL; + AcquiredCurrentFcb = TRUE; + + } else { + // Stop cleaning up - restore pointers + CurrentFcb->FileInfo->Fcb = CurrentFcb; + if (CurrentFcb->FileInfo->Dloc) { + CurrentFcb->FileInfo->Dloc->CommonFcb = CurrentFcb; + } + + UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); + CurrentFcb = ParentFcb; + ParentFcb = NULL; + AcquiredCurrentFcb = TRUE; + } + } else { + // Cannot delete - release and move to parent + if (CurrentFcb != StartingFcb || AcquiredCurrentFcb) { + UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); + } + CurrentFcb = ParentFcb; + ParentFcb = NULL; + AcquiredCurrentFcb = TRUE; + } + + } while (CurrentFcb != NULL); + + } _SEH2_FINALLY { + + // + // Release the current Fcb if we have acquired it. + // + if (AcquiredCurrentFcb && (CurrentFcb != NULL)) { + UDFReleaseResource(&CurrentFcb->FcbNonpaged->FcbResource); + } + + // + // Clear the teardown flag. + // + if (!Recursive) { + ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_IN_TEARDOWN); + } + + } _SEH2_END; + + *RemovedStartingFcb = (CurrentFcb != StartingFcb); + + AdPrint(("UDFTeardownStructures, RemovedStartingFcb -> %c\n", + *RemovedStartingFcb ? 'T' : 'F')); + +} // end UDFTeardownStructures() + PFCB UDFLookupFcbTable ( _In_ PIRP_CONTEXT IrpContext, @@ -558,11 +872,15 @@ UDFInitializeFCB( Fcb->FcbState = Flags; - UDFInsertFcbTable(IrpContext, Fcb); - SetFlag(Fcb->FcbState, FCB_STATE_IN_FCB_TABLE); + // NOTE: FCB is NOT added to FcbTable here. + // Caller is responsible for calling UDFInsertFcbTable after + // FCB is fully initialized (matching MS pattern where + // UdfInsertFcbTable is called at the END of initialization). // initialize the various list heads InitializeListHead(&Fcb->NextCCB); + InitializeListHead(&Fcb->ParentLcbQueue); + InitializeListHead(&Fcb->ChildLcbQueue); Fcb->FcbReference = 0; Fcb->FcbCleanup = 0; @@ -837,65 +1155,6 @@ UDFInitializeVCB( } _SEH2_END; } // end UDFInitializeVCB() -VOID -UDFCleanUpFCB( - PFCB Fcb - ) -{ - UDFPrint(("UDFCleanUpFCB: %x\n", Fcb)); - if (!Fcb) return; - - ASSERT_FCB(Fcb); - - _SEH2_TRY { - // Deinitialize FCBName field - if (Fcb->FCBName) { - if (Fcb->FCBName->ObjectName.Buffer) { - MyFreePool__(Fcb->FCBName->ObjectName.Buffer); - Fcb->FCBName->ObjectName.Buffer = NULL; -#ifdef UDF_DBG - Fcb->FCBName->ObjectName.Length = - Fcb->FCBName->ObjectName.MaximumLength = 0; -#endif - } -#ifdef UDF_DBG - else { - UDFPrint(("UDF: Fcb has invalid FCBName Buffer\n")); - BrutePoint(); - } -#endif - UDFReleaseObjectName(Fcb->FCBName); - Fcb->FCBName = NULL; - } -#ifdef UDF_DBG - else { - UDFPrint(("UDF: Fcb has invalid FCBName field\n")); - BrutePoint(); - } -#endif - - - // begin transaction { - - UDFLockVcb(IrpContext, Fcb->Vcb); - - if (FlagOn(Fcb->FcbState, FCB_STATE_IN_FCB_TABLE)) { - - UDFDeleteFcbTable(IrpContext, Fcb); - ClearFlag(Fcb->FcbState, FCB_STATE_IN_FCB_TABLE); - } - - UDFUnlockVcb(IrpContext, Fcb->Vcb); - - // } end transaction - - // Free memory - UDFDeleteFcb(0, Fcb); - } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - BrutePoint(); - } _SEH2_END; -} // end UDFCleanUpFCB() - NTSTATUS UDFCompleteMount( IN PIRP_CONTEXT IrpContext, @@ -945,7 +1204,7 @@ UDFCompleteMount( if (!RootName) { - UDFCleanUpFCB(Vcb->RootIndexFcb); + UDFDeleteFcb(IrpContext, Vcb->RootIndexFcb); Vcb->RootIndexFcb = NULL; try_return(Status = STATUS_INSUFFICIENT_RESOURCES); } @@ -961,7 +1220,7 @@ UDFCompleteMount( insuf_res_1: MyFreePool__(RootName->ObjectName.Buffer); UDFReleaseObjectName(RootName); - UDFCleanUpFCB(Vcb->RootIndexFcb); + UDFDeleteFcb(IrpContext, Vcb->RootIndexFcb); Vcb->RootIndexFcb = NULL; try_return(Status); } @@ -996,11 +1255,20 @@ UDFCompleteMount( UDFCleanUpFile__(Vcb, Vcb->RootIndexFcb->FileInfo); MyFreePool__(Vcb->RootIndexFcb->FileInfo); - UDFCleanUpFCB(Vcb->RootIndexFcb); + + // FCB was not inserted into table (UDFInitializeFCB failed + // before UDFInsertFcbIntoTable was called) + UDFUnlockVcb(IrpContext, Vcb); + UnlockVcb = FALSE; + + UDFDeleteFcb(IrpContext, Vcb->RootIndexFcb); Vcb->RootIndexFcb = NULL; try_return(Status); } + // Insert into FcbTable after successful initialization + UDFInsertFcbIntoTable(IrpContext, Vcb->RootIndexFcb); + // this is a part of UDF_RESIDUAL_REFERENCE InterlockedIncrement((PLONG)&Vcb->VcbReference); Vcb->RootIndexFcb->FcbCleanup = 1; diff --git a/drivers/filesystems/udfs/struct.h b/drivers/filesystems/udfs/struct.h index 35a44a8d443fd..d934d36a4a914 100644 --- a/drivers/filesystems/udfs/struct.h +++ b/drivers/filesystems/udfs/struct.h @@ -36,6 +36,8 @@ struct IRP_CONTEXT_LITE; struct IO_CONTEXT; struct IRP_CONTEXT; +struct LCB; +typedef struct LCB *PLCB; /************************************************************************** every structure has a node type, and a node size associated with it. @@ -82,6 +84,8 @@ struct CCB { UDFIdentifier NodeIdentifier; // ptr to the associated FCB FCB* Fcb; + // ptr to the LCB used to open this file + PLCB Lcb; // all CCB structures for a FCB are linked together LIST_ENTRY NextCCB; // each CCB is associated with a file object @@ -94,7 +98,6 @@ struct CCB { // need to maintain a search pattern PUNICODE_STRING DirectorySearchPattern; HASH_ENTRY hashes; - ULONG TreeLength; }; using PCCB = CCB*; @@ -267,6 +270,13 @@ struct FCB { PVOID LazyWriteThread; FCB* ParentFcb; + + // LCB queues for parent-child relationships + // ParentLcbQueue - LCBs linking this FCB to parent directories (for hardlinks, usually 1) + LIST_ENTRY ParentLcbQueue; + // ChildLcbQueue - LCBs linking child files to this directory FCB + LIST_ENTRY ChildLcbQueue; + // Pointer to IrpContextLite in delayed queue. IRP_CONTEXT_LITE* IrpContextLite; uint32 CcbCount; @@ -297,6 +307,9 @@ using PFCB = FCB*; values are bit fields; therefore we can test whether a bit position is set (1) or not set (0). **************************************************************************/ +// File data is embedded in ICB (IN_ICB allocation mode) +// Requires exclusive lock for writes since data shares sector with metadata +#define UDF_FCB_EMBEDDED_DATA (0x00000001) #define UDF_FCB_VALID (0x00000002) #define UDF_FCB_DIRECTORY (0x00000008) #define UDF_FCB_ROOT_DIRECTORY (0x00000010) @@ -334,6 +347,53 @@ enum UDFFSD_MEDIA_TYPE { MediaDvdrw }; +//*************************************************************************** +// LCB (Link Control Block) +//*************************************************************************** + +/** + Link Control Block (LCB) - links parent directory to child file. + Similar to MS UDF driver's LCB structure. + + Used to defer directory linkage until create operation completes successfully. + This prevents partial creates from being visible in directory lookups. +*/ +struct LCB { + UDFIdentifier NodeIdentifier; // Node type = UDFS_NTC_LCB + + // Links in parent FCB's ChildLcbQueue + LIST_ENTRY ParentFcbLinks; + // Links in child FCB's ParentLcbQueue + LIST_ENTRY ChildFcbLinks; + + // Parent directory FCB + PFCB ParentFcb; + // Child file FCB + PFCB ChildFcb; + + // Reference count (incremented by CCB, decremented on cleanup) + ULONG Reference; + // LCB flags + ULONG Flags; + // Index in parent's DirIndex (for quick lookup) + ULONG Index; +}; + +// LCB Flags +#define UDF_LCB_FLAG_DELETE_ON_CLEANUP 0x00000001 // Delete file on cleanup +#define UDF_LCB_FLAG_LINK_DELETED 0x00000002 // Link has been deleted +#define UDF_LCB_FLAG_PENDING_CREATE 0x00000004 // Create not yet complete +#define UDF_LCB_FLAG_POOL_ALLOCATED 0x00000008 // Allocated from pool (not lookaside) +#define UDF_LCB_FLAG_IGNORE_CASE 0x00000010 // Case-insensitive name +#define UDF_LCB_FLAG_SHORT_NAME 0x00000020 // Short name match + +// LCB lookaside size - fits LCB + 16 WCHARs for short names +#define SIZEOF_LOOKASIDE_LCB (sizeof(LCB) + (sizeof(WCHAR) * 16)) + +//*************************************************************************** +// VCB (Volume Control Block) +//*************************************************************************** + enum VCB_CONDITION { VcbNotMounted = 0, @@ -704,7 +764,6 @@ struct IRP_CONTEXT { NTSTATUS ExceptionStatus; // For queued close operation we save Fcb FCB* Fcb; - ULONG TreeLength; // Io context for a read request. // Address of Fcb for teardown oplock in create case. @@ -789,7 +848,6 @@ struct IRP_CONTEXT_LITE { ULONG UserReference; // Real device object. This represents the physical device closest to the media. PDEVICE_OBJECT RealDevice; - ULONG TreeLength; }; using PIRP_CONTEXT_LITE = IRP_CONTEXT_LITE*; @@ -834,6 +892,7 @@ typedef struct _UDFData { PAGED_LOOKASIDE_LIST UDFFcbDataLookasideList; PAGED_LOOKASIDE_LIST CcbLookasideList; + PAGED_LOOKASIDE_LIST LcbLookasideList; LIST_ENTRY AsyncCloseQueue; ULONG AsyncCloseCount; @@ -874,6 +933,7 @@ typedef struct _UDFData { #define TAG_FCB_NONPAGED 'nfdU' #define TAG_FCB 'pfdU' #define TAG_CCB 'ccdU' +#define TAG_LCB 'lcdU' #define TAG_VPB 'pvdU' #define TAG_FCB_TABLE 'tfdU' #define TAG_FILE_NAME 'nFdU' diff --git a/drivers/filesystems/udfs/udf_info/dirtree.cpp b/drivers/filesystems/udfs/udf_info/dirtree.cpp index 247376ff93ce7..b4e1e1a5f0aec 100644 --- a/drivers/filesystems/udfs/udf_info/dirtree.cpp +++ b/drivers/filesystems/udfs/udf_info/dirtree.cpp @@ -1048,6 +1048,51 @@ UDFFindFile( } // end UDFFindFile() +/* + Find file in directory and fill enumeration context. + This separates search from open, allowing caller to inspect + the found entry before opening. +*/ +NTSTATUS +UDFFindDirEntry( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PUNICODE_STRING FileName, + IN BOOLEAN IgnoreCase, + IN BOOLEAN NotDeleted, + OUT PDIR_ENUM_CONTEXT DirContext + ) +{ + NTSTATUS status; + uint_di Index = 0; + + // Initialize context + RtlZeroMemory(DirContext, sizeof(DIR_ENUM_CONTEXT)); + DirContext->ParentInfo = DirInfo; + + if (!DirInfo->Dloc->DirIndex) { + return STATUS_NOT_A_DIRECTORY; + } + + DirContext->DirIndex = DirInfo->Dloc->DirIndex; + + // Find the file + status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, FileName, DirInfo, &Index); + if (!NT_SUCCESS(status)) { + return status; + } + + // Get the directory entry + DirContext->DirNdx = UDFDirIndex(DirContext->DirIndex, Index); + if (!DirContext->DirNdx) { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + DirContext->Index = Index; + return STATUS_SUCCESS; + +} // end UDFFindDirEntry() + /* This routine returns pointer to parent DirIndex */ diff --git a/drivers/filesystems/udfs/udf_info/udf_info.cpp b/drivers/filesystems/udfs/udf_info/udf_info.cpp index 6042fd6339a47..f42028d4bb8f0 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.cpp +++ b/drivers/filesystems/udfs/udf_info/udf_info.cpp @@ -1645,6 +1645,9 @@ UDFWriteFile__( ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode; WasInIcb = TRUE; + // Clear embedded data flag since file is no longer in ICB mode + ASSERT(FileInfo->Fcb); + FileInfo->Fcb->FcbState &= ~UDF_FCB_EMBEDDED_DATA; } // increase extent ExtPrint((" %s %s %s\n", @@ -2146,6 +2149,178 @@ UDFOpenFile__( } // end UDFOpenFile__() +/* + Open file from directory context. + This is called after UDFFindDirEntry to open the found file. + */ +NTSTATUS +UDFOpenObjectFromDirContext( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN PDIR_ENUM_CONTEXT DirContext, + IN BOOLEAN NotDeleted, + OUT PUDF_FILE_INFO* _FileInfo + ) +{ + NTSTATUS status; + EXTENT_AD FEExt; + uint16 Ident; + PDIR_INDEX_ITEM DirNdx = DirContext->DirNdx; + PUDF_FILE_INFO DirInfo = DirContext->ParentInfo; + PUDF_FILE_INFO FileInfo; + PUDF_FILE_INFO ParFileInfo; + ULONG ReadBytes; + uint_di i = DirContext->Index; + + *_FileInfo = NULL; + + if (!DirNdx) { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + if ((FileInfo = DirNdx->FileInfo)) { + // file is already opened + if ((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) { + AdPrint((" FILE_DELETED on open\n")); + return STATUS_FILE_DELETED; + } + if ((FileInfo->ParentFile != DirInfo) && + (FileInfo->Index >= 2)) { + ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo); + BrutePoint(); + if (ParFileInfo->ParentFile != DirInfo) { + FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_FINF_TAG); + *_FileInfo = FileInfo; + if (!FileInfo) return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO)); + UDFInsertLinkedFile(FileInfo, DirNdx->FileInfo); + DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; + FileInfo->RefCount = 0; + FileInfo->ParentFile = DirInfo; + FileInfo->Fcb = NULL; + } else { + FileInfo = ParFileInfo; + } + } + // Just increase some counters & exit + UDFReferenceFile__(FileInfo); + + ASSERT(FileInfo->ParentFile == DirInfo); + ValidateFileInfo(FileInfo); + + *_FileInfo = FileInfo; + return STATUS_SUCCESS; + } + + // Check deleted for new open + if ((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) { + AdPrint((" FILE_DELETED on open (2)\n")); + return STATUS_FILE_DELETED; + } + + FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_FINF_TAG); + *_FileInfo = FileInfo; + if (!FileInfo) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); + // init horizontal links + FileInfo->NextLinkedFile = + FileInfo->PrevLinkedFile = FileInfo; + // read FileIdent + FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG); + if (!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES; + FileInfo->FileIdentLen = DirNdx->Length; + if (!NT_SUCCESS(status = UDFReadExtent(IrpContext, Vcb, &DirInfo->Dloc->DataLoc, DirNdx->Offset, + DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes))) + return status; + if (FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) { + BrutePoint(); + return STATUS_FILE_CORRUPT_ERROR; + } + // check for opened links + if (!NT_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation))))) + return status; + // init pointer to parent object + FileInfo->Index = i; + FileInfo->ParentFile = DirInfo; + // init pointers to linked files (if any) + if (FileInfo->Dloc->LinkedFileInfo != FileInfo) + UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo); + if (FileInfo->Dloc->FileEntry) + goto init_tree_entry; + // read (Ex)FileEntry + FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->SectorSize, MEM_FE_TAG); + if (!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES; + if (!NT_SUCCESS(status = UDFReadFileEntry(IrpContext, Vcb, &FileInfo->FileIdent->icb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident))) + return status; + // build mappings for Data & AllocDescs + if (!FileInfo->Dloc->AllocLoc.Mapping) { + FEExt.extLength = FileInfo->FileIdent->icb.extLength; + FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation)); + if (FEExt.extLocation == LBA_OUT_OF_EXTENT) + return STATUS_FILE_CORRUPT_ERROR; + FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt); + if (!(FileInfo->Dloc->AllocLoc.Mapping)) + return STATUS_INSUFFICIENT_RESOURCES; + } + // read location info + status = UDFLoadExtInfo(IrpContext, Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FileInfo->FileIdent->icb, + &FileInfo->Dloc->DataLoc, &FileInfo->Dloc->AllocLoc); + if (!NT_SUCCESS(status)) + return status; + // init (Ex)FileEntry mapping + FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset : + FileInfo->Dloc->AllocLoc.Offset; + FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt); + FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length); + // we get here immediately when opened link encountered +init_tree_entry: + // init back pointer from parent object + ASSERT(!DirNdx->FileInfo); + DirNdx->FileInfo = FileInfo; + // init DirIndex + if (UDFGetFileLinkCount(FileInfo) > 1) { + DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; + } else { + DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED; + } + // resize FE cache + if (!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->SectorSize, + (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen)) + return STATUS_INSUFFICIENT_RESOURCES; + // check if this file has a SDir + if ((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) && + ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength) + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR; + if (!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) { + UDFReferenceFile__(FileInfo); + ASSERT(FileInfo->ParentFile == DirInfo); + UDFReleaseDloc(Vcb, FileInfo->Dloc); + return STATUS_SUCCESS; + } + + UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); + + // build index for directories + if (!FileInfo->Dloc->DirIndex) { + status = UDFIndexDirectory(IrpContext, Vcb, FileInfo); + if (!NT_SUCCESS(status)) + return status; + + if ((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) && + !(Vcb->VcbState & VCB_STATE_VOLUME_READ_ONLY)) { + status = UDFPackDirectory__(IrpContext, Vcb, FileInfo); + if (!NT_SUCCESS(status)) + return status; + } + } + UDFReferenceFile__(FileInfo); + UDFReleaseDloc(Vcb, FileInfo->Dloc); + ASSERT(FileInfo->ParentFile == DirInfo); + + return status; +} // end UDFOpenObjectFromDirContext() + + /* This routine inits UDF_FILE_INFO structure for root directory */ @@ -2860,8 +3035,12 @@ try_exit: NOTHING; } _SEH2_FINALLY { if (!NT_SUCCESS(status)) { - if (FEAllocated) + if (FEAllocated && FileInfo->Dloc) { + // Free FE space first (needs Dloc->FELoc), then remove Dloc entry UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); + UDFRemoveDloc(Vcb, FileInfo->Dloc); + FileInfo->Dloc = NULL; + } } } _SEH2_END return status; @@ -3527,6 +3706,9 @@ UDFResizeFile__( // switch to IN_ICB mode ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB; + // Set embedded data flag since file is now in ICB mode + ASSERT(FileInfo->Fcb); + FileInfo->Fcb->FcbState |= UDF_FCB_EMBEDDED_DATA; // init new data location descriptors FileInfo->Dloc->DataLoc.Mapping = NewMap; RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP)); @@ -3612,6 +3794,8 @@ UDFLoadVAT( VatFileInfo = Vcb->VatFileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_VATFINF_TAG); if (!VatFileInfo) return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(VatFileInfo, sizeof(UDF_FILE_INFO)); + VatFileInfo->NextLinkedFile = VatFileInfo->PrevLinkedFile = VatFileInfo; // load VAT FE (we know its location) VatFELoc.partitionReferenceNum = PartNum; retry_load_vat: diff --git a/drivers/filesystems/udfs/udf_info/udf_info.h b/drivers/filesystems/udfs/udf_info/udf_info.h index c10108ae41195..630953010e080 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.h +++ b/drivers/filesystems/udfs/udf_info/udf_info.h @@ -131,6 +131,23 @@ __inline NTSTATUS UDFFindFile__(IN PVCB Vcb, return UDFFindFile(Vcb, IgnoreCase, TRUE, Name, DirInfo, &i); } +// Find file in directory and fill enumeration context +NTSTATUS UDFFindDirEntry( + IN PVCB Vcb, + IN PUDF_FILE_INFO DirInfo, + IN PUNICODE_STRING FileName, + IN BOOLEAN IgnoreCase, + IN BOOLEAN NotDeleted, + OUT PDIR_ENUM_CONTEXT DirContext); + +// Open file from directory context (after UDFFindDirEntry) +NTSTATUS UDFOpenObjectFromDirContext( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN PDIR_ENUM_CONTEXT DirContext, + IN BOOLEAN NotDeleted, + OUT PUDF_FILE_INFO* FileInfo); + // calculate file mapping length (in bytes) including ZERO-terminator uint32 UDFGetMappingLength(IN PEXTENT_MAP Extent); // merge 2 sequencial file mappings diff --git a/drivers/filesystems/udfs/udf_info/udf_rel.h b/drivers/filesystems/udfs/udf_info/udf_rel.h index 602a8f6e2cafa..0a8a6089dd19c 100644 --- a/drivers/filesystems/udfs/udf_info/udf_rel.h +++ b/drivers/filesystems/udfs/udf_info/udf_rel.h @@ -441,6 +441,18 @@ typedef struct _UDF_DIR_SCAN_CONTEXT { uint_di i; } UDF_DIR_SCAN_CONTEXT, *PUDF_DIR_SCAN_CONTEXT; +/** + Directory enumeration context for find/open operations. + Separates directory search from file open operations. +*/ +typedef struct _DIR_ENUM_CONTEXT { + PUDF_FILE_INFO ParentInfo; // Parent directory FileInfo + PDIR_INDEX_HDR DirIndex; // Directory index header + PDIR_INDEX_ITEM DirNdx; // Found directory entry (or NULL) + uint_di Index; // Index of found entry + BOOLEAN ShortNameMatch; // TRUE if matched by 8.3 short name +} DIR_ENUM_CONTEXT, *PDIR_ENUM_CONTEXT; + typedef EXT_RELOCATION_ENTRY EXT_RELOC_MAP; typedef PEXT_RELOCATION_ENTRY PEXT_RELOC_MAP; diff --git a/drivers/filesystems/udfs/udffs.h b/drivers/filesystems/udfs/udffs.h index 80af91080509b..5eff0e08995b0 100644 --- a/drivers/filesystems/udfs/udffs.h +++ b/drivers/filesystems/udfs/udffs.h @@ -17,6 +17,8 @@ #ifndef _UDF_UDF_H_ #define _UDF_UDF_H_ +#pragma warning(disable : 28172) + /**************** OPTIONS *****************/ //#define UDF_TRACK_UNICODE_STR @@ -54,7 +56,7 @@ #define UDF_DEFAULT_SPARSE_THRESHOLD (256*PACKETSIZE_UDF) -#define ALLOW_SPARSE +//#define ALLOW_SPARSE #define UDF_PACK_DIRS diff --git a/drivers/filesystems/udfs/udfinit.cpp b/drivers/filesystems/udfs/udfinit.cpp index 0453c669d109f..41e2a087633af 100644 --- a/drivers/filesystems/udfs/udfinit.cpp +++ b/drivers/filesystems/udfs/udfinit.cpp @@ -312,7 +312,7 @@ UDFInitializeFunctionPointers( PtrFastIoDispatch->FastIoQueryNetworkOpenInfo = UDFFastIoQueryNetInfo; PtrFastIoDispatch->AcquireForModWrite = UDFFastIoAcqModWrite; - PtrFastIoDispatch->ReleaseForModWrite = UDFFastIoRelModWrite; + PtrFastIoDispatch->ReleaseForModWrite = NULL; PtrFastIoDispatch->AcquireForCcFlush = UDFFastIoAcqCcFlush; PtrFastIoDispatch->ReleaseForCcFlush = UDFFastIoRelCcFlush; diff --git a/drivers/filesystems/udfs/volinfo.cpp b/drivers/filesystems/udfs/volinfo.cpp index d8be1796c6138..21e41a4011d70 100644 --- a/drivers/filesystems/udfs/volinfo.cpp +++ b/drivers/filesystems/udfs/volinfo.cpp @@ -415,11 +415,7 @@ UDFQueryFsAttributeInfo( Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | (UDFIsStreamsSupported(Vcb) ? FILE_NAMED_STREAMS : 0) | -#ifdef ALLOW_SPARSE - FILE_SUPPORTS_SPARSE_FILES | -#endif //ALLOW_SPARSE ((Vcb->VcbState & VCB_STATE_VOLUME_READ_ONLY) ? FILE_READ_ONLY_VOLUME : 0) | - FILE_UNICODE_ON_DISK; Buffer->MaximumComponentNameLength = UDF_X_NAME_LEN-1; diff --git a/drivers/filesystems/udfs/write.cpp b/drivers/filesystems/udfs/write.cpp index 92919033cd68f..75feee29a023a 100644 --- a/drivers/filesystems/udfs/write.cpp +++ b/drivers/filesystems/udfs/write.cpp @@ -39,12 +39,14 @@ NTSTATUS UDFCommonWrite( PIRP_CONTEXT IrpContext, - PIRP Irp) + PIRP Irp) { - NTSTATUS RC = STATUS_SUCCESS; - PIO_STACK_LOCATION IrpSp = NULL; - LARGE_INTEGER ByteOffset; - ULONG WriteLength = 0, TruncatedLength = 0; + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + LONGLONG StartingOffset; + ULONG ByteCount; + LONGLONG ByteRange; + ULONG TruncatedLength; SIZE_T NumberBytesWritten = 0; PFILE_OBJECT FileObject = NULL; TYPE_OF_OPEN TypeOfOpen; @@ -52,7 +54,6 @@ UDFCommonWrite( PCCB Ccb = NULL; PVCB Vcb = NULL; PVOID SystemBuffer = NULL; - PIRP TopIrp; LONGLONG ASize; LONGLONG OldVDL; @@ -61,121 +62,146 @@ UDFCommonWrite( BOOLEAN MainResourceAcquired = FALSE; BOOLEAN VcbAcquired = FALSE; - BOOLEAN MainResourceAcquiredExclusive = FALSE; - BOOLEAN MainResourceCanDemoteToShared = FALSE; - - BOOLEAN CanWait = FALSE; + BOOLEAN Wait = FALSE; BOOLEAN PagingIo = FALSE; BOOLEAN NonCachedIo = FALSE; BOOLEAN SynchronousIo = FALSE; - BOOLEAN IsThisADeferredWrite = FALSE; + BOOLEAN IsLazyWriteThread = FALSE; BOOLEAN WriteToEOF = FALSE; BOOLEAN FileSizesChanged = FALSE; BOOLEAN RecursiveWriteThrough = FALSE; - BOOLEAN WriteFileSizeToDirNdx = FALSE; BOOLEAN ZeroBlock = FALSE; BOOLEAN ZeroBlockDone = FALSE; - TmPrint(("UDFCommonWrite: irp %x\n", Irp)); + // Examine our input parameters to determine if this is noncached and/or + // a paging io operation. - _SEH2_TRY { + Wait = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); + PagingIo = FlagOn(Irp->Flags, IRP_PAGING_IO); + NonCachedIo = FlagOn(Irp->Flags, IRP_NOCACHE); + SynchronousIo = FlagOn(IrpSp->FileObject->Flags, FO_SYNCHRONOUS_IO); + FileObject = IrpSp->FileObject; - TopIrp = IoGetTopLevelIrp(); - - switch((ULONG_PTR)TopIrp) { - case FSRTL_FSP_TOP_LEVEL_IRP: - UDFPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n")); - break; - case FSRTL_CACHE_TOP_LEVEL_IRP: - UDFPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n")); - break; - case FSRTL_MOD_WRITE_TOP_LEVEL_IRP: - UDFPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n")); - break; - case FSRTL_FAST_IO_TOP_LEVEL_IRP: - UDFPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n")); - BrutePoint(); - break; - case NULL: - UDFPrint((" NULL TOP_LEVEL_IRP\n")); - break; - default: - if (TopIrp == Irp) { - UDFPrint((" TOP_LEVEL_IRP\n")); - } else { - UDFPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp)); - } - break; - } + // Extract and decode the file object. - // First, get a pointer to the current I/O stack location - IrpSp = IoGetCurrentIrpStackLocation(Irp); - ASSERT(IrpSp); - MmPrint((" Enter Irp, MDL=%x\n", Irp->MdlAddress)); + TypeOfOpen = UDFDecodeFileObject(IrpSp->FileObject, &Fcb, &Ccb); - FileObject = IrpSp->FileObject; - ASSERT(FileObject); + if (TypeOfOpen != UserFileOpen && + TypeOfOpen != UserVolumeOpen && + (TypeOfOpen != StreamFileOpen || !NonCachedIo || !PagingIo)) { - // If this is a request at IRQL DISPATCH_LEVEL, then post the request - if (IrpSp->MinorFunction & IRP_MN_DPC) { - try_return(RC = STATUS_PENDING); - } + UDFCompleteRequest(IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST); + return STATUS_INVALID_DEVICE_REQUEST; + } - // Decode the file object and verify we support read on this. It - // must be a user file, stream file or volume file (for a data disk). + Vcb = Fcb->Vcb; - TypeOfOpen = UDFDecodeFileObject(IrpSp->FileObject, &Fcb, &Ccb); + ASSERT_CCB(Ccb); + ASSERT_FCB(Fcb); + ASSERT_VCB(Vcb); - Vcb = Fcb->Vcb; + // Check if this volume has already been shut down. If it has, fail + // this write request. - ASSERT_CCB(Ccb); - ASSERT_FCB(Fcb); - ASSERT_VCB(Vcb); + if (FlagOn(Vcb->VcbState, VCB_STATE_SHUTDOWN)) { - if (Fcb->FcbState & UDF_FCB_DELETED) { - ASSERT(FALSE); - try_return(RC = STATUS_TOO_LATE); - } + UDFCompleteRequest(IrpContext, Irp, STATUS_TOO_LATE); + return STATUS_TOO_LATE; + } + + if (FlagOn(Vcb->VcbState, VCB_STATE_VOLUME_READ_ONLY) && (TypeOfOpen != UserVolumeOpen)) { - // is this operation allowed ? - if (Vcb->VcbState & VCB_STATE_MEDIA_WRITE_PROTECT) { - try_return(RC = STATUS_ACCESS_DENIED); + if (FlagOn(Vcb->VcbState, VCB_STATE_MEDIA_WRITE_PROTECT)) { + Status = STATUS_MEDIA_WRITE_PROTECTED; + } + else if (PagingIo) { + Status = STATUS_FILE_INVALID; + } + else { + Status = FlagOn(Vcb->VcbState, VCB_STATE_MOUNTED_DIRTY) ? + STATUS_VOLUME_DIRTY : STATUS_ACCESS_DENIED; } - // Disk based file systems might decide to verify the logical volume - // (if required and only if removable media are supported) at this time - // As soon as Tray is locked, we needn't call UDFVerifyVcb() - - ByteOffset = IrpSp->Parameters.Write.ByteOffset; - - CanWait = (IrpContext->Flags & IRP_CONTEXT_FLAG_WAIT) ? TRUE : FALSE; - PagingIo = (Irp->Flags & IRP_PAGING_IO) ? TRUE : FALSE; - NonCachedIo = (Irp->Flags & IRP_NOCACHE) ? TRUE : FALSE; - SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE; - UDFPrint((" Flags: %s; %s; %s; %s; Irp(W): %8.8x\n", - CanWait ? "Wt" : "nw", PagingIo ? "Pg" : "np", - NonCachedIo ? "NonCached" : "Cached", SynchronousIo ? "Snc" : "Asc", - Irp->Flags)); - - // Get some of the parameters supplied to us - WriteLength = IrpSp->Parameters.Write.Length; - if (WriteLength == 0) { - // a 0 byte write can be immediately succeeded - if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) { - // NT expects changing CurrentByteOffset to zero in this case - FileObject->CurrentByteOffset.QuadPart = 0; - } - try_return(RC); + UDFCompleteRequest(IrpContext, Irp, Status); + return Status; + } + + // If this is async paging io then check if we are being called by the mapped page writer. + // Convert it back to synchronous if not. + + if (!Wait && PagingIo) { + + Wait = TRUE; + SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); + } + + StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart; + ByteCount = IrpSp->Parameters.Write.Length; + ByteRange = StartingOffset + ByteCount; + + Irp->IoStatus.Information = 0; + + // Check if writing to end of file (FILE_WRITE_TO_END_OF_FILE = -1) + + BOOLEAN WriteToEof = (StartingOffset < 0); + + // Validate file offset - overflow check only for normal offsets + + if (((MAXLONGLONG - StartingOffset) < ByteCount) && !WriteToEof) { + + UDFCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + + // Handle zero-length write + if (ByteCount == 0) { + + UDFCompleteRequest(IrpContext, Irp, STATUS_SUCCESS); + return STATUS_SUCCESS; + } + + // See if we have to defer the write. + + if (!NonCachedIo && + !CcCanIWrite(FileObject, + ByteCount, + (BOOLEAN)(Wait && !BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_IN_FSP)), + BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE))) { + + BOOLEAN Retrying = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE); + + UDFPrePostIrp(IrpContext, Irp); + + SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE); + + CcDeferWrite(FileObject, UDFDeferredWriteCallBack, IrpContext, Irp, ByteCount, Retrying); + return STATUS_PENDING; + } + + _SEH2_TRY { + + // If this is a request at IRQL DISPATCH_LEVEL, then post the request + if (IrpSp->MinorFunction & IRP_MN_DPC) { + try_return(Status = STATUS_PENDING); } - // If this is the normal file we have to check for - // write access according to the current state of the file locks. - if (!PagingIo && - Fcb->FileLock != NULL && - !FsRtlCheckLockForWriteAccess(Fcb->FileLock, Irp) ) { + // If this is a non paging write to a data stream object we have to + // check for access according to the current state op/filelocks. + // + // Note that after this point, operations will be performed on the file. + // No modifying activity can occur prior to this point in the write + // path. + + if (!PagingIo && TypeOfOpen == UserFileOpen) { + + // And finally check the regular file locks. - try_return( RC = STATUS_FILE_LOCK_CONFLICT ); + if (Fcb->FileLock != NULL && + !FsRtlCheckLockForWriteAccess(Fcb->FileLock, Irp )) { + + try_return(Status = STATUS_FILE_LOCK_CONFLICT); + } } // ********** @@ -185,11 +211,11 @@ UDFCommonWrite( // Yup, we need to send this on to the disk driver after // validation of the offset and length. - if (!CanWait) - try_return(RC = STATUS_PENDING); + if (!Wait) + try_return(Status = STATUS_PENDING); // I dislike the idea of writing to not locked media if (!(Vcb->VcbState & VCB_STATE_LOCKED)) { - try_return(RC = STATUS_ACCESS_DENIED); + try_return(Status = STATUS_ACCESS_DENIED); } if (IrpContext->Flags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) { @@ -216,76 +242,31 @@ UDFCommonWrite( // Forward the request to the lower level driver // Lock the callers buffer - if (!NT_SUCCESS(RC = UDFLockUserBuffer(IrpContext, WriteLength, IoReadAccess))) { - try_return(RC); + if (!NT_SUCCESS(Status = UDFLockUserBuffer(IrpContext, ByteCount, IoReadAccess))) { + try_return(Status); } SystemBuffer = UDFMapUserBuffer(Irp); if (!SystemBuffer) - try_return(RC = STATUS_INVALID_USER_BUFFER); + try_return(Status = STATUS_INVALID_USER_BUFFER); // Make sure, that volume will never be quick-remounted // It is very important for ChkUdf utility. Vcb->SerialNumber--; // Perform actual Write - RC = UDFTWrite(IrpContext, Vcb, SystemBuffer, WriteLength, - (ULONG)(ByteOffset.QuadPart >> Vcb->SectorShift), + Status = UDFTWrite(IrpContext, Vcb, SystemBuffer, ByteCount, + (ULONG)(StartingOffset >> Vcb->SectorShift), &NumberBytesWritten); UDFUnlockCallersBuffer(IrpContext, Irp, SystemBuffer); - try_return(RC); - } - - if (Vcb->VcbState & VCB_STATE_VOLUME_READ_ONLY) { - try_return(RC = STATUS_ACCESS_DENIED); - } - - // The FSD (if it is a "nice" FSD) should check whether it is - // convenient to allow the write to proceed by utilizing the - // CcCanIWrite() function call. If it is not convenient to perform - // the write at this time, we should defer the request for a while. - // The check should not however be performed for non-cached write - // operations. To determine whether we are retrying the operation - // or now, use Flags in the IrpContext structure we have created - - IsThisADeferredWrite = BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE); - - if (!NonCachedIo && - !CcCanIWrite(FileObject, WriteLength, CanWait, IsThisADeferredWrite)) { - - // Cache Manager and/or the VMM does not want us to perform - // the write at this time. Post the request. - - SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED_WRITE); - - CcDeferWrite(FileObject, UDFDeferredWriteCallBack, IrpContext, Irp, WriteLength, IsThisADeferredWrite); - try_return(RC = STATUS_PENDING); - } - - // We can continue. Check whether this write operation is targeted - // to a directory object in which case the UDF FSD will disallow - // the write request. - if (Fcb->FcbState & UDF_FCB_DIRECTORY) { - RC = STATUS_INVALID_DEVICE_REQUEST; - try_return(RC); + try_return(Status); } // Validate start offset and length supplied. // Here is a special check that determines whether the caller wishes to // begin the write at current end-of-file (whatever the value of that // offset might be) - if (ByteOffset.HighPart == (LONG)0xFFFFFFFF) { - if (ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) { - WriteToEOF = TRUE; - ByteOffset = Fcb->Header.FileSize; - } else - if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) { - ByteOffset = FileObject->CurrentByteOffset; - } - } - - // Check if this volume has already been shut down. If it has, fail - // this write request. - if (Vcb->VcbState & VCB_STATE_SHUTDOWN) { - try_return(RC = STATUS_TOO_LATE); + if (StartingOffset == -1) { + WriteToEOF = TRUE; + StartingOffset = Fcb->Header.FileSize.QuadPart; } // Paging I/O write operations are special. If paging i/o write @@ -293,15 +274,15 @@ UDFCommonWrite( // If paging i/o // requests extend beyond current end of file, they should be truncated // to current end-of-file. - if (PagingIo && (WriteToEOF || ((ByteOffset.QuadPart + WriteLength) > Fcb->Header.FileSize.QuadPart))) { - if (ByteOffset.QuadPart > Fcb->Header.FileSize.QuadPart) { + if (PagingIo && (WriteToEOF || ((StartingOffset + ByteCount) > Fcb->Header.FileSize.QuadPart))) { + if (StartingOffset > Fcb->Header.FileSize.QuadPart) { TruncatedLength = 0; } else { - TruncatedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); + TruncatedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - StartingOffset); } - if (!TruncatedLength) try_return(RC = STATUS_SUCCESS); + if (!TruncatedLength) try_return(Status = STATUS_SUCCESS); } else { - TruncatedLength = WriteLength; + TruncatedLength = ByteCount; } // There are certain complications that arise when the same file stream @@ -314,67 +295,63 @@ UDFCommonWrite( // information though the purge will probably fail if the file has been // mapped into some process' virtual address space // WARNING !!! we should not flush data beyond valid data length - if (NonCachedIo && - !PagingIo && + if (!PagingIo && + NonCachedIo && Fcb->FcbNonpaged->SegmentObject.DataSectionObject && TruncatedLength && - (ByteOffset.QuadPart < Fcb->Header.FileSize.QuadPart)) { + (StartingOffset < Fcb->Header.FileSize.QuadPart)) { - // Try to acquire the FCB MainResource exclusively - if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, CanWait)) { - try_return(RC = STATUS_PENDING); - } - MainResourceAcquired = TRUE; + UDFAcquireFcbExclusive(IrpContext, Fcb, FALSE); - // We hold PagingIo exclusive around the flush and CcPurgeCacheSection to fix a - // cache coherency problem. - UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbPagingIoResource, TRUE); - PagingIoResourceAcquired = TRUE; + MainResourceAcquired = TRUE; // Flush and then attempt to purge the cache - if ((ByteOffset.QuadPart + TruncatedLength) > Fcb->Header.FileSize.QuadPart) { + if ((StartingOffset + TruncatedLength) > Fcb->Header.FileSize.QuadPart) { NumberBytesWritten = TruncatedLength; } else { - NumberBytesWritten = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart); + NumberBytesWritten = (ULONG)(Fcb->Header.FileSize.QuadPart - StartingOffset); } - MmPrint((" CcFlushCache()\n")); - CcFlushCache(&Fcb->FcbNonpaged->SegmentObject, &ByteOffset, NumberBytesWritten, &Irp->IoStatus); + CcFlushCache(&Fcb->FcbNonpaged->SegmentObject, + WriteToEof ? &Fcb->Header.FileSize : (PLARGE_INTEGER)&StartingOffset, + NumberBytesWritten, + &Irp->IoStatus); // If the flush failed, return error to the caller - if (!NT_SUCCESS(RC = Irp->IoStatus.Status)) { + if (!NT_SUCCESS(Status = Irp->IoStatus.Status)) { NumberBytesWritten = 0; - try_return(RC); + try_return(Status); } // Attempt the purge - MmPrint((" CcPurgeCacheSection()\n")); - BOOLEAN SuccessfulPurge = CcPurgeCacheSection(&Fcb->FcbNonpaged->SegmentObject, &ByteOffset, - NumberBytesWritten, FALSE); + BOOLEAN SuccessfulPurge = CcPurgeCacheSection(&Fcb->FcbNonpaged->SegmentObject, + (PLARGE_INTEGER)&StartingOffset, + NumberBytesWritten, + FALSE); NumberBytesWritten = 0; - UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); - PagingIoResourceAcquired = FALSE; - // We are finished with our flushing and purging if (!SuccessfulPurge) { - try_return(RC = STATUS_PURGE_FAILED); + try_return(Status = STATUS_PURGE_FAILED); } - - MainResourceCanDemoteToShared = TRUE; } // Determine if we were called by the lazywriter. - // We reuse 'IsThisADeferredWrite' here to decrease stack usage - IsThisADeferredWrite = (Fcb->LazyWriteThread == PsGetCurrentThread()); + + IsLazyWriteThread = (Fcb->LazyWriteThread == PsGetCurrentThread()); // Acquire the appropriate FCB resource if (PagingIo) { - if (!UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbPagingIoResource, TRUE)) { - try_return(RC = STATUS_PENDING); + // For PagingIo: FcbResource already acquired by UDFAcqLazyWrite/UDFFastIoAcqModWrite + // callback before this function is called + + if (Fcb->FcbState & UDF_FCB_EMBEDDED_DATA) { + ASSERT_EXCLUSIVE_FCB(Fcb); + } + else { + ASSERT_SHARED_FCB(Fcb); } - PagingIoResourceAcquired = TRUE; ASSERT(NonCachedIo); @@ -382,49 +359,25 @@ UDFCommonWrite( // Try to acquire the FCB MainResource shared if (NonCachedIo) { if (!MainResourceAcquired) { - if (!UDFAcquireSharedWaitForExclusive(&Fcb->FcbNonpaged->FcbResource, CanWait)) { - try_return(RC = STATUS_PENDING); + if (!UDFAcquireSharedWaitForExclusive(&Fcb->FcbNonpaged->FcbResource, Wait)) { + try_return(Status = STATUS_PENDING); } MainResourceAcquired = TRUE; } } else { if (!MainResourceAcquired) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - if (!UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, CanWait)) { - try_return(RC = STATUS_PENDING); + if (!UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, Wait)) { + try_return(Status = STATUS_PENDING); } MainResourceAcquired = TRUE; } } } - // Set the flag indicating if Fast I/O is possible - Fcb->Header.IsFastIoPossible = UDFIsFastIoPossible(Fcb); -/* if (Fcb->CommonFCBHeader.IsFastIoPossible == FastIoIsPossible) { - Fcb->CommonFCBHeader.IsFastIoPossible = FastIoIsQuestionable; - }*/ - - if ((Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) && - (IrpContext->Flags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL)) { + if (!Ccb || !FlagOn(Ccb->Flags, CCB_FLAG_DISMOUNT_ON_CLOSE)) { - // This clause determines if the top level request was - // in the FastIo path. - if ((ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG && - NodeType(TopIrp) == IO_TYPE_IRP) { - - PIO_STACK_LOCATION IrpStack; - ASSERT( TopIrp->Type == IO_TYPE_IRP ); - IrpStack = IoGetCurrentIrpStackLocation(TopIrp); - - // Finally this routine detects if the Top irp was a - // write to this file and thus we are the writethrough. - if ((IrpStack->MajorFunction == IRP_MJ_WRITE) && - (IrpStack->FileObject->FsContext == FileObject->FsContext)) { - - RecursiveWriteThrough = TRUE; - IrpContext->Flags |= IRP_CONTEXT_FLAG_WRITE_THROUGH; - } - } + UDFVerifyFcbOperation(IrpContext, Fcb, Ccb); } // Here is the deal with ValidDataLength and FileSize: @@ -450,62 +403,46 @@ UDFCommonWrite( // will subsequently not fail due to lack of disk space. OldVDL = Fcb->Header.ValidDataLength.QuadPart; - ZeroBlock = (ByteOffset.QuadPart > OldVDL); + ZeroBlock = (StartingOffset > OldVDL); if (!PagingIo && !RecursiveWriteThrough && - !IsThisADeferredWrite) { + !IsLazyWriteThread) { BOOLEAN ExtendFS; - ExtendFS = (ByteOffset.QuadPart + TruncatedLength > Fcb->Header.FileSize.QuadPart); + ExtendFS = (StartingOffset + TruncatedLength > Fcb->Header.FileSize.QuadPart); if ( WriteToEOF || ZeroBlock || ExtendFS) { // we are extending the file; - if (!CanWait) - try_return(RC = STATUS_PENDING); + if (!Wait) + try_return(Status = STATUS_PENDING); // CanWait = TRUE; - // Try to acquire the FCB MainResource exclusively - if (!MainResourceAcquiredExclusive) { - - UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); - MainResourceAcquired = FALSE; - - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, CanWait)) { - try_return(RC = STATUS_PENDING); - } - MainResourceAcquired = TRUE; - } - UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbPagingIoResource, TRUE); PagingIoResourceAcquired = TRUE; if (ExtendFS) { - RC = UDFResizeFile__(IrpContext, Vcb, Fcb->FileInfo, ByteOffset.QuadPart + TruncatedLength); + Status = UDFResizeFile__(IrpContext, Vcb, Fcb->FileInfo, StartingOffset + TruncatedLength); - if (!NT_SUCCESS(RC)) { - try_return(RC); + if (!NT_SUCCESS(Status)) { + try_return(Status); } FileSizesChanged = TRUE; // ... and inform the Cache Manager about it - Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + TruncatedLength; - Fcb->Header.AllocationSize.QuadPart = UDFGetFileAllocationSize(Vcb, Fcb->FileInfo); - if (!Vcb->LowFreeSpace) { - Fcb->Header.AllocationSize.QuadPart += (PAGE_SIZE*9-1); - } else { - Fcb->Header.AllocationSize.QuadPart += (PAGE_SIZE-1); + Fcb->Header.FileSize.QuadPart = StartingOffset + TruncatedLength; + + if (Fcb->Header.AllocationSize.QuadPart < (LONGLONG)LlSectorAlign(Vcb, Fcb->Header.FileSize.QuadPart)) { + + Fcb->Header.AllocationSize.QuadPart = LlSectorAlign(Vcb, Fcb->Header.FileSize.QuadPart); } - Fcb->Header.AllocationSize.LowPart &= ~(PAGE_SIZE-1); } UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); PagingIoResourceAcquired = FALSE; - UDFPrint(("UDFCommonWrite: Set size %x (alloc size %x)\n", ByteOffset.LowPart + TruncatedLength, Fcb->Header.AllocationSize.LowPart)); if (CcIsFileCached(FileObject)) { if (ExtendFS) { MmPrint((" CcSetFileSizes()\n")); @@ -524,7 +461,7 @@ UDFCommonWrite( FileObject, OldVDL, Fcb->Header.FileSize.QuadPart - OldVDL, - CanWait); + Wait); #ifdef UDF_DBG ZeroBlockDone = TRUE; #endif //UDF_DBG @@ -534,26 +471,24 @@ UDFCommonWrite( } - if (Fcb && Fcb->FileInfo && Fcb->FileInfo->Dloc) { - AdPrint(("UDFCommonWrite: DataLoc %x, Mapping %x\n", Fcb->FileInfo->Dloc->DataLoc, Fcb->FileInfo->Dloc->DataLoc.Mapping)); - } + // Branch here for cached vs non-cached I/O - // Branch here for cached vs non-cached I/O if (!NonCachedIo) { // The caller wishes to perform cached I/O. Initiate caching if // this is the first cached I/O operation using this file object + if (!FileObject->PrivateCacheMap) { // This is the first cached I/O operation. You must ensure // that the FCB Header contains valid sizes at this time - UDFPrint(("UDFCommonWrite: Init system cache\n")); - MmPrint((" CcInitializeCacheMap()\n")); - CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, - FALSE, // We will not utilize pin access for this file - &(UdfData.CacheMgrCallBacks), // callbacks - Fcb); // The context used in callbacks - MmPrint((" CcSetReadAheadGranularity()\n")); + + CcInitializeCacheMap(FileObject, + (PCC_FILE_SIZES)&Fcb->Header.AllocationSize, + FALSE, + &UdfData.CacheMgrCallBacks, + Fcb); + CcSetReadAheadGranularity(FileObject, READ_AHEAD_GRANULARITY); } @@ -562,16 +497,44 @@ UDFCommonWrite( UDFZeroData(Vcb, FileObject, OldVDL, - ByteOffset.QuadPart + TruncatedLength - OldVDL, - CanWait); - if (ByteOffset.LowPart & (PAGE_SIZE-1)) { + StartingOffset + TruncatedLength - OldVDL, + Wait); + if (StartingOffset & (PAGE_SIZE-1)) { } } - WriteFileSizeToDirNdx = (IrpContext->Flags & IRP_CONTEXT_FLAG_WRITE_THROUGH) ? - TRUE : FALSE; - // Check and see if this request requires a MDL returned to the caller - if (IrpSp->MinorFunction & IRP_MN_MDL) { + // Write to the cache if this is not an Mdl read. + + if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL)) { + + // Get hold of the user's buffer. + + SystemBuffer = UDFMapUserBuffer(Irp); + + Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; + + if (!CcCopyWrite(FileObject, + (PLARGE_INTEGER)&StartingOffset, + TruncatedLength, + Wait, + SystemBuffer)) { + + // The caller was not prepared to block and data is not immediately + // available in the system cache + // Mark Irp Pending ... + try_return(Status = STATUS_PENDING); + } + + UDFUnlockCallersBuffer(IrpContext, Irp, SystemBuffer); + // We have the data + Status = STATUS_SUCCESS; + NumberBytesWritten = TruncatedLength; + + try_return(Status); + + // Otherwise perform the MdlRead operation. + + } else { // Caller does want a MDL returned. Note that this mode // implies that the caller is prepared to block MmPrint((" CcPrepareMdlWrite()\n")); @@ -580,37 +543,10 @@ UDFCommonWrite( // RC = Irp->IoStatus.Status; NumberBytesWritten = 0; - RC = STATUS_INVALID_PARAMETER; + Status = STATUS_INVALID_PARAMETER; - try_return(RC); + try_return(Status); } - - // This is a regular run-of-the-mill cached I/O request. Let the - // Cache Manager worry about it! - // First though, we need a buffer pointer (address) that is valid - - // We needn't call CcZeroData 'cause udf_info.cpp will care about it - SystemBuffer = UDFMapUserBuffer(Irp); - if (!SystemBuffer) - try_return(RC = STATUS_INVALID_USER_BUFFER); - ASSERT(SystemBuffer); - Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; - - MmPrint((" CcCopyWrite()\n")); - if (!CcCopyWrite(FileObject, &(ByteOffset), TruncatedLength, CanWait, SystemBuffer)) { - // The caller was not prepared to block and data is not immediately - // available in the system cache - // Mark Irp Pending ... - try_return(RC = STATUS_PENDING); - } - - UDFUnlockCallersBuffer(IrpContext, Irp, SystemBuffer); - // We have the data - RC = STATUS_SUCCESS; - NumberBytesWritten = TruncatedLength; - - try_return(RC); - } else { MmPrint((" Write NonCachedIo\n")); @@ -619,115 +555,91 @@ UDFCommonWrite( // 'cause we've already done it above // (see call to UDFZeroDataEx() ) if (!RecursiveWriteThrough && - !IsThisADeferredWrite && - (OldVDL < ByteOffset.QuadPart)) { + !IsLazyWriteThread && + (OldVDL < StartingOffset)) { #ifdef UDF_DBG ASSERT(!ZeroBlockDone); #endif //UDF_DBG UDFZeroData(Vcb, FileObject, OldVDL, - ByteOffset.QuadPart - OldVDL, - CanWait); + StartingOffset - OldVDL, + Wait); } - if (OldVDL < (ByteOffset.QuadPart + TruncatedLength)) { - Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + TruncatedLength; + if (OldVDL < (StartingOffset + TruncatedLength)) { + Fcb->Header.ValidDataLength.QuadPart = StartingOffset + TruncatedLength; } // Send the request to lower level drivers - if (!CanWait) { - UDFPrint(("UDFCommonWrite: Post physical write %x bytes at %x\n", TruncatedLength, ByteOffset.LowPart)); + if (!Wait) { + UDFPrint(("UDFCommonWrite: Post physical write %x bytes at %x\n", TruncatedLength, StartingOffset.LowPart)); - try_return(RC = STATUS_PENDING); + try_return(Status = STATUS_PENDING); } // Lock the callers buffer - if (!NT_SUCCESS(RC = UDFLockUserBuffer(IrpContext, TruncatedLength, IoReadAccess))) { - try_return(RC); + if (!NT_SUCCESS(Status = UDFLockUserBuffer(IrpContext, TruncatedLength, IoReadAccess))) { + try_return(Status); } SystemBuffer = UDFMapUserBuffer(Irp); if (!SystemBuffer) { - try_return(RC = STATUS_INVALID_USER_BUFFER); + try_return(Status = STATUS_INVALID_USER_BUFFER); } Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; - RC = UDFWriteFile__(IrpContext, Vcb, Fcb->FileInfo, ByteOffset.QuadPart, TruncatedLength, + Status = UDFWriteFile__(IrpContext, Vcb, Fcb->FileInfo, StartingOffset, TruncatedLength, FALSE, (PCHAR)SystemBuffer, &NumberBytesWritten); UDFUnlockCallersBuffer(IrpContext, Irp, SystemBuffer); - WriteFileSizeToDirNdx = TRUE; + ASize = UDFGetFileAllocationSize(Vcb, Fcb->FileInfo); + UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &ASize); - try_return(RC); + try_return(Status); } try_exit: NOTHING; } _SEH2_FINALLY { - if (RC == STATUS_PENDING) { - - // Release any resources acquired here ... - if (PagingIoResourceAcquired) { - UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); - } - - if (MainResourceAcquired) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); - } + if (Irp != NULL) { + Irp->IoStatus.Information = NumberBytesWritten; + Irp->IoStatus.Status = Status; + } - if (VcbAcquired) { - UDFReleaseResource(&Vcb->VcbResource); - } + if (NT_SUCCESS(Status) && !AbnormalTermination()) { - } else { // For synchronous I/O, the FSD must maintain the current byte offset // Do not do this however, if I/O is marked as paging-io - if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) { - FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + NumberBytesWritten; + + if (SynchronousIo && !PagingIo && NT_SUCCESS(Status)) { + FileObject->CurrentByteOffset.QuadPart = StartingOffset + NumberBytesWritten; } + // If the write completed successfully and this was not a paging-io // operation, set a flag in the CCB that indicates that a write was // performed and that the file time should be updated at cleanup - if (NT_SUCCESS(RC) && !PagingIo) { + + if (NT_SUCCESS(Status) && !PagingIo) { + // If the file size was changed, set a flag in the FCB indicating that // this occurred. - SetFlag(FileObject->Flags, FO_FILE_MODIFIED); - - if (FileSizesChanged) { - if (!WriteFileSizeToDirNdx) { - - FileObject->Flags |= FO_FILE_SIZE_CHANGED; - } else { - - ASize = UDFGetFileAllocationSize(Vcb, Fcb->FileInfo); - UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &ASize); - - if (UDFIsAStream(Fcb->FileInfo)) { - - UDFNotifyFullReportChange(Vcb, - Fcb, - FILE_NOTIFY_CHANGE_STREAM_SIZE, - FILE_ACTION_MODIFIED_STREAM); - } else { - - UDFNotifyFullReportChange(Vcb, - Fcb, - FILE_NOTIFY_CHANGE_SIZE, - FILE_ACTION_MODIFIED); - } - } + SetFlag(FileObject->Flags, FO_FILE_MODIFIED); + + if (FileSizesChanged) { + + SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED); } + // Update ValidDataLength - if (!IsThisADeferredWrite) { + if (!IsLazyWriteThread) { - if (Fcb->Header.ValidDataLength.QuadPart < (ByteOffset.QuadPart + NumberBytesWritten)) { + if (Fcb->Header.ValidDataLength.QuadPart < (StartingOffset + NumberBytesWritten)) { Fcb->Header.ValidDataLength.QuadPart = min(Fcb->Header.FileSize.QuadPart, - ByteOffset.QuadPart + NumberBytesWritten); + StartingOffset + NumberBytesWritten); if (NonCachedIo && CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); @@ -735,47 +647,38 @@ try_exit: NOTHING; } } } + } - // Release any resources acquired here ... - if (PagingIoResourceAcquired) { - UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); - } + // Release any resources acquired here ... - if (MainResourceAcquired) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); - } + if (PagingIoResourceAcquired) { + UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); + } - if (VcbAcquired) { - UDFReleaseResource(&Vcb->VcbResource); - } - // If the request failed, and we had done some nasty stuff like - // extending the file size (including informing the Cache Manager - // about the new file size), and allocating on-disk space etc., undo - // it at this time. - - // Can complete the IRP here if no exception was encountered - if (!_SEH2_AbnormalTermination() && - Irp) { - Irp->IoStatus.Status = RC; - Irp->IoStatus.Information = NumberBytesWritten; - } + if (MainResourceAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); } + + if (VcbAcquired) { + UDFReleaseResource(&Vcb->VcbResource); + } + } _SEH2_END; // end of "__finally" processing // Post IRP if required - if (RC == STATUS_PENDING) { + if (Status == STATUS_PENDING) { - RC = UDFFsdPostRequest(IrpContext, Irp); - } - else { + Status = UDFFsdPostRequest(IrpContext, Irp); + + } else { - UDFCompleteRequest(IrpContext, Irp, RC); + UDFCompleteRequest(IrpContext, Irp, Status); } UDFPrint(("\n")); - return(RC); + return(Status); } // end UDFCommonWrite() /************************************************************************* From a3305a9413f031174379812c5f74f0142dea4899 Mon Sep 17 00:00:00 2001 From: Gleb Lamm Date: Sun, 15 Feb 2026 02:28:45 +0400 Subject: [PATCH 2/5] UDFInsertPrefix --- drivers/filesystems/udfs/prefxsup.cpp | 352 ++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 drivers/filesystems/udfs/prefxsup.cpp diff --git a/drivers/filesystems/udfs/prefxsup.cpp b/drivers/filesystems/udfs/prefxsup.cpp new file mode 100644 index 0000000000000..a520cef8ac3e8 --- /dev/null +++ b/drivers/filesystems/udfs/prefxsup.cpp @@ -0,0 +1,352 @@ +//////////////////////////////////////////////////////////////////// +// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine +// All rights reserved +// This file was released under the GPLv2 on June 2015. +//////////////////////////////////////////////////////////////////// +/* + + File: PrefxSup.cpp + + Module: UDF File System Driver (Kernel mode execution only) + + Description: + This module implements the UDF Prefix support routines. + Based on Microsoft UDF driver pattern. + +*/ + +#include "udffs.h" + +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_MISC + +/* + This routine creates and inserts an LCB linking the parent FCB to child FCB. + + Similar to MS UdfInsertPrefix but simplified - we don't use splay trees + for prefix lookup since we use FileInfo-based navigation. + + The LCB is linked into: + - ParentFcb->ChildLcbQueue (via Lcb->ParentFcbLinks) + - ChildFcb->ParentLcbQueue (via Lcb->ChildFcbLinks) +*/ +PLCB +UDFInsertPrefix( + IN PIRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PFCB ChildFcb, + IN ULONG Index + ) +{ + PLCB Lcb; + ULONG Flags = 0; + + UNREFERENCED_PARAMETER(IrpContext); + + ASSERT(ParentFcb); + ASSERT(ChildFcb); + + // + // Allocate LCB - use lookaside for small allocations + // + if (sizeof(LCB) > SIZEOF_LOOKASIDE_LCB) { + + Lcb = (PLCB)FsRtlAllocatePoolWithTag(PagedPool, + sizeof(LCB), + TAG_LCB); + if (!Lcb) { + return NULL; + } + + SetFlag(Flags, UDF_LCB_FLAG_POOL_ALLOCATED); + + } else { + + Lcb = (PLCB)ExAllocateFromPagedLookasideList(&UdfData.LcbLookasideList); + if (!Lcb) { + return NULL; + } + } + + // + // Initialize LCB + // + RtlZeroMemory(Lcb, sizeof(LCB)); + + Lcb->NodeIdentifier.NodeTypeCode = UDF_NODE_TYPE_LCB; + Lcb->NodeIdentifier.NodeByteSize = sizeof(LCB); + + // Set up FCB pointers + Lcb->ParentFcb = ParentFcb; + Lcb->ChildFcb = ChildFcb; + Lcb->Index = Index; + + // Set flags + Lcb->Flags = Flags; + + // Initial reference count + Lcb->Reference = 0; + + // + // Link LCB into the FCB queues + // + // Insert into parent's child queue + InsertHeadList(&ParentFcb->ChildLcbQueue, &Lcb->ParentFcbLinks); + // Insert into child's parent queue + InsertHeadList(&ChildFcb->ParentLcbQueue, &Lcb->ChildFcbLinks); + + return Lcb; +} // end UDFInsertPrefix() + + +/* + This routine removes an LCB from FCB queues and frees it. +*/ +VOID +UDFRemovePrefix( + IN PIRP_CONTEXT IrpContext, + IN PLCB Lcb + ) +{ + UNREFERENCED_PARAMETER(IrpContext); + + if (!Lcb) { + return; + } + + ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); + + // + // Remove from parent FCB's ChildLcbQueue + // + RemoveEntryList(&Lcb->ParentFcbLinks); + InitializeListHead(&Lcb->ParentFcbLinks); + + // + // Remove from child FCB's ParentLcbQueue + // + RemoveEntryList(&Lcb->ChildFcbLinks); + InitializeListHead(&Lcb->ChildFcbLinks); + + // + // Free the LCB based on how it was allocated + // + if (FlagOn(Lcb->Flags, UDF_LCB_FLAG_POOL_ALLOCATED)) { + + ExFreePool(Lcb); + + } else { + + ExFreeToPagedLookasideList(&UdfData.LcbLookasideList, Lcb); + } +} // end UDFRemovePrefix() + + +/* + This routine finds an existing LCB linking the parent FCB to child FCB. + Returns NULL if no such LCB exists. +*/ +PLCB +UDFFindPrefix( + IN PIRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PFCB ChildFcb + ) +{ + PLIST_ENTRY ListEntry; + PLCB Lcb; + + UNREFERENCED_PARAMETER(IrpContext); + + ASSERT(ParentFcb); + ASSERT(ChildFcb); + + // + // Walk the child FCB's ParentLcbQueue to find LCB pointing to this parent + // + for (ListEntry = ChildFcb->ParentLcbQueue.Flink; + ListEntry != &ChildFcb->ParentLcbQueue; + ListEntry = ListEntry->Flink) { + + Lcb = CONTAINING_RECORD(ListEntry, LCB, ChildFcbLinks); + + ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); + + if (Lcb->ParentFcb == ParentFcb) { + return Lcb; + } + } + + return NULL; +} // end UDFFindPrefix() + + +/* + This routine acquires or creates an LCB linking the parent FCB to child FCB. + If LCB already exists, increments its Reference count. + If new LCB is created: + - Increments parent FCB's FcbReference + - Increments parent's FileInfo->RefCount (if available) + + This is the primary function to call when establishing a parent-child + relationship during file open. + + Returns the LCB (existing or newly created), or NULL on allocation failure. +*/ +PLCB +UDFAcquirePrefix( + IN PIRP_CONTEXT IrpContext, + IN PFCB ParentFcb, + IN PFCB ChildFcb, + IN ULONG Index + ) +{ + PLCB Lcb; + + UNREFERENCED_PARAMETER(IrpContext); + + ASSERT(ParentFcb); + ASSERT(ChildFcb); + + // + // First try to find existing LCB + // + Lcb = UDFFindPrefix(IrpContext, ParentFcb, ChildFcb); + + if (Lcb) { + // + // Found existing LCB - just increment reference + // + InterlockedIncrement((PLONG)&Lcb->Reference); + return Lcb; + } + + // + // Need to create new LCB + // + Lcb = UDFInsertPrefix(IrpContext, ParentFcb, ChildFcb, Index); + + if (Lcb) { + // + // New LCB created - set initial reference and increment parent's references + // The parent's FcbReference represents this LCB's existence + // + Lcb->Reference = 1; + InterlockedIncrement((PLONG)&ParentFcb->FcbReference); + + // + // Also reference parent's FileInfo if available + // This mirrors how TreeLength used to work - parent is referenced + // for each child link. When LCB is removed, we'll call UDFCloseFile__. + // + if (ParentFcb->FileInfo) { + UDFReferenceFile__(ParentFcb->FileInfo); + } + } + + return Lcb; +} // end UDFAcquirePrefix() + + +/* + This routine releases a reference to an LCB. + If Reference goes to zero, the LCB is eligible for removal during teardown. + + Note: This does NOT remove the LCB or decrement parent's FcbReference. + That is done during teardown when walking the ParentLcbQueue. +*/ +VOID +UDFReleasePrefix( + IN PIRP_CONTEXT IrpContext, + IN PLCB Lcb + ) +{ + UNREFERENCED_PARAMETER(IrpContext); + + if (!Lcb) { + return; + } + + ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); + ASSERT(Lcb->Reference > 0); + + InterlockedDecrement((PLONG)&Lcb->Reference); +} // end UDFReleasePrefix() + + +/* + This routine releases a reference to an LCB and, if Reference becomes 0, + immediately removes the LCB and decrements parent references. + + This is used during rename operations where we need immediate cleanup + of the old parent link rather than waiting for teardown. + + Parameters: + IrpContext - The IRP context + Lcb - The LCB to release + CloseParentFileInfo - If TRUE and LCB is removed, call UDFCloseFile__ + on parent's FileInfo + + Returns: + TRUE if the LCB was removed, FALSE if it still has references +*/ +BOOLEAN +UDFReleasePrefixImmediate( + IN PIRP_CONTEXT IrpContext, + IN PLCB Lcb, + IN BOOLEAN CloseParentFileInfo + ) +{ + PFCB ParentFcb; + PUDF_FILE_INFO ParentFileInfo; + PVCB Vcb; + LONG NewRef; + + if (!Lcb) { + return FALSE; + } + + ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); + ASSERT(Lcb->Reference > 0); + + // + // Decrement reference + // + NewRef = InterlockedDecrement((PLONG)&Lcb->Reference); + + if (NewRef > 0) { + // + // Still has references, leave it in place + // + return FALSE; + } + + // + // Reference is now 0 - remove LCB and decrement parent refs + // + ParentFcb = Lcb->ParentFcb; + ParentFileInfo = ParentFcb ? ParentFcb->FileInfo : NULL; + Vcb = ParentFcb ? ParentFcb->Vcb : NULL; + + // + // Remove LCB from queues and free it + // + UDFRemovePrefix(IrpContext, Lcb); + + // + // Decrement parent's FcbReference + // + if (ParentFcb) { + ASSERT(ParentFcb->FcbReference > 0); + InterlockedDecrement((PLONG)&ParentFcb->FcbReference); + + // + // Close parent's FileInfo if requested + // + if (CloseParentFileInfo && ParentFileInfo && Vcb) { + UDFCloseFile__(IrpContext, Vcb, ParentFileInfo); + } + } + + return TRUE; +} // end UDFReleasePrefixImmediate() From b5df050160ca497737763b890ed399623d781659 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 19:53:23 +0000 Subject: [PATCH 3/5] Initial plan From 0d82d1e3f764fc18fa33d58424cba56e12a13db1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 20:11:41 +0000 Subject: [PATCH 4/5] drivers/filesystems/udfs: Convert from C++ to C - Rename all .cpp source files to .c - Update CMakeLists.txt: .cpp -> .c, remove C++-specific warning flags - struct.h: Add C typedef forward declarations, replace using/static_assert/enum with C equivalents, add placeholder members to empty structs - protos.h: Remove extern "C" from DriverEntry, add typedef for TYPE_OF_ACQUIRE enum - Include/phys_lib.h: Remove default parameter values (= 0) from UDFTRead/UDFTWrite - Include/mem_tools.h: Wrap internal memmanager declarations in #ifdef, change inline to static inline - Include/Sys_spec_lib.h: Add ULONG_PTR cast for pointer-to-integer conversion - Include/string_lib.c: Remove extern "C" linkage specifiers - Include/phys_lib.c: Fix IOCTL argument order, remove unreachable code, add explicit Flags=0 arguments - strucsup.c: Change standalone inline to static inline - misc.c: Change false to FALSE - fscntrl.c: Replace auto with explicit type, use _SEH2 macros for SEH - write.c: Add explicit Flags=0 argument to UDFTWrite, fix LARGE_INTEGER initializers - verfysup.c: Add default case to switch statement - env_spec.c: Remove unused PVCB Vcb = NULL variables - udf_info/udf_info.c: Fix return type in UDFReadTagged - udf_info/ecma_167.h: Add C typedef aliases for struct types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Zero3K20 <258969903+Zero3K20@users.noreply.github.com> --- drivers/filesystems/udfs/CMakeLists.txt | 78 +++++++++---------- .../{Sys_spec_lib.cpp => Sys_spec_lib.c} | 0 .../filesystems/udfs/Include/Sys_spec_lib.h | 2 +- .../Include/{mem_tools.cpp => mem_tools.c} | 0 drivers/filesystems/udfs/Include/mem_tools.h | 11 ++- .../udfs/Include/{phys_lib.cpp => phys_lib.c} | 9 +-- drivers/filesystems/udfs/Include/phys_lib.h | 4 +- .../udfs/Include/{regtools.cpp => regtools.c} | 0 .../Include/{string_lib.cpp => string_lib.c} | 4 - .../udfs/{cleanup.cpp => cleanup.c} | 0 .../filesystems/udfs/{close.cpp => close.c} | 0 .../filesystems/udfs/{create.cpp => create.c} | 0 .../udfs/{devcntrl.cpp => devcntrl.c} | 0 .../udfs/{dircntrl.cpp => dircntrl.c} | 0 .../udfs/{env_spec.cpp => env_spec.c} | 3 - .../filesystems/udfs/{fastio.cpp => fastio.c} | 0 .../udfs/{fileinfo.cpp => fileinfo.c} | 0 .../udfs/{filobsup.cpp => filobsup.c} | 0 .../filesystems/udfs/{flush.cpp => flush.c} | 0 .../udfs/{fscntrl.cpp => fscntrl.c} | 8 +- .../udfs/{lockctrl.cpp => lockctrl.c} | 0 drivers/filesystems/udfs/{mem.cpp => mem.c} | 2 +- drivers/filesystems/udfs/{misc.cpp => misc.c} | 4 +- .../udfs/{namesup.cpp => namesup.c} | 0 drivers/filesystems/udfs/{pnp.cpp => pnp.c} | 0 .../udfs/{prefxsup.cpp => prefxsup.c} | 0 drivers/filesystems/udfs/protos.h | 4 +- drivers/filesystems/udfs/{read.cpp => read.c} | 0 .../udfs/{secursup.cpp => secursup.c} | 0 .../udfs/{shutdown.cpp => shutdown.c} | 0 .../udfs/{strucsup.cpp => strucsup.c} | 14 ++-- drivers/filesystems/udfs/struct.h | 49 ++++++++---- .../udfs/{sys_spec.cpp => sys_spec.c} | 2 +- .../udfs/{udf_dbg.cpp => udf_dbg.c} | 0 .../udfs/udf_info/{alloc.cpp => alloc.c} | 0 .../udfs/udf_info/{dirtree.cpp => dirtree.c} | 0 drivers/filesystems/udfs/udf_info/ecma_167.h | 7 ++ .../udfs/udf_info/{extent.cpp => extent.c} | 0 .../udfs/udf_info/{mount.cpp => mount.c} | 0 .../udf_info/{phys_eject.cpp => phys_eject.c} | 0 .../udf_info/{physical.cpp => physical.c} | 2 +- .../udfs/udf_info/{remap.cpp => remap.c} | 0 .../udf_info/{udf_info.cpp => udf_info.c} | 2 +- .../udfs/{udfdata.cpp => udfdata.c} | 0 .../udfs/{udfinit.cpp => udfinit.c} | 0 .../filesystems/udfs/{unload.cpp => unload.c} | 0 .../udfs/{verfysup.cpp => verfysup.c} | 3 + .../udfs/{volinfo.cpp => volinfo.c} | 0 .../filesystems/udfs/{write.cpp => write.c} | 6 +- 49 files changed, 117 insertions(+), 97 deletions(-) rename drivers/filesystems/udfs/Include/{Sys_spec_lib.cpp => Sys_spec_lib.c} (100%) rename drivers/filesystems/udfs/Include/{mem_tools.cpp => mem_tools.c} (100%) rename drivers/filesystems/udfs/Include/{phys_lib.cpp => phys_lib.c} (99%) rename drivers/filesystems/udfs/Include/{regtools.cpp => regtools.c} (100%) rename drivers/filesystems/udfs/Include/{string_lib.cpp => string_lib.c} (98%) rename drivers/filesystems/udfs/{cleanup.cpp => cleanup.c} (100%) rename drivers/filesystems/udfs/{close.cpp => close.c} (100%) rename drivers/filesystems/udfs/{create.cpp => create.c} (100%) rename drivers/filesystems/udfs/{devcntrl.cpp => devcntrl.c} (100%) rename drivers/filesystems/udfs/{dircntrl.cpp => dircntrl.c} (100%) rename drivers/filesystems/udfs/{env_spec.cpp => env_spec.c} (99%) rename drivers/filesystems/udfs/{fastio.cpp => fastio.c} (100%) rename drivers/filesystems/udfs/{fileinfo.cpp => fileinfo.c} (100%) rename drivers/filesystems/udfs/{filobsup.cpp => filobsup.c} (100%) rename drivers/filesystems/udfs/{flush.cpp => flush.c} (100%) rename drivers/filesystems/udfs/{fscntrl.cpp => fscntrl.c} (99%) rename drivers/filesystems/udfs/{lockctrl.cpp => lockctrl.c} (100%) rename drivers/filesystems/udfs/{mem.cpp => mem.c} (93%) rename drivers/filesystems/udfs/{misc.cpp => misc.c} (99%) rename drivers/filesystems/udfs/{namesup.cpp => namesup.c} (100%) rename drivers/filesystems/udfs/{pnp.cpp => pnp.c} (100%) rename drivers/filesystems/udfs/{prefxsup.cpp => prefxsup.c} (100%) rename drivers/filesystems/udfs/{read.cpp => read.c} (100%) rename drivers/filesystems/udfs/{secursup.cpp => secursup.c} (100%) rename drivers/filesystems/udfs/{shutdown.cpp => shutdown.c} (100%) rename drivers/filesystems/udfs/{strucsup.cpp => strucsup.c} (99%) rename drivers/filesystems/udfs/{sys_spec.cpp => sys_spec.c} (95%) rename drivers/filesystems/udfs/{udf_dbg.cpp => udf_dbg.c} (100%) rename drivers/filesystems/udfs/udf_info/{alloc.cpp => alloc.c} (100%) rename drivers/filesystems/udfs/udf_info/{dirtree.cpp => dirtree.c} (100%) rename drivers/filesystems/udfs/udf_info/{extent.cpp => extent.c} (100%) rename drivers/filesystems/udfs/udf_info/{mount.cpp => mount.c} (100%) rename drivers/filesystems/udfs/udf_info/{phys_eject.cpp => phys_eject.c} (100%) rename drivers/filesystems/udfs/udf_info/{physical.cpp => physical.c} (95%) rename drivers/filesystems/udfs/udf_info/{remap.cpp => remap.c} (100%) rename drivers/filesystems/udfs/udf_info/{udf_info.cpp => udf_info.c} (99%) rename drivers/filesystems/udfs/{udfdata.cpp => udfdata.c} (100%) rename drivers/filesystems/udfs/{udfinit.cpp => udfinit.c} (100%) rename drivers/filesystems/udfs/{unload.cpp => unload.c} (100%) rename drivers/filesystems/udfs/{verfysup.cpp => verfysup.c} (99%) rename drivers/filesystems/udfs/{volinfo.cpp => volinfo.c} (100%) rename drivers/filesystems/udfs/{write.cpp => write.c} (99%) diff --git a/drivers/filesystems/udfs/CMakeLists.txt b/drivers/filesystems/udfs/CMakeLists.txt index 1ae3d50d9b070..4c80d75da5aa4 100644 --- a/drivers/filesystems/udfs/CMakeLists.txt +++ b/drivers/filesystems/udfs/CMakeLists.txt @@ -2,55 +2,53 @@ include_directories(Include) list(APPEND SOURCE - udf_info/alloc.cpp - udf_info/dirtree.cpp - udf_info/extent.cpp - udf_info/mount.cpp - udf_info/phys_eject.cpp - udf_info/physical.cpp - udf_info/remap.cpp - udf_info/udf_info.cpp - cleanup.cpp - close.cpp - create.cpp - devcntrl.cpp - dircntrl.cpp - env_spec.cpp - fastio.cpp - fileinfo.cpp - flush.cpp - fscntrl.cpp - lockctrl.cpp - mem.cpp - misc.cpp - namesup.cpp - prefxsup.cpp - pnp.cpp - read.cpp - secursup.cpp - shutdown.cpp - sys_spec.cpp - udf_dbg.cpp - udfinit.cpp - unload.cpp - verfysup.cpp - volinfo.cpp - write.cpp - strucsup.cpp - filobsup.cpp - udfdata.cpp + udf_info/alloc.c + udf_info/dirtree.c + udf_info/extent.c + udf_info/mount.c + udf_info/phys_eject.c + udf_info/physical.c + udf_info/remap.c + udf_info/udf_info.c + cleanup.c + close.c + create.c + devcntrl.c + dircntrl.c + env_spec.c + fastio.c + fileinfo.c + flush.c + fscntrl.c + lockctrl.c + mem.c + misc.c + namesup.c + prefxsup.c + pnp.c + read.c + secursup.c + shutdown.c + sys_spec.c + udf_dbg.c + udfinit.c + unload.c + verfysup.c + volinfo.c + write.c + strucsup.c + filobsup.c + udfdata.c udffs.h) add_library(udfs MODULE ${SOURCE} udffs.rc) if(CMAKE_C_COMPILER_ID STREQUAL "GNU") target_compile_options(udfs PRIVATE -Wno-unused-but-set-variable) - target_compile_options(udfs PRIVATE -Wno-invalid-offsetof) - target_compile_options(udfs PRIVATE -Wno-error -fpermissive) endif() if(CMAKE_C_COMPILER_ID STREQUAL "Clang") - target_compile_options(udfs PRIVATE -Wno-extern-c-compat -Wno-unused-value) + target_compile_options(udfs PRIVATE -Wno-unused-value) target_compile_options(udfs PRIVATE -Wno-tautological-constant-out-of-range-compare) target_compile_options(udfs PRIVATE -Wno-tautological-unsigned-zero-compare -Wno-self-assign) target_compile_options(udfs PRIVATE -Wno-sometimes-uninitialized -Wno-parentheses-equality) diff --git a/drivers/filesystems/udfs/Include/Sys_spec_lib.cpp b/drivers/filesystems/udfs/Include/Sys_spec_lib.c similarity index 100% rename from drivers/filesystems/udfs/Include/Sys_spec_lib.cpp rename to drivers/filesystems/udfs/Include/Sys_spec_lib.c diff --git a/drivers/filesystems/udfs/Include/Sys_spec_lib.h b/drivers/filesystems/udfs/Include/Sys_spec_lib.h index 7187ab6e0371b..696022e2d2d4c 100644 --- a/drivers/filesystems/udfs/Include/Sys_spec_lib.h +++ b/drivers/filesystems/udfs/Include/Sys_spec_lib.h @@ -104,7 +104,7 @@ __inline LARGE_INTEGER UDFMakeLargeInteger(LONGLONG value) { #define UDFGetNTFileId(Vcb, fi) \ UDFMakeLargeInteger((((fi)->Dloc->FELoc.Mapping[0].extLocation - UDFPartStart(Vcb, -2)) + \ - ((LONGLONG)Vcb<<32))) + ((LONGLONG)(ULONG_PTR)Vcb<<32))) #define UnicodeIsPrint(a) RtlIsValidOemCharacter(&(a)) diff --git a/drivers/filesystems/udfs/Include/mem_tools.cpp b/drivers/filesystems/udfs/Include/mem_tools.c similarity index 100% rename from drivers/filesystems/udfs/Include/mem_tools.cpp rename to drivers/filesystems/udfs/Include/mem_tools.c diff --git a/drivers/filesystems/udfs/Include/mem_tools.h b/drivers/filesystems/udfs/Include/mem_tools.h index fa06ad9708fb5..259d95e1a4dcc 100644 --- a/drivers/filesystems/udfs/Include/mem_tools.h +++ b/drivers/filesystems/udfs/Include/mem_tools.h @@ -46,6 +46,7 @@ extern ULONG MemTotalAllocated; #define MY_HEAP_MAX_FRAMES 512 #define MY_HEAP_MAX_BLOCKS 4*1024 // blocks per frame +#ifdef MY_USE_INTERNAL_MEMMANAGER // Mem BOOLEAN MyAllocInit(VOID); VOID MyAllocRelease(VOID); @@ -66,6 +67,8 @@ ULONG __fastcall MyReallocPool( PCHAR addr, ULONG OldLength, PCHAR* NewBuff, ULO #endif VOID __fastcall MyFreePool(PCHAR addr); +#endif // MY_USE_INTERNAL_MEMMANAGER + #ifdef MY_HEAP_CHECK_BOUNDS #define MY_HEAP_ALIGN 63 #else @@ -130,7 +133,7 @@ MyFindMemBaseByAddr( #define MyAlignSize__(size) (size) #endif -BOOLEAN inline MyAllocInit(VOID) {return TRUE;} +static inline BOOLEAN MyAllocInit(VOID) {return TRUE;} #define MyAllocRelease() #ifndef MY_MEM_BOUNDS_CHECK @@ -176,7 +179,7 @@ PVOID inline MyAllocatePool__(ULONG type, ULONG len) { } */ -PVOID inline MyAllocatePoolTag__(ULONG type, ULONG len, /*PCHAR*/ULONG tag) { +static inline PVOID MyAllocatePoolTag__(ULONG type, ULONG len, /*PCHAR*/ULONG tag) { PCHAR newaddr; ULONG i; // newaddr = (PCHAR)MyAllocatePoolTag_(type, len+MY_HEAP_ALIGN+1, tag); @@ -193,7 +196,7 @@ PVOID inline MyAllocatePoolTag__(ULONG type, ULONG len, /*PCHAR*/ULONG tag) { return newaddr; } -VOID inline MyFreePool__(PVOID addr) { +static inline VOID MyFreePool__(PVOID addr) { PCHAR newaddr; // ULONG i; newaddr = (PCHAR)addr; @@ -220,7 +223,7 @@ VOID inline MyFreePool__(PVOID addr) { #pragma GCC diagnostic ignored "-Wstringop-overflow" #endif -ULONG inline MyReallocPool__(PCHAR addr, ULONG len, PCHAR *pnewaddr, ULONG newlen) { +static inline ULONG MyReallocPool__(PCHAR addr, ULONG len, PCHAR *pnewaddr, ULONG newlen) { ULONG _len, _newlen; _newlen = MyAlignSize__(newlen); _len = MyAlignSize__(len); diff --git a/drivers/filesystems/udfs/Include/phys_lib.cpp b/drivers/filesystems/udfs/Include/phys_lib.c similarity index 99% rename from drivers/filesystems/udfs/Include/phys_lib.cpp rename to drivers/filesystems/udfs/Include/phys_lib.c index bba91e86d1c06..b8da310d2e039 100644 --- a/drivers/filesystems/udfs/Include/phys_lib.cpp +++ b/drivers/filesystems/udfs/Include/phys_lib.c @@ -796,14 +796,14 @@ UDFGetBlockSize( if (UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) { UDFPrint(("UDFGetBlockSize: HDD\n")); RC = UDFPhSendIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,DeviceObject, - 0,NULL, + NULL,0, &DiskGeometryEx,sizeof(DISK_GEOMETRY_EX), TRUE,NULL ); if (!NT_SUCCESS(RC)) try_return(RC); RC = UDFPhSendIOCTL(IOCTL_DISK_GET_PARTITION_INFO,DeviceObject, - 0,NULL, + NULL,0, &PartitionInfo,sizeof(PARTITION_INFORMATION), TRUE,NULL ); if (!NT_SUCCESS(RC)) { @@ -1002,7 +1002,6 @@ UDFPrepareForReadOperation( Vcb->VcbState &= ~UDF_VCB_LAST_WRITE; return STATUS_SUCCESS; } - uint32 i = Vcb->LastReadTrack; #ifdef _UDF_STRUCTURES_H_ if (Vcb->BSBM_Bitmap) { @@ -1036,7 +1035,7 @@ UDFReadSectors( OUT PULONG ReadBytes ) { - return UDFTRead(IrpContext, Vcb, Buffer, BCount*Vcb->SectorSize, Lba, ReadBytes); + return UDFTRead(IrpContext, Vcb, Buffer, BCount*Vcb->SectorSize, Lba, ReadBytes, 0); } // end UDFReadSectors() /* @@ -1167,7 +1166,7 @@ UDFWriteSectors( Vcb->LastLBA = Lba+BCount-1; } - status = UDFTWrite(IrpContext, Vcb, Buffer, BCount<SectorShift, Lba, WrittenBytes); + status = UDFTWrite(IrpContext, Vcb, Buffer, BCount<SectorShift, Lba, WrittenBytes, 0); ASSERT(NT_SUCCESS(status)); return status; diff --git a/drivers/filesystems/udfs/Include/phys_lib.h b/drivers/filesystems/udfs/Include/phys_lib.h index 747b95450acf7..19203d202daa5 100644 --- a/drivers/filesystems/udfs/Include/phys_lib.h +++ b/drivers/filesystems/udfs/Include/phys_lib.h @@ -15,7 +15,7 @@ UDFTRead( SIZE_T Length, ULONG LBA, PULONG ReadBytes, - ULONG Flags = 0 + ULONG Flags ); NTSTATUS @@ -26,7 +26,7 @@ UDFTWrite( IN SIZE_T Length, IN ULONG LBA, OUT PSIZE_T WrittenBytes, - IN ULONG Flags = 0 + IN ULONG Flags ); #define PH_TMP_BUFFER 1 diff --git a/drivers/filesystems/udfs/Include/regtools.cpp b/drivers/filesystems/udfs/Include/regtools.c similarity index 100% rename from drivers/filesystems/udfs/Include/regtools.cpp rename to drivers/filesystems/udfs/Include/regtools.c diff --git a/drivers/filesystems/udfs/Include/string_lib.cpp b/drivers/filesystems/udfs/Include/string_lib.c similarity index 98% rename from drivers/filesystems/udfs/Include/string_lib.cpp rename to drivers/filesystems/udfs/Include/string_lib.c index 1750feb27ff16..37bd1d894879a 100644 --- a/drivers/filesystems/udfs/Include/string_lib.cpp +++ b/drivers/filesystems/udfs/Include/string_lib.c @@ -4,7 +4,6 @@ // This file was released under the GPLv2 on June 2015. //////////////////////////////////////////////////////////////////// -extern "C" ULONG MyRtlCompareMemory( PVOID s1, @@ -26,7 +25,6 @@ MyRtlCompareMemory( #ifndef NT_NATIVE_MODE -extern "C" ULONG RtlCompareUnicodeString( PUNICODE_STRING s1, @@ -41,7 +39,6 @@ RtlCompareUnicodeString( return i; } -extern "C" NTSTATUS RtlUpcaseUnicodeString( PUNICODE_STRING dst, @@ -57,7 +54,6 @@ RtlUpcaseUnicodeString( return STATUS_SUCCESS; } -extern "C" NTSTATUS RtlAppendUnicodeToString( IN PUNICODE_STRING Str1, diff --git a/drivers/filesystems/udfs/cleanup.cpp b/drivers/filesystems/udfs/cleanup.c similarity index 100% rename from drivers/filesystems/udfs/cleanup.cpp rename to drivers/filesystems/udfs/cleanup.c diff --git a/drivers/filesystems/udfs/close.cpp b/drivers/filesystems/udfs/close.c similarity index 100% rename from drivers/filesystems/udfs/close.cpp rename to drivers/filesystems/udfs/close.c diff --git a/drivers/filesystems/udfs/create.cpp b/drivers/filesystems/udfs/create.c similarity index 100% rename from drivers/filesystems/udfs/create.cpp rename to drivers/filesystems/udfs/create.c diff --git a/drivers/filesystems/udfs/devcntrl.cpp b/drivers/filesystems/udfs/devcntrl.c similarity index 100% rename from drivers/filesystems/udfs/devcntrl.cpp rename to drivers/filesystems/udfs/devcntrl.c diff --git a/drivers/filesystems/udfs/dircntrl.cpp b/drivers/filesystems/udfs/dircntrl.c similarity index 100% rename from drivers/filesystems/udfs/dircntrl.cpp rename to drivers/filesystems/udfs/dircntrl.c diff --git a/drivers/filesystems/udfs/env_spec.cpp b/drivers/filesystems/udfs/env_spec.c similarity index 99% rename from drivers/filesystems/udfs/env_spec.cpp rename to drivers/filesystems/udfs/env_spec.c index 52e1cb5382576..6872a86d9924f 100644 --- a/drivers/filesystems/udfs/env_spec.cpp +++ b/drivers/filesystems/udfs/env_spec.c @@ -134,7 +134,6 @@ UDFPhReadSynchronous( PIO_STACK_LOCATION IrpSp; KIRQL CurIrql = KeGetCurrentIrql(); PVOID IoBuf = NULL; - PVCB Vcb = NULL; ROffset.QuadPart = Offset; (*ReadBytes) = 0; @@ -252,8 +251,6 @@ UDFPhWriteSynchronous( KIRQL CurIrql = KeGetCurrentIrql(); PVOID IoBuf = NULL; - PVCB Vcb = NULL; - #ifdef DBG if (UDF_SIMULATE_WRITES) { /* FIXME ReactOS diff --git a/drivers/filesystems/udfs/fastio.cpp b/drivers/filesystems/udfs/fastio.c similarity index 100% rename from drivers/filesystems/udfs/fastio.cpp rename to drivers/filesystems/udfs/fastio.c diff --git a/drivers/filesystems/udfs/fileinfo.cpp b/drivers/filesystems/udfs/fileinfo.c similarity index 100% rename from drivers/filesystems/udfs/fileinfo.cpp rename to drivers/filesystems/udfs/fileinfo.c diff --git a/drivers/filesystems/udfs/filobsup.cpp b/drivers/filesystems/udfs/filobsup.c similarity index 100% rename from drivers/filesystems/udfs/filobsup.cpp rename to drivers/filesystems/udfs/filobsup.c diff --git a/drivers/filesystems/udfs/flush.cpp b/drivers/filesystems/udfs/flush.c similarity index 100% rename from drivers/filesystems/udfs/flush.cpp rename to drivers/filesystems/udfs/flush.c diff --git a/drivers/filesystems/udfs/fscntrl.cpp b/drivers/filesystems/udfs/fscntrl.c similarity index 99% rename from drivers/filesystems/udfs/fscntrl.cpp rename to drivers/filesystems/udfs/fscntrl.c index 74982610e6a43..9eb4cec14ce27 100644 --- a/drivers/filesystems/udfs/fscntrl.cpp +++ b/drivers/filesystems/udfs/fscntrl.c @@ -296,7 +296,7 @@ UDFMountVolume( ASSERT(IrpSp); UDFPrint(("\n !!! UDFMountVolume\n")); - auto RealDevice = Vpb->RealDevice; + PDEVICE_OBJECT RealDevice = Vpb->RealDevice; SetDoVerifyOnFail = UDFRealDevNeedsVerify(RealDevice); @@ -1339,7 +1339,7 @@ UDFGetVolumeBitmap( // Fill in the fixed part of the output buffer - __try { + _SEH2_TRY { // StartingLcn in output = aligned starting block @@ -1349,10 +1349,10 @@ UDFGetVolumeBitmap( OutputBuffer->BitmapSize.QuadPart = DesiredClusters; - } __except (EXCEPTION_EXECUTE_HANDLER) { + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { try_return(Status = STATUS_INVALID_USER_BUFFER); - } + } _SEH2_END OutputBufferLength -= FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer); diff --git a/drivers/filesystems/udfs/lockctrl.cpp b/drivers/filesystems/udfs/lockctrl.c similarity index 100% rename from drivers/filesystems/udfs/lockctrl.cpp rename to drivers/filesystems/udfs/lockctrl.c diff --git a/drivers/filesystems/udfs/mem.cpp b/drivers/filesystems/udfs/mem.c similarity index 93% rename from drivers/filesystems/udfs/mem.cpp rename to drivers/filesystems/udfs/mem.c index 072602c852327..301ead0d8ba72 100644 --- a/drivers/filesystems/udfs/mem.cpp +++ b/drivers/filesystems/udfs/mem.c @@ -8,4 +8,4 @@ // define the file specific bug-check id #define UDF_BUG_CHECK_ID UDF_FILE_MEM -#include "Include/mem_tools.cpp" +#include "Include/mem_tools.c" diff --git a/drivers/filesystems/udfs/misc.cpp b/drivers/filesystems/udfs/misc.c similarity index 99% rename from drivers/filesystems/udfs/misc.cpp rename to drivers/filesystems/udfs/misc.c index 75765fe90ce48..3607dc774a31d 100644 --- a/drivers/filesystems/udfs/misc.cpp +++ b/drivers/filesystems/udfs/misc.c @@ -501,7 +501,7 @@ UDFCreateIrpContext( } // TODO: fix - if (false && IrpSp->FileObject != NULL) { + if (FALSE && IrpSp->FileObject != NULL) { PFILE_OBJECT FileObject = IrpSp->FileObject; @@ -1867,5 +1867,5 @@ UDFWaitForIoAtEof( return TRUE; } -#include "Include/regtools.cpp" +#include "Include/regtools.c" diff --git a/drivers/filesystems/udfs/namesup.cpp b/drivers/filesystems/udfs/namesup.c similarity index 100% rename from drivers/filesystems/udfs/namesup.cpp rename to drivers/filesystems/udfs/namesup.c diff --git a/drivers/filesystems/udfs/pnp.cpp b/drivers/filesystems/udfs/pnp.c similarity index 100% rename from drivers/filesystems/udfs/pnp.cpp rename to drivers/filesystems/udfs/pnp.c diff --git a/drivers/filesystems/udfs/prefxsup.cpp b/drivers/filesystems/udfs/prefxsup.c similarity index 100% rename from drivers/filesystems/udfs/prefxsup.cpp rename to drivers/filesystems/udfs/prefxsup.c diff --git a/drivers/filesystems/udfs/protos.h b/drivers/filesystems/udfs/protos.h index acaa3cd52b8b4..885565c236f65 100644 --- a/drivers/filesystems/udfs/protos.h +++ b/drivers/filesystems/udfs/protos.h @@ -1047,7 +1047,7 @@ UDFCommonShutdown( /************************************************************************* * Prototypes for the file UDFinit.cpp *************************************************************************/ -extern "C" NTSTATUS NTAPI DriverEntry( +NTSTATUS NTAPI DriverEntry( PDRIVER_OBJECT DriverObject, // created by the I/O sub-system PUNICODE_STRING RegistryPath); // path to the registry key @@ -1337,6 +1337,8 @@ enum TYPE_OF_ACQUIRE { }; +typedef enum TYPE_OF_ACQUIRE TYPE_OF_ACQUIRE; + _Requires_lock_held_(_Global_critical_region_) _When_(Type == AcquireExclusive && return != FALSE, _Acquires_exclusive_lock_(*Resource)) _When_(Type == AcquireShared && return != FALSE, _Acquires_shared_lock_(*Resource)) diff --git a/drivers/filesystems/udfs/read.cpp b/drivers/filesystems/udfs/read.c similarity index 100% rename from drivers/filesystems/udfs/read.cpp rename to drivers/filesystems/udfs/read.c diff --git a/drivers/filesystems/udfs/secursup.cpp b/drivers/filesystems/udfs/secursup.c similarity index 100% rename from drivers/filesystems/udfs/secursup.cpp rename to drivers/filesystems/udfs/secursup.c diff --git a/drivers/filesystems/udfs/shutdown.cpp b/drivers/filesystems/udfs/shutdown.c similarity index 100% rename from drivers/filesystems/udfs/shutdown.cpp rename to drivers/filesystems/udfs/shutdown.c diff --git a/drivers/filesystems/udfs/strucsup.cpp b/drivers/filesystems/udfs/strucsup.c similarity index 99% rename from drivers/filesystems/udfs/strucsup.cpp rename to drivers/filesystems/udfs/strucsup.c index 6e746f30fc8a4..9fa943a659de0 100644 --- a/drivers/filesystems/udfs/strucsup.cpp +++ b/drivers/filesystems/udfs/strucsup.c @@ -46,7 +46,7 @@ UDFInsertFcbIntoTable( SetFlag(Fcb->FcbState, FCB_STATE_IN_FCB_TABLE); } -inline +static inline PFCB_NONPAGED UDFAllocateFcbNonpaged( ) @@ -54,7 +54,7 @@ UDFAllocateFcbNonpaged( return (PFCB_NONPAGED)ExAllocateFromNPagedLookasideList(&UdfData.UDFNonPagedFcbLookasideList); } -inline +static inline PFCB UDFAllocateFcbIndex( ) @@ -62,7 +62,7 @@ UDFAllocateFcbIndex( return (PFCB)ExAllocateFromPagedLookasideList(&UdfData.UDFFcbIndexLookasideList); } -inline +static inline PFCB UDFAllocateFcbData( ) @@ -70,7 +70,7 @@ UDFAllocateFcbData( return (PFCB)ExAllocateFromPagedLookasideList(&UdfData.UDFFcbDataLookasideList); } -inline +static inline PFCB UDFAllocateFcb( ) @@ -78,7 +78,7 @@ UDFAllocateFcb( return (PFCB)ExAllocatePoolWithTag(NonPagedPool, sizeof(FCB), TAG_FCB); } -inline +static inline VOID UDFDeallocateFcbNonpaged( PFCB_NONPAGED FcbNonpaged @@ -87,7 +87,7 @@ UDFDeallocateFcbNonpaged( ExFreeToNPagedLookasideList(&UdfData.UDFNonPagedFcbLookasideList, FcbNonpaged); } -inline +static inline VOID UDFDeallocateFcbIndex( PFCB Fcb @@ -96,7 +96,7 @@ UDFDeallocateFcbIndex( ExFreeToPagedLookasideList(&UdfData.UDFFcbIndexLookasideList, Fcb); } -inline +static inline VOID UDFDeallocateFcbData( PFCB Fcb diff --git a/drivers/filesystems/udfs/struct.h b/drivers/filesystems/udfs/struct.h index 74c032224266d..895fa13c767f8 100644 --- a/drivers/filesystems/udfs/struct.h +++ b/drivers/filesystems/udfs/struct.h @@ -38,6 +38,22 @@ struct IO_CONTEXT; struct IRP_CONTEXT; struct LCB; +/* C typedef aliases – allow plain name usage without the 'struct' keyword */ +typedef struct IRP_CONTEXT_LITE IRP_CONTEXT_LITE; +typedef struct IO_CONTEXT IO_CONTEXT; +typedef struct IRP_CONTEXT IRP_CONTEXT; +typedef struct LCB LCB; +typedef struct UDFIdentifier UDFIdentifier; +typedef struct UDFObjectName UDFObjectName; +typedef struct CCB CCB; +typedef struct FCB_NONPAGED FCB_NONPAGED; +typedef struct FCB_DATA FCB_DATA; +typedef struct FCB_INDEX FCB_INDEX; +typedef struct FCB FCB; +typedef struct VCB VCB; +typedef struct VOLUME_DEVICE_OBJECT VOLUME_DEVICE_OBJECT; +typedef struct THREAD_CONTEXT THREAD_CONTEXT; + /************************************************************************** every structure has a node type, and a node size associated with it. The node type serves as a signature field. The size is used for @@ -48,8 +64,7 @@ struct UDFIdentifier { NODE_BYTE_SIZE NodeByteSize; // computed as sizeof(structure) }; -static_assert(sizeof(UDFIdentifier) == offsetof(FSRTL_ADVANCED_FCB_HEADER, Flags), - "UDFIdentifier size mismatch with NodeTypeCode and NodeByteSize in FSRTL_ADVANCED_FCB_HEADER"); +C_ASSERT(sizeof(UDFIdentifier) == offsetof(FSRTL_ADVANCED_FCB_HEADER, Flags)); /************************************************************************** Every open on-disk object must have a name associated with it @@ -68,7 +83,7 @@ struct UDFObjectName { // an absolute pathname of the object is stored below UNICODE_STRING ObjectName; }; -using PtrUDFObjectName = UDFObjectName*; +typedef UDFObjectName* PtrUDFObjectName; /************************************************************************** Each file open instance is represented by a context control block. @@ -107,7 +122,7 @@ struct CCB { PUNICODE_STRING DirectorySearchPattern; HASH_ENTRY hashes; }; -using PCCB = CCB*; +typedef CCB* PCCB; #define CCB_FLAG_IGNORE_CASE (0x00000004) // the CCB has had an IRP_MJ_CLEANUP issued on it. we must @@ -165,7 +180,7 @@ struct FCB_NONPAGED { FAST_MUTEX FcbFastMutex; }; -using PFCB_NONPAGED = FCB_NONPAGED*; +typedef FCB_NONPAGED* PFCB_NONPAGED; /************************************************************************** each open file/directory/volume is represented by a file control block. @@ -206,11 +221,11 @@ using PFCB_NONPAGED = FCB_NONPAGED*; /***************************************************/ struct FCB_DATA { - + UCHAR Placeholder; }; struct FCB_INDEX { - + UCHAR Placeholder; }; struct FCB { @@ -312,7 +327,7 @@ struct FCB { FCB_INDEX FcbIndex; }; }; -using PFCB = FCB*; +typedef FCB* PFCB; #define SIZEOF_FCB_DATA \ (FIELD_OFFSET(FCB, FcbType) + sizeof(FCB_DATA)) @@ -355,7 +370,7 @@ using PFCB = FCB*; **************************************************************************/ -enum UDFFSD_MEDIA_TYPE { +typedef enum UDFFSD_MEDIA_TYPE { MediaUnknown = 0, MediaHdd, MediaCdr, @@ -365,7 +380,7 @@ enum UDFFSD_MEDIA_TYPE { MediaFloppy, MediaDvdr, MediaDvdrw -}; +} UDFFSD_MEDIA_TYPE; //*************************************************************************** // LCB (Link Control Block) @@ -439,7 +454,7 @@ struct LCB { UNICODE_STRING FileName; // +0xE8 File name }; -using PLCB = LCB*; +typedef LCB* PLCB; // LCB Flags #define UDF_LCB_FLAG_POOL_ALLOCATED 0x00000001 // Allocated from pool (not lookaside) @@ -465,14 +480,14 @@ using PLCB = LCB*; // VCB (Volume Control Block) //*************************************************************************** -enum VCB_CONDITION { +typedef enum VCB_CONDITION { VcbNotMounted = 0, VcbMountInProgress, VcbMounted, VcbInvalid, VcbDismountInProgress -}; +} VCB_CONDITION; struct VCB { @@ -736,7 +751,7 @@ struct VCB { PVPB SwapVpb; }; -using PVCB = VCB*; +typedef VCB* PVCB; // One for root #define UDFS_BASE_RESIDUAL_REFERENCE (4)//(6) @@ -810,7 +825,7 @@ struct THREAD_CONTEXT { // will store the IrpContext for the request in this stack location. IRP_CONTEXT* TopLevelIrpContext; }; -using PTHREAD_CONTEXT = THREAD_CONTEXT*; +typedef THREAD_CONTEXT* PTHREAD_CONTEXT; /************************************************************************** The IRP context encapsulates the current request. This structure is @@ -854,7 +869,7 @@ struct IRP_CONTEXT { VCB* Vcb; }; -using PIRP_CONTEXT = IRP_CONTEXT*; +typedef IRP_CONTEXT* PIRP_CONTEXT; #define IRP_CONTEXT_FLAG_ON_STACK (0x00000001) #define IRP_CONTEXT_FLAG_MORE_PROCESSING (0x00000002) @@ -919,7 +934,7 @@ struct IRP_CONTEXT_LITE { // Real device object. This represents the physical device closest to the media. PDEVICE_OBJECT RealDevice; }; -using PIRP_CONTEXT_LITE = IRP_CONTEXT_LITE*; +typedef IRP_CONTEXT_LITE* PIRP_CONTEXT_LITE; /************************************************************************** we will store all of our global variables in one structure. diff --git a/drivers/filesystems/udfs/sys_spec.cpp b/drivers/filesystems/udfs/sys_spec.c similarity index 95% rename from drivers/filesystems/udfs/sys_spec.cpp rename to drivers/filesystems/udfs/sys_spec.c index e9a11ab152817..df66b8c66f22e 100644 --- a/drivers/filesystems/udfs/sys_spec.cpp +++ b/drivers/filesystems/udfs/sys_spec.c @@ -20,6 +20,6 @@ // define the file specific bug-check id #define UDF_BUG_CHECK_ID UDF_FILE_SYS_SPEC -#include "Include/Sys_spec_lib.cpp" +#include "Include/Sys_spec_lib.c" //#include "Include/tools.cpp" diff --git a/drivers/filesystems/udfs/udf_dbg.cpp b/drivers/filesystems/udfs/udf_dbg.c similarity index 100% rename from drivers/filesystems/udfs/udf_dbg.cpp rename to drivers/filesystems/udfs/udf_dbg.c diff --git a/drivers/filesystems/udfs/udf_info/alloc.cpp b/drivers/filesystems/udfs/udf_info/alloc.c similarity index 100% rename from drivers/filesystems/udfs/udf_info/alloc.cpp rename to drivers/filesystems/udfs/udf_info/alloc.c diff --git a/drivers/filesystems/udfs/udf_info/dirtree.cpp b/drivers/filesystems/udfs/udf_info/dirtree.c similarity index 100% rename from drivers/filesystems/udfs/udf_info/dirtree.cpp rename to drivers/filesystems/udfs/udf_info/dirtree.c diff --git a/drivers/filesystems/udfs/udf_info/ecma_167.h b/drivers/filesystems/udfs/udf_info/ecma_167.h index 6ca06a7c47fc2..7e4ebc9c9f064 100644 --- a/drivers/filesystems/udfs/udf_info/ecma_167.h +++ b/drivers/filesystems/udfs/udf_info/ecma_167.h @@ -772,5 +772,12 @@ typedef EXTENDED_FILE_ENTRY ExtendedFileEntry; #pragma pack(pop) +typedef struct VolStructDesc VolStructDesc; +typedef struct BeginningExtendedAreaDesc BeginningExtendedAreaDesc; +typedef struct TerminatingExtendedAreaDesc TerminatingExtendedAreaDesc; +typedef struct PrimaryVolDesc PrimaryVolDesc; +typedef struct AnchorVolDescPtr AnchorVolDescPtr; +typedef struct VolDescPtr VolDescPtr; + #endif /* __ECMA_167_H__ */ diff --git a/drivers/filesystems/udfs/udf_info/extent.cpp b/drivers/filesystems/udfs/udf_info/extent.c similarity index 100% rename from drivers/filesystems/udfs/udf_info/extent.cpp rename to drivers/filesystems/udfs/udf_info/extent.c diff --git a/drivers/filesystems/udfs/udf_info/mount.cpp b/drivers/filesystems/udfs/udf_info/mount.c similarity index 100% rename from drivers/filesystems/udfs/udf_info/mount.cpp rename to drivers/filesystems/udfs/udf_info/mount.c diff --git a/drivers/filesystems/udfs/udf_info/phys_eject.cpp b/drivers/filesystems/udfs/udf_info/phys_eject.c similarity index 100% rename from drivers/filesystems/udfs/udf_info/phys_eject.cpp rename to drivers/filesystems/udfs/udf_info/phys_eject.c diff --git a/drivers/filesystems/udfs/udf_info/physical.cpp b/drivers/filesystems/udfs/udf_info/physical.c similarity index 95% rename from drivers/filesystems/udfs/udf_info/physical.cpp rename to drivers/filesystems/udfs/udf_info/physical.c index 1ba8a147f02f1..9468996cacd37 100644 --- a/drivers/filesystems/udfs/udf_info/physical.cpp +++ b/drivers/filesystems/udfs/udf_info/physical.c @@ -17,5 +17,5 @@ // define the file specific bug-check id #define UDF_BUG_CHECK_ID UDF_FILE_PHYSICAL -#include "Include/phys_lib.cpp" +#include "Include/phys_lib.c" diff --git a/drivers/filesystems/udfs/udf_info/remap.cpp b/drivers/filesystems/udfs/udf_info/remap.c similarity index 100% rename from drivers/filesystems/udfs/udf_info/remap.cpp rename to drivers/filesystems/udfs/udf_info/remap.c diff --git a/drivers/filesystems/udfs/udf_info/udf_info.cpp b/drivers/filesystems/udfs/udf_info/udf_info.c similarity index 99% rename from drivers/filesystems/udfs/udf_info/udf_info.cpp rename to drivers/filesystems/udfs/udf_info/udf_info.c index e9556aa93de31..fe3dde19cd202 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.cpp +++ b/drivers/filesystems/udfs/udf_info/udf_info.c @@ -4589,7 +4589,7 @@ UDFReadTagged( // Read the block if (Block == 0xFFFFFFFF) - return NULL; + return STATUS_UNSUCCESSFUL; _SEH2_TRY { RC = UDFReadSectors(IrpContext, Vcb, FALSE, Block, 1, FALSE, Buf, &ReadBytes); diff --git a/drivers/filesystems/udfs/udfdata.cpp b/drivers/filesystems/udfs/udfdata.c similarity index 100% rename from drivers/filesystems/udfs/udfdata.cpp rename to drivers/filesystems/udfs/udfdata.c diff --git a/drivers/filesystems/udfs/udfinit.cpp b/drivers/filesystems/udfs/udfinit.c similarity index 100% rename from drivers/filesystems/udfs/udfinit.cpp rename to drivers/filesystems/udfs/udfinit.c diff --git a/drivers/filesystems/udfs/unload.cpp b/drivers/filesystems/udfs/unload.c similarity index 100% rename from drivers/filesystems/udfs/unload.cpp rename to drivers/filesystems/udfs/unload.c diff --git a/drivers/filesystems/udfs/verfysup.cpp b/drivers/filesystems/udfs/verfysup.c similarity index 99% rename from drivers/filesystems/udfs/verfysup.cpp rename to drivers/filesystems/udfs/verfysup.c index 015af5a6b423b..aad0057c6650c 100644 --- a/drivers/filesystems/udfs/verfysup.cpp +++ b/drivers/filesystems/udfs/verfysup.c @@ -234,6 +234,9 @@ UDFVerifyVcb( UDFRaiseStatus(IrpContext, STATUS_FILE_INVALID); } break; + + default: + break; } } // end UDFVerifyVcb() diff --git a/drivers/filesystems/udfs/volinfo.cpp b/drivers/filesystems/udfs/volinfo.c similarity index 100% rename from drivers/filesystems/udfs/volinfo.cpp rename to drivers/filesystems/udfs/volinfo.c diff --git a/drivers/filesystems/udfs/write.cpp b/drivers/filesystems/udfs/write.c similarity index 99% rename from drivers/filesystems/udfs/write.cpp rename to drivers/filesystems/udfs/write.c index 076e5a6cbe305..7adf7b952c3a8 100644 --- a/drivers/filesystems/udfs/write.cpp +++ b/drivers/filesystems/udfs/write.c @@ -243,7 +243,7 @@ UDFCommonWrite( // Perform actual Write Status = UDFTWrite(IrpContext, Vcb, SystemBuffer, ByteCount, (ULONG)(StartingOffset >> Vcb->SectorShift), - &NumberBytesWritten); + &NumberBytesWritten, 0); UDFUnlockCallersBuffer(IrpContext, Irp, SystemBuffer); try_return(Status); } @@ -894,8 +894,8 @@ UDFZeroData ( --*/ { - LARGE_INTEGER ZeroStart = {0,0}; - LARGE_INTEGER BeyondZeroEnd = {0,0}; + LARGE_INTEGER ZeroStart = {{0, 0}}; + LARGE_INTEGER BeyondZeroEnd = {{0, 0}}; BOOLEAN Finished; From 990dd7885437a8cfa7495d990374205ab75d52d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Apr 2026 01:06:23 +0000 Subject: [PATCH 5/5] Fix remaining C++ constructs: RTL_CONSTANT_STRING, FILE_ID{}, inline functions Agent-Logs-Url: https://github.com/Zero3K20/reactos/sessions/d198a06e-6980-41da-9b86-185fb05f968d Co-authored-by: Zero3K20 <258969903+Zero3K20@users.noreply.github.com> --- drivers/filesystems/udfs/protos.h | 10 +++++----- drivers/filesystems/udfs/strucsup.c | 10 +++++----- drivers/filesystems/udfs/udffs.h | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/filesystems/udfs/protos.h b/drivers/filesystems/udfs/protos.h index 885565c236f65..e40e55610e1dd 100644 --- a/drivers/filesystems/udfs/protos.h +++ b/drivers/filesystems/udfs/protos.h @@ -1385,7 +1385,7 @@ UDFAcquireResource( #define UDFReleasePagingIo(IC,F) \ ExReleaseResourceLite((F)->Header.PagingIoResource) -inline +static inline ULONG UDFHighBit( ULONG Word @@ -1409,7 +1409,7 @@ UDFHighBit( #define SectorSize(V) ((V)->SectorSize) -inline +static inline ULONG SectorAlign( PVCB Vcb, @@ -1419,7 +1419,7 @@ SectorAlign( return (Length + (Vcb->SectorSize - 1)) & ~(Vcb->SectorSize - 1); } -inline +static inline ULONGLONG LlSectorAlign( PVCB Vcb, @@ -1441,7 +1441,7 @@ UDFSetThreadContext( (IC)->ThreadContext = NULL -inline +static inline BOOLEAN UdfIsExtendedFESupported( _In_ PVCB Vcb ) @@ -1449,7 +1449,7 @@ BOOLEAN UdfIsExtendedFESupported( return Vcb->NSRDesc == VRS_NSR03_FOUND; } -inline +static inline BOOLEAN UDFIsStreamsSupported( _In_ PVCB Vcb ) diff --git a/drivers/filesystems/udfs/strucsup.c b/drivers/filesystems/udfs/strucsup.c index 9fa943a659de0..84ad29f046bf0 100644 --- a/drivers/filesystems/udfs/strucsup.c +++ b/drivers/filesystems/udfs/strucsup.c @@ -1185,7 +1185,7 @@ UDFCompleteMount( UNICODE_STRING LocalPath; ULONG LastSector = 0; BOOLEAN UnlockVcb = FALSE; - FILE_ID FileId{}; + FILE_ID FileId = {0}; PAGED_CODE(); @@ -1305,7 +1305,7 @@ UDFCompleteMount( // Open Unallocatable space stream // Generally, it should be placed in SystemStreamDirectory, but some // stupid apps think that RootDirectory is much better place.... :(( - LocalPath = RTL_CONSTANT_STRING(UDF_FN_NON_ALLOCATABLE); + RtlInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE); Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->RootIndexFcb->FileInfo, &Vcb->NonAllocFileInfo, NULL); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { @@ -1328,7 +1328,7 @@ UDFCompleteMount( UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; } else { /* try to read Non-allocatable from alternate locations */ - LocalPath = RTL_CONSTANT_STRING(UDF_FN_NON_ALLOCATABLE_2); + RtlInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE_2); Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->RootIndexFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { goto unwind_1; @@ -1338,7 +1338,7 @@ UDFCompleteMount( UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; } else if (Vcb->SysSDirFileInfo) { - LocalPath = RTL_CONSTANT_STRING(UDF_SN_NON_ALLOCATABLE); + RtlInitUnicodeString(&LocalPath, UDF_SN_NON_ALLOCATABLE); Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->NonAllocFileInfo), NULL); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { goto unwind_1; @@ -1357,7 +1357,7 @@ UDFCompleteMount( /* Read SN UID mapping */ if (Vcb->SysSDirFileInfo) { - LocalPath = RTL_CONSTANT_STRING(UDF_SN_UID_MAPPING); + RtlInitUnicodeString(&LocalPath, UDF_SN_UID_MAPPING); Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &Vcb->UniqueIDMapFileInfo, NULL); diff --git a/drivers/filesystems/udfs/udffs.h b/drivers/filesystems/udfs/udffs.h index 272046b907e62..2aae42ef2fa5f 100644 --- a/drivers/filesystems/udfs/udffs.h +++ b/drivers/filesystems/udfs/udffs.h @@ -133,7 +133,7 @@ extern UDFData UdfData; // Encapsulate safe pool freeing -inline +static inline VOID UDFFreePool( _Inout_ _At_(*Pool, __drv_freesMem(Mem) _Post_null_) PVOID *Pool @@ -152,7 +152,7 @@ UDFFreePool( // small check for illegal open mode (desired access) if volume is // read only (on standard CD-ROM device or another like this) -inline +static inline BOOLEAN UDFIllegalFcbAccess( IN PVCB Vcb, @@ -398,7 +398,7 @@ UDFIllegalFcbAccess( #define FID_DIR_MASK 0x80000000 // high order bit means directory. -inline +static inline FILE_ID UdfGetFidFromLbAddr(lb_addr lbAddr) {