diff --git a/drivers/filesystems/udfs/Include/udf_reg.h b/drivers/filesystems/udfs/Include/udf_reg.h index 46002b71cfde0..32d15648b04b9 100644 --- a/drivers/filesystems/udfs/Include/udf_reg.h +++ b/drivers/filesystems/udfs/Include/udf_reg.h @@ -7,6 +7,7 @@ #ifndef __DWUDF_REGISTRY__H__ #define __DWUDF_REGISTRY__H__ + #define UDF_BM_FLUSH_PERIOD_NAME L"BitmapFlushPeriod" #define UDF_TREE_FLUSH_PERIOD_NAME L"DirTreeFlushPeriod" #define UDF_NO_UPDATE_PERIOD_NAME L"MaxNoUpdatePeriod" diff --git a/drivers/filesystems/udfs/close.cpp b/drivers/filesystems/udfs/close.cpp index 88b74886c080c..31a0166982da0 100644 --- a/drivers/filesystems/udfs/close.cpp +++ b/drivers/filesystems/udfs/close.cpp @@ -168,6 +168,7 @@ UDFCommonClose( try_return(RC = STATUS_SUCCESS); } + if ((Vcb->VcbCleanup == 0) && (Vcb->VcbCondition != VcbMounted)) { diff --git a/drivers/filesystems/udfs/create.cpp b/drivers/filesystems/udfs/create.cpp index 8518dcf82256f..b1df095809451 100644 --- a/drivers/filesystems/udfs/create.cpp +++ b/drivers/filesystems/udfs/create.cpp @@ -128,6 +128,7 @@ try_exit: NOTHING; } // end UDFSupersedeOrOverwriteFile() + /************************************************************************* * * Function: UDFOpenExistingFcb() @@ -997,6 +998,7 @@ try_exit: NOTHING; * *************************************************************************/ static + VOID UDFNormalizeStreamSuffix( IN PIRP_CONTEXT IrpContext, @@ -1020,6 +1022,7 @@ UDFNormalizeStreamSuffix( return; } + // Check if there's a second ':' at all — if so, it's an unknown stream type PWCHAR buf = Name->Buffer; USHORT len = Name->Length / sizeof(WCHAR); @@ -1030,6 +1033,7 @@ UDFNormalizeStreamSuffix( } } + /************************************************************************* * * Function: UDFCommonCreate() @@ -1289,6 +1293,8 @@ UDFCommonCreate( _SEH2_TRY { + + // Verify that the Vcb is not in an unusable condition. This routine // will raise if not usable. @@ -1360,15 +1366,19 @@ UDFCommonCreate( CreateDisposition == FILE_OVERWRITE_IF || CreateDisposition == FILE_CREATE) { + try_return(Status = STATUS_ACCESS_DENIED); + } CurrentFcb = Vcb->VolumeDasdFcb; // Acquire the Fcb exclusively before completing the open + UDFAcquireFcbExclusive(IrpContext, CurrentFcb, FALSE); + Status = UDFCompleteFcbOpen(IrpContext, IrpSp, Vcb, @@ -1379,7 +1389,9 @@ UDFCommonCreate( FALSE, // VcbLocked FILE_OPENED); // DesiredInformation + try_return(Status); + } if (UDFIllegalFcbAccess(Vcb, DesiredAccess)) { @@ -1406,10 +1418,12 @@ UDFCommonCreate( try_return(Status = STATUS_ACCESS_DENIED); } + try_return(Status = UDFOpenObjectByFileId(IrpContext, IrpSp, Vcb, &CurrentFcb)); + } // @@ -1504,7 +1518,9 @@ UDFCommonCreate( try_return(Status = STATUS_OBJECT_NAME_INVALID); } if (StreamOpen && !UDFIsStreamsSupported(Vcb)) { + try_return(Status = STATUS_OBJECT_NAME_INVALID); + } // RemainingName was set by UDFNormalizeFileNames to point to the relative path @@ -1846,6 +1862,7 @@ UDFCommonCreate( Status = STATUS_OBJECT_NAME_NOT_FOUND; } } + if (NT_SUCCESS(Status)) { // Re-inject stream name: next iteration will search // for FinalName within the stream directory. @@ -1864,6 +1881,7 @@ UDFCommonCreate( &NewFileInfo, &PtrNewFcb); if (NT_SUCCESS(Status)) { LastGoodFileInfo = NewFileInfo; + } else { // FCB setup failed — close stream dir and exit UDFCloseFile__(IrpContext, Vcb, StreamDirInfo); @@ -2027,9 +2045,11 @@ UDFCommonCreate( // ... and exit with error try_return(Status); } + // Note: With LCB model, FcbReference is not incremented during path traversal, // so no decrement is needed here (removed the old InterlockedDecrement). Status = STATUS_SUCCESS; + ASSERT(!OpenTargetDirectory); // Restore PtrNewFcb/NewFileInfo from last good state. // The stream dir branch didn't open anything in this iteration, @@ -2079,8 +2099,10 @@ UDFCommonCreate( // FILE_CREATED, allocation size, attributes, and notification are // all handled inside UDFOpenExistingFcb via CreateDisposition == FILE_CREATE. + LastGoodFileInfo = NewFileInfo; try_return(Status); + } // **************** @@ -2159,10 +2181,12 @@ UDFCommonCreate( // thread can have the file stream open at this time. RelatedFileInfo = OldRelatedFileInfo; + Status = UDFCreateFile__(IrpContext, Vcb, IgnoreCase, &FinalName, 0, 0, UdfIsExtendedFESupported(Vcb), (CreateDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo); if (!NT_SUCCESS(Status)) { + AdPrint((" Creation error\n")); try_return(Status); } @@ -2211,6 +2235,8 @@ UDFCommonCreate( } LastGoodFileInfo = NewFileInfo; + + UDFNotifyReportChange(IrpContext, Vcb, NewFileInfo->Fcb, UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, @@ -2243,11 +2269,15 @@ UDFCommonCreate( } LastGoodFileInfo = NewFileInfo; + + // PHASE 2: Create stream file in the stream directory RelatedFileInfo = NewFileInfo; + StreamName.Buffer++; StreamName.Length -= sizeof(WCHAR); Status = UDFCreateFile__(IrpContext, Vcb, IgnoreCase, &StreamName, 0, 0, + UdfIsExtendedFESupported(Vcb), (CreateDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo); if (!NT_SUCCESS(Status)) { @@ -2372,8 +2402,10 @@ try_exit: NOTHING; if (NT_SUCCESS(Status) && PtrNewFcb) { + if (DeleteOnClose) { ASSERT(!(PtrNewFcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); + } if (StreamOpen) { @@ -2832,6 +2864,7 @@ UDFCompleteFcbOpen( if (!(Ccb = UDFCreateCcb())) { + return STATUS_INSUFFICIENT_RESOURCES; } @@ -2839,6 +2872,7 @@ UDFCompleteFcbOpen( _SEH2_TRY { + if (AddedAccess) { ClearFlag(DesiredAccess, AddedAccess); @@ -3018,6 +3052,7 @@ UDFCompleteFcbOpen( Fcb->FcbState &= ~UDF_FCB_DELAY_CLOSE; + // Increment all reference counts here when CCB is successfully created. // If VcbLocked is TRUE, caller already holds VcbMutex - use simple ++. // If VcbLocked is FALSE, acquire VcbMutex for atomicity. @@ -3026,6 +3061,7 @@ UDFCompleteFcbOpen( UDFLockVcb(IrpContext, Fcb->Vcb); } + // Cleanup counts: Fcb->FcbCleanup++; Fcb->Vcb->VcbCleanup++; diff --git a/drivers/filesystems/udfs/env_spec.cpp b/drivers/filesystems/udfs/env_spec.cpp index 52e1cb5382576..c56ccbd8c46ff 100644 --- a/drivers/filesystems/udfs/env_spec.cpp +++ b/drivers/filesystems/udfs/env_spec.cpp @@ -556,5 +556,6 @@ UDFNotifyReportChange( if (PathAllocated && FullPath.Buffer) { ExFreePool(FullPath.Buffer); } + } diff --git a/drivers/filesystems/udfs/fileinfo.cpp b/drivers/filesystems/udfs/fileinfo.cpp index 92fcd88eaf98e..cf5d1362b8ee3 100644 --- a/drivers/filesystems/udfs/fileinfo.cpp +++ b/drivers/filesystems/udfs/fileinfo.cpp @@ -1840,7 +1840,9 @@ 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() + InterlockedIncrement((PLONG)&Vcb->VcbReference); @@ -1852,12 +1854,14 @@ 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); (*AcquiredDir1) = TRUE; @@ -2284,6 +2288,7 @@ UDFSetRenameInfo( ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME; + // Step 1: Notify OLD location (LCB still points to old parent) // Use FileObject->FileName — stable path independent of LCB chain if (SingleDir && !ReplaceIfExists) { @@ -2292,8 +2297,10 @@ UDFSetRenameInfo( } else { UDFNotifyReportChange(IrpContext, Vcb, Fcb, Filter, FILE_ACTION_REMOVED, Ccb->Lcb, FileObject); + } + // Step 2: Move LCB to new parent and update name if (Ccb->Lcb) { RC = UDFRenameMovePrefix(IrpContext, Ccb->Lcb, &NewName, @@ -2306,6 +2313,7 @@ UDFSetRenameInfo( // Step 3: Update FCB parent pointer for cross-directory rename if (!SingleDir) { Fcb->ParentFcb = TargetDirInfo->Fcb; + } // Step 4: Notify NEW location (LCB now points to new parent) diff --git a/drivers/filesystems/udfs/flush.cpp b/drivers/filesystems/udfs/flush.cpp index 65240f50e2a7e..81de11662019d 100644 --- a/drivers/filesystems/udfs/flush.cpp +++ b/drivers/filesystems/udfs/flush.cpp @@ -112,6 +112,7 @@ UDFCommonFlush( // action we take. if ((Fcb == Fcb->Vcb->VolumeDasdFcb) || (Fcb->FcbState & UDF_FCB_ROOT_DIRECTORY)) { + UDFFspClose(Vcb); UDFAcquireVcbExclusive(IrpContext, Vcb, FALSE); diff --git a/drivers/filesystems/udfs/fscntrl.cpp b/drivers/filesystems/udfs/fscntrl.cpp index 74982610e6a43..8de95b408bf37 100644 --- a/drivers/filesystems/udfs/fscntrl.cpp +++ b/drivers/filesystems/udfs/fscntrl.cpp @@ -669,16 +669,19 @@ UDFCleanupVCB( MyFreeMemoryAndPointer(Vcb->Partitions); MyFreeMemoryAndPointer(Vcb->LVid); - MyFreeMemoryAndPointer(Vcb->Vat); + if (Vcb->Vat) { + UDFFreeChunked(Vcb->Vat); + Vcb->Vat = NULL; + } MyFreeMemoryAndPointer(Vcb->SparingTable); if (Vcb->FSBM_Bitmap) { - DbgFreePool(Vcb->FSBM_Bitmap); + UDFFreeChunked(Vcb->FSBM_Bitmap); Vcb->FSBM_Bitmap = NULL; } if (Vcb->BSBM_Bitmap) { - DbgFreePool(Vcb->BSBM_Bitmap); + UDFFreeChunked(Vcb->BSBM_Bitmap); Vcb->BSBM_Bitmap = NULL; } #ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS @@ -688,7 +691,7 @@ UDFCleanupVCB( } #endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS if (Vcb->FSBM_OldBitmap) { - DbgFreePool(Vcb->FSBM_OldBitmap); + UDFFreeChunked(Vcb->FSBM_OldBitmap); Vcb->FSBM_OldBitmap = NULL; } diff --git a/drivers/filesystems/udfs/protos.h b/drivers/filesystems/udfs/protos.h index acaa3cd52b8b4..5ef8e5adca18b 100644 --- a/drivers/filesystems/udfs/protos.h +++ b/drivers/filesystems/udfs/protos.h @@ -693,6 +693,8 @@ UDFFastUnlockAllByKey( * Prototypes for the file misc.cpp *************************************************************************/ + + _IRQL_requires_max_(APC_LEVEL) __drv_dispatchType(DRIVER_DISPATCH) __drv_dispatchType(IRP_MJ_CREATE) @@ -868,6 +870,8 @@ UDFInsertFcbIntoTable( _In_ PFCB Fcb ); + + _Ret_valid_ PIRP_CONTEXT UDFCreateIrpContext( _In_ PIRP Irp, diff --git a/drivers/filesystems/udfs/read.cpp b/drivers/filesystems/udfs/read.cpp index c920331dee579..372a1e2aafe82 100644 --- a/drivers/filesystems/udfs/read.cpp +++ b/drivers/filesystems/udfs/read.cpp @@ -309,6 +309,7 @@ UDFCommonRead( Status = UDFReadFile__(IrpContext, Vcb, Fcb->FileInfo, StartingOffset, ByteCount, FALSE, (PCHAR)SystemBuffer, &NumberBytesRead); + /* // AFAIU, CacheManager wants this: if (!NT_SUCCESS(RC)) { NumberBytesRead = 0; diff --git a/drivers/filesystems/udfs/shutdown.cpp b/drivers/filesystems/udfs/shutdown.cpp index 93dd97b067f36..ee0908e0713e2 100644 --- a/drivers/filesystems/udfs/shutdown.cpp +++ b/drivers/filesystems/udfs/shutdown.cpp @@ -181,6 +181,7 @@ UDFCommonShutdown( UdfData.UDFDeviceObject_HDD = NULL; } + UDFCompleteRequest(IrpContext, Irp, STATUS_SUCCESS); } _SEH2_END; // end of "__finally" processing diff --git a/drivers/filesystems/udfs/strucsup.cpp b/drivers/filesystems/udfs/strucsup.cpp index 6e746f30fc8a4..b50d85f085ac2 100644 --- a/drivers/filesystems/udfs/strucsup.cpp +++ b/drivers/filesystems/udfs/strucsup.cpp @@ -148,6 +148,8 @@ Return Value: ExInitializeFastMutex(&FcbNonpaged->AdvancedFcbHeaderMutex); ExInitializeFastMutex(&FcbNonpaged->FcbFastMutex); + ExInitializeResourceLite(&FcbNonpaged->CcbListResource); + return FcbNonpaged; } @@ -181,6 +183,8 @@ Return Value: ExDeleteResourceLite(&FcbNonpaged->FcbResource); ExDeleteResourceLite(&FcbNonpaged->FcbPagingIoResource); + + UDFDeallocateFcbNonpaged(FcbNonpaged); return; @@ -902,10 +906,12 @@ UDFInitializeFCB( Fcb->FcbReference = 0; Fcb->FcbCleanup = 0; + // Initialize file name cache synchronization Fcb->FcbLockThread = NULL; Fcb->FcbLockCount = 0; + Fcb->Vcb = Vcb; return STATUS_SUCCESS; @@ -1076,6 +1082,7 @@ UDFInitializeVCB( ExInitializeResourceLite(&Vcb->VcbResource); ExInitializeResourceLite(&Vcb->BitMapResource1); + ExInitializeResourceLite(&Vcb->DlocResource); ExInitializeResourceLite(&Vcb->DlocResource2); ExInitializeResourceLite(&Vcb->FlushResource); @@ -1162,6 +1169,7 @@ UDFInitializeVCB( // TRUE, // We will use pinned access. // &(UDFGlobalData.CacheMgrCallBacks), Vcb); + Vcb->SectorSize = DiskGeometry->BytesPerSector; Vcb->SectorShift = UDFHighBit(DiskGeometry->BytesPerSector); Vcb->MediaChangeCount = MediaChangeCount; @@ -1175,6 +1183,8 @@ UDFInitializeVCB( } _SEH2_END; } // end UDFInitializeVCB() + + NTSTATUS UDFCompleteMount( IN PIRP_CONTEXT IrpContext, diff --git a/drivers/filesystems/udfs/struct.h b/drivers/filesystems/udfs/struct.h index 74c032224266d..2a275c6688eda 100644 --- a/drivers/filesystems/udfs/struct.h +++ b/drivers/filesystems/udfs/struct.h @@ -151,6 +151,8 @@ struct FCB_NONPAGED { ERESOURCE FcbPagingIoResource; + ERESOURCE CcbListResource; + // This is the FastMutex for this Fcb. FAST_MUTEX FcbMutex; @@ -658,7 +660,7 @@ struct VCB { // VAT uint32 InitVatCount; uint32 VatCount; - uint32* Vat; + PCHAR Vat; uint32 VatPartNdx; PUDF_FILE_INFO VatFileInfo; // sparing table diff --git a/drivers/filesystems/udfs/udf_info/alloc.cpp b/drivers/filesystems/udfs/udf_info/alloc.cpp index 530d6b168767e..9a846a7a6aab0 100644 --- a/drivers/filesystems/udfs/udf_info/alloc.cpp +++ b/drivers/filesystems/udfs/udf_info/alloc.cpp @@ -261,39 +261,98 @@ UDFGetBitmapLen( return 0;//(Offs == Lim); } - BOOLEAN bit = UDFGetBit(Bitmap, Offs); - SIZE_T i=Offs>>5; - SIZE_T len=0; - uint8 j=(uint8)(Offs&31); - uint8 lLim=(uint8)(Lim&31); + if (!UDFIsChunked(Bitmap)) { + BOOLEAN bit = UDFGetBit(Bitmap, Offs); + SIZE_T i = Offs >> 5; + SIZE_T len = 0; + uint8 j = (uint8)(Offs & 31); + uint8 lLim = (uint8)(Lim & 31); + uint32 a; - Lim = Lim>>5; + Lim = Lim >> 5; - ASSERT((bit == 0) || (bit == 1)); + ASSERT((bit == 0) || (bit == 1)); - uint32 a; + a = Bitmap[i] >> j; - a = Bitmap[i] >> j; + while(i <= Lim) { - while(i<=Lim) { + while( j < ((i>=1; + j++; + } + j=0; +SkipFullWord: + i++; + a = Bitmap[i]; - while( j < ((i>=1; - j++; + if (i> 3)) >> (Offs & 7) & 1); + SIZE_T i = Offs; + SIZE_T len = 0; + PUDF_CHUNKED_BUF Chunked = UDFGetChunked(Bitmap); + UCHAR bitPattern = bit ? 0xFFu : 0x00u; /* full-byte sentinel */ - if (i> 3); + ULONG chunkIdx = byteIdx >> UDF_CHUNK_SHIFT; + + if (!Chunked->Chunks[chunkIdx]) { + /* Null chunk is all-zero bits. */ + if (bit != 0) + return len; /* looking for 1-bits – none here, stop */ + /* All bits in this chunk are 0 and match; consume the whole chunk. */ + SIZE_T chunkEndBit = (SIZE_T)(chunkIdx + 1) << (UDF_CHUNK_SHIFT + 3); + SIZE_T advance = min(chunkEndBit, Lim) - i; + len += advance; + i += advance; + continue; + } + + /* Chunk is allocated; scan byte-by-byte within it. */ + { + PUCHAR chunkData = (PUCHAR)Chunked->Chunks[chunkIdx]; + SIZE_T chunkEndBit = (SIZE_T)(chunkIdx + 1) << (UDF_CHUNK_SHIFT + 3); + SIZE_T limitBit = min(chunkEndBit, Lim); + + while (i < limitBit) { + ULONG bOff = (ULONG)(i & 7); + ULONG bIdx = (ULONG)(i >> 3) & UDF_CHUNK_MASK; + UCHAR b = chunkData[bIdx]; + + /* Full-byte fast path */ + if (bOff == 0 && (i + 8) <= limitBit) { + if (b == bitPattern) { + len += 8; + i += 8; + continue; + } + /* Mixed byte: fall through to bit loop */ + } + + /* Bit-by-bit for partial or mixed bytes */ + while (bOff < 8 && i < limitBit) { + if ((BOOLEAN)((b >> bOff) & 1) != bit) + return len; + len++; + i++; + bOff++; + } } } } @@ -515,15 +574,17 @@ UDFMarkBadSpaceAsUsed( IN ULONG len ) { - uint32 j; -#define BIT_C (sizeof(Vcb->BSBM_Bitmap[0])*8) - len = (lba+len+BIT_C-1)/BIT_C; + uint32 StartByteIndex, ByteSpanLength; + + StartByteIndex = lba >> 3; + ByteSpanLength = ((lba + len + 7) >> 3) - StartByteIndex; + UDFPrint(("UDFMarkBadSpaceAsUsed: lba=%x len=%x StartByteIndex=%x ByteSpanLength=%x BSBM=%p\n", + lba, len, StartByteIndex, ByteSpanLength, Vcb->BSBM_Bitmap)); if (Vcb->BSBM_Bitmap) { - for(j=lba/BIT_C; jFSBM_Bitmap[j] &= ~Vcb->BSBM_Bitmap[j]; - } + // FSBM uses bit=1=USED semantics; OR the bad-block bitmap in so bad blocks + // are marked as used (bit=1 in FSBM), preventing them from being allocated. + UDFChunkedOrMemory(Vcb->FSBM_Bitmap, Vcb->BSBM_Bitmap, StartByteIndex, ByteSpanLength); } -#undef BIT_C } // UDFMarkBadSpaceAsUsed() /* @@ -620,9 +681,9 @@ UDFMarkSpaceAsXXXNoProtect_( // mark logical blocks in VAT as used for(j=0;jVat[lba-root+j] == UDF_VAT_FREE_ENTRY) && + if ((UDFVatGetEntry(Vcb->Vat, lba-root+j) == UDF_VAT_FREE_ENTRY) && (lba > Vcb->LastLBA)) { - Vcb->Vat[lba-root+j] = 0x7fffffff; + UDFVatSetEntry(Vcb->Vat, lba-root+j, 0x7fffffff); } } } @@ -650,7 +711,7 @@ UDFMarkSpaceAsXXXNoProtect_( // this operation can decrease resulting VAT size for(j=0;jVat[lba-root+j] = UDF_VAT_FREE_ENTRY; + UDFVatSetEntry(Vcb->Vat, lba-root+j, UDF_VAT_FREE_ENTRY); } } // mark discarded extent as Not-Alloc-Not-Rec to @@ -833,15 +894,35 @@ UDFGetPartFreeSpace( IN uint32 partNum ) { - uint32 lim/*, len=1*/; - uint32 s=0; - uint32 j; - PUCHAR cur = (PUCHAR)(Vcb->FSBM_Bitmap); - - lim = (UDFPartEnd(Vcb,partNum)+7)/8; - for(j=(UDFPartStart(Vcb,partNum)+7)/8; j= endBit) { + return 0; } + + for (i = startBit; (i < endBit) && (i & 7); i++) { + if (UDFGetFreeBit(Vcb->FSBM_Bitmap, i)) + s++; + } + + ASSERT((i & 7) == 0); + for (; i + 7 < endBit; i += 8) { + // FSBM uses bit=1=USED semantics: count zero bits (= free blocks). + // For null chunks UDFChunkedGetByte returns 0; ~0 = 0xFF; bit_count_tab[0xFF] = 8. + s += bit_count_tab[(UCHAR)(~UDFChunkedGetByte(Vcb->FSBM_Bitmap, i >> 3))]; + } + + for (; i < endBit; i++) { + if (UDFGetFreeBit(Vcb->FSBM_Bitmap, i)) + s++; + } + return s; } // end UDFGetPartFreeSpace() diff --git a/drivers/filesystems/udfs/udf_info/dirtree.cpp b/drivers/filesystems/udfs/udf_info/dirtree.cpp index e4ed3534956e4..7b51aada5fdcc 100644 --- a/drivers/filesystems/udfs/udf_info/dirtree.cpp +++ b/drivers/filesystems/udfs/udf_info/dirtree.cpp @@ -685,6 +685,8 @@ UDFIndexDirectory( } // end UDFIndexDirectory() + + /* This routine rebuilds tags for all entries from Dir. */ diff --git a/drivers/filesystems/udfs/udf_info/extent.cpp b/drivers/filesystems/udfs/udf_info/extent.cpp index f76d82b4577c0..0687e4cf1b275 100644 --- a/drivers/filesystems/udfs/udf_info/extent.cpp +++ b/drivers/filesystems/udfs/udf_info/extent.cpp @@ -1324,6 +1324,8 @@ UDFBuildExtAllocDescs( } // end UDFBuildExtAllocDescs()*/ + + NTSTATUS UDFInitAllocationCache( IN PVCB Vcb, @@ -1504,9 +1506,11 @@ UDFAllocateFESpace( IN uint32 Len ) { + UNREFERENCED_PARAMETER(DirInfo); return UDFAllocFreeExtent(IrpContext, Vcb, Len, UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY); + } // end UDFAllocateFESpace() /* @@ -1519,7 +1523,9 @@ UDFFreeFESpace( IN PEXTENT_INFO FEExtInfo ) { + UNREFERENCED_PARAMETER(DirInfo); + UDFMarkSpaceAsXXX(Vcb, 0, FEExtInfo->Mapping, AS_DISCARDED); // free FEExtInfo->Mapping[0].extLocation = 0; FEExtInfo->Mapping[0].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); diff --git a/drivers/filesystems/udfs/udf_info/mount.cpp b/drivers/filesystems/udfs/udf_info/mount.cpp index 62fa4048fc624..8841f821f7d7c 100644 --- a/drivers/filesystems/udfs/udf_info/mount.cpp +++ b/drivers/filesystems/udfs/udf_info/mount.cpp @@ -57,7 +57,7 @@ UDFPrepareXSpaceBitmap( IN OUT uint32* XSl ) { - uint32 BS, j, LBS; + uint32 j, LBS; uint32 plen; NTSTATUS status; EXTENT_MAP TmpExt; @@ -77,11 +77,11 @@ UDFPrepareXSpaceBitmap( locAddr.partitionReferenceNum = (uint16)RefPartNum; plen = UDFPartStart(Vcb, RefPartNum) + UDFPartLen(Vcb, RefPartNum); - BS = Vcb->SectorSize; + LBS = Vcb->SectorSize; *XSl = sizeof(SPACE_BITMAP_DESC) + ((plen+7)>>3); - _XSBM = (int8*)DbgAllocatePool(NonPagedPool, (*XSl + BS - 1) & ~(BS-1) ); + _XSBM = UDFAllocChunked(*XSl); *XSBM = _XSBM; switch (XSpaceBitmap->extLength >> 30) { @@ -138,25 +138,33 @@ UDFPrepareXSpaceBitmap( switch (XSpaceBitmap->extLength >> 30) { case EXTENT_RECORDED_ALLOCATED: { - // read descriptor & bitmap - if ((!NT_SUCCESS(status = UDFReadTagged(IrpContext, Vcb, *XSBM, (j = TmpExt.extLocation), - locAddr.logicalBlockNum, &Ident))) || - (Ident != TID_SPACE_BITMAP_DESC) || - (!NT_SUCCESS(status = UDFReadExtent(IrpContext, Vcb, XSBMExtInfo, 0, *XSl, FALSE, *XSBM, &ReadBytes))) ) { - if (NT_SUCCESS(status)) { + // Validate the descriptor tag with a temporary flat sector buffer, + // then read the full extent directly into the chunked bitmap buffer. + int8* tmpTag = (int8*)DbgAllocatePool(NonPagedPool, LBS); + if (!tmpTag) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + status = UDFReadTagged(IrpContext, Vcb, tmpTag, (j = TmpExt.extLocation), + locAddr.logicalBlockNum, &Ident); + DbgFreePool(tmpTag); + if (NT_SUCCESS(status) && Ident != TID_SPACE_BITMAP_DESC) { BrutePoint(); status = STATUS_FILE_CORRUPT_ERROR; } + if (NT_SUCCESS(status)) { + status = UDFReadExtentIntoChunked(IrpContext, Vcb, XSBMExtInfo, + 0, *XSl, FALSE, *XSBM, &ReadBytes); + } + } + if (!NT_SUCCESS(status)) { if (XSBMExtInfo->Mapping) { MyFreePool__(XSBMExtInfo->Mapping); XSBMExtInfo->Mapping = NULL; } - DbgFreePool(*XSBM); + UDFFreeChunked(*XSBM); *XSl = 0; *XSBM = NULL; return status; - } else { -// BrutePoint(); } return STATUS_SUCCESS; } @@ -169,10 +177,21 @@ UDFPrepareXSpaceBitmap( #endif } - PSPACE_BITMAP_DESC XSDesc = (PSPACE_BITMAP_DESC)(*XSBM); + // Fresh allocation for a not-yet-recorded bitmap: set up the descriptor header. + // Chunks are zero-initialised on allocation; no RtlZeroMemory needed. + PSPACE_BITMAP_DESC XSDesc = (PSPACE_BITMAP_DESC)UDFChunkedGetOrAllocBytePtr(*XSBM, 0); + if (!XSDesc) { + if (XSBMExtInfo->Mapping) { + MyFreePool__(XSBMExtInfo->Mapping); + XSBMExtInfo->Mapping = NULL; + } + UDFFreeChunked(*XSBM); + *XSBM = NULL; + *XSl = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } XSpaceBitmap->extLength = (*XSl + LBS -1) & ~(LBS-1); - RtlZeroMemory(*XSBM, *XSl); XSDesc->descTag.tagIdent = TID_SPACE_BITMAP_DESC; UDFSetUpTag(Vcb, &(XSDesc->descTag), 0, XSpaceBitmap->extPosition, 0); XSDesc->numOfBits = plen; @@ -197,8 +216,6 @@ UDFUpdateXSpaceBitmaps( int8* bad_bm; int8* old_bm; int8* new_bm; - int8* fpart_bm; - int8* upart_bm; NTSTATUS status, status2; int8* USBM=NULL; int8* FSBM=NULL; @@ -228,7 +245,7 @@ UDFUpdateXSpaceBitmaps( // try to recover insufficient resources if (USl && USBMExtInfo.Mapping) { USl -= sizeof(SPACE_BITMAP_DESC); - status = UDFWriteExtent(IrpContext, Vcb, &USBMExtInfo, sizeof(SPACE_BITMAP_DESC), USl, FALSE, new_bm, &WrittenBytes); + status = UDFWriteExtentFromChunked(IrpContext, Vcb, &USBMExtInfo, sizeof(SPACE_BITMAP_DESC), USl, FALSE, new_bm, &WrittenBytes); #ifdef UDF_DBG } else { UDFPrint(("Can't update USBM\n")); @@ -238,7 +255,7 @@ UDFUpdateXSpaceBitmaps( if (FSl && FSBMExtInfo.Mapping) { FSl -= sizeof(SPACE_BITMAP_DESC); - status2 = UDFWriteExtent(IrpContext, Vcb, &FSBMExtInfo, sizeof(SPACE_BITMAP_DESC), FSl, FALSE, new_bm, &WrittenBytes); + status2 = UDFWriteExtentFromChunked(IrpContext, Vcb, &FSBMExtInfo, sizeof(SPACE_BITMAP_DESC), FSl, FALSE, new_bm, &WrittenBytes); } else { status2 = status; UDFPrint(("Can't update FSBM\n")); @@ -246,8 +263,13 @@ UDFUpdateXSpaceBitmaps( if (FSBMExtInfo.Mapping) MyFreePool__(FSBMExtInfo.Mapping); } else { // normal way to record BitMaps - if (USBM) upart_bm = USBM + sizeof(SPACE_BITMAP_DESC); - if (FSBM) fpart_bm = FSBM + sizeof(SPACE_BITMAP_DESC); + // USBM and FSBM are chunked on-disk output buffers using the UDF on-disk + // convention (bit=1=free/unallocated, bit=0=used/allocated), indexed from + // bit offset sizeof(SPACE_BITMAP_DESC)*8 to skip past the descriptor header. + // new_bm = Vcb->FSBM_Bitmap and old_bm = Vcb->FSBM_OldBitmap are chunked + // FSBM buffers using the internal bit=1=USED / bit=0=FREE convention. + // Use raw UDFGetBit/UDFSetBit/UDFClrBit directly, not the UDFGetFreeBit/ + // UDFSetFreeBit wrappers, to avoid confusion between the two conventions. pend = min(pstart + plen, Vcb->FSBM_BitCount); d=1; @@ -256,32 +278,33 @@ UDFUpdateXSpaceBitmaps( for(i=pstart; iSectorSize, sizeof(LogicalVolDesc)) ); if (!lvd) { @@ -962,7 +987,7 @@ UDFUmount__( UDF_CHECK_BITMAP_RESOURCE(Vcb); // check if we should update BM - if (Vcb->FSBM_ByteCount == RtlCompareMemory(Vcb->FSBM_Bitmap, Vcb->FSBM_OldBitmap, Vcb->FSBM_ByteCount)) { + if (Vcb->FSBM_ByteCount == UDFChunkedCompareMemory(Vcb->FSBM_Bitmap, Vcb->FSBM_OldBitmap, Vcb->FSBM_ByteCount)) { flags &= ~1; } else { flags |= 1; @@ -984,7 +1009,7 @@ UDFUmount__( } if (flags & 1) - RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); + UDFChunkedCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); //skip_update_bitmap: @@ -1619,15 +1644,15 @@ UDFAddXSpaceBitmap( ) { int8* tmp; - int8* tmp_bm; - uint32 i, lim, j, lba, l, lim2, l2, k; + uint32 i, lim, j, lba, l, lim2; lb_addr locAddr; NTSTATUS status; uint16 Ident; uint32 flags; SIZE_T Length; ULONG ReadBytes; - BOOLEAN bit_set; + + UDF_CHECK_BITMAP_RESOURCE(Vcb); UDFPrint(("UDFAddXSpaceBitmap: at block=%x, partition=%d\n", @@ -1638,11 +1663,14 @@ UDFAddXSpaceBitmap( i=UDFPartStart(Vcb, RefPartNum); flags = bm->extLength >> 30; if (!flags /*|| flags == EXTENT_NOT_RECORDED_ALLOCATED*/) { - tmp = (int8*)DbgAllocatePool(NonPagedPool, max(Length, Vcb->SectorSize)); + + // Use a single sector buffer to avoid allocating the entire ~64MB bitmap at once. + tmp = (int8*)DbgAllocatePool(NonPagedPool, Vcb->SectorSize); + if (!tmp) return STATUS_INSUFFICIENT_RESOURCES; locAddr.partitionReferenceNum = (uint16)RefPartNum; locAddr.logicalBlockNum = bm->extPosition; - // read header of the Bitmap + // read header of the Bitmap (first sector - also verifies the tag) if (!NT_SUCCESS(status = UDFReadTagged(IrpContext, Vcb, tmp, lba = UDFPartLbaToPhys(Vcb, &locAddr), locAddr.logicalBlockNum, &Ident))) { err_addxsbm_1: @@ -1654,27 +1682,59 @@ UDFAddXSpaceBitmap( goto err_addxsbm_1; } - // read the whole Bitmap - if (!NT_SUCCESS(status = UDFReadData(IrpContext, Vcb, FALSE, ((uint64)lba)<SectorShift, Length, FALSE, tmp, &ReadBytes))) - goto err_addxsbm_1; - lim = min(i + (lim2 = ((PSPACE_BITMAP_DESC)tmp)->numOfBits), Vcb->FSBM_BitCount); - tmp_bm = tmp + sizeof(SPACE_BITMAP_DESC); + // Process the on-disk bitmap sector by sector to avoid a large flat allocation. + // The SPACE_BITMAP_DESC header occupies the first sizeof(SPACE_BITMAP_DESC) bytes; + // bitmap data follows immediately in the same sector and continues in subsequent ones. + lim2 = ((PSPACE_BITMAP_DESC)tmp)->numOfBits; + lim = min(i + lim2, Vcb->FSBM_BitCount); j = 0; - for(;(l = UDFGetBitmapLen((uint32*)tmp_bm, j, lim2)) && (iFSBM_Bitmap, i); - UDFSetFreeBitOwner(Vcb, i); + l = sizeof(SPACE_BITMAP_DESC); // byte offset within current sector where data begins + { + SIZE_T extByteOffset = 0; + for (;;) { + // Process all bitmap bytes in the current sector + while (l < (uint32)Vcb->SectorSize && j < lim2 && i < lim) { + uint8 bval = (uint8)tmp[l]; + uint32 bitsLeft = min(8u, lim2 - j); + if (bval == 0x00 && bitsLeft == 8 && (i & 7) == 0) { + // Fast path: all 8 on-disk bits are 0 = all used. + // Set all 8 FSBM bits to 1 (used) in one byte write. + UDFChunkedSetByte(Vcb->FSBM_Bitmap, i >> 3, 0xFF); +#ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS + for (uint32 b = 0; b < 8; b++) { + UDFSetUsedBitOwner(Vcb, i + b, 0); + } +#endif + j += 8; + i += 8; + } else { + for (uint32 b = 0; b < bitsLeft && i < lim; b++, j++, i++) { + if (!((bval >> b) & 1)) { + // on-disk bit=0 → sector is used → set FSBM bit to 1 + UDFSetUsedBit(Vcb->FSBM_Bitmap, i); + } else { + // on-disk bit=1 → sector is free → FSBM bit stays 0, no-op + UDFSetFreeBitOwner(Vcb, i); + } + } + } + l++; } - i++; + if (j >= lim2 || i >= lim) break; + // Advance to the next sector of the extent + extByteOffset += Vcb->SectorSize; + if (extByteOffset >= Length) break; + { + ULONG readLen = (ULONG)min((SIZE_T)Vcb->SectorSize, Length - extByteOffset); + if (!NT_SUCCESS(status = UDFReadData(IrpContext, Vcb, FALSE, + ((uint64)lba << Vcb->SectorShift) + extByteOffset, + readLen, FALSE, tmp, &ReadBytes))) + goto err_addxsbm_1; + } + l = 0; // next sectors have no header; start from byte 0 + } - j += l; } DbgFreePool(tmp); /* } else if ((bm->extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { @@ -1699,16 +1759,14 @@ UDFVerifyXSpaceBitmap( ) { int8* tmp; -// int8* tmp_bm; -// uint32 i, l2, k, lim, j, lim2; uint32 lba; lb_addr locAddr; NTSTATUS status; uint16 Ident; uint32 flags; uint32 Length; - ULONG ReadBytes; -// BOOLEAN bit_set; + + UDF_CHECK_BITMAP_RESOURCE(Vcb); @@ -1718,7 +1776,10 @@ UDFVerifyXSpaceBitmap( // i=UDFPartStart(Vcb, RefPartNum); flags = bm->extLength >> 30; if (!flags /*|| flags == EXTENT_NOT_RECORDED_ALLOCATED*/) { - tmp = (int8*)DbgAllocatePool(NonPagedPool, max(Length, Vcb->SectorSize)); + + // Only need one sector to verify the space bitmap descriptor tag. + tmp = (int8*)DbgAllocatePool(NonPagedPool, Vcb->SectorSize); + if (!tmp) return STATUS_INSUFFICIENT_RESOURCES; locAddr.partitionReferenceNum = (uint16)RefPartNum; locAddr.logicalBlockNum = bm->extPosition; @@ -1734,46 +1795,8 @@ UDFVerifyXSpaceBitmap( status = STATUS_DISK_CORRUPT_ERROR; goto err_vfyxsbm_1; } - // read the whole Bitmap - if (!NT_SUCCESS(status = UDFReadData(IrpContext, Vcb, FALSE, ((uint64)lba)<SectorShift, Length, FALSE, tmp, &ReadBytes))) - goto err_vfyxsbm_1; -// lim = min(i + ((lim2 = ((PSPACE_BITMAP_DESC)tmp)->numOfBits) << Vcb->LB2B_Bits), Vcb->FSBM_BitCount); -// tmp_bm = tmp + sizeof(SPACE_BITMAP_DESC); -// j = 0; -/* for(;(l = UDFGetBitmapLen((uint32*)tmp_bm, j, lim2)) && (iLB2B_Bits; - // ...and mark them - if (bm_type == UDF_FSPACE_BM) { - bit_set = UDFGetFreeBit(tmp_bm, j); - for(k=0;(kFSBM_Bitmap, i); - UDFSetFreeBitOwner(Vcb, i); - UDFSetZeroBit(Vcb->ZSBM_Bitmap, i); - } else { - // USED block - UDFClrZeroBit(Vcb->ZSBM_Bitmap, i); - } - i++; - } - } else { - bit_set = UDFGetZeroBit(tmp_bm, j); - for(k=0;(kZSBM_Bitmap, i); - } else { - // DATA block - UDFClrZeroBit(Vcb->ZSBM_Bitmap, i); - } - i++; - } - } - j += l; - }*/ + DbgFreePool(tmp); /* } else if ((bm->extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { i=Vcb->Partitions[RefPartNum].PartitionRoot; @@ -1959,10 +1982,15 @@ UDFBuildFreeSpaceBitmap( if (!(Vcb->FSBM_Bitmap)) { // init Bitmap buffer if necessary - Vcb->FSBM_Bitmap = (int8*)DbgAllocatePool(NonPagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3) ); - if (!(Vcb->FSBM_Bitmap)) return STATUS_INSUFFICIENT_RESOURCES; - RtlZeroMemory(Vcb->FSBM_Bitmap, i); + i = (Vcb->LastPossibleLBA+1+7)>>3; + UDFPrint(("UDFBuildFreeSpaceBitmap: allocating FSBM_Bitmap ByteCount=%x BitCount=%x\n", i, Vcb->LastPossibleLBA+1)); + Vcb->FSBM_Bitmap = UDFAllocChunked((i = (Vcb->LastPossibleLBA+1+7)>>3)); + if (!(Vcb->FSBM_Bitmap)) { + UDFPrint(("UDFBuildFreeSpaceBitmap: FSBM_Bitmap alloc failed\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + #ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS Vcb->FSBM_Bitmap_owners = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32)); @@ -2959,9 +2987,13 @@ UDFGetDiskInfoAndVerify( UDFLoadFileset(Vcb,FileSetDesc, &(Vcb->RootLbAddr), &(Vcb->SysStreamLbAddr)); - Vcb->FSBM_OldBitmap = (int8*)DbgAllocatePool(NonPagedPool, Vcb->FSBM_ByteCount); - if (!(Vcb->FSBM_OldBitmap)) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); - RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); + Vcb->FSBM_OldBitmap = UDFAllocChunked(Vcb->FSBM_ByteCount); + if (!(Vcb->FSBM_OldBitmap)) { + UDFPrint(("UDFGetDiskInfoAndVerify: FSBM_OldBitmap alloc failed (ByteCount=%x)\n", Vcb->FSBM_ByteCount)); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + UDFPrint(("UDFGetDiskInfoAndVerify: snapshotting FSBM_OldBitmap ByteCount=%x\n", Vcb->FSBM_ByteCount)); + UDFChunkedCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); try_exit: NOTHING; } _SEH2_FINALLY { @@ -2971,4 +3003,3 @@ try_exit: NOTHING; return(RC); } // end UDFGetDiskInfoAndVerify() - diff --git a/drivers/filesystems/udfs/udf_info/remap.cpp b/drivers/filesystems/udfs/udf_info/remap.cpp index 72a4079b07021..bc057f9c77689 100644 --- a/drivers/filesystems/udfs/udf_info/remap.cpp +++ b/drivers/filesystems/udfs/udf_info/remap.cpp @@ -218,15 +218,14 @@ UDFRelocateSector( } } else if (Vcb->Vat) { // use VAT for relocation - uint32* Map = Vcb->Vat; uint32 root; // check if given Lba lays in the partition covered by VAT if (Lba >= Vcb->NWA) return Vcb->NWA; if (Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot)) return Lba; - Map = &(Vcb->Vat[(i = Lba - root)]); - if ((i < Vcb->VatCount) && (i=(*Map)) ) { + i = Lba - root; + if ((i < Vcb->VatCount) && (i = UDFVatGetEntry(Vcb->Vat, i)) ) { if (i != UDF_VAT_FREE_ENTRY) { return i + root; } else { @@ -267,14 +266,12 @@ UDFAreSectorsRelocated( } else if (Vcb->Vat) { // use VAT for relocation uint32 i, root, j; - uint32* Map; if (Lba < (root = Vcb->Partitions[Vcb->VatPartNdx].PartitionRoot)) return FALSE; if (Lba+BlockCount >= Vcb->NWA) return TRUE; - Map = &(Vcb->Vat[Lba-root/*+i*/]); - for(i=0; iVat, Lba-root+i)) && (j != Lba-root+i) && ((j != UDF_VAT_FREE_ENTRY) || ((Lba+i) < Vcb->LastLBA))) return TRUE; diff --git a/drivers/filesystems/udfs/udf_info/udf_info.cpp b/drivers/filesystems/udfs/udf_info/udf_info.cpp index e9556aa93de31..f91e780a02ee2 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.cpp +++ b/drivers/filesystems/udfs/udf_info/udf_info.cpp @@ -1587,7 +1587,9 @@ UDFWriteFile__( elen - Dloc->DataLoc.Offset, Dloc->DataLoc.Length)); UDFSetFileSize(FileInfo, t); + Dloc->DataLoc.Modified = TRUE; + Dloc->DataLoc.Length = t; return UDFWriteExtent(IrpContext, Vcb, &Dloc->DataLoc, Offset, Length, Direct, Buffer, WrittenBytes); } @@ -1612,10 +1614,12 @@ UDFWriteFile__( ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_SHORT; 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; } + } // increase extent ExtPrint((" %s %s %s\n", @@ -1681,7 +1685,9 @@ UDFWriteFile__( return status; UDFSetFileSize(FileInfo, t); Dloc->DataLoc.Modified = TRUE; + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + return STATUS_SUCCESS; } // end UDFWriteFile__() @@ -3631,8 +3637,10 @@ 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)); + MyFreePool__(FileInfo.FileIdent); if (!NT_SUCCESS(status)) return status; if (CurDirNdx) CurDirNdx->FileCharacteristics = @@ -3733,10 +3741,12 @@ 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; } + // init new data location descriptors FileInfo->Dloc->DataLoc.Mapping = NewMap; RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP)); @@ -3768,8 +3778,10 @@ UDFResizeFile__( UDFSetFileSize(FileInfo, NewLength); } + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + return status; } // end UDFResizeFile__() @@ -3897,7 +3909,7 @@ UDFLoadVAT( goto err_vat_15; } // read VAT & remember old version - Vcb->Vat = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) ); + Vcb->Vat = (PCHAR)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) ); if (!Vcb->Vat) { goto err_vat_15_2; } @@ -3924,7 +3936,7 @@ UDFLoadVAT( // contain _relative_ addresses len = Vcb->NWA - root; for(i=0; i<=len; i++) { - Vcb->Vat[i] = i; + UDFVatSetEntry(Vcb->Vat, i, i); } RtlCopyMemory(Vcb->Vat, VatOldData+Offset, to_read); Vcb->InitVatCount = @@ -3932,10 +3944,10 @@ UDFLoadVAT( Vcb->VatPartNdx = PartNdx; Vcb->CDR_Mode = TRUE; len = Vcb->VatCount; - RtlFillMemory(&(Vcb->Vat[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff); + RtlFillMemory(&(((uint32*)Vcb->Vat)[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff); // sync VAT and FSBM for(i=0; iVat[i] == UDF_VAT_FREE_ENTRY) { + if (((uint32*)Vcb->Vat)[i] == UDF_VAT_FREE_ENTRY) { UDFSetFreeBit(Vcb->FSBM_Bitmap, root+i); } } @@ -4090,7 +4102,9 @@ UDFFlushFE( return status; } #ifdef UDF_DBG + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; #endif // UDF_DBG // initiate update of lengthAllocDescs @@ -4120,7 +4134,9 @@ UDFFlushFE( ASSERT(UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping) == 0); } else { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } #endif // UDF_DBG } @@ -5062,7 +5078,7 @@ UDFRecordVAT( uint32 OldLen; EntityID* eID; - if (!(Vat = Vcb->Vat) || !VatFileInfo) return STATUS_INVALID_PARAMETER; + if (!(Vat = (uint32*)Vcb->Vat) || !VatFileInfo) return STATUS_INVALID_PARAMETER; // Disable VAT-based translation Vcb->Vat = NULL; // sync VAT and FSBM @@ -5181,7 +5197,9 @@ UDFRecordVAT( UDFWriteData(IrpContext, Vcb, TRUE, ((uint64)Vcb->NWA) << Vcb->SectorShift, 1, FALSE, Old, &WrittenBytes); PacketOffset++; } else { - Vcb->Vat = (uint32*)(New+Offset); + + Vcb->Vat = (PCHAR)(New+Offset); + Vcb->Vat = NULL; } VatFileInfo->Dloc->FELoc.Mapping[0].extLocation = @@ -5203,7 +5221,9 @@ UDFRecordVAT( if (!NT_SUCCESS(status)) return status; // update VAT with locations of not flushed blocks if (PacketOffset) { - Vcb->Vat = (uint32*)(New+Offset); + + Vcb->Vat = (PCHAR)(New+Offset); + Vcb->Vat = NULL; } @@ -5339,7 +5359,7 @@ UDFUpdateVAT( for(i=0; i= Vcb->VatCount) Vcb->VatCount = CurLba+1; - Vcb->Vat[CurLba] = NWA; + ((uint32*)Vcb->Vat)[CurLba] = NWA; } return STATUS_SUCCESS; } // end UDFUpdateVAT() diff --git a/drivers/filesystems/udfs/udf_info/udf_info.h b/drivers/filesystems/udfs/udf_info/udf_info.h index d68b0d6437f3f..59b7b42517631 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.h +++ b/drivers/filesystems/udfs/udf_info/udf_info.h @@ -1388,28 +1388,600 @@ UDFDirIndex( #define CheckAddr(addr) {ASSERT((uint32)(addr) & 0x80000000);} -#define UDFGetBit(arr, bit) ( (BOOLEAN) ( ((((uint32*)(arr))[(bit)>>5]) >> ((bit)&31)) &1 ) ) -#define UDFSetBit(arr, bit) ( (((uint32*)(arr))[(bit)>>5]) |= (((uint32)1) << ((bit)&31)) ) -#define UDFClrBit(arr, bit) ( (((uint32*)(arr))[(bit)>>5]) &= (~(((uint32)1) << ((bit)&31))) ) - -#define UDFSetBits(arr, bit, bc) \ -{uint32 j; \ - for(j=0;jSignature == UDF_CHUNKED_BUF_SIGNATURE); +} + +__inline +PUDF_CHUNKED_BUF +UDFGetChunked( + IN PVOID Bitmap + ) +{ + return (PUDF_CHUNKED_BUF)(((ULONG_PTR)Bitmap) & ~UDF_CHUNKED_PTR_TAG); +} + +__inline +PCHAR +UDFTagChunked( + IN PUDF_CHUNKED_BUF Bitmap + ) +{ + return (PCHAR)(((ULONG_PTR)Bitmap) | UDF_CHUNKED_PTR_TAG); +} + +__inline +PUCHAR +UDFChunkedGetBytePtr( + IN PVOID Bitmap, + IN ULONG ByteIndex + ) +{ + PUDF_CHUNKED_BUF Chunked; + + if (!UDFIsChunked(Bitmap)) { + return &((PUCHAR)Bitmap)[ByteIndex]; + } + + Chunked = UDFGetChunked(Bitmap); + if (!Chunked->Chunks[ByteIndex >> UDF_CHUNK_SHIFT]) { + /* Fixed-size zero page – size is independent of UDF_CHUNK_SIZE so that + * changing UDF_CHUNK_SHIFT does not inflate the driver binary. The + * static assertion below guards against UDF_CHUNK_SIZE ever exceeding + * this buffer. Callers may only read up to + * UDFChunkedGetContiguousLength() bytes from the returned pointer, which + * is at most UDF_CHUNK_SIZE bytes. */ + static const UCHAR ZeroChunk[4096] = {0}; + C_ASSERT(UDF_CHUNK_SIZE <= sizeof(ZeroChunk)); + return (PUCHAR)&ZeroChunk[ByteIndex & UDF_CHUNK_MASK]; + } + return &((PUCHAR)(Chunked->Chunks[ByteIndex >> UDF_CHUNK_SHIFT]))[ByteIndex & UDF_CHUNK_MASK]; +} + +__inline +PUCHAR +UDFChunkedGetOrAllocBytePtr( + IN PVOID Bitmap, + IN ULONG ByteIndex + ) +{ + PUDF_CHUNKED_BUF Chunked; + ULONG ChunkIdx; + ULONG ChunkLength; + PCHAR Chunk; + + if (!UDFIsChunked(Bitmap)) { + return &((PUCHAR)Bitmap)[ByteIndex]; + } + + Chunked = UDFGetChunked(Bitmap); + ChunkIdx = ByteIndex >> UDF_CHUNK_SHIFT; + if (!Chunked->Chunks[ChunkIdx]) { + ChunkLength = min((ULONG)UDF_CHUNK_SIZE, Chunked->ByteCount - (ChunkIdx << UDF_CHUNK_SHIFT)); + // PagedPool is intentional: chunked bitmap chunks are only ever dereferenced + // at PASSIVE_LEVEL (under Vcb resource locks), so paged memory is safe and + // avoids exhausting the much-smaller NonPagedPool for large bitmaps. + Chunk = (PCHAR)DbgAllocatePool(PagedPool, ChunkLength); + if (!Chunk) { + UDFPrint(("UDFChunkedGetOrAllocBytePtr: chunk[%x] alloc failed\n", ChunkIdx)); + return NULL; + } + RtlZeroMemory(Chunk, ChunkLength); + Chunked->Chunks[ChunkIdx] = Chunk; + } + return &((PUCHAR)(Chunked->Chunks[ChunkIdx]))[ByteIndex & UDF_CHUNK_MASK]; +} + +__inline +ULONG +UDFChunkedGetContiguousLength( + IN PVOID Bitmap, + IN ULONG ByteIndex + ) +{ + if (!UDFIsChunked(Bitmap)) { + return MAXULONG; + } + return UDF_CHUNK_SIZE - (ByteIndex & UDF_CHUNK_MASK); +} + +__inline +UCHAR +UDFChunkedGetByte( + IN PVOID Bitmap, + IN ULONG ByteIndex + ) +{ + return *(UDFChunkedGetBytePtr(Bitmap, ByteIndex)); +} + +__inline +VOID +UDFChunkedSetByte( + IN PVOID Bitmap, + IN ULONG ByteIndex, + IN UCHAR Value + ) +{ + PUCHAR pByte = UDFChunkedGetOrAllocBytePtr(Bitmap, ByteIndex); + if (pByte) *pByte = Value; +} + +__inline +VOID +UDFChunkedSetBit( + IN PVOID Bitmap, + IN ULONG BitIndex + ) +{ + PUCHAR pByte = UDFChunkedGetOrAllocBytePtr(Bitmap, BitIndex >> 3); + if (pByte) (*pByte) |= (UCHAR)(1 << (BitIndex & 7)); +} + +__inline +VOID +UDFChunkedClearBit( + IN PVOID Bitmap, + IN ULONG BitIndex + ) +{ + PUCHAR pByte; + if (UDFIsChunked(Bitmap) && !UDFGetChunked(Bitmap)->Chunks[(BitIndex >> 3) >> UDF_CHUNK_SHIFT]) + return; // chunk not allocated; bit is already 0 (cleared), no-op + pByte = UDFChunkedGetBytePtr(Bitmap, BitIndex >> 3); + (*pByte) &= (UCHAR)(~(1 << (BitIndex & 7))); +} + +__inline +PCHAR +UDFAllocChunked( + IN ULONG ByteCount + ) +{ + ULONG ChunkCount; + SIZE_T HeaderLength; + PUDF_CHUNKED_BUF Chunked; + + UDFPrint(("UDFAllocChunked: ByteCount=%x\n", ByteCount)); + + if (!ByteCount) + return NULL; + + ChunkCount = (ByteCount + UDF_CHUNK_MASK) >> UDF_CHUNK_SHIFT; + HeaderLength = sizeof(UDF_CHUNKED_BUF) + (ChunkCount - 1) * sizeof(PCHAR); + + UDFPrint(("UDFAllocChunked: ChunkCount=%x HeaderLength=%x\n", ChunkCount, (ULONG)HeaderLength)); + + Chunked = (PUDF_CHUNKED_BUF)DbgAllocatePool(NonPagedPool, HeaderLength); + if (!Chunked) { + UDFPrint(("UDFAllocChunked: header alloc failed\n")); + return NULL; + } + + ASSERT((((ULONG_PTR)Chunked) & UDF_CHUNKED_PTR_TAG) == 0); + RtlZeroMemory(Chunked, HeaderLength); + Chunked->Signature = UDF_CHUNKED_BUF_SIGNATURE; + Chunked->ByteCount = ByteCount; + Chunked->ChunkCount = ChunkCount; + + // Chunks are NOT pre-allocated; they are lazily allocated on first write + // via UDFChunkedGetOrAllocBytePtr, keeping boot-time memory usage minimal. + + UDFPrint(("UDFAllocChunked: done (lazy), header=%p tagged=%p\n", Chunked, UDFTagChunked(Chunked))); + return UDFTagChunked(Chunked); +} + +__inline +VOID +UDFFreeChunked( + IN PCHAR Bitmap + ) +{ + ULONG i; + PUDF_CHUNKED_BUF Chunked; + + UDFPrint(("UDFFreeChunked: Bitmap=%p\n", Bitmap)); + + if (!Bitmap) + return; + + if (!UDFIsChunked(Bitmap)) { + UDFPrint(("UDFFreeChunked: flat bitmap, freeing directly\n")); + DbgFreePool(Bitmap); + return; + } + + Chunked = UDFGetChunked(Bitmap); + UDFPrint(("UDFFreeChunked: chunked header=%p ChunkCount=%x\n", Chunked, Chunked->ChunkCount)); + for (i = 0; i < Chunked->ChunkCount; i++) { + if (Chunked->Chunks[i]) { + UDFPrint(("UDFFreeChunked: freeing chunk[%x]=%p\n", i, Chunked->Chunks[i])); + DbgFreePool(Chunked->Chunks[i]); + } + } + DbgFreePool(Chunked); + UDFPrint(("UDFFreeChunked: done\n")); +} + +__inline +VOID +UDFChunkedFillMemory( + IN PCHAR Bitmap, + IN ULONG ByteIndex, + IN ULONG ByteCount, + IN UCHAR Value + ) +{ + ULONG i = 0; + ULONG c; + PUCHAR ptr; + + if (!UDFIsChunked(Bitmap)) { + RtlFillMemory(Bitmap + ByteIndex, ByteCount, Value); + return; + } + while (i < ByteCount) { + c = min(UDFChunkedGetContiguousLength(Bitmap, ByteIndex + i), ByteCount - i); + if (Value == 0) { + // Zero-fill: null chunks are already all-zero (free by default in FSBM). + // Skip allocation if this chunk has never been written. + ULONG chunkIdx = (ByteIndex + i) >> UDF_CHUNK_SHIFT; + if (!UDFGetChunked(Bitmap)->Chunks[chunkIdx]) { + i += c; + continue; + } + } + ptr = UDFChunkedGetOrAllocBytePtr(Bitmap, ByteIndex + i); + if (ptr) RtlFillMemory(ptr, c, Value); + i += c; + } +} + +/* + * UDFChunkedSetBitRange - set BitCount bits starting at BitStart. + * + * For the chunked case this avoids the per-bit chunk-pointer lookup that the + * old UDFSetBits loop caused. Instead it touches at most three byte-level + * accesses (leading partial byte, bulk fill, trailing partial byte), making + * large-range operations O(bytes) rather than O(bits). + */ +__inline +VOID +UDFChunkedSetBitRange( + IN PVOID Bitmap, + IN ULONG BitStart, + IN ULONG BitCount + ) +{ + ULONG firstByte, lastByte; + ULONG firstBit, lastBit; + PUCHAR pByte; + + if (!BitCount) + return; + + firstBit = BitStart & 7; + lastBit = (BitStart + BitCount - 1) & 7; + firstByte = BitStart >> 3; + lastByte = (BitStart + BitCount - 1) >> 3; + + if (firstByte == lastByte) { + /* All bits within one byte */ + UCHAR mask = (UCHAR)((0xFFU << firstBit) & (0xFFU >> (7 - lastBit))); + pByte = UDFChunkedGetOrAllocBytePtr(Bitmap, firstByte); + if (pByte) *pByte |= mask; + return; + } + + /* Leading partial byte */ + if (firstBit) { + pByte = UDFChunkedGetOrAllocBytePtr(Bitmap, firstByte); + if (pByte) *pByte |= (UCHAR)(0xFFU << firstBit); + firstByte++; + } + + /* Trailing partial byte */ + if (lastBit != 7) { + pByte = UDFChunkedGetOrAllocBytePtr(Bitmap, lastByte); + if (pByte) *pByte |= (UCHAR)(0xFFU >> (7 - lastBit)); + lastByte--; + } + + /* Bulk fill of complete bytes */ + if (firstByte <= lastByte) { + UDFChunkedFillMemory((PCHAR)Bitmap, firstByte, lastByte - firstByte + 1, 0xFF); + } +} + +/* + * UDFChunkedClrBitRange - clear BitCount bits starting at BitStart. + * + * Symmetric to UDFChunkedSetBitRange. Unallocated (null) chunks are already + * all-zero so they are skipped without allocation. + */ +__inline +VOID +UDFChunkedClrBitRange( + IN PVOID Bitmap, + IN ULONG BitStart, + IN ULONG BitCount + ) +{ + ULONG firstByte, lastByte; + ULONG firstBit, lastBit; + BOOLEAN isChunked; + PUCHAR pByte; + + if (!BitCount) + return; + + firstBit = BitStart & 7; + lastBit = (BitStart + BitCount - 1) & 7; + firstByte = BitStart >> 3; + lastByte = (BitStart + BitCount - 1) >> 3; + isChunked = UDFIsChunked(Bitmap); + + if (firstByte == lastByte) { + UCHAR mask = (UCHAR)((0xFFU << firstBit) & (0xFFU >> (7 - lastBit))); + /* Null chunk means bits are already 0 – no-op */ + if (isChunked && !UDFGetChunked(Bitmap)->Chunks[firstByte >> UDF_CHUNK_SHIFT]) + return; + pByte = UDFChunkedGetBytePtr(Bitmap, firstByte); + *pByte &= (UCHAR)~mask; + return; + } + + /* Leading partial byte */ + if (firstBit) { + if (!isChunked || UDFGetChunked(Bitmap)->Chunks[firstByte >> UDF_CHUNK_SHIFT]) { + pByte = UDFChunkedGetBytePtr(Bitmap, firstByte); + *pByte &= (UCHAR)(~(0xFFU << firstBit)); + } + firstByte++; + } + + /* Trailing partial byte */ + if (lastBit != 7) { + if (!isChunked || UDFGetChunked(Bitmap)->Chunks[lastByte >> UDF_CHUNK_SHIFT]) { + pByte = UDFChunkedGetBytePtr(Bitmap, lastByte); + *pByte &= (UCHAR)(~(0xFFU >> (7 - lastBit))); + } + lastByte--; + } + + /* Bulk zero of complete bytes – UDFChunkedFillMemory skips null chunks */ + if (firstByte <= lastByte) { + UDFChunkedFillMemory((PCHAR)Bitmap, firstByte, lastByte - firstByte + 1, 0x00); + } +} + +__inline +uint32 +UDFVatGetEntry( + IN PCHAR Vat, + IN ULONG idx + ) +{ + return *(uint32*)UDFChunkedGetBytePtr(Vat, idx * sizeof(uint32)); +} + +__inline +VOID +UDFVatSetEntry( + IN PCHAR Vat, + IN ULONG idx, + IN uint32 val + ) +{ + PUCHAR pByte = UDFChunkedGetOrAllocBytePtr(Vat, idx * sizeof(uint32)); + if (pByte) *(uint32*)pByte = val; +} + +__inline +VOID +UDFChunkedCopyMemory( + IN PCHAR Destination, + IN PCHAR Source, + IN ULONG Length + ) +{ + ULONG i = 0; + ULONG c1, c2, c; + PUCHAR dst; + PUCHAR src; + + if (!UDFIsChunked(Destination) && !UDFIsChunked(Source)) { + RtlCopyMemory(Destination, Source, Length); + return; + } + while (i < Length) { + src = UDFChunkedGetBytePtr(Source, i); + c1 = UDFChunkedGetContiguousLength(Destination, i); + c2 = UDFChunkedGetContiguousLength(Source, i); + c = min(min(c1, c2), Length - i); + dst = UDFChunkedGetOrAllocBytePtr(Destination, i); + if (dst) RtlCopyMemory(dst, src, c); + i += c; + } +} + +__inline +ULONG +UDFChunkedCompareMemory( + IN PCHAR Buffer1, + IN PCHAR Buffer2, + IN ULONG Length + ) +{ + ULONG i; + + if (!UDFIsChunked(Buffer1) && !UDFIsChunked(Buffer2)) + return (ULONG)RtlCompareMemory(Buffer1, Buffer2, Length); + for (i = 0; i < Length; i++) { + if (UDFChunkedGetByte(Buffer1, i) != UDFChunkedGetByte(Buffer2, i)) + return i; + } + return Length; +} + +__inline +VOID +UDFChunkedAndNotMemory( + IN PCHAR Destination, + IN PCHAR Source, + IN ULONG StartByte, + IN ULONG ByteCount + ) +{ + ULONG i = 0; + ULONG c1, c2, c, j; + PUCHAR dst; + PUCHAR src; + while (i < ByteCount) { + src = UDFChunkedGetBytePtr(Source, StartByte + i); + c1 = UDFChunkedGetContiguousLength(Destination, StartByte + i); + c2 = UDFChunkedGetContiguousLength(Source, StartByte + i); + c = min(min(c1, c2), ByteCount - i); + dst = UDFChunkedGetOrAllocBytePtr(Destination, StartByte + i); + if (dst) { + for (j = 0; j < c; j++) { + dst[j] &= (UCHAR)(~src[j]); + } + } + i += c; + } +} + +// UDFChunkedOrMemory: Destination |= Source (byte-by-byte over [StartByte, StartByte+ByteCount)). +// Used to OR bad-block bitmap (BSBM) into the free-space bitmap (FSBM) so that bad blocks +// are marked as used (bit=1) in the FSBM. Source bytes that are zero are skipped so that no +// destination chunk is allocated unless at least one source bit is set. +__inline +VOID +UDFChunkedOrMemory( + IN PCHAR Destination, + IN PCHAR Source, + IN ULONG StartByte, + IN ULONG ByteCount + ) +{ + ULONG i; + PUCHAR dst; + UCHAR s; + for (i = 0; i < ByteCount; i++) { + s = *UDFChunkedGetBytePtr(Source, StartByte + i); + if (s == 0) + continue; // no bits to OR in; skip destination chunk allocation + dst = UDFChunkedGetOrAllocBytePtr(Destination, StartByte + i); + if (dst) *dst |= s; + } +} + +__inline +NTSTATUS +UDFReadExtentIntoChunked( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, + IN int64 Offset, + IN ULONG Length, + IN BOOLEAN Direct, + IN PCHAR Bitmap, + OUT PULONG ReadBytes + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG off = 0, c, _ReadBytes; + *ReadBytes = 0; + while (off < Length) { + PUCHAR ptr; + c = min(UDFChunkedGetContiguousLength(Bitmap, off), Length - off); + ptr = UDFChunkedGetOrAllocBytePtr(Bitmap, off); + if (!ptr) { status = STATUS_INSUFFICIENT_RESOURCES; break; } + status = UDFReadExtent(IrpContext, Vcb, ExtInfo, Offset + off, c, Direct, + (int8*)ptr, &_ReadBytes); + if (!NT_SUCCESS(status)) break; + *ReadBytes += _ReadBytes; + off += c; + } + return status; +} + +__inline +NTSTATUS +UDFWriteExtentFromChunked( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN PEXTENT_INFO ExtInfo, + IN int64 Offset, + IN ULONG Length, + IN BOOLEAN Direct, + IN PCHAR Bitmap, + OUT PSIZE_T WrittenBytes + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG off = 0, c; + SIZE_T _WrittenBytes; + *WrittenBytes = 0; + while (off < Length) { + c = min(UDFChunkedGetContiguousLength(Bitmap, off), Length - off); + status = UDFWriteExtent(IrpContext, Vcb, ExtInfo, Offset + off, c, Direct, + (int8*)UDFChunkedGetBytePtr(Bitmap, off), &_WrittenBytes); + if (!NT_SUCCESS(status)) break; + *WrittenBytes += _WrittenBytes; + off += c; + } + return status; +} + +#define UDFGetBit(arr, bit) ( UDFIsChunked((arr)) ? \ + (BOOLEAN)((UDFChunkedGetByte((arr), (ULONG)((bit)>>3)) >> ((bit)&7)) & 1) : \ + (BOOLEAN)((((uint32*)(arr))[(bit)>>5] >> ((bit)&31) & 1)) ) +#define UDFSetBit(arr, bit) do { if (UDFIsChunked((arr))) UDFChunkedSetBit((arr), (ULONG)(bit)); \ + else (((uint32*)(arr))[(bit)>>5]) |= (((uint32)1) << ((bit)&31)); } while (0) +#define UDFClrBit(arr, bit) do { if (UDFIsChunked((arr))) UDFChunkedClearBit((arr), (ULONG)(bit)); \ + else (((uint32*)(arr))[(bit)>>5]) &= (~(((uint32)1) << ((bit)&31))); } while (0) + +#define UDFSetBits(arr, bit, bc) UDFChunkedSetBitRange((arr), (ULONG)(bit), (ULONG)(bc)) + +#define UDFClrBits(arr, bit, bc) UDFChunkedClrBitRange((arr), (ULONG)(bit), (ULONG)(bc)) + +// FSBM_Bitmap uses inverted bit semantics: bit=1 means USED, bit=0 means FREE. +// Null (unallocated) chunks are implicitly all-zero = all FREE, so chunk allocation +// is only triggered when marking blocks as USED — keeping memory usage minimal even +// on mostly-free large disks. +#define UDFGetUsedBit(arr,bit) UDFGetBit(arr,bit) +#define UDFGetFreeBit(arr,bit) (!UDFGetBit(arr,bit)) +#define UDFSetUsedBit(arr,bit) UDFSetBit(arr,bit) +#define UDFSetFreeBit(arr,bit) UDFClrBit(arr,bit) +#define UDFSetUsedBits(arr,bit,bc) UDFSetBits(arr,bit,bc) +#define UDFSetFreeBits(arr,bit,bc) UDFClrBits(arr,bit,bc) #define UDFGetBadBit(arr,bit) UDFGetBit(arr,bit) diff --git a/drivers/filesystems/udfs/udffs.h b/drivers/filesystems/udfs/udffs.h index 272046b907e62..2c0f2ace1f725 100644 --- a/drivers/filesystems/udfs/udffs.h +++ b/drivers/filesystems/udfs/udffs.h @@ -19,8 +19,6 @@ #pragma warning(disable : 28172) -/**************** OPTIONS *****************/ - //#define UDF_LIMIT_NAME_LEN //#define UDF_LIMIT_DIR_SIZE @@ -34,7 +32,6 @@ #endif //UDF_LIMIT_NAME_LEN //#define UDF_ASYNC_IO - #define UDF_ALLOW_FRAG_AD // Read ahead amount used for normal data files @@ -117,6 +114,13 @@ extern UDFData UdfData; #include "Include/Sys_spec_lib.h" +#if !defined(UDF_DBG) +#define UDFPrint(Args) +#else +#define UDFPrint(Args) KdPrint(Args) +#endif +#define UDFPrintErr(Args) KdPrint(Args) + #include "udf_info/udf_info.h" #include "protos.h" @@ -177,7 +181,6 @@ UDFIllegalFcbAccess( #define UDFPrint(Args) KdPrint(Args) #endif #define UDFPrintErr(Args) KdPrint(Args) - #define UDFAcquireDeviceShared(IrpContext, Vcb, ResourceThreadId) \ ((void)0) /* No operation - CD/DVD write modes not currently supported */ diff --git a/drivers/filesystems/udfs/udfinit.cpp b/drivers/filesystems/udfs/udfinit.cpp index 657034565142c..e00eedb95f9a3 100644 --- a/drivers/filesystems/udfs/udfinit.cpp +++ b/drivers/filesystems/udfs/udfinit.cpp @@ -270,6 +270,7 @@ DriverEntry( IoDeleteDevice(UdfData.UDFDeviceObject_HDD); UdfData.UDFDeviceObject_HDD = NULL; } + } } _SEH2_END; diff --git a/drivers/filesystems/udfs/write.cpp b/drivers/filesystems/udfs/write.cpp index 076e5a6cbe305..b24caef33e481 100644 --- a/drivers/filesystems/udfs/write.cpp +++ b/drivers/filesystems/udfs/write.cpp @@ -44,9 +44,11 @@ UDFCommonWrite( NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); LONGLONG StartingOffset; + ULONG ByteCount; LONGLONG ByteRange; ULONG TruncatedLength; + SIZE_T NumberBytesWritten = 0; PFILE_OBJECT FileObject = NULL; TYPE_OF_OPEN TypeOfOpen; @@ -62,6 +64,8 @@ UDFCommonWrite( BOOLEAN MainResourceAcquired = FALSE; BOOLEAN VcbAcquired = FALSE; + + BOOLEAN Wait = FALSE; BOOLEAN PagingIo = FALSE; BOOLEAN NonCachedIo = FALSE; @@ -73,6 +77,7 @@ UDFCommonWrite( BOOLEAN ZeroBlock = FALSE; BOOLEAN ZeroBlockDone = FALSE; + // Examine our input parameters to determine if this is noncached and/or // a paging io operation. @@ -81,6 +86,7 @@ UDFCommonWrite( 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 +107,8 @@ UDFCommonWrite( ASSERT_FCB(Fcb); ASSERT_VCB(Vcb); + + // Check if this volume has already been shut down. If it has, fail // this write request. @@ -138,8 +146,10 @@ UDFCommonWrite( StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart; ByteCount = IrpSp->Parameters.Write.Length; + ByteRange = StartingOffset + ByteCount; + Irp->IoStatus.Information = 0; // Check if writing to end of file (FILE_WRITE_TO_END_OF_FILE = -1) @@ -216,6 +226,8 @@ UDFCommonWrite( // I dislike the idea of writing to not locked media if (!(Vcb->VcbState & VCB_STATE_LOCKED)) { try_return(Status = STATUS_ACCESS_DENIED); + + } // Acquire the volume resource exclusive @@ -408,7 +420,9 @@ UDFCommonWrite( try_return(Status = STATUS_PENDING); // CanWait = TRUE; + UDFAcquirePagingIoExclusive(IrpContext, Fcb); + PagingIoResourceAcquired = TRUE; if (ExtendFS) { @@ -577,6 +591,7 @@ UDFCommonWrite( } 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. @@ -588,6 +603,7 @@ UDFCommonWrite( PagingIoResourceAcquired = TRUE; } + Status = UDFWriteFile__(IrpContext, Vcb, Fcb->FileInfo, StartingOffset, TruncatedLength, FALSE, (PCHAR)SystemBuffer, &NumberBytesWritten); @@ -652,6 +668,7 @@ try_exit: NOTHING; // Release any resources acquired here ... if (PagingIoResourceAcquired) { + UDFReleasePagingIo(IrpContext, Fcb); } @@ -661,6 +678,7 @@ try_exit: NOTHING; if (VcbAcquired) { UDFReleaseVcb(IrpContext, Vcb); + } } _SEH2_END; // end of "__finally" processing