diff --git a/drivers/filesystems/udfs/CMakeLists.txt b/drivers/filesystems/udfs/CMakeLists.txt index 1ae3d50d9b070..485676d28658f 100644 --- a/drivers/filesystems/udfs/CMakeLists.txt +++ b/drivers/filesystems/udfs/CMakeLists.txt @@ -2,51 +2,49 @@ 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 + 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) + target_compile_options(udfs PRIVATE -Wno-error) endif() if(CMAKE_C_COMPILER_ID STREQUAL "Clang") 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..54ce6574662ef 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); @@ -65,6 +66,7 @@ PCHAR __fastcall MyAllocatePool(ULONG Type, ULONG size ULONG __fastcall MyReallocPool( PCHAR addr, ULONG OldLength, PCHAR* NewBuff, ULONG NewLength); #endif VOID __fastcall MyFreePool(PCHAR addr); +#endif // MY_USE_INTERNAL_MEMMANAGER #ifdef MY_HEAP_CHECK_BOUNDS #define MY_HEAP_ALIGN 63 @@ -130,7 +132,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 +178,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 +195,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 +222,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 57% rename from drivers/filesystems/udfs/cleanup.cpp rename to drivers/filesystems/udfs/cleanup.c index 4a42b7da33427..b85c16a7d32c7 100644 --- a/drivers/filesystems/udfs/cleanup.cpp +++ b/drivers/filesystems/udfs/cleanup.c @@ -50,6 +50,7 @@ UDFCommonCleanup( { IO_STATUS_BLOCK IoStatus; NTSTATUS RC = STATUS_SUCCESS; + NTSTATUS RC2; PFILE_OBJECT FileObject = NULL; PFCB Fcb = NULL; PCCB Ccb = NULL; @@ -77,13 +78,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) { @@ -154,6 +155,8 @@ UDFCommonCleanup( // we've cached close InterlockedDecrement((PLONG)&Fcb->CachedOpenHandleCount); } + ASSERT(Fcb->FcbCleanup <= (Fcb->FcbReference-1)); + MmPrint((" CcUninitializeCacheMap()\n")); CcUninitializeCacheMap(FileObject, NULL, NULL); @@ -171,29 +174,30 @@ UDFCommonCleanup( AcquiredVcb = TRUE; } - // Acquire current object only - // Parent is acquired later only for delete operations (Child → Parent order) + // 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 UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFAcquireFcbExclusive(IrpContext, Fcb, FALSE); + UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, TRUE); AcquiredFCB = TRUE; // Decrement the cleanup counts in the Vcb and Fcb. - // Also decrement LCB reference count. UDFLockVcb(IrpContext, Vcb); UDFDecrementCleanupCounts(IrpContext, Fcb); - if (Ccb->Lcb) { - ASSERT(Ccb->Lcb->Reference > 0); - Ccb->Lcb->Reference--; - } UDFUnlockVcb(IrpContext, Vcb); if (FileObject->Flags & FO_CACHE_SUPPORTED) { // we've cached close InterlockedDecrement((PLONG)&Fcb->CachedOpenHandleCount); } - // No ASSERT on FcbCleanup vs FcbReference here - FcbCleanup - // can be temporarily bumped by try-lock reordering in create.cpp + ASSERT(Fcb->FcbCleanup <= (Fcb->FcbReference-1)); // check if Ccb being cleaned up has DeleteOnClose flag set if (Ccb->Flags & UDF_CCB_DELETE_ON_CLOSE) { @@ -224,147 +228,181 @@ UDFCommonCleanup( // get Link count lc = UDFGetFileLinkCount(Fcb->FileInfo); - NextFileInfo = Fcb->FileInfo; - - // Attempt delete if this is the last cleanup and DELETE_ON_CLOSE is set - if ((Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) && + if ( (Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) && !(Fcb->FcbCleanup)) { - - BOOLEAN DeleteAttempted = FALSE; - // This can be useful for Streams, those were brutally deleted // (together with parent object) ASSERT(!(Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); FileObject->DeletePending = TRUE; - // Check if directory is non-empty — if so, discard delete - if ((Fcb->FcbState & UDF_FCB_DIRECTORY) && - !UDFIsDirEmpty__(NextFileInfo)) { + // we should mark all streams of the file being deleted + // for deletion too, if there are no more Links to + // main data stream + if ((lc <= 1) && + !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; - Fcb->FcbState &= ~UDF_FCB_DELETE_ON_CLOSE; + // Make system to issue last Close request + // for our Target ... - } else { +#ifdef UDF_DELAYED_CLOSE + UDFFspClose(Fcb->Vcb); +#endif //UDF_DELAYED_CLOSE - DeleteAttempted = TRUE; + UDFAcquireResourceShared(&Vcb->VcbResource, TRUE); + AcquiredVcb = TRUE; + if (Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); + UDFAcquireResourceExclusive(&(Fcb->ParentFcb->FcbNonpaged->FcbResource), TRUE); + } else { + UDFAcquireResourceShared(&Vcb->VcbResource, 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 + if (lc <= 1) { + // Synchronize here with paging IO + UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbPagingIoResource, TRUE); + // set file size to zero (for system cache manager) +// Fcb->CommonFCBHeader.ValidDataLength.QuadPart = + Fcb->Header.FileSize.QuadPart = + Fcb->Header.ValidDataLength.QuadPart = 0; + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); + + UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); + } + } - // Mark all streams for deletion if no more links - if ((lc <= 1) && - !UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) { - RC = UDFMarkStreamsForDeletion(IrpContext, Vcb, Fcb, TRUE); // Delete - } +#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 - // Acquire parent for delete operation (after current — child first order) - if (Fcb->FileInfo->ParentFile) { - UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); - UDFAcquireFcbExclusive(IrpContext, Fcb->ParentFcb, FALSE); - AcquiredParentFCB = TRUE; - } + NextFileInfo = Fcb->FileInfo; - // Note: do NOT set file sizes to zero here before unlink. - // If unlink fails (STATUS_CANNOT_DELETE), the file stays visible - // with FSize=0 — other threads see truncated data. + // do we need to delete it now ? + if ( (Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) && + !(Fcb->FcbCleanup)) { - // Mark parent object for deletion if requested - if ((Fcb->FcbState & UDF_FCB_DELETE_PARENT) && - Fcb->ParentFcb) { - ASSERT(!(Fcb->ParentFcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); - Fcb->ParentFcb->FcbState |= UDF_FCB_DELETE_ON_CLOSE; + // can we do it ? + if (Fcb->FcbState & UDF_FCB_DIRECTORY) { + ASSERT(!(Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); + if (!UDFIsDirEmpty__(NextFileInfo)) { + // forget about it + Fcb->FcbState &= ~UDF_FCB_DELETE_ON_CLOSE; + goto DiscardDelete; } - - // Flush file. It is required by UDFUnlinkFile__() - RC = UDFFlushFile__(IrpContext, Vcb, NextFileInfo); - if (!NT_SUCCESS(RC)) { - AdPrint(("Error flushing file !!!\n")); + } else + if (lc <= 1) { + // Synchronize here with paging IO + BOOLEAN AcquiredPagingIo; + AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&Fcb->FcbNonpaged->FcbPagingIoResource); + // set file size to zero (for UdfInfo package) + // we should not do this for directories and linked files + UDFResizeFile__(IrpContext, Vcb, NextFileInfo, 0); + if (AcquiredPagingIo) { + UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); } - - // Try to unlink - RC = UDFUnlinkFile__(IrpContext, Vcb, NextFileInfo, TRUE); - - if (RC == STATUS_CANNOT_DELETE) { - - if (NextFileInfo->Dloc && - NextFileInfo->Dloc->SDirInfo && - NextFileInfo->Dloc->SDirInfo->Fcb) { - - // Can't delete file with open streams — pretend deleted. - // Streams will trigger parent deletion on their cleanup. - BrutePoint(); - if (!UDFIsSDirDeleted(NextFileInfo->Dloc->SDirInfo)) { - UDFPretendFileDeleted__(Vcb, Fcb->FileInfo); - } - - } else { - - // Can't delete due to references/permissions/other. - BrutePoint(); - ForcedCleanUp = TRUE; - Fcb->FcbState |= UDF_FCB_DELETED; - // Remove LCB from parent's splay trees immediately. - // Parent is held exclusive (AcquiredParentFCB). - if (Ccb->Lcb && Ccb->Lcb->ParentFcb) { - UdfRemoveNameLinks(Ccb->Lcb->ParentFcb, Ccb->Lcb); - } - RC = STATUS_SUCCESS; + } + // mark parent object for deletion if requested + if ((Fcb->FcbState & UDF_FCB_DELETE_PARENT) && + Fcb->ParentFcb) { + ASSERT(!(Fcb->ParentFcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); + Fcb->ParentFcb->FcbState |= UDF_FCB_DELETE_ON_CLOSE; + } + // flush file. It is required by UDFUnlinkFile__() + RC = UDFFlushFile__(IrpContext, Vcb, NextFileInfo, 0); + if (!NT_SUCCESS(RC)) { + AdPrint(("Error flushing file !!!\n")); + } + // try to unlink + if ((RC = UDFUnlinkFile__(IrpContext, Vcb, NextFileInfo, TRUE)) == STATUS_CANNOT_DELETE) { + // If we can't delete file with Streams due to references, + // mark SDir & Streams + // for Deletion. We shall also set DELETE_PARENT flag to + // force Deletion of the current file later... when curently + // opened Streams would be cleaned up. + + // WARNING! We should keep SDir & Streams if there is a + // link to this file + if (NextFileInfo->Dloc && + NextFileInfo->Dloc->SDirInfo && + NextFileInfo->Dloc->SDirInfo->Fcb) { + + BrutePoint(); + if (!UDFIsSDirDeleted(NextFileInfo->Dloc->SDirInfo)) { +// RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete +//#ifdef UDF_ALLOW_PRETEND_DELETED + UDFPretendFileDeleted__(Vcb, Fcb->FileInfo); +//#endif //UDF_ALLOW_PRETEND_DELETED } + goto NotifyDelete; } else { - - // Unlink completed (success or other error) — mark as deleted - ASSERT(!(Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); - ForcedCleanUp = TRUE; - if (NT_SUCCESS(RC)) - Fcb->FcbState &= ~UDF_FCB_DELETE_ON_CLOSE; - Fcb->FcbState |= UDF_FCB_DELETED; - // Remove LCB from parent's splay trees immediately. - // Parent is held exclusive (AcquiredParentFCB). - if (Ccb->Lcb && Ccb->Lcb->ParentFcb) { - UdfRemoveNameLinks(Ccb->Lcb->ParentFcb, Ccb->Lcb); - } - // Note: do NOT call CcSetFileSizes(0) here. - // CcUninitializeCacheMap with TruncateSize=0 below (ForcedCleanUp path) - // already purges the cache. Setting Fcb->Header.FileSize=0 here would - // leave a stale FCB with FSize=0 in the prefix table — if the FCB is - // reused (e.g., by rename), the renamed file appears as 0-byte. - RC = STATUS_SUCCESS; + // Getting here means that we can't delete file because of + // References/PemissionsDenied/Smth.Else, + // but not Linked+OpenedStream + BrutePoint(); +// RC = STATUS_SUCCESS; + goto DiscardDelete_1; } + } else { +DiscardDelete_1: + // We have got an ugly ERROR, or + // file is deleted, so forget about it + ASSERT(!(Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); + ForcedCleanUp = TRUE; + if (NT_SUCCESS(RC)) + Fcb->FcbState &= ~UDF_FCB_DELETE_ON_CLOSE; + Fcb->FcbState |= UDF_FCB_DELETED; + RC = STATUS_SUCCESS; } - - if (DeleteAttempted) { - // Prevent SetEOF operations on completely deleted data streams - if (lc < 1) { - Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; - } - // Report that we have removed an entry. - if (UDFIsAStream(NextFileInfo)) { - UDFNotifyReportChange( IrpContext, Vcb, NextFileInfo->Fcb, - FILE_NOTIFY_CHANGE_STREAM_NAME, - FILE_ACTION_REMOVED_STREAM, - Ccb->Lcb, FileObject); - } else { - UDFNotifyReportChange( IrpContext, Vcb, NextFileInfo->Fcb, - UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, - FILE_ACTION_REMOVED, - Ccb->Lcb, FileObject); - } +NotifyDelete: + // We should prevent SetEOF operations on completly + // deleted data streams + if (lc < 1) { + Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; + } + // Report that we have removed an entry. + if (UDFIsAStream(NextFileInfo)) { + UDFNotifyFullReportChange( Vcb, NextFileInfo->Fcb, + FILE_NOTIFY_CHANGE_STREAM_NAME, + FILE_ACTION_REMOVED_STREAM); } else { - // Delete discarded (e.g. non-empty directory) — notify modification - UDFNotifyReportChange( IrpContext, Vcb, NextFileInfo->Fcb, - ((Ccb->Flags & UDF_CCB_ACCESS_TIME_SET) ? FILE_NOTIFY_CHANGE_LAST_ACCESS : 0) | - ((Ccb->Flags & UDF_CCB_WRITE_TIME_SET) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE) : 0) | - 0, - UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, - Ccb->Lcb, FileObject); + UDFNotifyFullReportChange( Vcb, NextFileInfo->Fcb, + UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_REMOVED); } - - } else if (Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) { - - // DELETE_ON_CLOSE is set but FcbCleanup > 0 (other handles still open) - UDFNotifyReportChange( IrpContext, Vcb, NextFileInfo->Fcb, + } else + if (Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) { +DiscardDelete: + UDFNotifyFullReportChange( Vcb, NextFileInfo->Fcb, ((Ccb->Flags & UDF_CCB_ACCESS_TIME_SET) ? FILE_NOTIFY_CHANGE_LAST_ACCESS : 0) | ((Ccb->Flags & UDF_CCB_WRITE_TIME_SET) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE) : 0) | 0, - UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, - Ccb->Lcb, FileObject); + UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED); } if (Fcb->FcbState & UDF_FCB_DIRECTORY) { @@ -422,7 +460,7 @@ UDFCommonCleanup( /* MmPrint((" CcPurgeCacheSection()\n")); CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);*/ } - // we needn't Flush here. It will be done in UDFCloseFile__ + // we needn't Flush here. It will be done in UDFCloseFileInfoChain() } // Update FileTimes & Attrs @@ -472,19 +510,17 @@ UDFCommonCleanup( if (UDFIsAStream(Fcb->FileInfo)) { - UDFNotifyReportChange(IrpContext, Vcb, + UDFNotifyFullReportChange(Vcb, Fcb, FILE_NOTIFY_CHANGE_STREAM_SIZE, - FILE_ACTION_MODIFIED_STREAM, - Ccb->Lcb, FileObject); + FILE_ACTION_MODIFIED_STREAM); } else { - UDFNotifyReportChange(IrpContext, Vcb, + UDFNotifyFullReportChange(Vcb, Fcb, FILE_NOTIFY_CHANGE_SIZE, - FILE_ACTION_MODIFIED, - Ccb->Lcb, FileObject); + FILE_ACTION_MODIFIED); } } @@ -509,19 +545,6 @@ UDFCommonCleanup( } } - // Flush FE (File Entry) to disk on last cleanup of non-deleted files. - // This prevents a race in UDFTeardownStructures where the FCB is removed - // from the FCB table (line ~497) before UDFFlushFile__ writes the FE to - // disk (line ~520). Without this, a concurrent open between those two - // points reads stale FE from disk with informationLength=0. - if (!Fcb->FcbCleanup && - !ForcedCleanUp && - !(Fcb->FcbState & UDF_FCB_DELETED) && - !(Vcb->VcbState & VCB_STATE_VOLUME_READ_ONLY) && - NextFileInfo) { - UDFFlushFile__(IrpContext, Vcb, NextFileInfo); - } - if (!(Fcb->FcbState & UDF_FCB_DIRECTORY) && ForcedCleanUp) { // flush system cache @@ -533,20 +556,23 @@ UDFCommonCleanup( } // release resources now. - UDFReleaseFcb(IrpContext, Fcb); + // they'll be acquired in UDFCloseFileInfoChain() + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); AcquiredFCB = FALSE; - if (AcquiredParentFCB && Fcb->FileInfo->ParentFile) { - UDFReleaseFcb(IrpContext, Fcb->FileInfo->ParentFile->Fcb); - AcquiredParentFCB = FALSE; + if (Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); + UDFReleaseResource(&Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource); + } else { + UDFReleaseResource(&Vcb->VcbResource); } - - // Close the target file's FileInfo - this decrements FileInfo->RefCount - // Parent FileInfo references are now handled by LCB mechanism in UDFTeardownStructures + AcquiredParentFCB = FALSE; + // close the chain ASSERT(AcquiredVcb); - if (NextFileInfo) { - UDFCloseFile__(IrpContext, Vcb, NextFileInfo); - } + RC2 = UDFCloseFileInfoChain(IrpContext, Vcb, NextFileInfo, Ccb->TreeLength, TRUE); + if (NT_SUCCESS(RC)) + RC = RC2; Ccb->Flags |= UDF_CCB_CLEANED; @@ -564,15 +590,21 @@ try_exit: NOTHING; } _SEH2_FINALLY { if (AcquiredFCB) { - UDFReleaseFcb(IrpContext, Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); } - if (AcquiredParentFCB && Fcb->FileInfo->ParentFile) { - UDFReleaseFcb(IrpContext, Fcb->FileInfo->ParentFile->Fcb); + 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 (AcquiredVcb) { - UDFReleaseVcb(IrpContext, Vcb); + UDFReleaseResource(&Vcb->VcbResource); AcquiredVcb = FALSE; } @@ -590,6 +622,85 @@ 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.c similarity index 70% rename from drivers/filesystems/udfs/close.cpp rename to drivers/filesystems/udfs/close.c index 88b74886c080c..367523a1f40d1 100644 --- a/drivers/filesystems/udfs/close.cpp +++ b/drivers/filesystems/udfs/close.c @@ -78,6 +78,7 @@ UDFCommonClose( PFCB Fcb = NULL; PCCB Ccb = NULL; PVCB Vcb = NULL; + ULONG i = 0; TYPE_OF_OPEN TypeOfOpen; ULONG UserReference = 0; BOOLEAN PotentialVcbTeardown = FALSE; @@ -120,6 +121,10 @@ UDFCommonClose( if (Irp) { UserReference = 1; + IrpContext->TreeLength = + i = Ccb->TreeLength; + // remember the number of incomplete Close requests + InterlockedIncrement((PLONG)&(Fcb->CcbCount)); // we can release CCB in any case UDFDeleteCcb(Ccb); FileObject->FsContext2 = NULL; @@ -132,6 +137,7 @@ UDFCommonClose( if ((Fcb->FcbState & UDF_FCB_DELAY_CLOSE) && (Vcb->VcbCondition == VcbMounted) && (Fcb->FcbState & UDF_FCB_DELETED) == 0 && + (Fcb->FcbState & UDF_FCB_POSTED_RENAME) == 0 && //(Fcb->FcbCondition == FcbGood) && (Fcb->FcbReference == 1) && ((TypeOfOpen == UserFileOpen) || @@ -146,34 +152,36 @@ UDFCommonClose( } else { - // Decrement reference counts - // These were incremented in UDFCompleteFcbOpen. + // Close request is near completion, Vcb is acquired. + // Now we can safely decrease CcbCount, because no Rename + // operation can run until Vcb release. + InterlockedDecrement((PLONG)&Fcb->CcbCount); - UDFLockVcb(IrpContext, Vcb); + InterlockedDecrement((PLONG)&Vcb->VcbReference); - Fcb->FcbReference--; - Fcb->FcbUserReference--; - Vcb->VcbReference--; - Vcb->VcbUserReference--; - - if (Fcb == Vcb->VolumeDasdFcb) { + if (!i || (Fcb == Fcb->Vcb->VolumeDasdFcb)) { AdPrint(("UDF: Closing volume\n")); AdPrint(("UDF: ReferenceCount: %x\n",Fcb->FcbReference)); - ASSERT(Fcb == Fcb->Vcb->VolumeDasdFcb); - UDFUnlockVcb(IrpContext, Vcb); - if (Vcb->VcbCleanup > 0) { + ASSERT(Fcb == Fcb->Vcb->VolumeDasdFcb); + InterlockedDecrement((PLONG)&Fcb->FcbReference); + ASSERT(Fcb); + try_return(RC = STATUS_SUCCESS); } + ASSERT(Fcb == Fcb->Vcb->VolumeDasdFcb); + InterlockedDecrement((PLONG)&Fcb->FcbReference); + ASSERT(Fcb); + if ((Vcb->VcbCleanup == 0) && (Vcb->VcbCondition != VcbMounted)) { // Possible dismount. Acquire CdData to synchronise with the remount path // before looking at the vcb condition again. - + UDFAcquireUdfData(IrpContext); if ((Vcb->VcbCleanup == 0) && @@ -200,20 +208,8 @@ UDFCommonClose( try_return(RC = STATUS_SUCCESS); } - // Release VcbMutex BEFORE TeardownStructures - UDFUnlockVcb(IrpContext, Vcb); - // try to clean up as long chain as it is possible - // 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); - } - } + UDFTeardownStructures(IrpContext, Fcb, i, NULL); } try_exit: NOTHING; @@ -236,6 +232,224 @@ 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, 0); + 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, 0); + } 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 @@ -406,6 +620,7 @@ Return Value: // Copy RealDevice for workque algorithms. + IrpContext->TreeLength = IrpContextLite->TreeLength; IrpContext->RealDevice = IrpContextLite->RealDevice; // The Vcb is found in the Fcb. @@ -507,9 +722,8 @@ 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, FALSE, &RemovedFcb); + UDFTeardownStructures(IrpContext, Fcb, IrpContext->TreeLength, &RemovedFcb); if (!RemovedFcb) { @@ -776,6 +990,7 @@ 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.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 98% rename from drivers/filesystems/udfs/dircntrl.cpp rename to drivers/filesystems/udfs/dircntrl.c index c9b2f7d62cf64..854597afbdb6b 100644 --- a/drivers/filesystems/udfs/dircntrl.cpp +++ b/drivers/filesystems/udfs/dircntrl.c @@ -413,21 +413,16 @@ 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 we already found an entry then just exit. - - if (CurrentOffset != 0) { + // 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) { try_return(RC = STATUS_SUCCESS); } - - // Reduce the FileNameBytes to just fit in the buffer. - - FileNameBytes = BytesRemainingInBuffer - BaseLength; + // strange policy... 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/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 80% rename from drivers/filesystems/udfs/fileinfo.cpp rename to drivers/filesystems/udfs/fileinfo.c index 92fcd88eaf98e..d527a8902ac7c 100644 --- a/drivers/filesystems/udfs/fileinfo.cpp +++ b/drivers/filesystems/udfs/fileinfo.c @@ -229,6 +229,8 @@ UDFCommonSetInfo( PCCB Ccb = NULL; PVCB Vcb = NULL; BOOLEAN MainResourceAcquired = FALSE; + BOOLEAN ParentResourceAcquired = FALSE; + BOOLEAN PagingIoResourceAcquired = FALSE; PVOID Buffer = NULL; FILE_INFORMATION_CLASS FunctionalityRequested; BOOLEAN CanWait = FALSE; @@ -300,21 +302,73 @@ UDFCommonSetInfo( VcbAcquired = TRUE; } - // - // Acquire FcbResource exclusive for all operations except - // rename/link (those acquire resources in their own functions). - // - if ((FunctionalityRequested != FileRenameInformation) && + // Rename, and link operations require creation of a directory + // entry and possibly deletion of another directory entry. + + // Unless this is an operation on a page file, we should go ahead and + // acquire the FCB exclusively at this time. Note that we will pretty + // much block out anything being done to the FCB from this point on. + if ((FunctionalityRequested != FilePositionInformation) && + (FunctionalityRequested != FileRenameInformation) && (FunctionalityRequested != FileLinkInformation)) { + // Acquire the Parent & Main Resources exclusive. + if (Fcb->FileInfo->ParentFile) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); + if (!UDFAcquireResourceExclusive(&Fcb->ParentFcb->FcbNonpaged->FcbResource, CanWait)) { + PostRequest = TRUE; + try_return(Status = STATUS_PENDING); + } + ParentResourceAcquired = TRUE; + } + + if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, CanWait)) { + PostRequest = TRUE; + try_return(Status = STATUS_PENDING); + } + MainResourceAcquired = TRUE; - UDFAcquireFcbExclusive(IrpContext, Fcb, FALSE); + if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbPagingIoResource, CanWait)) { + PostRequest = TRUE; + try_return(Status = STATUS_PENDING); + } + PagingIoResourceAcquired = TRUE; + } else + // The only operations that could conceivably proceed from this point + // on are paging-IO read/write operations. For delete, link (rename), + // set allocation size, and set EOF, should also acquire the paging-IO + // resource, thereby synchronizing with paging-IO requests. + if ((FunctionalityRequested == FileDispositionInformation) || + (FunctionalityRequested == FileAllocationInformation) || + (FunctionalityRequested == FileEndOfFileInformation)) { + + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + if (!UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, CanWait)) { + PostRequest = TRUE; + try_return(Status = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + // Acquire the PagingResource exclusive. + if (!UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbPagingIoResource, CanWait)) { + PostRequest = TRUE; + try_return(Status = STATUS_PENDING); + } + PagingIoResourceAcquired = TRUE; + } else if ((FunctionalityRequested != FileRenameInformation) && + (FunctionalityRequested != FileLinkInformation)) { + // Acquire the MainResource shared. + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + if (!UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, CanWait)) { + PostRequest = TRUE; + try_return(Status = STATUS_PENDING); + } MainResourceAcquired = TRUE; } // Do whatever the caller asked us to do switch (FunctionalityRequested) { case FileBasicInformation: - Status = UDFSetBasicInformation(IrpContext, Fcb, Ccb, FileObject, (PFILE_BASIC_INFORMATION)Buffer); + Status = UDFSetBasicInformation(Fcb, Ccb, FileObject, (PFILE_BASIC_INFORMATION)Buffer); break; case FilePositionInformation: { // Check if no intermediate buffering has been specified. @@ -372,11 +426,22 @@ try_exit: NOTHING; } _SEH2_FINALLY { + if (PagingIoResourceAcquired) { + UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); + PagingIoResourceAcquired = FALSE; + } + if (MainResourceAcquired) { - UDFReleaseFcb(IrpContext, Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); MainResourceAcquired = FALSE; } + if (ParentResourceAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb); + UDFReleaseResource(&(Fcb->ParentFcb->FcbNonpaged->FcbResource)); + ParentResourceAcquired = FALSE; + } + if (VcbAcquired) { UDFReleaseVcb(IrpContext, Vcb); @@ -397,12 +462,14 @@ try_exit: NOTHING; if (!_SEH2_AbnormalTermination()) { +#ifdef UDF_DELAYED_CLOSE if (NT_SUCCESS(Status)) { if (FunctionalityRequested == FileDispositionInformation) { UDFFspClose(Vcb); } } +#endif //UDF_DELAYED_CLOSE UDFCompleteRequest(IrpContext, Irp, Status); } @@ -813,7 +880,7 @@ UDFGetFileStreamInformation( PUDF_FILE_INFO FileInfo; PUDF_FILE_INFO SDirInfo; PVCB Vcb; - + BOOLEAN FcbAcquired = FALSE; uint_di i; ULONG CurrentSize; PDIR_INDEX_HDR hSDirIndex; @@ -831,6 +898,9 @@ UDFGetFileStreamInformation( _SEH2_TRY { + UDFAcquireResourceExclusive(&(Fcb->Vcb->FileIdResource), TRUE); + FcbAcquired = TRUE; + FileInfo = Fcb->FileInfo; if (!FileInfo) { AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); @@ -919,6 +989,8 @@ UDFGetFileStreamInformation( try_exit: NOTHING; } _SEH2_FINALLY { + if (FcbAcquired) + UDFReleaseResource(&(Fcb->Vcb->FileIdResource)); if (NTFileInfo) MyFreePool__(NTFileInfo); } _SEH2_END; @@ -931,7 +1003,6 @@ try_exit: NOTHING; */ NTSTATUS UDFSetBasicInformation( - IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCCB Ccb, IN PFILE_OBJECT FileObject, @@ -1070,11 +1141,10 @@ UDFSetBasicInformation( if (NotifyFilter) { - UDFNotifyReportChange(IrpContext, Fcb->Vcb, + UDFNotifyFullReportChange(Fcb->Vcb, Fcb, NotifyFilter, - FILE_ACTION_MODIFIED, - Ccb->Lcb, FileObject); + FILE_ACTION_MODIFIED); UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, NULL); Fcb->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; @@ -1124,7 +1194,7 @@ UDFMarkStreamsForDeletion( if (SDirInfo->Fcb) { UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb); - UDFAcquireFcbExclusive(IrpContext, SDirInfo->Fcb, TRUE); + UDFAcquireResourceExclusive(&SDirInfo->Fcb->FcbNonpaged->FcbResource, TRUE); SDirAcq = TRUE; } @@ -1172,7 +1242,7 @@ UDFMarkStreamsForDeletion( if (FileInfo->Fcb) { UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb); - UDFAcquireFcbExclusive(IrpContext, FileInfo->Fcb, TRUE); + UDFAcquireResourceExclusive(&FileInfo->Fcb->FcbNonpaged->FcbResource, TRUE); StrAcq = TRUE; #ifndef UDF_ALLOW_LINKS_TO_STREAMS @@ -1213,7 +1283,8 @@ UDFMarkStreamsForDeletion( MyFreePool__(FileInfo); } if (StrAcq) { - UDFReleaseFcb(IrpContext, FileInfo->Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb); + UDFReleaseResource(&FileInfo->Fcb->FcbNonpaged->FcbResource); StrAcq = FALSE; } } @@ -1267,14 +1338,16 @@ try_exit: NOTHING; MyFreePool__(FileInfo); } if (StrAcq) { - UDFReleaseFcb(IrpContext, FileInfo->Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb); + UDFReleaseResource(&FileInfo->Fcb->FcbNonpaged->FcbResource); } SDirInfo = NULL; } if (SDirInfo) { UDFCloseFile__(IrpContext, Vcb, SDirInfo); if (SDirAcq) { - UDFReleaseFcb(IrpContext, SDirInfo->Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb); + UDFReleaseResource(&SDirInfo->Fcb->FcbNonpaged->FcbResource); } if (UDFCleanUpFile__(Vcb, SDirInfo)) { MyFreePool__(SDirInfo); @@ -1548,15 +1621,13 @@ UDFSetAllocationInfo( // Inform any pending IRPs (notify change directory). if (UDFIsAStream(Fcb->FileInfo)) { - UDFNotifyReportChange(IrpContext, Vcb, Fcb, + UDFNotifyFullReportChange(Vcb, Fcb, FILE_NOTIFY_CHANGE_STREAM_SIZE, - FILE_ACTION_MODIFIED_STREAM, - Ccb->Lcb, FileObject); + FILE_ACTION_MODIFIED_STREAM); } else { - UDFNotifyReportChange(IrpContext, Vcb, Fcb, + UDFNotifyFullReportChange(Vcb, Fcb, FILE_NOTIFY_CHANGE_SIZE, - FILE_ACTION_MODIFIED, - Ccb->Lcb, FileObject); + FILE_ACTION_MODIFIED); } } @@ -1749,7 +1820,7 @@ UDFSetEndOfFileInfo( // NT expects AllocationSize to be decreased on Close only Fcb->Header.AllocationSize.QuadPart = PtrBuffer->EndOfFile.QuadPart; - +// UDFSysGetAllocSize(Vcb, UDFGetFileSize(Fcb->FileInfo)); UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &(PtrBuffer->EndOfFile.QuadPart)); } @@ -1793,15 +1864,13 @@ UDFSetEndOfFileInfo( // Inform any pending IRPs (notify change directory). if (UDFIsAStream(Fcb->FileInfo)) { - UDFNotifyReportChange( IrpContext, Vcb, Fcb, + UDFNotifyFullReportChange( Vcb, Fcb, FILE_NOTIFY_CHANGE_STREAM_SIZE, - FILE_ACTION_MODIFIED_STREAM, - Ccb->Lcb, FileObject); + FILE_ACTION_MODIFIED_STREAM); } else { - UDFNotifyReportChange( IrpContext, Vcb, Fcb, + UDFNotifyFullReportChange( Vcb, Fcb, FILE_NOTIFY_CHANGE_SIZE, - FILE_ACTION_MODIFIED, - Ccb->Lcb, FileObject); + FILE_ACTION_MODIFIED); } } @@ -1823,7 +1892,6 @@ try_exit: NOTHING; NTSTATUS UDFPrepareForRenameMoveLink( - IN PIRP_CONTEXT IrpContext, PVCB Vcb, PBOOLEAN SingleDir, PBOOLEAN AcquiredDir1, @@ -1840,7 +1908,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 - // cleanup operations or UDFTeardownStructures() + // CleanUpFcbChain() or UDFCloseFileInfoChain() InterlockedIncrement((PLONG)&Vcb->VcbReference); @@ -1852,74 +1920,17 @@ UDFPrepareForRenameMoveLink( } else { InterlockedDecrement((PLONG)&Vcb->VcbReference); - // Child-first lock ordering - // File1 (child) first, Dir1 (parent) second - UDF_CHECK_PAGING_IO_RESOURCE(File1->Fcb); - UDFAcquireFcbExclusive(IrpContext, File1->Fcb, TRUE); - (*AcquiredFcb1) = TRUE; - UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb); - UDFAcquireFcbExclusive(IrpContext, Dir1->Fcb, TRUE); + UDFAcquireResourceExclusive(&Dir1->Fcb->FcbNonpaged->FcbResource, TRUE); (*AcquiredDir1) = TRUE; + + UDF_CHECK_PAGING_IO_RESOURCE(File1->Fcb); + UDFAcquireResourceExclusive(&File1->Fcb->FcbNonpaged->FcbResource, TRUE); + (*AcquiredFcb1) = TRUE; } return STATUS_SUCCESS; } // end UDFPrepareForRenameMoveLink() -/* - Check if a directory subtree has any open handles (FcbCleanup != 0). - Iterative depth-first walk via ChildLcbQueue — no recursion, kernel-safe. - Returns TRUE if subtree is clean (no open handles), FALSE otherwise. -*/ -BOOLEAN -UDFCheckDirOpenHandles( - IN PFCB DirectoryFcb - ) -{ - PFCB CheckFcb = DirectoryFcb; - PLIST_ENTRY CheckLink = CheckFcb->ChildLcbQueue.Flink; - - while (CheckFcb != NULL) { - - // Process all children at current level - while (CheckLink != &CheckFcb->ChildLcbQueue) { - PLCB ChildLcb = CONTAINING_RECORD(CheckLink, LCB, ParentFcbLinks); - PFCB ChildFcb = ChildLcb->ChildFcb; - CheckLink = CheckLink->Flink; - - if (!ChildFcb) continue; - - if (ChildFcb->FcbCleanup != 0) { - return FALSE; - } - - // If child is a directory with children, descend into it - if ((ChildFcb->FcbState & UDF_FCB_DIRECTORY) && - !IsListEmpty(&ChildFcb->ChildLcbQueue)) { - CheckFcb = ChildFcb; - CheckLink = CheckFcb->ChildLcbQueue.Flink; - } - } - - // Back to root — done - if (CheckFcb == DirectoryFcb) break; - - // Ascend: find our LCB in parent, advance to next sibling - PLIST_ENTRY ParentLink; - for (ParentLink = CheckFcb->ParentLcbQueue.Flink; - ParentLink != &CheckFcb->ParentLcbQueue; - ParentLink = ParentLink->Flink) { - PLCB ParentLcb = CONTAINING_RECORD(ParentLink, LCB, ChildFcbLinks); - if (ParentLcb->ParentFcb) { - CheckFcb = ParentLcb->ParentFcb; - CheckLink = ParentLcb->ParentFcbLinks.Flink; - break; - } - } - } - - return TRUE; -} - /* Rename or move file */ @@ -1945,30 +1956,27 @@ UDFSetRenameInfo( BOOLEAN IgnoreCase; BOOLEAN ParentFcbAcquired = FALSE; BOOLEAN TargetParentFcbAcquired = FALSE; - BOOLEAN StaleFcbAcquired = FALSE; - PFCB StaleFcb = NULL; - PLCB StaleLcb = NULL; - BOOLEAN NeedRemovePrefix = FALSE; BOOLEAN SingleDir = TRUE; + BOOLEAN UseClose; 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; LocalPath.Buffer = NULL; - // Make sure we can wait for this request. - - if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { - - UDFRaiseStatus(IrpContext, STATUS_CANT_WAIT); - } - _SEH2_TRY { - // do we try to rename Volume ? if (ParentFcb == NULL) { @@ -1997,8 +2005,6 @@ UDFSetRenameInfo( if (!TargetFileObject) { TargetDirInfo = FileInfo->ParentFile; - // For streams or same-dir rename, target FCB is the parent - TargetFcb = TargetDirInfo->Fcb; } else { @@ -2011,24 +2017,7 @@ UDFSetRenameInfo( try_return (RC = STATUS_INVALID_PARAMETER); } - // Check if TargetFcb is a directory or a file - // TargetFileObject should be a directory. - // But if it points to a file (e.g., existing file to be replaced), - // we need to use its parent directory for correct SingleDir calculation - - if (UDFIsADirectory(TargetFcb->FileInfo)) { - - TargetDirInfo = TargetFcb->FileInfo; - - } else { - - // TargetFileObject points to a file, use its parent directory - TargetDirInfo = TargetFcb->FileInfo->ParentFile; - - if (!TargetDirInfo) { - try_return (RC = STATUS_INVALID_PARAMETER); - } - } + TargetDirInfo = TargetFcb->FileInfo; } // invalid destination ? @@ -2042,290 +2031,289 @@ UDFSetRenameInfo( } } - // Parse NewName before acquiring locks to enable early-out optimizations - if (!TargetFileObject) { - // Make sure the name is of legal length. - if (PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) { - try_return(RC = STATUS_OBJECT_NAME_INVALID); - } - NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength); - NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName); - } else { - // TargetFileObject->FileName is set up by UDFCommonCreate for - // SL_OPEN_TARGET_DIRECTORY: - // Length = parent directory path (trimmed to last '\') - // MaximumLength = full original path (parent + '\' + filename) - // Extract the filename component starting after Length. - USHORT FileNameStart = TargetFileObject->FileName.Length; - - if (FileNameStart < TargetFileObject->FileName.MaximumLength && - TargetFileObject->FileName.Buffer[FileNameStart / sizeof(WCHAR)] == L'\\') { - FileNameStart += sizeof(WCHAR); - } - - NewName.Length = TargetFileObject->FileName.MaximumLength - FileNameStart; - NewName.MaximumLength = NewName.Length; - NewName.Buffer = (PWCHAR)((PCHAR)TargetFileObject->FileName.Buffer + FileNameStart); - } - - IgnoreCase = FlagOn(Ccb->Flags, CCB_FLAG_IGNORE_CASE); - SingleDir = (TargetDirInfo->Fcb == ParentFcb); - // Self-rename check: if same directory and same name → no-op - if (SingleDir && !ReplaceIfExists && Ccb->Lcb) { - if (FsRtlAreNamesEqual(&NewName, &Ccb->Lcb->FileName, IgnoreCase, NULL)) { - try_return(RC = STATUS_SUCCESS); - } - } - - // - // Always acquire source parent directory — needed for splay tree - // modifications in UDFRenameMovePrefix and UDFRemovePrefix. - // if (SingleDir) { - UDFAcquireFcbExclusive(IrpContext, ParentFcb, FALSE); - ParentFcbAcquired = TRUE; + //TODO: FsRtlAreNamesEqual - } else { + // Check ReplaceIfExists for same directory + if (ReplaceIfExists) { - // Cross-directory rename: acquire both parents. - // Use address ordering to prevent ABBA deadlock. - if ((ULONG_PTR)ParentFcb < (ULONG_PTR)TargetDirInfo->Fcb) { - UDFAcquireFcbExclusive(IrpContext, ParentFcb, FALSE); - ParentFcbAcquired = TRUE; - UDFAcquireFcbExclusive(IrpContext, TargetDirInfo->Fcb, FALSE); - TargetParentFcbAcquired = TRUE; - } else if (ParentFcb != TargetDirInfo->Fcb) { - UDFAcquireFcbExclusive(IrpContext, TargetDirInfo->Fcb, FALSE); - TargetParentFcbAcquired = TRUE; - UDFAcquireFcbExclusive(IrpContext, ParentFcb, FALSE); - ParentFcbAcquired = TRUE; - } else { - // Same directory (shouldn't happen for !SingleDir, but handle gracefully) UDFAcquireFcbExclusive(IrpContext, ParentFcb, FALSE); ParentFcbAcquired = TRUE; } - } - // check if the source file is in use - if (Fcb->FcbCleanup > 1) { + } else { - try_return (RC = STATUS_ACCESS_DENIED); + UDFAcquireFcbExclusive(IrpContext, TargetDirInfo->Fcb, FALSE); + TargetParentFcbAcquired = TRUE; } + // check if the source file is in use + if (Fcb->FcbCleanup > 1) + try_return (RC = STATUS_ACCESS_DENIED); ASSERT(Fcb->FcbCleanup); ASSERT(!Fcb->IrpContextLite); - if (Fcb->IrpContextLite) { try_return (RC = STATUS_ACCESS_DENIED); } - - // For directories: check that no descendant has open handles. - if ((Fcb->FcbState & UDF_FCB_DIRECTORY) && - !UDFCheckDirOpenHandles(Fcb)) { - try_return (RC = STATUS_ACCESS_DENIED); + // Check if we have parallel/pending Close threads + if (Fcb->CcbCount && !SingleDir) { + // if this is the 1st attempt, we'll try to + // synchronize with Close requests + // otherwise fail request + RC = STATUS_ACCESS_DENIED; +post_rename: + if (Fcb->FcbState & UDF_FCB_POSTED_RENAME) { + Fcb->FcbState &= ~UDF_FCB_POSTED_RENAME; + try_return (RC); + } + Fcb->FcbState |= UDF_FCB_POSTED_RENAME; + try_return (RC = STATUS_PENDING); } - // Check if renaming to stream name - only allowed for streams - if (!TargetFileObject && NewName.Length >= sizeof(WCHAR) && NewName.Buffer[0] == L':') { - - if (!UDFIsAStream(FileInfo)) { - + if (!TargetFileObject) { + // Make sure the name is of legal length. + if (PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) { try_return(RC = STATUS_OBJECT_NAME_INVALID); } + NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength); + NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName); + } else { + // This name is by definition legal. + NewName = *((PUNICODE_STRING)&TargetFileObject->FileName); } - // UDFDoesOSAllowFileToBeMoved__ (= UDFDoesOSAllowFileToBeUnlinked__) - // checks DirNdx->FileInfo != NULL for each child — blocks if any - // child has a cached FileInfo structure, even with FcbCleanup=0 - // (no user handles). This is too strict for rename/move where file - // data stays intact. The subtree is already validated above via - // UDFCheckDirOpenHandles which checks FcbCleanup (user handles). - { - - // Note: With LCB model, FcbReference may not always be >= RefCount - // for directories opened internally during path traversal - - // Pre-validate target for ReplaceIfExists: look up the target name - // in the directory index, then search for its LCB by FCB pointer - // (not by name). This correctly handles case-insensitive matches, - // short name aliases, and avoids string comparison overhead. - if (ReplaceIfExists) { - - PFCB TargetParentFcb = TargetDirInfo->Fcb; - - if (TargetParentFcb) { - - // Look up target name in directory index - DIR_ENUM_CONTEXT TargetDirContext; - NTSTATUS FindStatus = UDFFindDirEntry(Vcb, TargetDirInfo, - &NewName, IgnoreCase, - TRUE, &TargetDirContext); - - if (NT_SUCCESS(FindStatus) && TargetDirContext.DirNdx) { - - PDIR_INDEX_ITEM FoundDirNdx = TargetDirContext.DirNdx; - - // Cannot replace a directory - if (FoundDirNdx->FileCharacteristics & FILE_DIRECTORY) { - - try_return(RC = STATUS_OBJECT_NAME_COLLISION); - } - - // Skip stale LCB logic for self-rename (e.g. case change) - BOOLEAN IsSelfRename = (SingleDir && - FoundDirNdx->FileInfo == FileInfo); - - if (!IsSelfRename) { - - // If target was previously opened, find its LCB - // by matching ChildFcb pointer - if (FoundDirNdx->FileInfo && - FoundDirNdx->FileInfo->Fcb) { - - PFCB TargetFileFcb = FoundDirNdx->FileInfo->Fcb; - - PLIST_ENTRY Link; - for (Link = TargetParentFcb->ChildLcbQueue.Flink; - Link != &TargetParentFcb->ChildLcbQueue; - Link = Link->Flink) { - PLCB TestLcb = CONTAINING_RECORD(Link, LCB, ParentFcbLinks); - if (TestLcb != Ccb->Lcb && - !(TestLcb->Flags & UDF_LCB_FLAG_LINK_DELETED) && - TestLcb->ChildFcb == TargetFileFcb) { - StaleLcb = TestLcb; - break; - } - } - } - // If FileInfo is NULL (never opened), no FCB/LCB exists. - // UDFRenameMoveFile__ will handle the on-disk deletion. - - if (StaleLcb) { - - StaleFcb = StaleLcb->ChildFcb; - - // Acquire target FCB to serialize with cleanup - if (StaleFcb) { - UDF_CHECK_PAGING_IO_RESOURCE(StaleFcb); - UDFAcquireFcbExclusive(IrpContext, StaleFcb, TRUE); - StaleFcbAcquired = TRUE; - } - - // Cannot remove LCB that still has open references. - if (StaleLcb->Reference != 0) { + IgnoreCase = FlagOn(Ccb->Flags, CCB_FLAG_IGNORE_CASE); - try_return(RC = STATUS_ACCESS_DENIED); - } - } - } - } - // If target not found in directory, proceed normally. - // UDFRenameMoveFile__ will create the new entry. + if (UDFIsDirOpened__(FileInfo)) { + // We can't rename file because of unclean references. + // UDF_INFO package can safely do it, but NT side cannot. + // In this case NT requires STATUS_OBJECT_NAME_COLLISION + // rather than STATUS_ACCESS_DENIED + if (NT_SUCCESS(UDFFindFile__(Vcb, IgnoreCase, &NewName, TargetDirInfo))) + try_return(RC = STATUS_OBJECT_NAME_COLLISION); + try_return (RC = STATUS_ACCESS_DENIED); + } else { + // Last check before Moving. + // We can't move across Dir referenced (even internally) file + if (!SingleDir) { + RC = UDFDoesOSAllowFileToBeMoved__(FileInfo); + if (!NT_SUCCESS(RC)) { +// try_return(RC); + goto post_rename; } } - // - // Pre-rename: mark stale LCB as deleted so concurrent - // create lookups won't find it during disk operations. - // Purge cache before modifying directory. - // - if (StaleLcb) { - StaleLcb->Flags |= UDF_LCB_FLAG_LINK_DELETED; - - // Remove from splay trees immediately so the renamed LCB - // can be inserted with the same name without duplicate conflict. - if (StaleLcb->ParentFcb) { - UdfRemoveNameLinks(StaleLcb->ParentFcb, StaleLcb); - } - - // Purge cache for target before disk operations - if (StaleFcb && StaleFcb->FcbNonpaged) { - if (StaleFcb->FcbNonpaged->SegmentObject.DataSectionObject || - StaleFcb->FcbNonpaged->SegmentObject.ImageSectionObject) { - MmPrint((" CcPurgeCacheSection() stale target\n")); - CcPurgeCacheSection(&StaleFcb->FcbNonpaged->SegmentObject, NULL, 0, FALSE); - } - } - } + ASSERT(Fcb->FcbReference >= FileInfo->RefCount); + ASSERT(DirInfo->Fcb->FcbReference >= DirInfo->RefCount); + ASSERT(TargetDirInfo->Fcb->FcbReference >= TargetDirInfo->RefCount); RC = UDFRenameMoveFile__(IrpContext, Vcb, IgnoreCase, &ReplaceIfExists, &NewName, DirInfo, TargetDirInfo, FileInfo); } - if (!NT_SUCCESS(RC)) { - // Rename failed — restore original state if target was not - // actually deleted on disk. - if (StaleLcb && !(StaleFcb && (StaleFcb->FcbState & UDF_FCB_DELETED))) { - ClearFlag(StaleLcb->Flags, UDF_LCB_FLAG_LINK_DELETED); - // Re-insert into splay trees (was removed before rename attempt) - if (StaleLcb->ParentFcb) { - UdfInsertNameLinks(StaleLcb->ParentFcb, StaleLcb); - } - } + if (!NT_SUCCESS(RC)) try_return (RC); - } - - // - // Rename succeeded — set NeedRemovePrefix so the finally - // handler removes the stale LCB from queues. - // - if (StaleLcb) { - NeedRemovePrefix = TRUE; - if (StaleFcb) { - StaleFcb->FcbState |= UDF_FCB_DELETED; - } - } ASSERT(UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index)->FileInfo == FileInfo); - { - ULONG Filter = UDFIsADirectory(FileInfo) - ? FILE_NOTIFY_CHANGE_DIR_NAME - : FILE_NOTIFY_CHANGE_FILE_NAME; + RC = MyCloneUnicodeString(&LocalPath, (TargetDirInfo->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) ? + &UdfData.UnicodeStrRoot : + &TargetDirInfo->Fcb->FCBName->ObjectName); + 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) { + RC = MyAppendUnicodeToString(&LocalPath, L"\\"); + if (!NT_SUCCESS(RC)) try_return (RC); + } + RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USREN_TAG); + if (!NT_SUCCESS(RC)) try_return (RC); - // Step 1: Notify OLD location (LCB still points to old parent) - // Use FileObject->FileName — stable path independent of LCB chain - if (SingleDir && !ReplaceIfExists) { - UDFNotifyReportChange(IrpContext, Vcb, Fcb, Filter, FILE_ACTION_RENAMED_OLD_NAME, - Ccb->Lcb, FileObject); + // Set Archive bit + DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index); + if (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT) { + Attr = UDFAttributesToNT(DirNdx, FileInfo->Dloc->FileEntry); + if (!(Attr & FILE_ATTRIBUTE_ARCHIVE)) + UDFAttributesToUDF(DirNdx, FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); + } + // Update Parent Objects (mark 'em as modified) + if (Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) { + if (TargetFileObject) { + TargetFileObject->Flags |= FO_FILE_MODIFIED; + if (!ReplaceIfExists) + TargetFileObject->Flags |= FO_FILE_SIZE_CHANGED; + } + } + // report changes + if (SingleDir && !ReplaceIfExists) { + UDFNotifyFullReportChange( Vcb, FileInfo->Fcb, + UDFIsADirectory(FileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_RENAMED_OLD_NAME); +/* UDFNotifyFullReportChange( Vcb, File2, + UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_RENAMED_NEW_NAME );*/ + FsRtlNotifyFullReportChange( Vcb->NotifySync, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((TargetDirInfo->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) ? 0 : TargetDirInfo->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + UDFIsADirectory(FileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_RENAMED_NEW_NAME, + NULL); + } else { + UDFNotifyFullReportChange( Vcb, FileInfo->Fcb, + UDFIsADirectory(FileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_REMOVED); + if (ReplaceIfExists) { +/* UDFNotifyFullReportChange( Vcb, File2, + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_EA, + FILE_ACTION_MODIFIED );*/ + FsRtlNotifyFullReportChange( Vcb->NotifySync, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((TargetDirInfo->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) ? + 0 : TargetDirInfo->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_EA, + FILE_ACTION_MODIFIED, + NULL); } else { - UDFNotifyReportChange(IrpContext, Vcb, Fcb, Filter, FILE_ACTION_REMOVED, - Ccb->Lcb, FileObject); +/* UDFNotifyFullReportChange( Vcb, File2, + UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED );*/ + FsRtlNotifyFullReportChange( Vcb->NotifySync, &(Vcb->NextNotifyIRP), + (PSTRING)&LocalPath, + ((TargetDirInfo->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) ? + 0 : TargetDirInfo->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), + NULL,NULL, + UDFIsADirectory(FileInfo) ? + FILE_NOTIFY_CHANGE_DIR_NAME : + FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_ADDED, + NULL); } + } - // Step 2: Move LCB to new parent and update name - if (Ccb->Lcb) { - RC = UDFRenameMovePrefix(IrpContext, Ccb->Lcb, &NewName, - SingleDir ? NULL : TargetDirInfo->Fcb); - if (!NT_SUCCESS(RC)) { - try_return (RC); + // this will prevent structutre release before call to + // UDFCleanUpFcbChain() + InterlockedIncrement((PLONG)&DirInfo->Fcb->FcbReference); + ASSERT(DirInfo->Fcb->FcbReference >= DirInfo->RefCount); + + // Look through Ccb list & decrement OpenHandleCounter(s) + // acquire CcbList + 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; } - } - // Step 3: Update FCB parent pointer for cross-directory rename - if (!SingleDir) { - Fcb->ParentFcb = TargetDirInfo->Fcb; + if (CurCcb->TreeLength > 1) { + DirRefCount++; + if (UseClose) + FileInfoRefCount++; + CurCcb->TreeLength = 2; +#ifdef UDF_DBG + } else { + BrutePoint(); +#endif // UDF_DBG + } } - - // Step 4: Notify NEW location (LCB now points to new parent) - // After UDFRenameMovePrefix, LCB has new name — pass it explicitly - if (SingleDir && !ReplaceIfExists) { - UDFNotifyReportChange(IrpContext, Vcb, Fcb, Filter, FILE_ACTION_RENAMED_NEW_NAME, - Ccb->Lcb, NULL); - } else if (ReplaceIfExists) { - UDFNotifyReportChange(IrpContext, Vcb, Fcb, - FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | - FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA, - FILE_ACTION_MODIFIED, Ccb->Lcb, NULL); - } else { - UDFNotifyReportChange(IrpContext, Vcb, Fcb, Filter, FILE_ACTION_ADDED, - Ccb->Lcb, NULL); + UDFReleaseResource(&Fcb->FcbNonpaged->CcbListResource); + + ASSERT(DirRefCount >= FileInfoRefCount); + // update counters & pointers + 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) { + MyFreePool__(Fcb->FCBName->ObjectName.Buffer); + } + UDFReleaseObjectName(Fcb->FCBName); + } + Fcb->FCBName = UDFAllocateObjectName(); + if (!(Fcb->FCBName)) { +insuf_res: + BrutePoint(); + // UDFCleanUpFcbChain()... + if (TargetParentFcbAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(TargetDirInfo->Fcb); + UDFReleaseResource(&TargetDirInfo->Fcb->FcbNonpaged->FcbResource); + TargetParentFcbAcquired = FALSE; } + if (ParentFcbAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(DirInfo->Fcb); + UDFReleaseResource(&DirInfo->Fcb->FcbNonpaged->FcbResource); + ParentFcbAcquired = FALSE; + } + UDFTeardownStructures(IrpContext, DirInfo->Fcb, 1, NULL); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } - ASSERT(TargetDirInfo->RefCount || SingleDir); + RC = MyCloneUnicodeString(&Fcb->FCBName->ObjectName, &TargetFcb->FCBName->ObjectName); + if (!NT_SUCCESS(RC)) + goto insuf_res; +/* RC = MyAppendUnicodeStringToString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName)); + if (!NT_SUCCESS(RC)) + 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) { + RC = MyAppendUnicodeToString(&Fcb->FCBName->ObjectName, L"\\"); + if (!NT_SUCCESS(RC)) + goto insuf_res; + } + RC = MyAppendUnicodeStringToStringTag(&Fcb->FCBName->ObjectName, &NewName, MEM_USREN2_TAG); + 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; @@ -2333,38 +2321,23 @@ try_exit: NOTHING; } _SEH2_FINALLY { - // - // Remove stale target LCB from queues (deferred here from - // success path). NeedRemovePrefix is only set after rename - // succeeded, so StaleFcb is already marked UDF_FCB_DELETED. - // Guard against concurrent teardown that may have already - // removed this LCB by checking ParentFcbLinks. - // - if (NeedRemovePrefix) { - if (StaleLcb->ParentFcbLinks.Flink != &StaleLcb->ParentFcbLinks) { - UDFRemovePrefix(IrpContext, StaleLcb); - } - if (StaleFcb) { - UDFLockFcbTable(IrpContext, Vcb); - UDFLockVcb(IrpContext, Vcb); - { - struct { FILE_ID FileId; PFCB Fcb; } _Key; - _Key.FileId = StaleFcb->FileId; - RtlDeleteElementGenericTable(&Vcb->FcbTable, &_Key); - } - UDFUnlockVcb(IrpContext, Vcb); - UDFUnlockFcbTable(IrpContext, Vcb); - } - } - if (StaleFcbAcquired) { - UDFReleaseFcb(IrpContext, StaleFcb); - } if (TargetParentFcbAcquired) { - UDFReleaseFcb(IrpContext, TargetDirInfo->Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(TargetDirInfo->Fcb); + UDFReleaseResource(&TargetDirInfo->Fcb->FcbNonpaged->FcbResource); } if (ParentFcbAcquired) { - UDFReleaseFcb(IrpContext, DirInfo->Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(DirInfo->Fcb); + UDFReleaseResource(&DirInfo->Fcb->FcbNonpaged->FcbResource); + } + // 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); } + if (LocalPath.Buffer) { MyFreePool__(LocalPath.Buffer); } @@ -2421,10 +2394,6 @@ UDFStoreFileId( LONG i; NTSTATUS RC = STATUS_SUCCESS; - // NOTE: This function appears to be unused legacy code (no callers found). - // TODO: If ever used, need to add IrpContext parameter and use UDFBuildFullPathFromLcb - // to build the path from LCB instead of FCBName (which no longer exists). - if ((i = UDFFindFileId(Vcb, FileId)) == (-1)) { if ((i = UDFFindFreeFileId(Vcb, FileId)) == (-1)) return STATUS_INSUFFICIENT_RESOURCES; } else { @@ -2432,11 +2401,10 @@ UDFStoreFileId( } Vcb->FileIdCache[i].Id = FileId; Vcb->FileIdCache[i].IgnoreCase = BooleanFlagOn(Ccb->Flags, CCB_FLAG_IGNORE_CASE); - - // TODO: Build path from LCB using UDFBuildFullPathFromLcb (requires IrpContext) - // For now, return error if this function is ever called - RC = STATUS_NOT_IMPLEMENTED; - + RC = MyCloneUnicodeString(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName)); +/* if (NT_SUCCESS(RC)) { + RC = MyAppendUnicodeStringToStringTag(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName), MEM_USFIDC_TAG); + }*/ return RC; } // end UDFStoreFileId() @@ -2573,7 +2541,7 @@ UDFHardLink( /* if (UDFIsAStreamDir(Dir2)) try_return (RC = STATUS_ACCESS_DENIED);*/ - RC = UDFPrepareForRenameMoveLink(IrpContext, Vcb, + RC = UDFPrepareForRenameMoveLink(Vcb, &SingleDir, &AcquiredDir1, &AcquiredFcb1, Ccb1, File1, @@ -2591,29 +2559,15 @@ UDFHardLink( NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength); NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName); } else { - // After OpenTargetDirectory, FileName is split: - // Length = parent directory path (trimmed) - // MaximumLength = full original path (including target name) - USHORT FullLength = DirObject2->FileName.MaximumLength; - USHORT ParentLength = DirObject2->FileName.Length; - PWCHAR Buffer = DirObject2->FileName.Buffer; - USHORT FileNameStart; - - if (ParentLength < FullLength && - Buffer[ParentLength / sizeof(WCHAR)] == L'\\') { - FileNameStart = ParentLength + sizeof(WCHAR); - } else { - FileNameStart = ParentLength; - } - - NewName.Length = FullLength - FileNameStart; - NewName.MaximumLength = NewName.Length; - NewName.Buffer = (PWCHAR)((PCHAR)Buffer + FileNameStart); + // This name is by definition legal. + NewName = *((PUNICODE_STRING)&DirObject2->FileName); } IgnoreCase = FlagOn(Ccb1->Flags, CCB_FLAG_IGNORE_CASE); - // Note: Fcb1 no longer has FCBName - removed debug print + AdPrint((" %ws ->\n %ws\n", + Fcb1->FCBName->ObjectName.Buffer, + NewName.Buffer)); RC = UDFHardLinkFile__(IrpContext, Vcb, IgnoreCase, &Replace, &NewName, Dir1, Dir2, File1); if (!NT_SUCCESS(RC)) try_return (RC); @@ -2627,31 +2581,19 @@ UDFHardLink( } } // report changes - UDFNotifyReportChange( IrpContext, Vcb, File1->Fcb, + UDFNotifyFullReportChange( Vcb, File1->Fcb, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS, - FILE_ACTION_MODIFIED, - Ccb1->Lcb, FileObject1); - - // Build full path for hardlink target - if (Dir2->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) { - RC = MyCloneUnicodeString(&LocalPath, &UdfData.UnicodeStrRoot); - if (!NT_SUCCESS(RC)) try_return (RC); - } else { - // Build parent path from LCB - PLCB Dir2Lcb = NULL; - if (!IsListEmpty(&Dir2->Fcb->ParentLcbQueue)) { - PLIST_ENTRY ListEntry = Dir2->Fcb->ParentLcbQueue.Flink; - Dir2Lcb = CONTAINING_RECORD(ListEntry, LCB, ChildFcbLinks); - RC = UDFBuildFullPathFromLcb(IrpContext, Dir2Lcb, &LocalPath, FALSE); - if (!NT_SUCCESS(RC)) try_return (RC); - } else { - RC = MyCloneUnicodeString(&LocalPath, &UdfData.UnicodeStrRoot); - if (!NT_SUCCESS(RC)) try_return (RC); - } - } + FILE_ACTION_MODIFIED ); - // Append separator and new name + RC = MyCloneUnicodeString(&LocalPath, (Dir2->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) ? + &UdfData.UnicodeStrRoot : + &(Dir2->Fcb->FCBName->ObjectName)); + 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 Dir2 is a RootDir, we shoud not append '\\' because + // it will be the 2nd '\\' character (RootDir's name is also '\\') if (Dir2->ParentFile) { RC = MyAppendUnicodeToString(&LocalPath, L"\\"); if (!NT_SUCCESS(RC)) try_return (RC); @@ -2659,19 +2601,13 @@ UDFHardLink( RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USHL_TAG); if (!NT_SUCCESS(RC)) try_return (RC); - // Calculate TargetNameOffset (parent path length) - USHORT HardLinkTargetNameOffset = (USHORT)(LocalPath.Length - NewName.Length); - if (Dir2->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) { - HardLinkTargetNameOffset = 0; - } - if (!Replace) { /* UDFNotifyFullReportChange( Vcb, File2, UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED );*/ FsRtlNotifyFullReportChange( Vcb->NotifySync, &(Vcb->NextNotifyIRP), (PSTRING)&LocalPath, - HardLinkTargetNameOffset, + ((Dir2->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), NULL,NULL, UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, @@ -2687,7 +2623,7 @@ UDFHardLink( FILE_ACTION_MODIFIED );*/ FsRtlNotifyFullReportChange( Vcb->NotifySync, &(Vcb->NextNotifyIRP), (PSTRING)&LocalPath, - HardLinkTargetNameOffset, + ((Dir2->Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), NULL,NULL, UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_NOTIFY_CHANGE_ATTRIBUTES | @@ -2705,12 +2641,13 @@ try_exit: NOTHING; } _SEH2_FINALLY { - // Release in reverse order of acquisition (parent first, then child) - if (AcquiredDir1) { - UDFReleaseFcb(IrpContext, Dir1->Fcb); - } if (AcquiredFcb1) { - UDFReleaseFcb(IrpContext, Fcb1); + UDF_CHECK_PAGING_IO_RESOURCE(Fcb1); + UDFReleaseResource(&Fcb1->FcbNonpaged->FcbResource); + } + if (AcquiredDir1) { + UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb); + UDFReleaseResource(&Dir1->Fcb->FcbNonpaged->FcbResource); } if (LocalPath.Buffer) { 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 96% rename from drivers/filesystems/udfs/flush.cpp rename to drivers/filesystems/udfs/flush.c index 65240f50e2a7e..ebe9dd16dffa1 100644 --- a/drivers/filesystems/udfs/flush.cpp +++ b/drivers/filesystems/udfs/flush.c @@ -112,9 +112,11 @@ UDFCommonFlush( // action we take. if ((Fcb == Fcb->Vcb->VolumeDasdFcb) || (Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY)) { +#ifdef UDF_DELAYED_CLOSE UDFFspClose(Vcb); +#endif //UDF_DELAYED_CLOSE - UDFAcquireVcbExclusive(IrpContext, Vcb, FALSE); + UDFAcquireResourceExclusive(&(Vcb->VcbResource), TRUE); AcquiredVCB = TRUE; // The caller wishes to flush all files for the mounted // logical volume. The flush volume routine below should simply @@ -125,9 +127,9 @@ UDFCommonFlush( UDFVerifyVcb(IrpContext, Vcb); - UDFFlushVolume(IrpContext, Vcb); + UDFFlushVolume(IrpContext, Vcb, 0); - UDFReleaseVcb(IrpContext, Vcb); + UDFReleaseResource(&(Vcb->VcbResource)); AcquiredVCB = FALSE; try_return(Status); @@ -137,18 +139,16 @@ UDFCommonFlush( Vcb = Fcb->Vcb; ASSERT(Vcb); - // Child-first lock ordering - UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFAcquireFcbExclusive(IrpContext, Fcb, FALSE); - 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); - UDFAcquireFcbExclusive(IrpContext, Fcb->FileInfo->ParentFile->Fcb, FALSE); + 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,19 +168,20 @@ try_exit: NOTHING; } _SEH2_FINALLY { - // Release in reverse order of acquisition (parent first, then child) - if (AcquiredParentFcb) { - UDFReleaseFcb(IrpContext, Fcb->FileInfo->ParentFile->Fcb); - AcquiredParentFcb = FALSE; - } - if (AcquiredFCB) { - UDFReleaseFcb(IrpContext, Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); AcquiredFCB = FALSE; } + if (AcquiredParentFcb) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb); + UDFReleaseResource(&Fcb->FileInfo->ParentFile->Fcb->FcbNonpaged->FcbResource); + AcquiredParentFcb = FALSE; + } + if (AcquiredVCB) { - UDFReleaseVcb(IrpContext, Vcb); + UDFReleaseResource(&Vcb->VcbResource); AcquiredVCB = FALSE; } diff --git a/drivers/filesystems/udfs/fscntrl.cpp b/drivers/filesystems/udfs/fscntrl.c similarity index 98% rename from drivers/filesystems/udfs/fscntrl.cpp rename to drivers/filesystems/udfs/fscntrl.c index 74982610e6a43..9e3be52d70309 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); @@ -639,15 +639,7 @@ UDFCloseResidual( UDFCloseFile__(IrpContext, Vcb, Vcb->RootIndexFcb->FileInfo); if (Vcb->RootIndexFcb->FcbCleanup) Vcb->RootIndexFcb->FcbCleanup--; - { - 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); - } - } + UDFTeardownStructures(IrpContext, Vcb->RootIndexFcb, 1, NULL); // Remove root FCB reference in vcb if (Vcb->VcbReference) InterlockedDecrement((PLONG)&Vcb->VcbReference); @@ -997,7 +989,7 @@ Return Value: // remaining after the purge then we can allow the volume to be locked. // - UDFFlushVolume(IrpContext, Vcb); + UDFFlushVolume(IrpContext, Vcb, 0); //CdPurgeVolume( IrpContext, Vcb, FALSE ); // @@ -1181,7 +1173,7 @@ UDFDismountVolume( } else { - UDFFlushVolume(IrpContext, Vcb); + UDFFlushVolume(IrpContext, Vcb, 0); // Invalidate the volume right now. // @@ -1339,7 +1331,7 @@ UDFGetVolumeBitmap( // Fill in the fixed part of the output buffer - __try { + _SEH2_TRY { // StartingLcn in output = aligned starting block @@ -1349,10 +1341,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); @@ -1807,7 +1799,7 @@ UDFInvalidateVolumes( UDFAcquireVcbExclusive(IrpContext, Vcb, FALSE); - UDFFlushVolume(IrpContext, Vcb); + UDFFlushVolume(IrpContext, Vcb, 0); UDFDoDismountSequence(Vcb, FALSE); diff --git a/drivers/filesystems/udfs/lockctrl.cpp b/drivers/filesystems/udfs/lockctrl.c similarity index 95% rename from drivers/filesystems/udfs/lockctrl.cpp rename to drivers/filesystems/udfs/lockctrl.c index da046e9434329..b6cbd095d38c4 100644 --- a/drivers/filesystems/udfs/lockctrl.cpp +++ b/drivers/filesystems/udfs/lockctrl.c @@ -5,7 +5,7 @@ //////////////////////////////////////////////////////////////////// /************************************************************************* * -* File: LockCtrl.cpp.cpp +* File: LockCtrl.c * * Module: UDF File System Driver (Kernel mode execution only) * @@ -141,34 +141,38 @@ UDFFastLock ( IN PDEVICE_OBJECT DeviceObject ) { - BOOLEAN FcbAcquired = FALSE; BOOLEAN Results = FALSE; + +// BOOLEAN AcquiredFCB = FALSE; TYPE_OF_OPEN TypeOfOpen; - PFCB Fcb = NULL; + PFCB Fcb = NULL; + + UDFPrint(("UDFFastLock\n")); // 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); - if (TypeOfOpen != UserFileOpen) { + ASSERT_FCB(Fcb); + + // Validate the sent-in FCB + if ( (Fcb == Fcb->Vcb->VolumeDasdFcb) || + (Fcb->FcbState & UDF_FCB_DIRECTORY)) { IoStatus->Status = STATUS_INVALID_PARAMETER; + IoStatus->Information = 0; return TRUE; } - ASSERT_FCB(Fcb); + // Acquire exclusive access to the Fcb this operation can always wait FsRtlEnterFileSystem(); - _SEH2_TRY { - - FcbAcquired = UDFAcquireFcbShared(NULL, Fcb, TRUE); - - if (FcbAcquired == FALSE) { + // BUGBUG: kenr + // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); - try_return(NOTHING); - } + _SEH2_TRY { // If we don't have a file lock, then get one now. if ((Fcb->FileLock == NULL) && !UDFCreateFileLock(NULL, Fcb, FALSE)) { @@ -200,13 +204,10 @@ UDFFastLock ( try_exit: NOTHING; } _SEH2_FINALLY { - // Release the Fcb, and return to our caller - - if (FcbAcquired) { - - UDFReleaseFcb(NULL, Fcb); - } + // Release the Fcb, and return to our caller + // BUGBUG: kenr + // UDFReleaseResource( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); 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 86% rename from drivers/filesystems/udfs/misc.cpp rename to drivers/filesystems/udfs/misc.c index 75765fe90ce48..d9cf307080076 100644 --- a/drivers/filesystems/udfs/misc.cpp +++ b/drivers/filesystems/udfs/misc.c @@ -30,6 +30,143 @@ #define UDFFreeIoContext(IO) ExFreePool( &(IO) ) +/* + + Function: UDFInitializeZones() + + Description: + Allocates some memory for global zones used to allocate FSD structures. + Either all memory will be allocated or we will back out gracefully. + + Expected Interrupt Level (for execution) : + + IRQL_PASSIVE_LEVEL + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +UDFInitializeZones(VOID) +{ + NTSTATUS RC = STATUS_UNSUCCESSFUL; + + _SEH2_TRY { + + // determine memory requirements + switch (MmQuerySystemSize()) { + case MmMediumSystem: + UdfData.MaxDelayedCloseCount = 32; + UdfData.MinDelayedCloseCount = 8; + break; + case MmLargeSystem: + UdfData.MaxDelayedCloseCount = 72; + UdfData.MinDelayedCloseCount = 18; + break; + case MmSmallSystem: + default: + UdfData.MaxDelayedCloseCount = 10; + UdfData.MinDelayedCloseCount = 2; + } + + ExInitializeNPagedLookasideList(&UdfData.IrpContextLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + sizeof(IRP_CONTEXT), + TAG_IRP_CONTEXT, + 0); + + // TODO: move to Paged? + ExInitializeNPagedLookasideList(&UdfData.ObjectNameLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + sizeof(UDFObjectName), + TAG_OBJECT_NAME, + 0); + + ExInitializeNPagedLookasideList(&UdfData.NonPagedFcbLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + sizeof(FCB), + TAG_FCB_NONPAGED, + 0); + + ExInitializeNPagedLookasideList(&UdfData.UDFNonPagedFcbLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + sizeof(FCB_NONPAGED), + TAG_FCB_NONPAGED, + 0); + + ExInitializePagedLookasideList(&UdfData.UDFFcbIndexLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + sizeof(FCB), //TODO: + TAG_FCB_NONPAGED, + 0); + + ExInitializePagedLookasideList(&UdfData.UDFFcbDataLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + sizeof(FCB), //TODO: + TAG_FCB_NONPAGED, + 0); + + ExInitializePagedLookasideList(&UdfData.CcbLookasideList, + NULL, + NULL, + POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE, + sizeof(CCB), + TAG_CCB, + 0); + + try_return(RC = STATUS_SUCCESS); + +try_exit: NOTHING; + + } _SEH2_FINALLY { + if (!NT_SUCCESS(RC)) { + // invoke the destroy routine now ... + UDFDestroyZones(); + } else { + // mark the fact that we have allocated zones ... + SetFlag(UdfData.Flags, UDF_DATA_FLAGS_ZONES_INITIALIZED); + } + } _SEH2_END; + + return(RC); +} + + +/************************************************************************* +* +* Function: UDFDestroyZones() +* +* Description: +* Free up the previously allocated memory. NEVER do this once the +* driver has been successfully loaded. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID UDFDestroyZones(VOID) +{ + ExDeleteNPagedLookasideList(&UdfData.IrpContextLookasideList); + ExDeleteNPagedLookasideList(&UdfData.ObjectNameLookasideList); + ExDeleteNPagedLookasideList(&UdfData.NonPagedFcbLookasideList); + + ExDeletePagedLookasideList(&UdfData.CcbLookasideList); +} + /************************************************************************* * * Function: UDFExceptionFilter() @@ -422,6 +559,79 @@ UDFCreateCcb() return NewCcb; } // end UDFCreateCcb() + +/************************************************************************* +* +* Function: UDFReleaseCCB() +* +* Description: +* Deallocate a previously allocated structure. +* +* Expected Interrupt Level (for execution) : +* +* IRQL_PASSIVE_LEVEL +* +* Return Value: None +* +*************************************************************************/ +VOID +UDFReleaseCCB( + PCCB Ccb + ) +{ + ASSERT(Ccb); + + ExFreeToPagedLookasideList(&UdfData.CcbLookasideList, Ccb); + +} // end UDFReleaseCCB() + +/* + Function: UDFCleanupCCB() + + Description: + Cleanup and deallocate a previously allocated structure. + + Expected Interrupt Level (for execution) : + + IRQL_PASSIVE_LEVEL + + Return Value: None + +*/ +VOID +UDFDeleteCcb( + PCCB Ccb +) +{ + ASSERT(Ccb); + if (!Ccb) return; // probably, we havn't allocated it... + ASSERT(Ccb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_CCB); + + _SEH2_TRY { + if (Ccb->Fcb) { + UDFAcquireResourceExclusive(&Ccb->Fcb->FcbNonpaged->CcbListResource, TRUE); + RemoveEntryList(&(Ccb->NextCCB)); + UDFReleaseResource(&Ccb->Fcb->FcbNonpaged->CcbListResource); + } else { + BrutePoint(); + } + + if (Ccb->DirectorySearchPattern) { + if (Ccb->DirectorySearchPattern->Buffer) { + MyFreePool__(Ccb->DirectorySearchPattern->Buffer); + Ccb->DirectorySearchPattern->Buffer = NULL; + } + + MyFreePool__(Ccb->DirectorySearchPattern); + Ccb->DirectorySearchPattern = NULL; + } + + UDFReleaseCCB(Ccb); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + BrutePoint(); + } _SEH2_END; +} // end UDFCleanUpCCB() + /************************************************************************* * * Function: UDFCreateIrpContext() @@ -501,7 +711,7 @@ UDFCreateIrpContext( } // TODO: fix - if (false && IrpSp->FileObject != NULL) { + if (FALSE && IrpSp->FileObject != NULL) { PFILE_OBJECT FileObject = IrpSp->FileObject; @@ -1220,6 +1430,27 @@ UDFReadRegKeys( { ptrUDFGetParameter UDFGetParameter = UDFGetRegParameter; + // What type of AllocDescs should we use + Vcb->DefaultAllocMode = (USHORT)UDFGetParameter(Vcb, REG_DEFALLOCMODE_NAME, + Update ? Vcb->DefaultAllocMode : ICB_FLAG_AD_SHORT); + if (Vcb->DefaultAllocMode > ICB_FLAG_AD_LONG) Vcb->DefaultAllocMode = ICB_FLAG_AD_SHORT; + + // FE allocation charge for plain Dirs + Vcb->FECharge = UDFGetParameter(Vcb, UDF_FE_CHARGE_NAME, Update ? Vcb->FECharge : 0); + if (!Vcb->FECharge) + Vcb->FECharge = UDF_DEFAULT_FE_CHARGE; + // FE allocation charge for Stream Dirs (SDir) + Vcb->FEChargeSDir = UDFGetParameter(Vcb, UDF_FE_CHARGE_SDIR_NAME, + Update ? Vcb->FEChargeSDir : 0); + if (!Vcb->FEChargeSDir) + Vcb->FEChargeSDir = UDF_DEFAULT_FE_CHARGE_SDIR; + // How many Deleted entries should contain Directory to make us + // start packing it. + Vcb->PackDirThreshold = UDFGetParameter(Vcb, UDF_DIR_PACK_THRESHOLD_NAME, + Update ? Vcb->PackDirThreshold : 0); + if (Vcb->PackDirThreshold == 0xffffffff) + Vcb->PackDirThreshold = UDF_DEFAULT_DIR_PACK_THRESHOLD; + // Timeouts for FreeSpaceBitMap & TheWholeDirTree flushes Vcb->BM_FlushPriod = UDFGetParameter(Vcb, UDF_BM_FLUSH_PERIOD_NAME, Update ? Vcb->BM_FlushPriod : 0); @@ -1262,10 +1493,17 @@ UDFReadRegKeys( UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_W, UDF_VCB_IC_UPDATE_DIR_WRITE, FALSE); // Should we update Dir's Times & Attrs on Access UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_R, UDF_VCB_IC_UPDATE_DIR_READ, FALSE); + // Should we allow user to write into Read-Only Directory + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_WRITE_IN_RO_DIR, UDF_VCB_IC_WRITE_IN_RO_DIR, TRUE); // Should we allow user to change Access Time for unchanged Directory UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_UPDATE_TIMES_ACCS_UCHG_DIR, UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME, FALSE); + // Should we record Allocation Descriptors in W2k-compatible form + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_ALLOC_DESCS, UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS, TRUE); // Should we read LONG_ADs with invalid PartitionReferenceNumber (generated by Nero Instant Burner) UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_INSTANT_COMPAT_ALLOC_DESCS, UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS, TRUE); + // Should we make a copy of VolumeLabel in LVD + // usually only PVD is updated + UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_VLABEL, UDF_VCB_IC_W2K_COMPAT_VLABEL, TRUE); // Should we ignore FO_SEQUENTIAL_ONLY UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_IGNORE_SEQUENTIAL_IO, UDF_VCB_IC_IGNORE_SEQUENTIAL_IO, FALSE); @@ -1338,7 +1576,7 @@ UDFDeleteVCB( UDFPrint(("UDF: Delete resources\n")); UDFDeleteResource(&(Vcb->VcbResource)); UDFDeleteResource(&(Vcb->BitMapResource1)); - + UDFDeleteResource(&(Vcb->FileIdResource)); UDFDeleteResource(&(Vcb->DlocResource)); UDFDeleteResource(&(Vcb->DlocResource2)); UDFDeleteResource(&(Vcb->FlushResource)); @@ -1406,6 +1644,7 @@ 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. @@ -1867,5 +2106,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/nodetype.h b/drivers/filesystems/udfs/nodetype.h index c9709c170741d..5027a9e327fbf 100644 --- a/drivers/filesystems/udfs/nodetype.h +++ b/drivers/filesystems/udfs/nodetype.h @@ -19,7 +19,6 @@ 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/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.cpp deleted file mode 100644 index 5bc2a4ff3aeda..0000000000000 --- a/drivers/filesystems/udfs/prefxsup.cpp +++ /dev/null @@ -1,1338 +0,0 @@ -//////////////////////////////////////////////////////////////////// -// 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. - -*/ - -#include "udffs.h" - -// define the file specific bug-check id -#define UDF_BUG_CHECK_ID UDF_FILE_MISC - -/* - Lexicographic comparison of two UNICODE_STRING names. - Returns LessThan, EqualTo, or GreaterThan. - Used for splay tree ordering. -*/ -static -FSRTL_COMPARISON_RESULT -UdfCompareNames( - IN PUNICODE_STRING NameA, - IN PUNICODE_STRING NameB - ) -{ - ULONG MinLength = NameA->Length; - FSRTL_COMPARISON_RESULT Result = LessThan; - - if (NameA->Length > NameB->Length) { - MinLength = NameB->Length; - Result = GreaterThan; - } else if (NameA->Length == NameB->Length) { - Result = EqualTo; - } - - ULONG i = (ULONG)RtlCompareMemory(NameA->Buffer, NameB->Buffer, MinLength); - - if (i < MinLength) { - return ((NameA->Buffer[i / 2] < NameB->Buffer[i / 2]) ? - LessThan : GreaterThan); - } - - return Result; -} - - -/* - Search a splay tree for an LCB matching the given name. - On match, rebalances the tree (splay) and returns the LCB. - Returns NULL if no match. - - LinksOffset: byte offset of RTL_SPLAY_LINKS within LCB structure - NameOffset: byte offset of UNICODE_STRING within LCB structure -*/ -static -PLCB -UdfFindNameLink( - IN PRTL_SPLAY_LINKS *RootNode, - IN PUNICODE_STRING Name, - IN ULONG LinksOffset, - IN ULONG NameOffset - ) -{ - PRTL_SPLAY_LINKS Links = *RootNode; - - while (Links != NULL) { - - PLCB Node = (PLCB)((PUCHAR)Links - LinksOffset); - PUNICODE_STRING NodeName = (PUNICODE_STRING)((PUCHAR)Node + NameOffset); - - FSRTL_COMPARISON_RESULT Comparison = UdfCompareNames(NodeName, Name); - - if (Comparison == GreaterThan) { - Links = RtlLeftChild(Links); - } else if (Comparison == LessThan) { - Links = RtlRightChild(Links); - } else { - *RootNode = RtlSplay(Links); - return Node; - } - } - - return NULL; -} - - -/* - Insert an LCB into a splay tree keyed by the given name. - Returns TRUE if inserted, FALSE if duplicate exists. - - LinksOffset: byte offset of RTL_SPLAY_LINKS within LCB structure - NameOffset: byte offset of UNICODE_STRING within LCB structure -*/ -static -BOOLEAN -UdfInsertNameLink( - IN PRTL_SPLAY_LINKS *RootNode, - IN PLCB NameLink, - IN ULONG LinksOffset, - IN ULONG NameOffset - ) -{ - PRTL_SPLAY_LINKS NewLinks = (PRTL_SPLAY_LINKS)((PUCHAR)NameLink + LinksOffset); - PUNICODE_STRING NewName = (PUNICODE_STRING)((PUCHAR)NameLink + NameOffset); - - RtlInitializeSplayLinks(NewLinks); - - if (*RootNode == NULL) { - *RootNode = NewLinks; - return TRUE; - } - - PLCB Node = (PLCB)((PUCHAR)*RootNode - LinksOffset); - - while (TRUE) { - - PRTL_SPLAY_LINKS NodeLinks = (PRTL_SPLAY_LINKS)((PUCHAR)Node + LinksOffset); - PUNICODE_STRING NodeName = (PUNICODE_STRING)((PUCHAR)Node + NameOffset); - - FSRTL_COMPARISON_RESULT Comparison = UdfCompareNames(NodeName, NewName); - - if (Comparison == EqualTo) { - // Duplicate name — not inserted. Caller will not set IN_TREE flag. - return FALSE; - } - - if (Comparison == GreaterThan) { - if (RtlLeftChild(NodeLinks) == NULL) { - RtlInsertAsLeftChild(NodeLinks, NewLinks); - break; - } - Node = (PLCB)((PUCHAR)RtlLeftChild(NodeLinks) - LinksOffset); - } else { - if (RtlRightChild(NodeLinks) == NULL) { - RtlInsertAsRightChild(NodeLinks, NewLinks); - break; - } - Node = (PLCB)((PUCHAR)RtlRightChild(NodeLinks) - LinksOffset); - } - } - - return TRUE; -} - - -/* - Insert LCB into all applicable splay trees of ParentFcb. - Called after LCB names are initialized. -*/ -VOID -UdfInsertNameLinks( - IN PFCB ParentFcb, - IN PLCB Lcb - ) -{ - // Exact case tree (keyed by FileName) - if (Lcb->FileName.Buffer && Lcb->FileName.Length > 0) { - if (UdfInsertNameLink(&ParentFcb->ExactCaseRoot, Lcb, - FIELD_OFFSET(LCB, ExactCaseLinks), - FIELD_OFFSET(LCB, FileName))) { - SetFlag(Lcb->Flags, UDF_LCB_FLAG_EXACT_CASE_IN_TREE); - } - } - - // Ignore case tree (keyed by IgnoreCaseLinkName) - if (Lcb->IgnoreCaseLinkName.Buffer && Lcb->IgnoreCaseLinkName.Length > 0) { - if (UdfInsertNameLink(&ParentFcb->IgnoreCaseRoot, Lcb, - FIELD_OFFSET(LCB, IgnoreCaseLinks), - FIELD_OFFSET(LCB, IgnoreCaseLinkName))) { - SetFlag(Lcb->Flags, UDF_LCB_FLAG_IGNORE_CASE_IN_TREE); - } - } - - // Short name tree (keyed by ShortName) - if (Lcb->ShortName.Buffer && Lcb->ShortName.Length > 0) { - if (UdfInsertNameLink(&ParentFcb->ShortNameRoot, Lcb, - FIELD_OFFSET(LCB, ShortNameLinks), - FIELD_OFFSET(LCB, ShortName))) { - SetFlag(Lcb->Flags, UDF_LCB_FLAG_SHORT_NAME_IN_TREE); - } - } -} - - -/* - Remove LCB from all splay trees of ParentFcb. - Uses IN_TREE flags to track which trees the LCB was inserted into. - After removal, clears all IN_TREE flags. - Idempotent — safe to call multiple times. -*/ -VOID -UdfRemoveNameLinks( - IN PFCB ParentFcb, - IN PLCB Lcb - ) -{ - if (FlagOn(Lcb->Flags, UDF_LCB_FLAG_EXACT_CASE_IN_TREE)) { - ParentFcb->ExactCaseRoot = RtlDelete(&Lcb->ExactCaseLinks); - } - - if (FlagOn(Lcb->Flags, UDF_LCB_FLAG_IGNORE_CASE_IN_TREE)) { - ParentFcb->IgnoreCaseRoot = RtlDelete(&Lcb->IgnoreCaseLinks); - } - - if (FlagOn(Lcb->Flags, UDF_LCB_FLAG_SHORT_NAME_IN_TREE)) { - ParentFcb->ShortNameRoot = RtlDelete(&Lcb->ShortNameLinks); - } - - ClearFlag(Lcb->Flags, UDF_LCB_FLAG_EXACT_CASE_IN_TREE | - UDF_LCB_FLAG_IGNORE_CASE_IN_TREE | - UDF_LCB_FLAG_SHORT_NAME_IN_TREE); -} - - -/* - This routine creates and inserts an LCB linking the parent FCB to child FCB. - - Creates LCB with dynamic name storage. - Names are stored in a buffer immediately after the LCB structure. - - The LCB is linked into: - - ParentFcb->ChildLcbQueue (via Lcb->ParentFcbLinks) - - ChildFcb->ParentLcbQueue (via Lcb->ChildFcbLinks) - - ParentFcb splay trees (ExactCaseRoot, IgnoreCaseRoot, ShortNameRoot) - - Parameters: - IrpContext - IRP context - ParentFcb - Parent directory FCB - ChildFcb - Child file FCB - FileName - File name (component name, may be NULL) - CaseFileName - Case-sensitive file name (may be NULL) - ShortName - 8.3 short name (may be NULL) - InitialOffset - Directory offset -*/ -PLCB -UDFInsertPrefix( - IN PIRP_CONTEXT IrpContext, - IN PFCB ParentFcb, - IN PFCB ChildFcb, - IN PUNICODE_STRING FileName OPTIONAL, - IN PUNICODE_STRING CaseFileName OPTIONAL, - IN PUNICODE_STRING ShortName OPTIONAL, - IN ULONGLONG InitialOffset - ) -{ - PLCB Lcb; - ULONG Flags = 0; - USHORT NameLength = 0; - ULONG AllocationSize; - PWCHAR NameBuffer; - - UNREFERENCED_PARAMETER(IrpContext); - - ASSERT(ParentFcb); - ASSERT(ChildFcb); - - // - // Calculate required allocation size for names - // Layout: FileName + padding(0x18) + CaseFileName + ShortName - // - if (FileName != NULL && FileName->Length > 0) { - // Size = FileName->Length + alignment(0x18) + CaseFileName->Length + ShortName->Length - NameLength = FileName->Length + 0x18; - if (CaseFileName != NULL && CaseFileName->Length > 0) { - NameLength += CaseFileName->Length; - } - if (ShortName != NULL && ShortName->Length > 0) { - NameLength += ShortName->Length; - } - } - - AllocationSize = UDF_LCB_BASE_SIZE + NameLength; - - // - // Allocate LCB - use lookaside for small allocations - // - if (AllocationSize > UDF_LCB_LOOKASIDE_SIZE) { - - Lcb = (PLCB)FsRtlAllocatePoolWithTag(PagedPool, - AllocationSize, - 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 structure - // - UDFPrint(("UDFInsertPrefix: Lcb=%p, AllocationSize=0x%X, sizeof(LCB)=%u, NameLength=%u\n", - Lcb, AllocationSize, (ULONG)sizeof(LCB), NameLength)); - - ULONG BytesToZero = min(AllocationSize, UDF_LCB_BASE_SIZE); - UDFPrint((" BytesToZero=0x%X (min of AllocationSize and UDF_LCB_BASE_SIZE=0x%X)\n", - BytesToZero, UDF_LCB_BASE_SIZE)); - - RtlZeroMemory(Lcb, BytesToZero); - - Lcb->NodeIdentifier.NodeTypeCode = UDF_NODE_TYPE_LCB; - Lcb->NodeIdentifier.NodeByteSize = (USHORT)AllocationSize; - - // Set up FCB pointers - Lcb->ParentFcb = ParentFcb; - Lcb->ChildFcb = ChildFcb; - Lcb->InitialOffset = InitialOffset; - - // Set flags - Lcb->Flags = Flags; - - // Initial reference count - Lcb->Reference = 0; - - // - // Initialize name buffer pointer - // Buffer is located immediately after LCB structure - // - if (NameLength > 0) { - Lcb->NameBuffer = (PVOID)((PUCHAR)Lcb + UDF_LCB_BASE_SIZE); - Lcb->FileName.MaximumLength = NameLength; - - NameBuffer = (PWCHAR)Lcb->NameBuffer; - - // - // Copy file names into buffer - // Layout: [FileName][padding 0x18][CaseFileName][ShortName] - // - if (FileName != NULL && FileName->Length > 0) { - // Copy FileName (exact case) - Lcb->FileName.Buffer = NameBuffer; - Lcb->FileName.Length = FileName->Length; - RtlCopyMemory(NameBuffer, FileName->Buffer, FileName->Length); - - // Copy CaseFileName (uppercase for ignore-case comparisons) - if (CaseFileName != NULL && CaseFileName->Length > 0) { - // Skip alignment padding (0x18 bytes) after FileName - NameBuffer = (PWCHAR)((PUCHAR)Lcb->NameBuffer + FileName->Length + 0x18); - - Lcb->IgnoreCaseLinkName.Buffer = NameBuffer; - Lcb->IgnoreCaseLinkName.Length = CaseFileName->Length; - Lcb->IgnoreCaseLinkName.MaximumLength = CaseFileName->Length; - RtlCopyMemory(NameBuffer, CaseFileName->Buffer, CaseFileName->Length); - - // Move pointer to next position for ShortName - NameBuffer += CaseFileName->Length / sizeof(WCHAR); - } else { - // No CaseFileName, position after FileName + padding - NameBuffer = (PWCHAR)((PUCHAR)Lcb->NameBuffer + FileName->Length + 0x18); - } - - // Copy ShortName (8.3 DOS name) - if (ShortName != NULL && ShortName->Length > 0) { - Lcb->ShortName.Buffer = NameBuffer; - Lcb->ShortName.Length = ShortName->Length; - Lcb->ShortName.MaximumLength = ShortName->Length; - RtlCopyMemory(NameBuffer, ShortName->Buffer, ShortName->Length); - - // Set flag indicating short name was created - SetFlag(Lcb->Flags, UDF_LCB_FLAG_SHORT_NAME_CREATED); - } - } - } - - // - // 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); - - // Insert into splay trees for O(log n) lookup by name. - // Caller must hold ParentFcb exclusive for splay tree protection. - UdfInsertNameLinks(ParentFcb, Lcb); - - return Lcb; -} // end UDFInsertPrefix() - - -/* - This routine removes an LCB from FCB queues and frees it. - Frees name buffer if separately allocated, then frees LCB structure - itself (from pool or lookaside list). -*/ -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 splay trees. - // All callers hold ParentFcb exclusive or VcbResource exclusive. - // - if (Lcb->ParentFcb) { - UdfRemoveNameLinks(Lcb->ParentFcb, 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 name buffer if separately allocated - // This flag indicates the NameBuffer was allocated independently, - // not as part of the LCB structure - // - if (FlagOn(Lcb->Flags, UDF_LCB_FLAG_HAS_NAME_BUFFER)) { - if (Lcb->NameBuffer != NULL) { - ExFreePool(Lcb->NameBuffer); - Lcb->NameBuffer = NULL; - } - } - - // - // Free FileName.Buffer if it was separately allocated (e.g., after rename) - // Check if it's not pointing to embedded buffer (within LCB structure) - // - if (Lcb->FileName.Buffer != NULL) { - BOOLEAN IsEmbedded = ((PUCHAR)Lcb->FileName.Buffer >= (PUCHAR)Lcb && - (PUCHAR)Lcb->FileName.Buffer < (PUCHAR)Lcb + Lcb->NodeIdentifier.NodeByteSize); - if (!IsEmbedded) { - MyFreePool__(Lcb->FileName.Buffer); - Lcb->FileName.Buffer = NULL; - } - } - - // - // Free Name.Buffer if present (ANSI name) - // - if (Lcb->Name.Buffer != NULL) { - ExFreePool(Lcb->Name.Buffer); - Lcb->Name.Buffer = NULL; - } - - // - // Free the LCB structure itself 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 PUNICODE_STRING FileName OPTIONAL, - IN PUNICODE_STRING CaseFileName OPTIONAL, - IN PUNICODE_STRING ShortName OPTIONAL, - IN ULONGLONG InitialOffset - ) -{ - 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 - return it as-is. - return Lcb; - } - - // - // Need to create new LCB with dynamic names - // - Lcb = UDFInsertPrefix(IrpContext, ParentFcb, ChildFcb, - FileName, CaseFileName, ShortName, InitialOffset); - - if (Lcb) { - // - // New LCB created - Reference=0 and stays 0. - // Lcb->Reference is only used for temporary lock protection, - // not for counting opens. Teardown checks Reference==0 before removal. - // - Lcb->Reference = 0; - - // - // Increment parent refs immediately after LCB creation. - // These will be decremented in UDFTeardownStructures when LCB is removed. - // - InterlockedIncrement((PLONG)&ParentFcb->FcbReference); - 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() - - -/* - Builds full path from LCB chain with caching support. - - Builds path by walking up the parent LCB chain from current LCB to root. - - Caching strategy: - - If Lcb->FileName.Buffer already contains full path → use cached value - - Otherwise, build path recursively and optionally cache it - - Uses FcbLockThread/FcbLockCount/FcbFastMutex for synchronization - - Parameters: - IrpContext - IRP context - Lcb - LCB to build path for (starting point) - FullPath - Output UNICODE_STRING for full path - CachePath - If TRUE, cache the built path in LCB->FileName - - Returns: - STATUS_SUCCESS - Path built successfully - STATUS_INSUFFICIENT_RESOURCES - Memory allocation failed -*/ -NTSTATUS -UDFBuildFullPathFromLcb( - IN PIRP_CONTEXT IrpContext, - IN PLCB Lcb, - OUT PUNICODE_STRING FullPath, - IN BOOLEAN CachePath - ) -{ - PLCB CurrentLcb; - PFCB CurrentFcb; - PFCB Fcb; - USHORT TotalLength = 0; - USHORT ComponentLength; - PWCHAR Buffer = NULL; - PWCHAR CurrentPosition; - PKTHREAD CurrentThread; - BOOLEAN CacheLockAcquired = FALSE; - NTSTATUS Status = STATUS_SUCCESS; - - if (!Lcb) { - return STATUS_INVALID_PARAMETER; - } - - CurrentFcb = Lcb->ChildFcb; - if (!CurrentFcb) { - return STATUS_INVALID_PARAMETER; - } - - Fcb = CurrentFcb; - - __try { - - // Check if path is already cached in this LCB - CurrentThread = KeGetCurrentThread(); - - if (CurrentThread != Fcb->FcbLockThread) { - ExAcquireFastMutex(&Fcb->FcbNonpaged->FcbFastMutex); - Fcb->FcbLockThread = CurrentThread; - } - - Fcb->FcbLockCount++; - CacheLockAcquired = TRUE; - - // Check if FileName contains cached full path (set by CachePath=TRUE) - if (FlagOn(Lcb->Flags, UDF_LCB_FLAG_HAS_NAME_BUFFER) && - Lcb->FileName.Buffer != NULL && Lcb->FileName.Length > 0) { - // Cached full path exists - use it - FullPath->Length = Lcb->FileName.Length; - FullPath->MaximumLength = Lcb->FileName.MaximumLength; - FullPath->Buffer = (PWCHAR)ExAllocatePoolWithTag(PagedPool, - FullPath->MaximumLength, - TAG_FILE_NAME); - if (!FullPath->Buffer) { - Status = STATUS_INSUFFICIENT_RESOURCES; - __leave; - } - - RtlCopyMemory(FullPath->Buffer, Lcb->FileName.Buffer, Lcb->FileName.Length); - __leave; - } - - // Release cache lock before building path - Fcb->FcbLockCount--; - if (Fcb->FcbLockCount == 0) { - Fcb->FcbLockThread = NULL; - ExReleaseFastMutex(&Fcb->FcbNonpaged->FcbFastMutex); - } - CacheLockAcquired = FALSE; - - // - // No cached path - build it from LCB chain - // - - // Calculate total path length by walking up parent chain - CurrentLcb = Lcb; - while (CurrentLcb) { - // Add component length + separator - if (CurrentLcb->FileName.Buffer && CurrentLcb->FileName.Length > 0) { - ComponentLength = CurrentLcb->FileName.Length; - } else if (CurrentLcb->ExactCaseLinkName.Buffer && CurrentLcb->ExactCaseLinkName.Length > 0) { - ComponentLength = CurrentLcb->ExactCaseLinkName.Length; - } else { - ComponentLength = 0; - } - - if (ComponentLength > 0) { - TotalLength += ComponentLength + sizeof(WCHAR); // +1 for backslash - } - - // Move to parent - CurrentFcb = CurrentLcb->ParentFcb; - if (!CurrentFcb || (CurrentFcb->FcbState & UDF_FCB_ROOT_DIRECTORY)) { - break; - } - - // Find parent LCB - if (!IsListEmpty(&CurrentFcb->ParentLcbQueue)) { - PLIST_ENTRY ListEntry = CurrentFcb->ParentLcbQueue.Flink; - CurrentLcb = CONTAINING_RECORD(ListEntry, LCB, ChildFcbLinks); - } else { - break; - } - } - - // Add root backslash - if (TotalLength == 0) { - TotalLength = sizeof(WCHAR); - } - - // Allocate buffer for full path - Buffer = (PWCHAR)ExAllocatePoolWithTag(PagedPool, TotalLength + sizeof(WCHAR), TAG_FILE_NAME); - if (!Buffer) { - Status = STATUS_INSUFFICIENT_RESOURCES; - __leave; - } - - // Build path backwards (from end to beginning) - CurrentPosition = (PWCHAR)((PUCHAR)Buffer + TotalLength); - *CurrentPosition = 0; // Null terminator - - // Walk up chain again and copy names - CurrentLcb = Lcb; - while (CurrentLcb) { - PUNICODE_STRING ComponentName; - - if (CurrentLcb->FileName.Buffer && CurrentLcb->FileName.Length > 0) { - ComponentName = &CurrentLcb->FileName; - } else if (CurrentLcb->ExactCaseLinkName.Buffer && CurrentLcb->ExactCaseLinkName.Length > 0) { - ComponentName = &CurrentLcb->ExactCaseLinkName; - } else { - ComponentName = NULL; - } - - if (ComponentName && ComponentName->Length > 0) { - // Add backslash - CurrentPosition--; - *CurrentPosition = L'\\'; - - // Add component name - CurrentPosition -= (ComponentName->Length / sizeof(WCHAR)); - RtlCopyMemory(CurrentPosition, ComponentName->Buffer, ComponentName->Length); - } - - // Move to parent - CurrentFcb = CurrentLcb->ParentFcb; - if (!CurrentFcb || (CurrentFcb->FcbState & UDF_FCB_ROOT_DIRECTORY)) { - break; - } - - // Find parent LCB - if (!IsListEmpty(&CurrentFcb->ParentLcbQueue)) { - PLIST_ENTRY ListEntry = CurrentFcb->ParentLcbQueue.Flink; - CurrentLcb = CONTAINING_RECORD(ListEntry, LCB, ChildFcbLinks); - } else { - break; - } - } - - // Add leading backslash if not already there - if (CurrentPosition > Buffer) { - CurrentPosition--; - *CurrentPosition = L'\\'; - } - - // Set output string - FullPath->Buffer = Buffer; - FullPath->Length = (USHORT)((PUCHAR)Buffer + TotalLength - (PUCHAR)CurrentPosition); - FullPath->MaximumLength = TotalLength + sizeof(WCHAR); - - // Move string to beginning of buffer if needed - if (CurrentPosition != Buffer) { - RtlMoveMemory(Buffer, CurrentPosition, FullPath->Length + sizeof(WCHAR)); - FullPath->Length = (USHORT)((PUCHAR)Buffer + TotalLength - (PUCHAR)CurrentPosition); - } - - // Optionally cache the path in LCB - if (CachePath && NT_SUCCESS(Status)) { - CurrentThread = KeGetCurrentThread(); - Fcb = Lcb->ChildFcb; - - if (CurrentThread != Fcb->FcbLockThread) { - ExAcquireFastMutex(&Fcb->FcbNonpaged->FcbFastMutex); - Fcb->FcbLockThread = CurrentThread; - } - - Fcb->FcbLockCount++; - CacheLockAcquired = TRUE; - - // Check if cache is still empty - if (Lcb->FileName.Buffer == NULL) { - // Allocate separate buffer for cache - PWCHAR CacheBuffer = (PWCHAR)ExAllocatePoolWithTag(PagedPool, - FullPath->Length + sizeof(WCHAR), - TAG_FILE_NAME); - if (CacheBuffer) { - RtlCopyMemory(CacheBuffer, FullPath->Buffer, FullPath->Length + sizeof(WCHAR)); - Lcb->FileName.Buffer = CacheBuffer; - Lcb->FileName.Length = FullPath->Length; - Lcb->FileName.MaximumLength = FullPath->Length + sizeof(WCHAR); - - // Set flag indicating separate buffer needs freeing - SetFlag(Lcb->Flags, UDF_LCB_FLAG_HAS_NAME_BUFFER); - } - } - } - - } __finally { - - if (CacheLockAcquired) { - Fcb->FcbLockCount--; - if (Fcb->FcbLockCount == 0) { - Fcb->FcbLockThread = NULL; - ExReleaseFastMutex(&Fcb->FcbNonpaged->FcbFastMutex); - } - } - - if (!NT_SUCCESS(Status) && Buffer) { - ExFreePool(Buffer); - FullPath->Buffer = NULL; - FullPath->Length = 0; - FullPath->MaximumLength = 0; - } - } - - return Status; -} // end UDFBuildFullPathFromLcb() - - -/* - 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() - - -/* - This routine searches for the maximum known prefix path in the LCB tree. - - Starting from StartFcb, walks through path components in RemainingName, - looking for matching LCBs in the ChildLcbQueue. Returns the LCB of the - deepest matched component and updates RemainingName to the unmatched portion. - - This optimization avoids redundant directory traversal - instead of always - starting from root, we find the deepest already-opened directory in the - path and start from there. - - Parameters: - IrpContext - IRP context - StartFcb - Starting FCB (usually RootIndexFcb or RelatedFcb) - IgnoreCase - Whether to use case-insensitive comparison - CurrentFcb - Output: FCB of the deepest matched component - RemainingName - Input: full path to search; Output: unmatched portion - ShortNameMatch - Output: TRUE if match was via short name - - Returns: - PLCB - LCB of the deepest matched component, or NULL if no match -*/ -/* - Walk path components starting from StartFcb, looking for the longest - match in the in-memory LCB tree. - - On entry: *CurrentFcb == StartFcb, caller holds StartFcb FcbResource exclusive. - On return: *CurrentFcb == deepest matched FCB (locked exclusive), - all ancestor FCB locks released. - RemainingName is advanced past matched components. - Returns the LCB used to reach *CurrentFcb, or NULL if no prefix found. - */ -PLCB -UDFFindPathPrefix( - IN PIRP_CONTEXT IrpContext, - IN PFCB StartFcb, - IN BOOLEAN IgnoreCase, - IN OUT PFCB *CurrentFcb, - IN OUT PUNICODE_STRING RemainingName, - OUT PBOOLEAN ShortNameMatch - ) -{ - PLCB CurrentLcb = NULL; - PLCB MatchLcb; - UNICODE_STRING LocalRemainingName; - UNICODE_STRING ComponentName; - WCHAR UpcaseBuffer[256]; - UNICODE_STRING UpcaseName; - - ASSERT(StartFcb); - ASSERT(CurrentFcb); - ASSERT(RemainingName); - ASSERT(ShortNameMatch); - - *ShortNameMatch = FALSE; - *CurrentFcb = StartFcb; - LocalRemainingName = *RemainingName; - - while (TRUE) { - - // Stop if no more path components or current FCB is not a directory - if (LocalRemainingName.Length == 0 || - !(*CurrentFcb) || - !((*CurrentFcb)->FcbState & UDF_FCB_DIRECTORY)) { - return CurrentLcb; - } - - // Skip leading backslashes - while (LocalRemainingName.Length >= sizeof(WCHAR) && - LocalRemainingName.Buffer[0] == L'\\') { - LocalRemainingName.Buffer++; - LocalRemainingName.Length -= sizeof(WCHAR); - } - - if (LocalRemainingName.Length == 0) { - return CurrentLcb; - } - - // Stop at stream boundary - if (LocalRemainingName.Buffer[0] == L':') { - return CurrentLcb; - } - - // Extract next component (up to next '\' or ':' or end) - ComponentName.Buffer = LocalRemainingName.Buffer; - ComponentName.Length = 0; - while (ComponentName.Length < LocalRemainingName.Length) { - WCHAR ch = ComponentName.Buffer[ComponentName.Length / sizeof(WCHAR)]; - if (ch == L'\\' || ch == L':') { - break; - } - ComponentName.Length += sizeof(WCHAR); - } - if (ComponentName.Length == 0) { - return CurrentLcb; - } - ComponentName.MaximumLength = ComponentName.Length; - - // Advance local remaining name past this component - LocalRemainingName.Buffer += ComponentName.Length / sizeof(WCHAR); - LocalRemainingName.Length -= ComponentName.Length; - - // - // Search for matching component. Try splay trees first (O(log n)), - // then fall back to list iteration (O(n)) for LCBs without names, - // duplicate-name LCBs, or names too long for upcase buffer. - // *CurrentFcb is held exclusive, so trees and queue are safe. - // - MatchLcb = NULL; - - // Splay tree search: try IgnoreCase or ExactCase tree - if (IgnoreCase && (*CurrentFcb)->IgnoreCaseRoot != NULL) { - // Upcase component for ignore-case tree lookup - if (ComponentName.Length <= sizeof(UpcaseBuffer)) { - UpcaseName.Buffer = UpcaseBuffer; - UpcaseName.MaximumLength = sizeof(UpcaseBuffer); - UpcaseName.Length = ComponentName.Length; - RtlCopyMemory(UpcaseBuffer, ComponentName.Buffer, ComponentName.Length); - RtlUpcaseUnicodeString(&UpcaseName, &UpcaseName, FALSE); - - MatchLcb = UdfFindNameLink(&(*CurrentFcb)->IgnoreCaseRoot, - &UpcaseName, - FIELD_OFFSET(LCB, IgnoreCaseLinks), - FIELD_OFFSET(LCB, IgnoreCaseLinkName)); - } - } else if (!IgnoreCase && (*CurrentFcb)->ExactCaseRoot != NULL) { - MatchLcb = UdfFindNameLink(&(*CurrentFcb)->ExactCaseRoot, - &ComponentName, - FIELD_OFFSET(LCB, ExactCaseLinks), - FIELD_OFFSET(LCB, FileName)); - } - - // Try short name splay tree if no match yet - if (!MatchLcb && (*CurrentFcb)->ShortNameRoot != NULL) { - if (ComponentName.Length <= sizeof(UpcaseBuffer)) { - UpcaseName.Buffer = UpcaseBuffer; - UpcaseName.MaximumLength = sizeof(UpcaseBuffer); - UpcaseName.Length = ComponentName.Length; - RtlCopyMemory(UpcaseBuffer, ComponentName.Buffer, ComponentName.Length); - RtlUpcaseUnicodeString(&UpcaseName, &UpcaseName, FALSE); - - MatchLcb = UdfFindNameLink(&(*CurrentFcb)->ShortNameRoot, - &UpcaseName, - FIELD_OFFSET(LCB, ShortNameLinks), - FIELD_OFFSET(LCB, ShortName)); - if (MatchLcb) { - *ShortNameMatch = TRUE; - } - } - } - - // List fallback: catches LCBs without names in splay trees - // (NULL names, duplicates, long names) and handles deleted-link filtering. - if (!MatchLcb) { - for (PLIST_ENTRY ListEntry = (*CurrentFcb)->ChildLcbQueue.Flink; - ListEntry != &(*CurrentFcb)->ChildLcbQueue; - ListEntry = ListEntry->Flink) { - - PLCB Lcb = CONTAINING_RECORD(ListEntry, LCB, ParentFcbLinks); - - ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); - ASSERT(Lcb->ParentFcb == *CurrentFcb); - - if (FlagOn(Lcb->Flags, UDF_LCB_FLAG_LINK_DELETED)) { - continue; - } - - // Try FileName (exact or case-insensitive) - if (Lcb->FileName.Buffer && Lcb->FileName.Length > 0 && - RtlEqualUnicodeString(&ComponentName, &Lcb->FileName, IgnoreCase)) { - MatchLcb = Lcb; - break; - } - // Try IgnoreCaseLinkName - if (IgnoreCase && - Lcb->IgnoreCaseLinkName.Buffer && Lcb->IgnoreCaseLinkName.Length > 0 && - RtlEqualUnicodeString(&ComponentName, &Lcb->IgnoreCaseLinkName, TRUE)) { - MatchLcb = Lcb; - break; - } - // Try ShortName - if (Lcb->ShortName.Buffer && Lcb->ShortName.Length > 0 && - RtlEqualUnicodeString(&ComponentName, &Lcb->ShortName, TRUE)) { - MatchLcb = Lcb; - *ShortNameMatch = TRUE; - break; - } - } - } - - // - // Validate the match: skip deleted links and deleted FCBs. - // A deleted FCB can still have LCBs in the splay tree/list if - // teardown hasn't run yet (between cleanup and close). - // Clean up stale splay entries when found. - // - if (MatchLcb && !FlagOn(MatchLcb->Flags, UDF_LCB_FLAG_LINK_DELETED) && - MatchLcb->ChildFcb && - (MatchLcb->ChildFcb->FcbState & UDF_FCB_DELETED)) { - // Child FCB was deleted — remove LCB from splay trees - // (we hold ParentFcb exclusive) and mark as deleted. - UdfRemoveNameLinks(*CurrentFcb, MatchLcb); - MatchLcb->Flags |= UDF_LCB_FLAG_LINK_DELETED; - MatchLcb = NULL; - } - - if (!MatchLcb || FlagOn(MatchLcb->Flags, UDF_LCB_FLAG_LINK_DELETED)) { - // No match or deleted link — stop, *CurrentFcb stays locked - return CurrentLcb; - } - - // Found a match. Descend into child FCB with proper locking: - // acquire child exclusive, then release parent. - CurrentLcb = MatchLcb; - *RemainingName = LocalRemainingName; - - PFCB ChildFcb = MatchLcb->ChildFcb; - - UDF_CHECK_PAGING_IO_RESOURCE(ChildFcb); - if (!UDFAcquireFcbExclusive(IrpContext, ChildFcb, TRUE)) { - // Try-lock failed. Bump references to keep child alive, - // release parent, then wait-acquire child. - PVCB Vcb = (PVCB)IrpContext->Vcb; - - UDFLockVcb(IrpContext, Vcb); - ChildFcb->FcbReference += 1; - MatchLcb->Reference += 1; - UDFUnlockVcb(IrpContext, Vcb); - - UDFReleaseFcb(IrpContext, *CurrentFcb); - - UDFAcquireFcbExclusive(IrpContext, ChildFcb, FALSE); - - UDFLockVcb(IrpContext, Vcb); - ChildFcb->FcbReference -= 1; - MatchLcb->Reference -= 1; - UDFUnlockVcb(IrpContext, Vcb); - } else { - // Try-lock succeeded. Release parent. - UDFReleaseFcb(IrpContext, *CurrentFcb); - } - - *CurrentFcb = ChildFcb; - } - - return CurrentLcb; -} // end UDFFindPathPrefix() - - -/* - Atomically rename an LCB and optionally move it to a new parent directory. - Updates the file name, moves between parent ChildLcbQueue lists, - and adjusts parent reference counts — all in one call. - - NewParentFcb = NULL for same-directory rename (name change only). -*/ -NTSTATUS -UDFRenameMovePrefix( - IN PIRP_CONTEXT IrpContext, - IN PLCB Lcb, - IN PUNICODE_STRING NewName, - IN PFCB NewParentFcb OPTIONAL - ) -{ - PWCHAR NewBuffer; - USHORT NewLength; - BOOLEAN OldBufferEmbedded; - - if (!Lcb || !NewName || NewName->Length == 0) { - return STATUS_INVALID_PARAMETER; - } - - ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); - - NewLength = NewName->Length; - - // Allocate new buffer for the name - NewBuffer = (PWCHAR)MyAllocatePool__(NonPagedPool, NewLength + sizeof(WCHAR)); - if (!NewBuffer) { - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlCopyMemory(NewBuffer, NewName->Buffer, NewLength); - NewBuffer[NewLength / sizeof(WCHAR)] = 0; - - // Remove from current parent's splay trees before changing names. - // Caller must hold ParentFcb exclusive (enforced in fileinfo.cpp). - if (Lcb->ParentFcb) { - UdfRemoveNameLinks(Lcb->ParentFcb, Lcb); - } - - // Check if old buffer was embedded in LCB structure - // or separately allocated. Only free if separately allocated. - OldBufferEmbedded = (Lcb->FileName.Buffer != NULL && - (PUCHAR)Lcb->FileName.Buffer >= (PUCHAR)Lcb && - (PUCHAR)Lcb->FileName.Buffer < (PUCHAR)Lcb + Lcb->NodeIdentifier.NodeByteSize); - - if (Lcb->FileName.Buffer && !OldBufferEmbedded) { - MyFreePool__(Lcb->FileName.Buffer); - } - - // Set new name (component name, not cached full path) - Lcb->FileName.Buffer = NewBuffer; - Lcb->FileName.Length = NewLength; - Lcb->FileName.MaximumLength = NewLength + sizeof(WCHAR); - - // Clear cached full path flag — FileName now holds component name only - ClearFlag(Lcb->Flags, UDF_LCB_FLAG_HAS_NAME_BUFFER); - - // Also update ExactCaseLinkName to point to same buffer - Lcb->ExactCaseLinkName = Lcb->FileName; - - // Free old IgnoreCaseLinkName if separately allocated - if (Lcb->IgnoreCaseLinkName.Buffer != NULL) { - BOOLEAN IgnoreCaseEmbedded = ((PUCHAR)Lcb->IgnoreCaseLinkName.Buffer >= (PUCHAR)Lcb && - (PUCHAR)Lcb->IgnoreCaseLinkName.Buffer < (PUCHAR)Lcb + Lcb->NodeIdentifier.NodeByteSize); - if (!IgnoreCaseEmbedded) { - ExFreePool(Lcb->IgnoreCaseLinkName.Buffer); - } - } - - // Rebuild IgnoreCaseLinkName — upcased version of new name. - // Required for IgnoreCase splay tree lookup (Windows opens case-insensitive). - { - PWCHAR UpcaseBuffer = (PWCHAR)ExAllocatePoolWithTag(PagedPool, - NewLength + sizeof(WCHAR), - TAG_FILE_NAME); - if (UpcaseBuffer) { - Lcb->IgnoreCaseLinkName.Buffer = UpcaseBuffer; - Lcb->IgnoreCaseLinkName.Length = NewLength; - Lcb->IgnoreCaseLinkName.MaximumLength = NewLength + sizeof(WCHAR); - RtlCopyMemory(UpcaseBuffer, NewBuffer, NewLength); - UpcaseBuffer[NewLength / sizeof(WCHAR)] = 0; - RtlUpcaseUnicodeString(&Lcb->IgnoreCaseLinkName, &Lcb->IgnoreCaseLinkName, FALSE); - } else { - // Allocation failed — clear IgnoreCaseLinkName. - // File will still be findable via list fallback. - Lcb->IgnoreCaseLinkName.Buffer = NULL; - Lcb->IgnoreCaseLinkName.Length = 0; - Lcb->IgnoreCaseLinkName.MaximumLength = 0; - } - } - - // Clear stale ShortName — old 8.3 name is invalid after rename. - // The embedded buffer data stays in LCB allocation but won't be used. - // Short name will be regenerated on next open if needed. - if (Lcb->ShortName.Buffer != NULL) { - BOOLEAN ShortNameEmbedded = ((PUCHAR)Lcb->ShortName.Buffer >= (PUCHAR)Lcb && - (PUCHAR)Lcb->ShortName.Buffer < (PUCHAR)Lcb + Lcb->NodeIdentifier.NodeByteSize); - if (!ShortNameEmbedded) { - ExFreePool(Lcb->ShortName.Buffer); - } - Lcb->ShortName.Buffer = NULL; - Lcb->ShortName.Length = 0; - Lcb->ShortName.MaximumLength = 0; - } - - // Move LCB to new parent directory if specified (cross-directory rename) - if (NewParentFcb && NewParentFcb != Lcb->ParentFcb) { - - PFCB OldParentFcb = Lcb->ParentFcb; - PUDF_FILE_INFO OldParentFileInfo = OldParentFcb ? OldParentFcb->FileInfo : NULL; - - // Remove from old parent's ChildLcbQueue - RemoveEntryList(&Lcb->ParentFcbLinks); - - // Insert into new parent's ChildLcbQueue - InsertHeadList(&NewParentFcb->ChildLcbQueue, &Lcb->ParentFcbLinks); - - // Update LCB to point to new parent - Lcb->ParentFcb = NewParentFcb; - - // Adjust reference counts - if (OldParentFcb) { - ASSERT(OldParentFcb->FcbReference > 0); - InterlockedDecrement((PLONG)&OldParentFcb->FcbReference); - - if (OldParentFileInfo && OldParentFcb->Vcb) { - UDFCloseFile__(IrpContext, OldParentFcb->Vcb, OldParentFileInfo); - } - } - - InterlockedIncrement((PLONG)&NewParentFcb->FcbReference); - - if (NewParentFcb->FileInfo) { - UDFReferenceFile__(NewParentFcb->FileInfo); - } - } - - // Re-insert into splay trees of (possibly new) parent. - // Caller must hold the (new) ParentFcb exclusive. - if (Lcb->ParentFcb) { - UdfInsertNameLinks(Lcb->ParentFcb, Lcb); - } - - return STATUS_SUCCESS; -} // end UDFRenameMovePrefix() diff --git a/drivers/filesystems/udfs/protos.h b/drivers/filesystems/udfs/protos.h index acaa3cd52b8b4..108b1ea853a56 100644 --- a/drivers/filesystems/udfs/protos.h +++ b/drivers/filesystems/udfs/protos.h @@ -66,6 +66,12 @@ UDFFastDecodeFileObject ( _Out_ PFCB *Fcb ); +PCCB +UDFDecodeFileObjectCcb( + _In_ PFILE_OBJECT FileObject + ); + + /************************************************************************* * Prototypes for the file create.cpp *************************************************************************/ @@ -79,28 +85,38 @@ UDFCommonCreate( IN PIRP Irp ); -NTSTATUS -UDFOpenObjectByFileId( - _In_ PIRP_CONTEXT IrpContext, - _In_ PIO_STACK_LOCATION IrpSp, - _In_ PVCB Vcb, - _Inout_ PFCB *CurrentFcb - ); - NTSTATUS UDFFirstOpenFile( IN PIRP_CONTEXT IrpContext, + IN PIO_STACK_LOCATION IrpSp, IN PVCB Vcb, + IN PFILE_OBJECT PtrNewFileObject, OUT PFCB* PtrNewFcb, IN PUDF_FILE_INFO RelatedFileInfo, - IN PUDF_FILE_INFO NewFileInfo + IN PUDF_FILE_INFO NewFileInfo, + IN PUNICODE_STRING LocalPath, + IN PUNICODE_STRING CurName, + IN ULONG CreateDisposition + ); + +NTSTATUS +UDFCompleteFcbOpen( + _In_ PIRP_CONTEXT IrpContext, + _In_ PIO_STACK_LOCATION IrpSp, + _In_ PVCB Vcb, + _Inout_ PFCB *CurrentFcb, + _In_ TYPE_OF_OPEN TypeOfOpen, + _In_ ULONG UserCcbFlags, + _In_ ULONG CreateDisposition ); NTSTATUS UDFInitializeFCB( IN PFCB PtrNewFcb, // FCB structure to be initialized IN PVCB Vcb, // logical volume (VCB) pointer - IN ULONG Flags // is this a file/directory, etc. + IN PtrUDFObjectName PtrObjectName, // name of the object + IN ULONG Flags, // is this a file/directory, etc. + IN PFILE_OBJECT FileObject // optional file object to be initialized ); /************************************************************************* @@ -114,6 +130,15 @@ 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 *************************************************************************/ @@ -133,7 +158,7 @@ VOID UDFTeardownStructures( _In_ PIRP_CONTEXT IrpContext, _Inout_ PFCB StartingFcb, - _In_ BOOLEAN Recursive, // TRUE if this is a recursive call (for hard links) + _In_ ULONG TreeLength, _Out_ PBOOLEAN RemovedStartingFcb ); @@ -400,8 +425,7 @@ UDFGetFileStreamInformation( ); extern NTSTATUS UDFSetBasicInformation( - IN PIRP_CONTEXT IrpContext, - IN PFCB Fcb, + IN PFCB Fcb, IN PCCB Ccb, IN PFILE_OBJECT FileObject, IN PFILE_BASIC_INFORMATION PtrBuffer); @@ -445,11 +469,6 @@ UDFSetEndOfFileInfo( IN PFILE_END_OF_FILE_INFORMATION PtrBuffer ); -BOOLEAN -UDFCheckDirOpenHandles( - IN PFCB DirectoryFcb - ); - NTSTATUS UDFSetRenameInfo( IN PIRP_CONTEXT IrpContext, @@ -512,7 +531,7 @@ ULONG UDFFlushAFile( IN PFCB Fcb, IN PCCB Ccb, OUT PIO_STATUS_BLOCK PtrIoStatus, - IN ULONG FlushFlags = 0 + IN ULONG FlushFlags ); ULONG @@ -521,14 +540,14 @@ UDFFlushADirectory( IN PVCB Vcb, IN PUDF_FILE_INFO FI, OUT PIO_STATUS_BLOCK PtrIoStatus, - ULONG FlushFlags = 0 + ULONG FlushFlags ); NTSTATUS UDFFlushVolume( PIRP_CONTEXT IrpContext, PVCB Vcb, - ULONG FlushFlags = 0 + ULONG FlushFlags ); extern NTSTATUS NTAPI UDFFlushCompletion( @@ -538,7 +557,7 @@ PVOID Context); extern BOOLEAN UDFFlushIsBreaking( IN PVCB Vcb, -IN ULONG FlushFlags = 0); +IN ULONG FlushFlags); extern VOID UDFFlushTryBreak( IN PVCB Vcb); @@ -651,9 +670,7 @@ extern NTSTATUS NTAPI UDFCommonLockControl( IN PIRP_CONTEXT IrpContext, IN PIRP Irp); -BOOLEAN -NTAPI -UDFFastLock( +extern BOOLEAN NTAPI UDFFastLock( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, @@ -692,6 +709,11 @@ UDFFastUnlockAllByKey( /************************************************************************* * Prototypes for the file misc.cpp *************************************************************************/ +extern NTSTATUS UDFInitializeZones( +VOID); + +extern VOID UDFDestroyZones( +VOID); _IRQL_requires_max_(APC_LEVEL) __drv_dispatchType(DRIVER_DISPATCH) @@ -740,114 +762,13 @@ PCCB UDFCreateCcb( ); -VOID -UDFDeallocateCcb( - PCCB Ccb - ); +extern VOID UDFReleaseCCB(PCCB Ccb); VOID UDFDeleteCcb( PCCB Ccb ); -// prefxsup.cpp - LCB functions -PLCB -UDFInsertPrefix( - IN PIRP_CONTEXT IrpContext, - IN PFCB ParentFcb, - IN PFCB ChildFcb, - IN PUNICODE_STRING FileName OPTIONAL, - IN PUNICODE_STRING CaseFileName OPTIONAL, - IN PUNICODE_STRING ShortName OPTIONAL, - IN ULONGLONG InitialOffset - ); - -VOID -UDFRemovePrefix( - IN PIRP_CONTEXT IrpContext, - IN PLCB Lcb - ); - -// Insert LCB into parent FCB's splay trees (ExactCase, IgnoreCase, ShortName). -// Caller must hold ParentFcb exclusive. -VOID -UdfInsertNameLinks( - IN PFCB ParentFcb, - IN PLCB Lcb - ); - -// Remove LCB from parent FCB's splay trees only (not from linked lists). -// Caller must hold ParentFcb exclusive. -VOID -UdfRemoveNameLinks( - IN PFCB ParentFcb, - 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 PUNICODE_STRING FileName OPTIONAL, - IN PUNICODE_STRING CaseFileName OPTIONAL, - IN PUNICODE_STRING ShortName OPTIONAL, - IN ULONGLONG InitialOffset - ); - -VOID -UDFReleasePrefix( - IN PIRP_CONTEXT IrpContext, - IN PLCB Lcb - ); - -NTSTATUS -UDFBuildFullPathFromLcb( - IN PIRP_CONTEXT IrpContext, - IN PLCB Lcb, - OUT PUNICODE_STRING FullPath, - IN BOOLEAN CachePath - ); - -BOOLEAN -UDFReleasePrefixImmediate( - IN PIRP_CONTEXT IrpContext, - IN PLCB Lcb, - IN BOOLEAN CloseParentFileInfo - ); - -NTSTATUS -UDFRenameMovePrefix( - IN PIRP_CONTEXT IrpContext, - IN PLCB Lcb, - IN PUNICODE_STRING NewName, - IN PFCB NewParentFcb OPTIONAL - ); - -PLCB -UDFFindPathPrefix( - IN PIRP_CONTEXT IrpContext, - IN PFCB StartFcb, - IN BOOLEAN IgnoreCase, - IN OUT PFCB *CurrentFcb, - IN OUT PUNICODE_STRING RemainingName, - OUT PBOOLEAN ShortNameMatch - ); - -PFCB -UDFLookupFcbTable ( - _In_ PIRP_CONTEXT IrpContext, - _In_ PVCB Vcb, - _In_ FILE_ID FileId - ); - PFCB UDFCreateFcb ( _In_ PIRP_CONTEXT IrpContext, @@ -858,16 +779,12 @@ UDFCreateFcb ( VOID UDFDeleteFcb( - _In_opt_ PIRP_CONTEXT IrpContext, - _In_ PFCB Fcb - ); - -VOID -UDFInsertFcbIntoTable( _In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb ); +VOID UDFCleanUpFCB(PFCB Fcb); + _Ret_valid_ PIRP_CONTEXT UDFCreateIrpContext( _In_ PIRP Irp, @@ -925,7 +842,7 @@ UDFReadRegKeys( extern ULONG UDFGetRegParameter( IN PVCB Vcb, IN PCWSTR Name, - IN ULONG DefValue = 0); + IN ULONG DefValue); VOID UDFDeleteVCB( @@ -1047,7 +964,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 @@ -1263,35 +1180,6 @@ UDFMarkDevForVerifyIfVcbMounted( (V)->VcbLockThread = NULL; \ ExReleaseFastMutexUnsafe( &(V)->VcbMutex ) -#define UDFLockFcbTable(IC,V) \ - ASSERT(KeAreApcsDisabled()); \ - ExAcquireFastMutexUnsafe( &(V)->FcbTableMutex ); \ - (V)->FcbTableLockThread = PsGetCurrentThread() - -#define UDFUnlockFcbTable(IC,V) \ - (V)->FcbTableLockThread = NULL; \ - ExReleaseFastMutexUnsafe( &(V)->FcbTableMutex ) - -#define UDFLockFcb(IC,F) { \ - PVOID _CurrentThread = PsGetCurrentThread(); \ - if (_CurrentThread != (F)->FcbLockThread) { \ - ASSERT(KeAreApcsDisabled()); \ - ExAcquireFastMutexUnsafe( &(F)->FcbNonpaged->FcbFastMutex ); \ - ASSERT( (F)->FcbLockCount == 0 ); \ - (F)->FcbLockThread = _CurrentThread; \ - } \ - (F)->FcbLockCount += 1; \ -} - -#define UDFUnlockFcb(IC,F) { \ - ASSERT( PsGetCurrentThread() == (F)->FcbLockThread); \ - (F)->FcbLockCount -= 1; \ - if ((F)->FcbLockCount == 0) { \ - (F)->FcbLockThread = NULL; \ - ExReleaseFastMutexUnsafe( &(F)->FcbNonpaged->FcbFastMutex ); \ - } \ -} - #define UDFIncrementCleanupCounts(IC,F) { \ ASSERT_LOCKED_VCB( (F)->Vcb ); \ (F)->FcbCleanup += 1; \ @@ -1336,6 +1224,7 @@ enum TYPE_OF_ACQUIRE { AcquireSharedStarveExclusive }; +typedef enum TYPE_OF_ACQUIRE TYPE_OF_ACQUIRE; _Requires_lock_held_(_Global_critical_region_) _When_(Type == AcquireExclusive && return != FALSE, _Acquires_exclusive_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 99% rename from drivers/filesystems/udfs/shutdown.cpp rename to drivers/filesystems/udfs/shutdown.c index 93dd97b067f36..9dbb827bcfe09 100644 --- a/drivers/filesystems/udfs/shutdown.cpp +++ b/drivers/filesystems/udfs/shutdown.c @@ -109,7 +109,7 @@ UDFCommonShutdown( UDFAcquireVcbExclusive(IrpContext, Vcb, FALSE); - UDFFlushVolume(IrpContext, Vcb); + UDFFlushVolume(IrpContext, Vcb, 0); ASSERT(CONTAINING_RECORD(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, VOLUME_DEVICE_OBJECT, diff --git a/drivers/filesystems/udfs/strucsup.cpp b/drivers/filesystems/udfs/strucsup.c similarity index 62% rename from drivers/filesystems/udfs/strucsup.cpp rename to drivers/filesystems/udfs/strucsup.c index 6e746f30fc8a4..860179a50b33f 100644 --- a/drivers/filesystems/udfs/strucsup.cpp +++ b/drivers/filesystems/udfs/strucsup.c @@ -29,24 +29,7 @@ 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 +static inline PFCB_NONPAGED UDFAllocateFcbNonpaged( ) @@ -54,7 +37,7 @@ UDFAllocateFcbNonpaged( return (PFCB_NONPAGED)ExAllocateFromNPagedLookasideList(&UdfData.UDFNonPagedFcbLookasideList); } -inline +static inline PFCB UDFAllocateFcbIndex( ) @@ -62,7 +45,7 @@ UDFAllocateFcbIndex( return (PFCB)ExAllocateFromPagedLookasideList(&UdfData.UDFFcbIndexLookasideList); } -inline +static inline PFCB UDFAllocateFcbData( ) @@ -70,7 +53,7 @@ UDFAllocateFcbData( return (PFCB)ExAllocateFromPagedLookasideList(&UdfData.UDFFcbDataLookasideList); } -inline +static inline PFCB UDFAllocateFcb( ) @@ -78,7 +61,7 @@ UDFAllocateFcb( return (PFCB)ExAllocatePoolWithTag(NonPagedPool, sizeof(FCB), TAG_FCB); } -inline +static inline VOID UDFDeallocateFcbNonpaged( PFCB_NONPAGED FcbNonpaged @@ -87,7 +70,7 @@ UDFDeallocateFcbNonpaged( ExFreeToNPagedLookasideList(&UdfData.UDFNonPagedFcbLookasideList, FcbNonpaged); } -inline +static inline VOID UDFDeallocateFcbIndex( PFCB Fcb @@ -96,7 +79,7 @@ UDFDeallocateFcbIndex( ExFreeToPagedLookasideList(&UdfData.UDFFcbIndexLookasideList, Fcb); } -inline +static inline VOID UDFDeallocateFcbData( PFCB Fcb @@ -146,7 +129,8 @@ Return Value: ExInitializeResourceLite(&FcbNonpaged->FcbResource); ExInitializeFastMutex(&FcbNonpaged->FcbMutex); ExInitializeFastMutex(&FcbNonpaged->AdvancedFcbHeaderMutex); - ExInitializeFastMutex(&FcbNonpaged->FcbFastMutex); + + ExInitializeResourceLite(&FcbNonpaged->CcbListResource); return FcbNonpaged; } @@ -180,6 +164,7 @@ Return Value: ExDeleteResourceLite(&FcbNonpaged->FcbResource); ExDeleteResourceLite(&FcbNonpaged->FcbPagingIoResource); + ExDeleteResourceLite(&FcbNonpaged->CcbListResource); UDFDeallocateFcbNonpaged(FcbNonpaged); @@ -188,7 +173,7 @@ Return Value: VOID UDFDeleteFcb( - _In_opt_ PIRP_CONTEXT IrpContext, + _In_ PIRP_CONTEXT IrpContext, _In_ PFCB Fcb ) @@ -200,16 +185,9 @@ 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: - IrpContext - Optional IrpContext (unused but kept for API consistency). - - Fcb - This is the Fcb to deallocate. + Fcb - This is the Fcb to deallcoate. Return Value: @@ -219,409 +197,101 @@ Return Value: { PVCB Vcb = NULL; - PAGED_CODE(); - UNREFERENCED_PARAMETER(IrpContext); + // Sanity check the counts. - UDFPrint(("UDFDeleteFcb: %x\n", Fcb)); + NT_ASSERT( Fcb->FcbCleanup == 0 ); + NT_ASSERT( Fcb->FcbReference == 0 ); - ASSERT_FCB(Fcb); + // Release any Filter Context structures associated with this FCB - // Sanity check the counts. + // FsRtlTeardownPerStreamContexts(&Fcb->Header); - NT_ASSERT( Fcb->FcbCleanup == 0 ); - NT_ASSERT( Fcb->FcbReference == 0 ); + // Start with the common structures. - // 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)); + // CdUninitializeMcb( IrpContext, Fcb ); - // LCB queues must be empty - all LCBs should be removed during teardown - NT_ASSERT(IsListEmpty(&Fcb->ParentLcbQueue)); - NT_ASSERT(IsListEmpty(&Fcb->ChildLcbQueue)); + // CdDeleteFcbNonpaged( IrpContext, Fcb->FcbNonpaged ); - // NOTE: FCB no longer stores FCBName - all names are stored in LCB. - // No FCBName cleanup needed. + // + // Check if we need to deallocate the prefix name buffer. + // - // Release any Filter Context structures associated with this FCB. - // Only if FCB was fully initialized (Header.Resource is set by - // UDFInitializeFCB). + // if ((Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != (PWCHAR) Fcb->FileNamePrefix.FileNameBuffer) && + // (Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer != NULL)) { - if (Fcb->Header.Resource) { - FsRtlTeardownPerStreamContexts(&Fcb->Header); - } + // CdFreePool( &Fcb->FileNamePrefix.ExactCaseName.FileName.Buffer ); + // } - // Delete non-paged portion (resources + dealloc). + // + // Now look at the short name prefix. + // + + // if (Fcb->ShortNamePrefix != NULL) { - UDFDeleteFcbNonpaged(IrpContext, Fcb->FcbNonpaged); + // CdFreePool( &Fcb->ShortNamePrefix ); + // } - // Now do the type specific structures. + // + // Now do the type specific structures. + // switch (Fcb->Header.NodeTypeCode) { case UDF_NODE_TYPE_INDEX: - if (Fcb == Fcb->Vcb->RootIndexFcb) { + // NT_ASSERT( Fcb->FileObject == NULL ); + // NT_ASSERT( IsListEmpty( &Fcb->FcbQueue )); - Vcb = Fcb->Vcb; - Vcb->RootIndexFcb = NULL; - } + // if (Fcb == Fcb->Vcb->RootIndexFcb) { + + // Vcb = Fcb->Vcb; + // Vcb->RootIndexFcb = NULL; + + // } else if (Fcb == Fcb->Vcb->PathTableFcb) { + + // Vcb = Fcb->Vcb; + // Vcb->PathTableFcb = NULL; + // } UDFDeallocateFcbIndex(Fcb); break; case UDF_NODE_TYPE_DATA: - if (Fcb->FileLock != NULL) { + // if (Fcb->FileLock != NULL) { - FsRtlFreeFileLock( Fcb->FileLock ); - } + // FsRtlFreeFileLock( Fcb->FileLock ); + // } - if (Fcb == Fcb->Vcb->VolumeDasdFcb) { + // FsRtlUninitializeOplock( CdGetFcbOplock(Fcb) ); - Vcb = Fcb->Vcb; - Vcb->VolumeDasdFcb = NULL; - } + if (Fcb == Fcb->Vcb->VolumeDasdFcb) { + + __debugbreak(); + + 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. - - 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) { - UDFReleaseFcb(IrpContext, ParentFcb); - } - } - - // - // Get this new parent Fcb to work on. - // - ParentFcb = Lcb->ParentFcb; - UDFAcquireFcbExclusive(IrpContext, ParentFcb, FALSE); - } - - // - // 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); - UDFReleaseFcb(IrpContext, ParentFcb); - 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 (this frees the LCB) - // - UDFRemovePrefix(IrpContext, Lcb); - - // - // Decrement parent's references, - // parent refs were incremented in UDFAcquirePrefix 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 ordering: FcbTableMutex (outer) before VcbMutex (inner). - // - UDFLockFcbTable(IrpContext, Vcb); - UDFLockVcb(IrpContext, Vcb); - - if (CurrentFcb->FcbReference != 0) { - // - // Nope, nothing more to do. Stop right now. - // - UDFUnlockVcb(IrpContext, Vcb); - UDFUnlockFcbTable(IrpContext, Vcb); - - if (ParentFcb != NULL) { - UDFReleaseFcb(IrpContext, ParentFcb); - } - 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); - UDFUnlockFcbTable(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); - } - else { - // File is already deleted - clear Modified flags without flushing to disk. - // The deletion was already written in cleanup.cpp via UDFUnlinkFile__. - // Any pending modifications are irrelevant for deleted files. - PUDF_FILE_INFO FileInfo = CurrentFcb->FileInfo; - PUDF_DATALOC_INFO Dloc = FileInfo->Dloc; - if (Dloc) { - Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; - Dloc->DataLoc.Modified = FALSE; - Dloc->DataLoc.Flags &= ~EXTENT_FLAG_PREALLOCATED; - Dloc->AllocLoc.Modified = FALSE; - Dloc->FELoc.Modified = FALSE; - } - // Also clear FI_Modified flag in parent's DirIndex - if (FileInfo->ParentFile && FileInfo->ParentFile->Dloc) { - PDIR_INDEX_ITEM DirNdx = UDFDirIndex( - FileInfo->ParentFile->Dloc->DirIndex, - FileInfo->Index); - if (DirNdx) { - DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED; - } - } - } - - // 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. - UDFReleaseFcb(IrpContext, CurrentFcb); - - // 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; - } - - UDFReleaseFcb(IrpContext, CurrentFcb); - CurrentFcb = ParentFcb; - ParentFcb = NULL; - AcquiredCurrentFcb = TRUE; - } - } else { - // Cannot delete - release and move to parent - if (CurrentFcb != StartingFcb || AcquiredCurrentFcb) { - UDFReleaseFcb(IrpContext, CurrentFcb); - } - CurrentFcb = ParentFcb; - ParentFcb = NULL; - AcquiredCurrentFcb = TRUE; - } - - } while (CurrentFcb != NULL); - - } _SEH2_FINALLY { - - // - // Release the current Fcb if we have acquired it. - // - if (AcquiredCurrentFcb && (CurrentFcb != NULL)) { - UDFReleaseFcb(IrpContext, CurrentFcb); - } - - // - // 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, @@ -871,7 +541,9 @@ NTSTATUS UDFInitializeFCB( IN PFCB Fcb, // FCB structure to be initialized IN PVCB Vcb, // logical volume (VCB) pointer - IN ULONG Flags) // is this a file/directory, etc. + IN PtrUDFObjectName PtrObjectName, // name of the object + IN ULONG Flags, // is this a file/directory, etc. + IN PFILE_OBJECT FileObject) // optional file object to be initialized { ASSERT_LOCKED_VCB(Vcb); @@ -886,25 +558,16 @@ UDFInitializeFCB( Fcb->FcbState = Flags; - // NOTE: FCB is NOT added to FcbTable here. - // Caller is responsible for calling UDFInsertFcbIntoTable after - // FCB is fully initialized. + UDFInsertFcbTable(IrpContext, Fcb); + SetFlag(Fcb->FcbState, FCB_STATE_IN_FCB_TABLE); // initialize the various list heads - InitializeListHead(&Fcb->ParentLcbQueue); - InitializeListHead(&Fcb->ChildLcbQueue); - - // Splay tree roots for fast child lookup by name - Fcb->ExactCaseRoot = NULL; - Fcb->IgnoreCaseRoot = NULL; - Fcb->ShortNameRoot = NULL; + InitializeListHead(&Fcb->NextCCB); Fcb->FcbReference = 0; Fcb->FcbCleanup = 0; - // Initialize file name cache synchronization - Fcb->FcbLockThread = NULL; - Fcb->FcbLockCount = 0; + Fcb->FCBName = PtrObjectName; Fcb->Vcb = Vcb; @@ -1075,7 +738,7 @@ UDFInitializeVCB( ExInitializeResourceLite(&Vcb->VcbResource); ExInitializeResourceLite(&Vcb->BitMapResource1); - + ExInitializeResourceLite(&Vcb->FileIdResource); ExInitializeResourceLite(&Vcb->DlocResource); ExInitializeResourceLite(&Vcb->DlocResource2); ExInitializeResourceLite(&Vcb->FlushResource); @@ -1083,7 +746,6 @@ UDFInitializeVCB( ExInitializeResourceLite(&Vcb->IoResource); ExInitializeFastMutex(&Vcb->VcbMutex); - ExInitializeFastMutex(&Vcb->FcbTableMutex); // Initialize the generic Fcb Table. @@ -1175,6 +837,65 @@ 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, @@ -1183,9 +904,10 @@ UDFCompleteMount( { NTSTATUS Status; UNICODE_STRING LocalPath; + PtrUDFObjectName RootName; ULONG LastSector = 0; BOOLEAN UnlockVcb = FALSE; - FILE_ID FileId{}; + FILE_ID FileId = {0}; PAGED_CODE(); @@ -1218,15 +940,32 @@ UDFCompleteMount( Vcb->RootIndexFcb->FileId = UdfGetFidFromLbAddr(Vcb->RootLbAddr); SetFlag(Vcb->RootIndexFcb->FileId.HighPart, FID_DIR_MASK); - Vcb->RootIndexFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO)); + // Allocate and set root FCB unique name + RootName = UDFAllocateObjectName(); - if (!Vcb->RootIndexFcb->FileInfo) { + if (!RootName) { - UDFDeleteFcb(IrpContext, Vcb->RootIndexFcb); + UDFCleanUpFCB(Vcb->RootIndexFcb); Vcb->RootIndexFcb = NULL; try_return(Status = STATUS_INSUFFICIENT_RESOURCES); } + Status = MyInitUnicodeString(&RootName->ObjectName, UDF_ROOTDIR_NAME); + if (!NT_SUCCESS(Status)) + goto insuf_res_1; + + Vcb->RootIndexFcb->FileInfo = (PUDF_FILE_INFO)MyAllocatePool__(NonPagedPool,sizeof(UDF_FILE_INFO)); + + if (!Vcb->RootIndexFcb->FileInfo) { + Status = STATUS_INSUFFICIENT_RESOURCES; + insuf_res_1: + MyFreePool__(RootName->ObjectName.Buffer); + UDFReleaseObjectName(RootName); + UDFCleanUpFCB(Vcb->RootIndexFcb); + Vcb->RootIndexFcb = NULL; + try_return(Status); + } + UDFPrint(("UDFCompleteMount: open Root Dir\n")); // Open Root Directory Status = UDFOpenRootFile__(IrpContext, Vcb, &Vcb->RootLbAddr, Vcb->RootIndexFcb->FileInfo); @@ -1235,9 +974,7 @@ UDFCompleteMount( UDFCleanUpFile__(Vcb, Vcb->RootIndexFcb->FileInfo); MyFreePool__(Vcb->RootIndexFcb->FileInfo); - UDFDeleteFcb(IrpContext, Vcb->RootIndexFcb); - Vcb->RootIndexFcb = NULL; - try_return(Status); + goto insuf_res_1; } Vcb->RootIndexFcb->FileInfo->Fcb = Vcb->RootIndexFcb; @@ -1249,7 +986,7 @@ UDFCompleteMount( UDFLockVcb(IrpContext, Vcb); UnlockVcb = TRUE; - Status = UDFInitializeFCB(Vcb->RootIndexFcb, Vcb, UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY); + Status = UDFInitializeFCB(Vcb->RootIndexFcb, Vcb, RootName, UDF_FCB_ROOT_DIRECTORY | UDF_FCB_DIRECTORY, NULL); if (!NT_SUCCESS(Status)) { @@ -1259,20 +996,11 @@ UDFCompleteMount( UDFCleanUpFile__(Vcb, Vcb->RootIndexFcb->FileInfo); MyFreePool__(Vcb->RootIndexFcb->FileInfo); - - // FCB was not inserted into table (UDFInitializeFCB failed - // before UDFInsertFcbIntoTable was called) - UDFUnlockVcb(IrpContext, Vcb); - UnlockVcb = FALSE; - - UDFDeleteFcb(IrpContext, Vcb->RootIndexFcb); + UDFCleanUpFCB(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; @@ -1305,8 +1033,11 @@ 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); - Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->RootIndexFcb->FileInfo, &Vcb->NonAllocFileInfo, NULL); + Status = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE); + if (NT_SUCCESS(Status)) { + Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->RootIndexFcb->FileInfo, &Vcb->NonAllocFileInfo, NULL); + MyFreePool__(LocalPath.Buffer); + } if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { @@ -1328,8 +1059,12 @@ 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); + Status = MyInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE_2); + if (!NT_SUCCESS(Status)) { + goto unwind_1; + } Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->RootIndexFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL); + MyFreePool__(LocalPath.Buffer); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { goto unwind_1; } @@ -1338,8 +1073,12 @@ 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); + Status = MyInitUnicodeString(&LocalPath, UDF_SN_NON_ALLOCATABLE); + if (!NT_SUCCESS(Status)) { + goto unwind_1; + } Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->NonAllocFileInfo), NULL); + MyFreePool__(LocalPath.Buffer); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { goto unwind_1; } @@ -1357,7 +1096,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); @@ -1420,6 +1159,8 @@ UDFCompleteMount( Vcb->VolumeDasdFcb = UDFCreateFcb(IrpContext, FileId, UDF_NODE_TYPE_DATA, NULL); + InitializeListHead(&Vcb->VolumeDasdFcb->NextCCB); + UDFIncrementReferenceCounts(IrpContext, Vcb->VolumeDasdFcb, 1, 1); UDFUnlockVcb(IrpContext, Vcb); UnlockVcb = FALSE; @@ -1475,61 +1216,3 @@ UDFCompleteMount( return Status; } // end UDFCompleteMount() - -/************************************************************************* -* -* Function: UDFDeallocateCcb() -* -* Description: -* Deallocate a previously allocated structure. -* -* Expected Interrupt Level (for execution) : -* -* IRQL_PASSIVE_LEVEL -* -* Return Value: None -* -*************************************************************************/ -VOID -UDFDeallocateCcb( - PCCB Ccb - ) -{ - ASSERT_CCB(Ccb); - - ExFreeToPagedLookasideList(&UdfData.CcbLookasideList, Ccb); - -} // end UDFDeallocateCcb() - -/* - Function: UDFDeleteCcb() - - Description: - Cleanup and deallocate a previously allocated structure. - - Expected Interrupt Level (for execution) : - - IRQL_PASSIVE_LEVEL - - Return Value: None - -*/ -VOID -UDFDeleteCcb( - PCCB Ccb -) -{ - if (Ccb->DirectorySearchPattern) { - - if (Ccb->DirectorySearchPattern->Buffer) { - - MyFreePool__(Ccb->DirectorySearchPattern->Buffer); - Ccb->DirectorySearchPattern->Buffer = NULL; - } - - MyFreePool__(Ccb->DirectorySearchPattern); - Ccb->DirectorySearchPattern = NULL; - } - - UDFDeallocateCcb(Ccb); -} // end UDFDeleteCcb() diff --git a/drivers/filesystems/udfs/struct.h b/drivers/filesystems/udfs/struct.h index 74c032224266d..bd09e2b23fcd1 100644 --- a/drivers/filesystems/udfs/struct.h +++ b/drivers/filesystems/udfs/struct.h @@ -36,7 +36,21 @@ struct IRP_CONTEXT_LITE; 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 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. @@ -48,8 +62,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 +81,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. @@ -81,33 +94,23 @@ using PtrUDFObjectName = UDFObjectName*; **************************************************************************/ struct CCB { UDFIdentifier NodeIdentifier; - - // Fcb for the file being opened. - - FCB* Fcb; - - // Lcb for the file being opened. - - LCB* Lcb; - + // ptr to the associated FCB + FCB* Fcb; + // all CCB structures for a FCB are linked together + LIST_ENTRY NextCCB; // each CCB is associated with a file object PFILE_OBJECT FileObject; - - // Flags. Indicates flags to apply for the current open. - - ULONG Flags; - + // flags (see below) associated with this CCB + uint32 Flags; // current index in directory is required sometimes - ULONG CurrentIndex; - // if this CCB represents a directory object open, we may // need to maintain a search pattern - PUNICODE_STRING DirectorySearchPattern; HASH_ENTRY hashes; + ULONG TreeLength; }; -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 @@ -151,6 +154,8 @@ struct FCB_NONPAGED { ERESOURCE FcbPagingIoResource; + ERESOURCE CcbListResource; + // This is the FastMutex for this Fcb. FAST_MUTEX FcbMutex; @@ -160,12 +165,8 @@ struct FCB_NONPAGED { FAST_MUTEX AdvancedFcbHeaderMutex; - // Fast mutex for file name cache synchronization - // Protects LCB->FileName when used as full path cache - 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 +207,11 @@ using PFCB_NONPAGED = FCB_NONPAGED*; /***************************************************/ struct FCB_DATA { - + UCHAR Pad; }; struct FCB_INDEX { - + UCHAR Pad; }; struct FCB { @@ -233,6 +234,9 @@ struct FCB { FILE_ID FileId; + // all CCB's for this particular FCB are linked off the following + // list head. + LIST_ENTRY NextCCB; // whenever a file stream has a create/open operation performed, // the Reference count below is incremented AND the OpenHandle count // below is also incremented. @@ -256,14 +260,9 @@ struct FCB { ULONG FileAttributes; - // File name cache synchronization - // FcbLockThread - owner of the file name cache mutex - // FcbLockCount - reference count for cached names in LCBs - PVOID FcbLockThread; // Thread owning the cache mutex - ULONG FcbLockCount; // Reference count for cache - - // NOTE: FCBName field REMOVED - all names are now stored in LCB. - // Full paths are built dynamically from LCB chain via UDFBuildFullPathFromLcb(). + // for the UDF fsd, there exists a 1-1 correspondence between a + // full object pathname and a FCB + PtrUDFObjectName FCBName; // Pointer to the Fcb non-paged structures. @@ -282,22 +281,9 @@ 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; - - // Splay tree roots for fast child LCB lookup by name. - // Protected by this FCB's FcbResource (exclusive for insert/remove, - // shared is NOT safe — splay rebalances on lookup). - PRTL_SPLAY_LINKS ExactCaseRoot; - PRTL_SPLAY_LINKS IgnoreCaseRoot; - PRTL_SPLAY_LINKS ShortNameRoot; - // Pointer to IrpContextLite in delayed queue. IRP_CONTEXT_LITE* IrpContextLite; + uint32 CcbCount; // The following field is used by the filelock module // to maintain current byte range locking information. @@ -312,7 +298,7 @@ struct FCB { FCB_INDEX FcbIndex; }; }; -using PFCB = FCB*; +typedef FCB* PFCB; #define SIZEOF_FCB_DATA \ (FIELD_OFFSET(FCB, FcbType) + sizeof(FCB_DATA)) @@ -337,10 +323,8 @@ using PFCB = FCB*; #define UDF_FCB_READ_ONLY (0x00001000) #define UDF_FCB_DELAY_CLOSE (0x00002000) #define UDF_FCB_DELETED (0x00004000) -// Verification failed — FID/ICB data on disk does not match FCB -#define UDF_FCB_NEEDS_VERIFICATION (0x00008000) -// Object not found on media during verification — stale FCB -#define UDF_FCB_NOT_FOUND_ON_MEDIA (0x00010000) +#define UDF_FCB_POSTED_RENAME (0x00010000) + #define FCB_STATE_INITIALIZED (0x00020000) #define FCB_STATE_IN_FCB_TABLE (0x00040000) @@ -366,104 +350,7 @@ enum UDFFSD_MEDIA_TYPE { MediaDvdr, MediaDvdrw }; - -//*************************************************************************** -// LCB (Link Control Block) -//*************************************************************************** - -/** - Link Control Block (LCB) - links parent directory to child file. - - Used to defer directory linkage until create operation completes successfully. - This prevents partial creates from being visible in directory lookups. -*/ -struct LCB { - UDFIdentifier NodeIdentifier; // +0x00 Node type = UDFS_NTC_LCB - - UCHAR Reserved1[4]; // +0x04 Padding for alignment - - // Links in parent FCB's ChildLcbQueue - LIST_ENTRY ParentFcbLinks; // +0x08 Links in parent FCB list - - // Parent directory FCB - PFCB ParentFcb; // +0x18 Pointer to parent FCB - - // Links in child FCB's ParentLcbQueue - LIST_ENTRY ChildFcbLinks; // +0x20 Links in child FCB list - - // Child file FCB - PFCB ChildFcb; // +0x30 Pointer to child FCB - - // Initial directory offset (for hard links and directory entries) - ULONGLONG InitialOffset; // +0x38 Initial offset - - // Reference count (incremented by CCB, decremented on cleanup) - ULONG Reference; // +0x40 Reference count - - // LCB flags - ULONG Flags; // +0x44 LCB flags - - // File attributes from directory entry - ULONG FileAttributes; // +0x48 File attributes - - UCHAR Reserved2[4]; // +0x4C Padding - - // ANSI name (for compatibility) - STRING Name; // +0x50 ANSI name (size 0x10) - - UCHAR Reserved3[8]; // +0x60 Padding - - // Splay tree links for exact case name matching - RTL_SPLAY_LINKS ExactCaseLinks; // +0x68 Exact case splay links - - // Exact case name (preserves original case from disk) - UNICODE_STRING ExactCaseLinkName; // +0x80 Exact case link name - - // Splay tree links for case-insensitive name matching - RTL_SPLAY_LINKS IgnoreCaseLinks; // +0x90 Ignore case splay links - - // Case-insensitive name (uppercased for fast comparison) - UNICODE_STRING IgnoreCaseLinkName; // +0xA8 Ignore case link name - - // Splay tree links for short (8.3) name matching - RTL_SPLAY_LINKS ShortNameLinks; // +0xB8 Short name splay links - - // Short (8.3) name for DOS compatibility - UNICODE_STRING ShortName; // +0xD0 Short name - - // Buffer pointer for dynamically allocated name data - // Points to memory immediately after LCB structure in most cases - PVOID NameBuffer; // +0xE0 Buffer pointer - - // Full file name (component name, not full path) - UNICODE_STRING FileName; // +0xE8 File name -}; - -using PLCB = LCB*; - -// LCB Flags -#define UDF_LCB_FLAG_POOL_ALLOCATED 0x00000001 // Allocated from pool (not lookaside) -#define UDF_LCB_FLAG_LINK_DELETED 0x00000002 // Link has been deleted -#define UDF_LCB_FLAG_HAS_NAME_BUFFER 0x00000004 // Name buffer needs freeing (separately allocated) -#define UDF_LCB_FLAG_DELETE_ON_CLEANUP 0x00000008 // Delete file on cleanup -#define UDF_LCB_FLAG_EXACT_CASE_IN_TREE 0x00000010 // In exact case splay tree -#define UDF_LCB_FLAG_IGNORE_CASE_IN_TREE 0x00000020 // In ignore case splay tree -#define UDF_LCB_FLAG_SHORT_NAME_IN_TREE 0x00000040 // In short name splay tree -#define UDF_LCB_FLAG_SHORT_NAME_CREATED 0x00000200 // Short name was created (bit 9) - -// LCB size constants -// Zero 0xF0 bytes (up to +0xE8, excluding FileName UNICODE_STRING buffer pointer) -// Actual structure size is 0xF8 (248 bytes) but we only zero first 0xF0 bytes -#define UDF_LCB_BASE_SIZE 0xF0 // 240 bytes - bytes to zero in RtlZeroMemory (excludes FileName buffer ptr) -#define UDF_LCB_LOOKASIDE_SIZE 0x158 // 344 bytes - max size for lookaside allocation - -// LCB lookaside size - fits LCB + 16 WCHARs for short names -// NOTE: SIZEOF_LOOKASIDE_LCB must be at least UDF_LCB_LOOKASIDE_SIZE (0x158) -#define SIZEOF_LOOKASIDE_LCB UDF_LCB_LOOKASIDE_SIZE - -//*************************************************************************** -// VCB (Volume Control Block) -//*************************************************************************** +typedef enum UDFFSD_MEDIA_TYPE UDFFSD_MEDIA_TYPE; enum VCB_CONDITION { @@ -473,6 +360,7 @@ enum VCB_CONDITION { VcbInvalid, VcbDismountInProgress }; +typedef enum VCB_CONDITION VCB_CONDITION; struct VCB { @@ -549,7 +437,7 @@ struct VCB { // a resource to protect the fields contained within the VCB ERESOURCE VcbResource; ERESOURCE BitMapResource1; - + ERESOURCE FileIdResource; ERESOURCE DlocResource; ERESOURCE DlocResource2; ERESOURCE PreallocResource; @@ -557,20 +445,13 @@ struct VCB { // Vcb fast mutex. This is used to synchronize the fields in the Vcb // when modified when the Vcb is not held exclusively. Included here - // are the count fields. + // are the count fields and Fcb table. // We also use this to synchronize changes to the Fcb reference field. FAST_MUTEX VcbMutex; PVOID VcbLockThread; - // FcbTable fast mutex. Protects Vcb->FcbTable operations (lookup, - // insert, delete) and ensures atomicity of FCB create + init sequence. - // Lock ordering: FcbTableMutex (outer) before VcbMutex (inner). - - FAST_MUTEX FcbTableMutex; - PVOID FcbTableLockThread; - //--------------- // Physical media parameters //--------------- @@ -711,6 +592,7 @@ struct VCB { PUDF_DATALOC_INDEX DlocList; ULONG DlocCount; // FS compatibility + USHORT DefaultAllocMode; // Default alloc mode (from registry) BOOLEAN LowFreeSpace; UDFFSD_MEDIA_TYPE MediaTypeEx; ULONG DefaultAttr; // Default file attributes (NT-style) @@ -720,14 +602,20 @@ struct VCB { UCHAR Reserved5[3]; // + ULONG FECharge; + ULONG FEChargeSDir; + ULONG PackDirThreshold; ULONG SparseThreshold; // in blocks + PUDF_ALLOCATION_CACHE_ITEM FEChargeCache; + ULONG FEChargeCacheMaxSize; + PUDF_ALLOCATION_CACHE_ITEM PreallocCache; ULONG PreallocCacheMaxSize; uint32 CompatFlags; - // Fcb table. Synchronized with FcbTableMutex. + // Fcb table. Synchronized with the Vcb fast mutex. RTL_GENERIC_TABLE FcbTable; @@ -736,7 +624,7 @@ struct VCB { PVPB SwapVpb; }; -using PVCB = VCB*; +typedef VCB* PVCB; // One for root #define UDFS_BASE_RESIDUAL_REFERENCE (4)//(6) @@ -810,7 +698,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 @@ -835,6 +723,7 @@ 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. @@ -854,7 +743,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) @@ -872,6 +761,7 @@ using PIRP_CONTEXT = IRP_CONTEXT*; #define IRP_CONTEXT_FLAG_TRAIL_BACKSLASH (0x00080000) #define UDF_IRP_CONTEXT_NOT_TOP_LEVEL (0x10000000) #define UDF_IRP_CONTEXT_FLUSH_REQUIRED (0x20000000) +#define UDF_IRP_CONTEXT_FLUSH2_REQUIRED (0x40000000) #define IRP_CONTEXT_FLAG_ALLOW_MEDIA_EJECT (0x80000000) // The following flags need to be cleared when a request is posted. @@ -918,8 +808,9 @@ 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*; +typedef IRP_CONTEXT_LITE* PIRP_CONTEXT_LITE; /************************************************************************** we will store all of our global variables in one structure. @@ -962,7 +853,6 @@ typedef struct _UDFData { PAGED_LOOKASIDE_LIST UDFFcbDataLookasideList; PAGED_LOOKASIDE_LIST CcbLookasideList; - PAGED_LOOKASIDE_LIST LcbLookasideList; LIST_ENTRY AsyncCloseQueue; ULONG AsyncCloseCount; @@ -995,7 +885,7 @@ typedef struct _UDFData { } UDFData, *PUDFData; -#define UDF_DATA_FLAGS_SHUTDOWN (0x00000001) +#define UDFS_FLAGS_SHUTDOWN (0x0001) #define TAG_IRP_CONTEXT 'cidU' #define TAG_IRP_CONTEXT_LITE 'lidU' @@ -1003,7 +893,6 @@ 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' @@ -1040,7 +929,9 @@ typedef struct _UDFData { #define UDF_VCB_IC_UPDATE_ARCH_BIT (0x00000008) #define UDF_VCB_IC_UPDATE_DIR_WRITE (0x00000010) #define UDF_VCB_IC_UPDATE_DIR_READ (0x00000020) +#define UDF_VCB_IC_WRITE_IN_RO_DIR (0x00000040) #define UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME (0x00000080) +#define UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS (0x00000100) #define UDF_VCB_IC_IGNORE_SEQUENTIAL_IO (0x00002000) #define UDF_VCB_IC_NO_SYNCCACHE_AFTER_WRITE (0x00004000) #define UDF_VCB_IC_BAD_RW_SEEK (0x00008000) @@ -1049,6 +940,12 @@ typedef struct _UDFData { #define UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS (0x00100000) #define UDF_VCB_IC_DIRTY_RO (0x04000000) +#define UDF_VCB_IC_W2K_COMPAT_VLABEL (0x08000000) +#define UDF_VCB_IC_ADAPTEC_NONALLOC_COMPAT (0x80000000) + +// valid flag values for the global data structure +#define UDF_DATA_FLAGS_ZONES_INITIALIZED (0x00000002) +#define UDF_DATA_FLAGS_SHUTDOWN (0x00000004) #define FILE_ID_CACHE_GRANULARITY 16 #define DLOC_LIST_GRANULARITY 16 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_dbg.h b/drivers/filesystems/udfs/udf_dbg.h index 63fc430bc3c83..d176b88eca8bb 100644 --- a/drivers/filesystems/udfs/udf_dbg.h +++ b/drivers/filesystems/udfs/udf_dbg.h @@ -49,7 +49,7 @@ ULONG _cdecl DbgPrint( - PCH Format, + PCSTR Format, ... ); 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 97% rename from drivers/filesystems/udfs/udf_info/dirtree.cpp rename to drivers/filesystems/udfs/udf_info/dirtree.c index e4ed3534956e4..2934f39e4e3f3 100644 --- a/drivers/filesystems/udfs/udf_info/dirtree.cpp +++ b/drivers/filesystems/udfs/udf_info/dirtree.c @@ -883,51 +883,6 @@ 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/ecma_167.h b/drivers/filesystems/udfs/udf_info/ecma_167.h index 6ca06a7c47fc2..8343008f62eb6 100644 --- a/drivers/filesystems/udfs/udf_info/ecma_167.h +++ b/drivers/filesystems/udfs/udf_info/ecma_167.h @@ -774,3 +774,35 @@ typedef EXTENDED_FILE_ENTRY ExtendedFileEntry; #endif /* __ECMA_167_H__ */ + +/* C typedef aliases for all non-typedef struct declarations */ +typedef struct VolStructDesc VolStructDesc; +typedef struct BeginningExtendedAreaDesc BeginningExtendedAreaDesc; +typedef struct TerminatingExtendedAreaDesc TerminatingExtendedAreaDesc; +typedef struct PrimaryVolDesc PrimaryVolDesc; +typedef struct AnchorVolDescPtr AnchorVolDescPtr; +typedef struct VolDescPtr VolDescPtr; +typedef struct ImpUseVolDesc ImpUseVolDesc; +typedef struct PartitionDesc PartitionDesc; +typedef struct LogicalVolDesc LogicalVolDesc; +typedef struct GenericPartitionMap GenericPartitionMap; +typedef struct GenericPartitionMap1 GenericPartitionMap1; +typedef struct GenericPartitionMap2 GenericPartitionMap2; +typedef struct TerminatingDesc TerminatingDesc; +typedef struct GenericDesc GenericDesc; +typedef struct LogicalVolIntegrityDesc LogicalVolIntegrityDesc; +typedef struct IndirectEntry IndirectEntry; +typedef struct TerminalEntry TerminalEntry; +typedef struct ExtendedAttrHeaderDesc ExtendedAttrHeaderDesc; +typedef struct GenericAttrFormat GenericAttrFormat; +typedef struct CharSetAttrFormat CharSetAttrFormat; +typedef struct AlternatePermissionsExtendedAttr AlternatePermissionsExtendedAttr; +typedef struct FileTimesExtendedAttr FileTimesExtendedAttr; +typedef struct InfoTimesExtendedAttr InfoTimesExtendedAttr; +typedef struct DeviceSpecificationExtendedAttr DeviceSpecificationExtendedAttr; +typedef struct ImpUseExtendedAttr ImpUseExtendedAttr; +typedef struct AppUseExtendedAttr AppUseExtendedAttr; +typedef struct UnallocatedSpaceEntry UnallocatedSpaceEntry; +typedef struct PartitionIntegrityEntry PartitionIntegrityEntry; +typedef struct LogicalVolHeaderDesc LogicalVolHeaderDesc; +typedef struct PathComponent PathComponent; 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 99% rename from drivers/filesystems/udfs/udf_info/mount.cpp rename to drivers/filesystems/udfs/udf_info/mount.c index 62fa4048fc624..4d425ecc52103 100644 --- a/drivers/filesystems/udfs/udf_info/mount.cpp +++ b/drivers/filesystems/udfs/udf_info/mount.c @@ -911,7 +911,7 @@ UDFUpdateNonAllocated( } UDFPackMapping(Vcb, DataLoc); DataLoc->Length = UDFGetExtentLength(DataLoc->Mapping); - UDFFlushFile__(IrpContext, Vcb, Vcb->NonAllocFileInfo); + UDFFlushFile__(IrpContext, Vcb, Vcb->NonAllocFileInfo, 0); // ensure that BAD space is marked as USED UDFMarkSpaceAsXXX(Vcb, 0, &(DataLoc->Mapping[0]), AS_USED); // mark as used @@ -2312,6 +2312,7 @@ UDFReadVDS( } break; case TID_VOL_DESC_PTR: // ISO 13346 3/10.3 + { struct VolDescPtr* pVDP; if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) { @@ -2329,6 +2330,7 @@ UDFReadVDS( vds, Buf); } break; + } case TID_IMP_USE_VOL_DESC: // ISO 13346 3/10.4 if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) { @@ -2730,7 +2732,7 @@ UDFFindLastFileSet( uint16 Ident; uint32 relPrevExt, prevExt; - relPrevExt, prevExt = NULL; + relPrevExt = prevExt = 0; FileSetDesc->nextExt.extLength = 1; // ;) // walk through FileSet chain // we've just pre-init'd extent length to read 1st FileSet diff --git a/drivers/filesystems/udfs/udf_info/osta_misc.h b/drivers/filesystems/udfs/udf_info/osta_misc.h index f9813bfb321c7..60b522c380bae 100644 --- a/drivers/filesystems/udfs/udf_info/osta_misc.h +++ b/drivers/filesystems/udfs/udf_info/osta_misc.h @@ -348,6 +348,17 @@ typedef UID_MAPPING_TABLE* PUID_MAPPING_TABLE; #define TID_ADAPTEC_LOGICAL_VOL_DESC 0x9999U +/* C typedef aliases for all non-typedef struct declarations */ +typedef struct LogicalVolIntegrityDescImpUse LogicalVolIntegrityDescImpUse; +typedef struct ImpUseVolDescImpUse ImpUseVolDescImpUse; +typedef struct UdfPartitionMap2 UdfPartitionMap2; +typedef struct VirtualPartitionMap VirtualPartitionMap; +typedef struct DVDCopyrightImpUse DVDCopyrightImpUse; +typedef struct ADImpUse ADImpUse; +typedef struct FidADImpUse FidADImpUse; +typedef struct VirtualAllocationTable15 VirtualAllocationTable15; +typedef struct VirtualAllocationTable20 VirtualAllocationTable20; + #pragma pack(pop) #endif /* _OSTA_MISC_H */ diff --git a/drivers/filesystems/udfs/udf_info/phys_eject.cpp b/drivers/filesystems/udfs/udf_info/phys_eject.c similarity index 98% rename from drivers/filesystems/udfs/udf_info/phys_eject.cpp rename to drivers/filesystems/udfs/udf_info/phys_eject.c index 2a7a794d27839..d07ccedf10ef0 100644 --- a/drivers/filesystems/udfs/udf_info/phys_eject.cpp +++ b/drivers/filesystems/udfs/udf_info/phys_eject.c @@ -28,7 +28,7 @@ UDFDoDismountSequence( ULONG i; // flush system cache - UDFFlushVolume(NULL, Vcb); + UDFFlushVolume(NULL, Vcb, 0); UDFPrint(("UDFDoDismountSequence:\n")); delay.QuadPart = -1000000; // 0.1 sec 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 91% rename from drivers/filesystems/udfs/udf_info/udf_info.cpp rename to drivers/filesystems/udfs/udf_info/udf_info.c index e9556aa93de31..8b29fdfd8b961 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.cpp +++ b/drivers/filesystems/udfs/udf_info/udf_info.c @@ -138,10 +138,35 @@ static const uint32 crc32_tab[] = { 0x2d02ef8dL }; +/* + This routine allocates new memory block, copies data there & free old one +*/ +/*uint32 +UDFMemRealloc( + int8* OldBuff, + uint32 OldLength, + int8** NewBuff, + uint32 NewLength + ) +{ + int8* new_buff; + + (*NewBuff) = OldBuff; + if (OldLength == NewLength) return OldLength; + new_buff = (int8*)MyAllocatePool__(NonPagedPool, NewLength); + if (!new_buff) return 0; + if (OldLength > NewLength) OldLength = NewLength; + RtlCopyMemory(new_buff, OldBuff, OldLength); + MyFreePool__(OldBuff); + (*NewBuff) = new_buff; + return OldLength; +} // end UDFMemRealloc()*/ + /* This routine converts compressed Unicode to standard */ -VOID +void +__fastcall UDFDecompressUnicode( IN OUT PUNICODE_STRING UName, IN uint8* CS0, @@ -1232,7 +1257,8 @@ UDFSetAllocDescLen( fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength - FileInfo->Dloc->AllocLoc.Offset, (uint32)(FileInfo->Dloc->AllocLoc.Length)); - } else { + } else + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length); } } else if (Ident == TID_EXTENDED_FILE_ENTRY) { @@ -1241,7 +1267,8 @@ UDFSetAllocDescLen( fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength - FileInfo->Dloc->AllocLoc.Offset, (uint32)(FileInfo->Dloc->AllocLoc.Length)); - } else { + } else + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length); } } @@ -1587,7 +1614,14 @@ UDFWriteFile__( elen - Dloc->DataLoc.Offset, Dloc->DataLoc.Length)); UDFSetFileSize(FileInfo, t); - Dloc->DataLoc.Modified = TRUE; + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ExtPrint((" w2k-compat -> rebuild allocs\n")); + Dloc->DataLoc.Modified = TRUE; + } else + if ((ULONG)((elen+Vcb->SectorSize-1) >> Vcb->SectorShift) != (ULONG)((t+Vcb->SectorSize-1) >> Vcb->SectorShift)) { + ExtPrint((" LBS boundary crossed -> rebuild allocs\n")); + Dloc->DataLoc.Modified = TRUE; + } Dloc->DataLoc.Length = t; return UDFWriteExtent(IrpContext, Vcb, &Dloc->DataLoc, Offset, Length, Direct, Buffer, WrittenBytes); } @@ -1609,13 +1643,11 @@ UDFWriteFile__( ExtPrint((" init Alloc mode\n")); if ((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; - ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_SHORT; + ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode; WasInIcb = TRUE; // Clear embedded data flag since file is no longer in ICB mode - // Fcb may be NULL during directory operations (FCB not yet created) - if (FileInfo->Fcb) { - FileInfo->Fcb->FcbState &= ~UDF_FCB_EMBEDDED_DATA; - } + ASSERT(FileInfo->Fcb); + FileInfo->Fcb->FcbState &= ~UDF_FCB_EMBEDDED_DATA; } // increase extent ExtPrint((" %s %s %s\n", @@ -1624,7 +1656,7 @@ UDFWriteFile__( Vcb->LowFreeSpace ? "LowSpace" : "")); if (UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) { FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL; - status = UDFResizeExtent(IrpContext, Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(ULONGLONG)(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc)); + status = UDFResizeExtent(IrpContext, Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(SIZE_T)(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc)); if (NT_SUCCESS(status)) { AdPrint((" preallocated space for Dir\n")); FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED; @@ -1681,7 +1713,14 @@ UDFWriteFile__( return status; UDFSetFileSize(FileInfo, t); Dloc->DataLoc.Modified = TRUE; - ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); +#ifdef UDF_DBG + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->SectorSize-1) & (Vcb->SectorSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->SectorSize-1) & (Vcb->SectorSize-1))); + } +#endif // UDF_DBG return STATUS_SUCCESS; } // end UDFWriteFile__() @@ -1719,30 +1758,11 @@ UDFUnlinkFile__( // check references Dloc = FileInfo->Dloc; - // Original check was too strict: (OpenCount) || (RefCount > 1) - // Problem: When we open a file via UDFOpenFile__ to delete it during rename, - // that adds +1 to RefCount. If there's also a delayed-close reference, - // RefCount becomes 2 and unlink fails even though OpenCount=0. - // Fix: Only check OpenCount. RefCount will be properly managed by Close/CleanUp. - // The key insight is: OpenCount tracks actual user handles, RefCount tracks - // internal references. If no user has the file open (OpenCount=0), we should - // be able to unlink it. - // When FreeSpace=FALSE (rename/move), we only unlink the FID from the - // directory — the file data stays intact. OpenCount/RefCount/SDirInfo checks - // are not relevant because the file remains alive under a new name. - if (FreeSpace) { - if (FileInfo->OpenCount) { - AdPrint(("UDFUnlinkFile__: OpenCount=%d, cannot delete\n", FileInfo->OpenCount)); - return STATUS_CANNOT_DELETE; - } - if (FileInfo->RefCount > 2) { - AdPrint(("UDFUnlinkFile__: RefCount=%d > 2, cannot delete\n", FileInfo->RefCount)); - return STATUS_CANNOT_DELETE; - } - if (Dloc->SDirInfo) - return STATUS_CANNOT_DELETE; - } - ASSERT(FileInfo->RefCount >= 1); + if ((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) || + (FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE; + if (Dloc->SDirInfo) + return STATUS_CANNOT_DELETE; + ASSERT(FileInfo->RefCount == 1); DirInfo = FileInfo->ParentFile; // root dir or self if (!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE; @@ -1815,7 +1835,7 @@ UDFUnlinkFile__( PUDF_FILE_INFO SFileInfo; // ... try to open it if (Dloc->SDirInfo) { - UDFFlushFile__(IrpContext, Vcb, FileInfo); + UDFFlushFile__(IrpContext, Vcb, FileInfo, 0); return STATUS_CANNOT_DELETE; } // open SDir @@ -1826,7 +1846,7 @@ UDFUnlinkFile__( cleanup_SDir: UDFCleanUpFile__(Vcb, SFileInfo); if (SFileInfo) MyFreePool__(SFileInfo); - UDFFlushFile__(IrpContext, Vcb, FileInfo); + UDFFlushFile__(IrpContext, Vcb, FileInfo, 0); return status; } SDirInfo = Dloc->SDirInfo; @@ -1840,7 +1860,7 @@ UDFUnlinkFile__( goto cleanup_SDir; } // delete SDir - UDFFlushFile__(IrpContext, Vcb, SDirInfo); + UDFFlushFile__(IrpContext, Vcb, SDirInfo, 0); AdPrint((" ")); UDFUnlinkFile__(IrpContext, Vcb, SDirInfo, TRUE); // close SDir @@ -1861,7 +1881,7 @@ UDFUnlinkFile__( // do deltree for Streams status = UDFUnlinkAllFilesInDir(IrpContext, Vcb, FileInfo); if (!NT_SUCCESS(status)) { - UDFFlushFile__(IrpContext, Vcb, FileInfo); + UDFFlushFile__(IrpContext, Vcb, FileInfo, 0); return status; } // update parent FileInfo @@ -1873,8 +1893,11 @@ UDFUnlinkFile__( FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR; UDFDecFileLinkCount(FileInfo->ParentFile); } + if (Dloc->DirIndex) { + UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_FOR_DEL); + } // flush file - UDFFlushFile__(IrpContext, Vcb, FileInfo); + UDFFlushFile__(IrpContext, Vcb, FileInfo, 0); UDFUnlinkDloc(Vcb, Dloc); // free allocation UDFFreeFileAllocation(Vcb, DirInfo, FileInfo); @@ -1929,7 +1952,7 @@ UDFUnlinkAllFilesInDir( return status; } - UDFFlushFile__(IrpContext, Vcb, FileInfo); + UDFFlushFile__(IrpContext, Vcb, FileInfo, 0); AdPrint((" ")); UDFUnlinkFile__(IrpContext, Vcb, FileInfo, TRUE); UDFCloseFile__(IrpContext, Vcb, FileInfo); @@ -2049,10 +2072,8 @@ UDFOpenFile__( // init pointers to linked files (if any) if (FileInfo->Dloc->LinkedFileInfo != FileInfo) UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo); - if (FileInfo->Dloc->FileEntry) { - // Dloc cached in UDFOpenFile__ — skip FE read from disk + 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; @@ -2112,178 +2133,20 @@ UDFOpenFile__( status = UDFIndexDirectory(IrpContext, Vcb, FileInfo); if (!NT_SUCCESS(status)) return status; - } - UDFReferenceFile__(FileInfo); - UDFReleaseDloc(Vcb, FileInfo->Dloc); - ASSERT(FileInfo->ParentFile == DirInfo); - - return status; -} // end UDFOpenFile__() - -/* - Open file from directory context. - This is called after UDFFindDirEntry to open the found file. - */ -NTSTATUS -UDFOpenFileInfoFromDirContext( - 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; - } + 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; } - // 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; } UDFReferenceFile__(FileInfo); UDFReleaseDloc(Vcb, FileInfo->Dloc); ASSERT(FileInfo->ParentFile == DirInfo); return status; -} // end UDFOpenFileInfoFromDirContext() +} // end UDFOpenFile__() /* @@ -2362,6 +2225,12 @@ UDFOpenRootFile__( 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); @@ -2457,70 +2326,11 @@ UDFCleanUpFile__( for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) { if (DirNdx->FileInfo) { if (!KeepDloc) { - // Orphaned FileInfo in DirIndex: loaded by - // UDFOpenFileInfoFromDirContext during path traversal - // but never opened as final component (no LCB). - // Recursively clean up instead of ASSERTing. - UDFPrint(("UDF: Cleaning orphaned FileInfo %x in DirIndex[%d]\n", - DirNdx->FileInfo, i)); - PUDF_FILE_INFO OrphanFi = DirNdx->FileInfo; - // Orphan must have a valid Dloc (loaded by UDFOpenFileInfoFromDirContext) - ASSERT(OrphanFi->Dloc); - // Orphan should be self-linked (not part of a parallel/linked chain) - ASSERT(OrphanFi->NextLinkedFile == OrphanFi); - // ParentFile must point to the FileInfo we're currently cleaning up - ASSERT(OrphanFi->ParentFile == FileInfo); - // Clear CommonFcb to ensure KeepDloc=FALSE in recursive call - // (floating FCB may have set CommonFcb != NULL). - // The floating FCB itself will leak until unmount — acceptable. - if (OrphanFi->Dloc->CommonFcb) { - UDFPrint(("UDF: Orphan %x has floating CommonFcb %x\n", - OrphanFi, OrphanFi->Dloc->CommonFcb)); - OrphanFi->Dloc->CommonFcb = NULL; - } - // Clear Fcb so UDFCleanUpFile__ doesn't bail at line 2465 - if (OrphanFi->Fcb) { - UDFPrint(("UDF: Orphan %x has floating Fcb %x\n", - OrphanFi, OrphanFi->Fcb)); - OrphanFi->Fcb->FileInfo = NULL; - OrphanFi->Fcb = NULL; - } - // Log original counts for diagnostics - UDFPrint(("UDF: Orphan counts: RefCount=%d, LinkRefCount=%d, OpenCount=%d\n", - OrphanFi->RefCount, - OrphanFi->Dloc->LinkRefCount, - OrphanFi->OpenCount)); - // Reset OpenCount — orphan's children (also orphans) may - // have incremented it via UDFReferenceFile__. These children - // will be recursively cleaned up by UDFCleanUpFile__. - OrphanFi->OpenCount = 0; - // Reset RefCount/LinkRefCount — may be non-zero if - // UDFCloseFile__ was never called for this orphan - OrphanFi->RefCount = 0; - OrphanFi->Dloc->LinkRefCount = 0; - // Clear Modified flags — orphan is being discarded along - // with the parent directory's DirIndex, so unflushed - // modifications would be lost anyway. Without this, - // recursive UDFCleanUpFile__ asserts !Modified when - // KeepDloc=FALSE (e.g., after rename-replace sets - // FI_MODIFIED on directory entries during UDFUnlinkFile__). - DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED; - OrphanFi->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; - OrphanFi->Dloc->DataLoc.Modified = FALSE; - OrphanFi->Dloc->DataLoc.Flags &= ~EXTENT_FLAG_PREALLOCATED; - OrphanFi->Dloc->AllocLoc.Modified = FALSE; - OrphanFi->Dloc->FELoc.Modified = FALSE; - // UDFCleanUpFile__ handles Dloc cleanup (frees via - // UDFRemoveDloc/UDFFreeDloc) and sets DirNdx->FileInfo=NULL - // in parent's DirIndex. We also free the FileInfo struct. - ULONG cleanupResult = UDFCleanUpFile__(Vcb, OrphanFi); - // Cleanup must have freed the Dloc (KeepDloc=FALSE path) - ASSERT(OrphanFi->Dloc == NULL); - ASSERT(cleanupResult & UDF_FREE_FILEINFO); - // Only free the FileInfo struct itself. - MyFreePool__(OrphanFi); - DirNdx->FileInfo = NULL; - continue; + ASSERT(FALSE); + UDFPrint(("UDF: Found not cleaned up reference.\n")); + UDFPrint((" Skipping cleanup (1)\n")); +// BrutePoint(); + return UDF_FREE_NOTHING; } // The file being cleaned up may have not closed Dirs // (linked Dir). In this case each of them may have @@ -2610,6 +2420,8 @@ UDFCleanUpFile__( if (DirNdx->FName.Buffer) MyFreePool__(DirNdx->FName.Buffer); } + // The only place where we can free FE_Charge extent is here + UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_KEEP); UDFDirIndexFree(Dloc->DirIndex); Dloc->DirIndex = NULL; #ifdef UDF_TRACK_ONDISK_ALLOCATION @@ -2902,23 +2714,31 @@ UDFCreateFile__( // try to find suitable unused FileIdent in DirIndex l = FileInfo->FileIdentLen; if (undel) goto CrF__2; - // search for suitable unused (deleted) entry to reuse - if (UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) { - while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) { - if ((DirNdx->Length == l) && UDFIsDeleted(DirNdx) && - !DirNdx->FileInfo ) { - // free unicode-buffer with old name - if (DirNdx->FName.Buffer) { - MyFreePool__(DirNdx->FName.Buffer); - DirNdx->FName.Buffer = NULL; +#ifndef UDF_LIMIT_DIR_SIZE + if (Vcb->CDR_Mode) { +#endif // UDF_LIMIT_DIR_SIZE + // search for suitable unused entry + if (UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) { + while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) { + if ((DirNdx->Length == l) && UDFIsDeleted(DirNdx) && + !DirNdx->FileInfo ) { + // free unicode-buffer with old name + if (DirNdx->FName.Buffer) { + MyFreePool__(DirNdx->FName.Buffer); + DirNdx->FName.Buffer = NULL; + } + i = ScanContext.i; + goto CrF__1; } - i = ScanContext.i; - goto CrF__1; } } +#ifndef UDF_LIMIT_DIR_SIZE + } else { +#endif // UDF_LIMIT_DIR_SIZE + i = UDFDirIndexGetLastIndex(hDirNdx); // 'i' points beyond EO DirIndex +#ifndef UDF_LIMIT_DIR_SIZE } - // no suitable deleted entry found, append new one - i = UDFDirIndexGetLastIndex(hDirNdx); +#endif // UDF_LIMIT_DIR_SIZE // append entry if (!NT_SUCCESS(status = UDFDirIndexGrow(&(DirInfo->Dloc->DirIndex), 1))) { @@ -2970,12 +2790,11 @@ UDFCreateFile__( RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length); DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0; CrF__2: - // Reset all flags: stale FI_INTERNAL from deleted entry would - // hide the new file from enumeration. - DirNdx->FI_Flags = UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL) - | UDF_FI_FLAG_FI_MODIFIED; + DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL); // we get here immediately when 'undel' occured FileInfo->Index = i; + DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; + DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; ASSERT(!DirNdx->FileInfo); DirNdx->FileInfo = FileInfo; DirNdx->FileEntryLoc = FEicb.extLocation; @@ -3044,12 +2863,8 @@ try_exit: NOTHING; } _SEH2_FINALLY { if (!NT_SUCCESS(status)) { - if (FEAllocated && FileInfo->Dloc) { - // Free FE space first (needs Dloc->FELoc), then remove Dloc entry + if (FEAllocated) UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); - UDFRemoveDloc(Vcb, FileInfo->Dloc); - FileInfo->Dloc = NULL; - } } } _SEH2_END return status; @@ -3280,10 +3095,11 @@ UDFCloseFile__( // we needn't flushing FE & Allocs untill all links are closed... if (!FileInfo->Dloc->LinkRefCount) { - // flush pre-allocation charge for directories + // flush FE and pre-allocation charge for directories if (FileInfo->Dloc && FileInfo->Dloc->DirIndex) { + UDFFlushFESpace(Vcb, FileInfo->Dloc, FLUSH_FE_KEEP); if (FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) { FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; status = UDFResizeExtent(IrpContext, Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc)); @@ -3411,60 +3227,35 @@ UDFRenameMoveFile__( if ((*Replace) && !Recovery) { Recovery = TRUE; status = UDFOpenFile__(IrpContext, Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL); - if (!NT_SUCCESS(status)) { - - goto cleanup_and_abort_rename; - } - // file opened successfully -; - status = UDFDoesOSAllowFileToBeTargetForRename__(FileInfo2); - - if (!NT_SUCCESS(status)) { - - UDFCloseFile__(IrpContext, Vcb, FileInfo2); - goto cleanup_and_abort_rename; - } - - // TODO: Refactor — don't use UDFCreateFile__ in rename path. - // Use direct FID unlink + create link instead. - // Quick fix: if target's Dloc == source's Dloc, the internal open got the - // wrong file (shared Dloc bug). Unlink would destroy the source data. - if (FileInfo2->Dloc == FileInfo->Dloc) { - + if (NT_SUCCESS(status)) { + status = UDFDoesOSAllowFileToBeTargetForRename__(FileInfo2); + if (!NT_SUCCESS(status)) { + UDFCloseFile__(IrpContext, Vcb, FileInfo2); + goto cleanup_and_abort_rename; + } + status = UDFUnlinkFile__(IrpContext, Vcb, FileInfo2, TRUE); +// UDFPretendFileDeleted__(Vcb, FileInfo2); UDFCloseFile__(IrpContext, Vcb, FileInfo2); - status = STATUS_ACCESS_DENIED; - goto cleanup_and_abort_rename; - } - status = UDFUnlinkFile__(IrpContext, Vcb, FileInfo2, TRUE); - - // Mark FCB as deleted to prevent it from going into delayed close queue - if (FileInfo2->Fcb) { - - FileInfo2->Fcb->FcbState |= UDF_FCB_DELETED; - } - UDFCloseFile__(IrpContext, Vcb, FileInfo2); - - if (UDFCleanUpFile__(Vcb, FileInfo2)) { - - MyFreePool__(FileInfo2); - FileInfo2 = NULL; - if (SameFE) - return status; - } else { - // we get here if the FileInfo has associated - // system-specific Fcb - // Such fact means that not all system references - // has already gone (except Linked file case) - - // Note: After UDFUnlinkFile__ link count is 0, which is expected - // Only return ACCESS_DENIED if unlink itself failed - if (!NT_SUCCESS(status)) - status = STATUS_ACCESS_DENIED; + if (UDFCleanUpFile__(Vcb, FileInfo2)) { + MyFreePool__(FileInfo2); + FileInfo2 = NULL; + if (SameFE) + return status; + } else { + // we get here if the FileInfo has associated + // system-specific Fcb + // Such fact means that not all system references + // has already gone (except Linked file case) +/* if (SameFE) + return status;*/ +// UDFRemoveOSReferences__(FileInfo2); + if (!NT_SUCCESS(status) || + (UDFGetFileLinkCount(FileInfo2) < 1)) + status = STATUS_ACCESS_DENIED; + } + if (NT_SUCCESS(status)) goto RenameRetry; } - - if (NT_SUCCESS(status)) goto RenameRetry; cleanup_and_abort_rename: - if (FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) { MyFreePool__(FileInfo2); FileInfo2 = NULL; @@ -3485,7 +3276,7 @@ UDFRenameMoveFile__( // unlink source FileIdent if (!NT_SUCCESS(status = UDFUnlinkFile__(IrpContext, Vcb, FileInfo, FALSE))) { // kill newly created entry - UDFFlushFile__(IrpContext, Vcb, FileInfo2); + UDFFlushFile__(IrpContext, Vcb, FileInfo2, 0); UDFUnlinkFile__(IrpContext, Vcb, FileInfo2, TRUE); UDFCloseFile__(IrpContext, Vcb, FileInfo2); UDFCleanUpFile__(Vcb, FileInfo2); @@ -3631,7 +3422,14 @@ UDFRecordDirectory__( status = UDFWriteFile__(IrpContext, Vcb, DirInfo, 0, FileInfo.FileIdentLen, FALSE, (int8*)(FileInfo.FileIdent), &WrittenBytes); // status = UDFFlushFI(Vcb, &FileInfo, PartNum); - ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)); +#ifdef UDF_DBG + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(DirInfo)+Vcb->SectorSize-1) & (Vcb->SectorSize-1)) == + ((UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)+Vcb->SectorSize-1) & (Vcb->SectorSize-1))); + } +#endif // UDF_DBG MyFreePool__(FileInfo.FileIdent); if (!NT_SUCCESS(status)) return status; @@ -3733,10 +3531,8 @@ UDFResizeFile__( ((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 - // Fcb may be NULL during directory operations (FCB not yet created) - if (FileInfo->Fcb) { - FileInfo->Fcb->FcbState |= UDF_FCB_EMBEDDED_DATA; - } + 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)); @@ -3768,7 +3564,14 @@ UDFResizeFile__( UDFSetFileSize(FileInfo, NewLength); } - ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); +#ifdef UDF_DBG + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->SectorSize-1) & (Vcb->SectorSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->SectorSize-1) & (Vcb->SectorSize-1))); + } +#endif // UDF_DBG return status; } // end UDFResizeFile__() @@ -3815,8 +3618,6 @@ 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: @@ -4090,7 +3891,12 @@ UDFFlushFE( return status; } #ifdef UDF_DBG - ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->SectorSize-1) & (Vcb->SectorSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->SectorSize-1) & (Vcb->SectorSize-1))); + } AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; #endif // UDF_DBG // initiate update of lengthAllocDescs @@ -4120,7 +3926,12 @@ UDFFlushFE( ASSERT(UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping) == 0); } else { - ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + if (Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } else { + ASSERT(((UDFGetFileSize(FileInfo)+Vcb->SectorSize-1) & (Vcb->SectorSize-1)) == + ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->SectorSize-1) & (Vcb->SectorSize-1))); + } } #endif // UDF_DBG } @@ -4166,20 +3977,6 @@ UDFFlushFE( // FileInfo->Dloc->FELoc.Length += UDFGetFileSize(FileInfo); // FileInfo->Dloc->FELoc.Length = FileInfo->Dloc->FileEntry->descCRCLength + sizeof(tag); UDFPrint(("descCRCLength %x\n", FileInfo->Dloc->FileEntry->descCRCLength)); - { - int64 _infoLen = (FileInfo->Dloc->FileEntry->tagIdent == TID_FILE_ENTRY) ? - ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->informationLength : - ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->informationLength; - if (_infoLen != FileInfo->Dloc->DataLoc.Length) { - - // Safety-net: correct informationLength from DataLoc.Length - UDFSetFileSize(FileInfo, FileInfo->Dloc->DataLoc.Length); - // Re-compute CRC after changing FE content - UDFSetUpTag( - Vcb, FileInfo->Dloc->FileEntry, (uint16)(FileInfo->Dloc->FileEntryLen), - UDFPhysLbaToPart(Vcb, PartNum, lba), 0); - } - } status = UDFWriteExtent( IrpContext, Vcb, &FileInfo->Dloc->FELoc, 0, (uint32)(FileInfo->Dloc->FELoc.Length), FALSE, @@ -4377,6 +4174,7 @@ UDFFlushFile__( // if Lite Flush is used, keep preallocations if (!(FlushFlags & UDF_FLUSH_FLAGS_LITE)) { full_flush: + UDFFlushFESpace(Vcb, FileInfo->Dloc, FLUSH_FE_KEEP); if (FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) { FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; status = UDFResizeExtent(IrpContext, Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc)); @@ -4589,7 +4387,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); @@ -5193,7 +4991,7 @@ UDFRecordVAT( UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation); // record data if (NT_SUCCESS(status = UDFWriteFile__(IrpContext, Vcb, VatFileInfo, 0, VatLen + hdrLen, FALSE, New, &WrittenBytes))) { - status = UDFFlushFile__(IrpContext, Vcb, VatFileInfo); + status = UDFFlushFile__(IrpContext, Vcb, VatFileInfo, 0); } return status; } @@ -5299,7 +5097,7 @@ UDFRecordVAT( UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->FELoc.Mapping[0].extLocation); VatFileInfo->Dloc->DataLoc.Modified = TRUE; - status = UDFFlushFile__(IrpContext, Vcb, VatFileInfo); + status = UDFFlushFile__(IrpContext, Vcb, VatFileInfo, 0); if (!NT_SUCCESS(status)) return status; diff --git a/drivers/filesystems/udfs/udf_info/udf_info.h b/drivers/filesystems/udfs/udf_info/udf_info.h index d68b0d6437f3f..764de6c5c61e0 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.h +++ b/drivers/filesystems/udfs/udf_info/udf_info.h @@ -11,6 +11,11 @@ #include "osta_misc.h" #include "udf_rel.h" +// memory re-allocation (returns new buffer size) +uint32 UDFMemRealloc(IN int8* OldBuff, // old buffer + IN uint32 OldLength, // old buffer size + OUT int8** NewBuff, // address to store new pointer + IN uint32 NewLength); // required size // convert offset in extent to Lba & calculate block parameters // it also returns pointer to last valid entry & flags uint32 @@ -58,16 +63,12 @@ UDFReadExtentLocation(IN PVCB Vcb, ); // calculate total length of extent int64 UDFGetExtentLength(IN PEXTENT_MAP Extent); // Extent array - // convert compressed Unicode to standard -VOID -UDFDecompressUnicode( - IN OUT PUNICODE_STRING UName, - IN uint8* CS0, - IN SIZE_T Length, - OUT uint16* valueCRC -); - +void +__fastcall UDFDecompressUnicode(IN OUT PUNICODE_STRING UName, + IN uint8* CS0, + IN SIZE_T Length, + OUT uint16* valueCRC); // calculate hashes for directory search uint8 UDFBuildHashEntry(IN PVCB Vcb, IN PUNICODE_STRING Name, @@ -130,23 +131,6 @@ __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 UDFOpenFileInfoFromDirContext( - 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 @@ -160,7 +144,7 @@ UDFShortAllocDescToMapping( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN uint32 PartNum, - IN PLONG_AD AllocDesc, + IN PSHORT_AD AllocDesc, IN uint32 AllocDescLength, IN uint32 SubCallCount, OUT PEXTENT_INFO AllocLoc @@ -182,7 +166,7 @@ PEXTENT_MAP UDFExtAllocDescToMapping( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, - IN PLONG_AD AllocDesc, + IN PEXT_AD AllocDesc, IN uint32 AllocDescLength, IN uint32 SubCallCount, OUT PEXTENT_INFO AllocLoc @@ -410,7 +394,8 @@ uint32 __fastcall UDFGetPartFreeSpace(IN PVCB Vcb, IN uint32 partNum); -#define UDF_PREALLOC_CLASS_DIR 0x00 +#define UDF_PREALLOC_CLASS_FE 0x00 +#define UDF_PREALLOC_CLASS_DIR 0x01 // try to find cached allocation NTSTATUS @@ -453,6 +438,13 @@ void UDFFreeFESpace(IN PVCB Vcb, IN PUDF_FILE_INFO DirInfo, IN PEXTENT_INFO FEExtInfo); +#define FLUSH_FE_KEEP FALSE +#define FLUSH_FE_FOR_DEL TRUE + +// flush FE charge +void UDFFlushFESpace(IN PVCB Vcb, + IN PUDF_DATALOC_INFO Dloc, + IN BOOLEAN Discard); // discard file allocation void UDFFreeFileAllocation(IN PVCB Vcb, IN PUDF_FILE_INFO DirInfo, @@ -832,7 +824,6 @@ NTSTATUS UDFReadFileLocation__(IN PVCB Vcb, */ // zero data in file described by FileInfo -__inline NTSTATUS UDFZeroFile__( IN PIRP_CONTEXT IrpContext, @@ -845,7 +836,6 @@ UDFZeroFile__( ); // make sparse area in file described by FileInfo -__inline NTSTATUS UDFSparseFile__( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, @@ -954,6 +944,13 @@ UDFRecordDirectory__( IN OUT PUDF_FILE_INFO DirInfo // source (opened) ); +// remove all DELETED entries from Dir & resize it. +NTSTATUS +UDFPackDirectory__( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN OUT PUDF_FILE_INFO FileInfo // source (opened) + ); // rebuild tags for all entries from Dir. NTSTATUS @@ -1023,7 +1020,7 @@ UDFFlushFile__( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PUDF_FILE_INFO FileInfo, - IN ULONG FlushFlags = 0 + IN ULONG FlushFlags ); // check if the file is flushed diff --git a/drivers/filesystems/udfs/udf_info/udf_rel.h b/drivers/filesystems/udfs/udf_info/udf_rel.h index cefcb3b8c2d0c..867ce947f1494 100644 --- a/drivers/filesystems/udfs/udf_info/udf_rel.h +++ b/drivers/filesystems/udfs/udf_info/udf_rel.h @@ -244,7 +244,7 @@ typedef struct _UDF_DATALOC_INFO { NT-specific field. As soon as NT supports HardLink concept it has own structure describing the file's actual data. */ - FCB* CommonFcb; // pointer to corresponding FCB + struct FCB* CommonFcb; // pointer to corresponding FCB /** Describes on-disk location of user data. If the file is recorded using IN_ICB method this structure points to the @@ -439,18 +439,6 @@ 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/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 94% rename from drivers/filesystems/udfs/write.cpp rename to drivers/filesystems/udfs/write.c index 076e5a6cbe305..e18ef76786207 100644 --- a/drivers/filesystems/udfs/write.cpp +++ b/drivers/filesystems/udfs/write.c @@ -44,9 +44,7 @@ UDFCommonWrite( NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); LONGLONG StartingOffset; - ULONG ByteCount; - LONGLONG ByteRange; - ULONG TruncatedLength; + ULONG ByteCount = 0, TruncatedLength = 0; SIZE_T NumberBytesWritten = 0; PFILE_OBJECT FileObject = NULL; TYPE_OF_OPEN TypeOfOpen; @@ -62,6 +60,9 @@ UDFCommonWrite( BOOLEAN MainResourceAcquired = FALSE; BOOLEAN VcbAcquired = FALSE; + BOOLEAN MainResourceAcquiredExclusive = FALSE; + BOOLEAN MainResourceCanDemoteToShared = FALSE; + BOOLEAN Wait = FALSE; BOOLEAN PagingIo = FALSE; BOOLEAN NonCachedIo = FALSE; @@ -73,14 +74,6 @@ UDFCommonWrite( BOOLEAN ZeroBlock = FALSE; BOOLEAN ZeroBlockDone = FALSE; - // Examine our input parameters to determine if this is noncached and/or - // a paging io operation. - - 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; // Extract and decode the file object. @@ -101,6 +94,14 @@ UDFCommonWrite( ASSERT_FCB(Fcb); ASSERT_VCB(Vcb); + // Examine our input parameters to determine if this is noncached and/or + // a paging io operation. + + 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); + // Check if this volume has already been shut down. If it has, fail // this write request. @@ -138,7 +139,6 @@ UDFCommonWrite( StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart; ByteCount = IrpSp->Parameters.Write.Length; - ByteRange = StartingOffset + ByteCount; Irp->IoStatus.Information = 0; @@ -218,14 +218,26 @@ UDFCommonWrite( try_return(Status = STATUS_ACCESS_DENIED); } + if (IrpContext->Flags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) { + + UDFPrint((" UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n")); + IrpContext->Flags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED; + + +#ifdef UDF_DELAYED_CLOSE + UDFFspClose(Vcb); +#endif //UDF_DELAYED_CLOSE + + } + // Acquire the volume resource exclusive - UDFAcquireVcbExclusive(IrpContext, Vcb, FALSE); + UDFAcquireResourceExclusive(&(Vcb->VcbResource), TRUE); VcbAcquired = TRUE; // I dislike the idea of writing to mounted media too, but M$ has another point of view... if (Vcb->VcbCondition == VcbMounted) { // flush system cache - UDFFlushVolume(IrpContext, Vcb); + UDFFlushVolume(IrpContext, Vcb, 0); } // Forward the request to the lower level driver @@ -243,7 +255,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); } @@ -322,6 +334,8 @@ UDFCommonWrite( if (!SuccessfulPurge) { try_return(Status = STATUS_PURGE_FAILED); } + + MainResourceCanDemoteToShared = TRUE; } // Determine if we were called by the lazywriter. @@ -408,7 +422,20 @@ UDFCommonWrite( try_return(Status = STATUS_PENDING); // CanWait = TRUE; - UDFAcquirePagingIoExclusive(IrpContext, Fcb); + // 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, Wait)) { + try_return(Status = STATUS_PENDING); + } + MainResourceAcquired = TRUE; + } + + UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbPagingIoResource, TRUE); PagingIoResourceAcquired = TRUE; if (ExtendFS) { @@ -428,7 +455,7 @@ UDFCommonWrite( } } - UDFReleasePagingIo(IrpContext, Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); PagingIoResourceAcquired = FALSE; if (CcIsFileCached(FileObject)) { @@ -576,18 +603,6 @@ UDFCommonWrite( try_return(Status = STATUS_INVALID_USER_BUFFER); } Fcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; - - // Acquire PagingIoResource exclusive to serialize with - // UDFMarkAllocatedAsRecorded which may free and replace - // ExtInfo->Mapping during NOT_RECORDED -> RECORDED conversion. - // Without this, a concurrent UDFResizeExtent (holding PagingIoResource - // exclusive for file extension) can use a stale Mapping pointer - // that was freed by our UDFMarkAllocatedAsRecorded call. - if (!PagingIoResourceAcquired) { - UDFAcquirePagingIoExclusive(IrpContext, Fcb); - PagingIoResourceAcquired = TRUE; - } - Status = UDFWriteFile__(IrpContext, Vcb, Fcb->FileInfo, StartingOffset, TruncatedLength, FALSE, (PCHAR)SystemBuffer, &NumberBytesWritten); @@ -652,15 +667,16 @@ try_exit: NOTHING; // Release any resources acquired here ... if (PagingIoResourceAcquired) { - UDFReleasePagingIo(IrpContext, Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); } if (MainResourceAcquired) { - UDFReleaseFcb(IrpContext, Fcb); + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); } if (VcbAcquired) { - UDFReleaseVcb(IrpContext, Vcb); + UDFReleaseResource(&Vcb->VcbResource); } } _SEH2_END; // end of "__finally" processing @@ -894,8 +910,8 @@ UDFZeroData ( --*/ { - LARGE_INTEGER ZeroStart = {0,0}; - LARGE_INTEGER BeyondZeroEnd = {0,0}; + LARGE_INTEGER ZeroStart = {{0, 0}}; + LARGE_INTEGER BeyondZeroEnd = {{0, 0}}; BOOLEAN Finished;