diff --git a/drivers/filesystems/fs_rec/fs_rec.h b/drivers/filesystems/fs_rec/fs_rec.h index db3112b06c78c..bd78691a9ca5e 100644 --- a/drivers/filesystems/fs_rec/fs_rec.h +++ b/drivers/filesystems/fs_rec/fs_rec.h @@ -137,6 +137,9 @@ typedef struct BIOS_PARAMETER_BLOCK USHORT BackupBootSector; } BIOS_PARAMETER_BLOCK, *PBIOS_PARAMETER_BLOCK; +/* UDFS Tag Identifier for Anchor Volume Descriptor Pointer (ECMA-167 7.2) */ +#define UDFS_TAG_ID_AVDP 0x0002 + /* UDFS Structures */ #include typedef struct _TAG diff --git a/drivers/filesystems/fs_rec/udfs.c b/drivers/filesystems/fs_rec/udfs.c index 655b6ea28c627..c2bf6af10da43 100644 --- a/drivers/filesystems/fs_rec/udfs.c +++ b/drivers/filesystems/fs_rec/udfs.c @@ -29,7 +29,12 @@ FsRecIsUdfsVolume(IN PDEVICE_OBJECT DeviceObject, int i; PAGED_CODE(); - Offset.QuadPart = 16 * SectorSize; + /* Per ECMA-167 section 8.4.1, the Volume Recognition Sequence starts at + * a fixed byte offset of 32768, regardless of the physical sector size. + * Using 16 * SectorSize is only correct for 2048-byte sectors (CD-ROM); + * for 512-byte sector devices (e.g. VHDs) it gives 8192 instead of 32768, + * causing the VRS to be missed entirely. */ + Offset.QuadPart = UDFS_VRS_START_OFFSET; for (i = 0; i < 16; i++) { if (!FsRecReadBlock(DeviceObject, @@ -55,6 +60,7 @@ FsRecIsUdfsVolume(IN PDEVICE_OBJECT DeviceObject, { DPRINT("NSR03 found\n"); ret = TRUE; + break; } if (!strncmp((const char*)VolumeStructDesc->Ident, @@ -63,6 +69,7 @@ FsRecIsUdfsVolume(IN PDEVICE_OBJECT DeviceObject, { DPRINT("NSR02 found\n"); ret = TRUE; + break; } if (!strncmp((const char*)VolumeStructDesc->Ident, @@ -98,6 +105,34 @@ FsRecIsUdfsVolume(IN PDEVICE_OBJECT DeviceObject, if (VolumeStructDesc) ExFreePool(VolumeStructDesc); + + /* If the VRS scan did not find an NSR descriptor, fall back to checking + * for the Anchor Volume Descriptor Pointer at sector 256. This covers + * disks where the VRS is absent or could not be read, and mirrors the + * detection approach used by the UDFS driver itself. */ + if (!ret) + { + PAVDP AnchorVDP = NULL; + + Offset.QuadPart = (LONGLONG)UDFS_AVDP_SECTOR * SectorSize; + if (FsRecReadBlock(DeviceObject, + &Offset, + sizeof(AVDP), + SectorSize, + (PVOID *)&AnchorVDP, + NULL)) + { + /* Tag identifier 2 = Anchor Volume Descriptor Pointer (ECMA-167 7.2) */ + if (AnchorVDP->DescriptorTag.Identifier == UDFS_TAG_ID_AVDP && + AnchorVDP->DescriptorTag.Location == UDFS_AVDP_SECTOR) + { + DPRINT("AVDP found at sector 256\n"); + ret = TRUE; + } + ExFreePool(AnchorVDP); + } + } + return ret; } diff --git a/drivers/filesystems/udfs/CMakeLists.txt b/drivers/filesystems/udfs/CMakeLists.txt index 1ae3d50d9b070..e1cc34d04db02 100644 --- a/drivers/filesystems/udfs/CMakeLists.txt +++ b/drivers/filesystems/udfs/CMakeLists.txt @@ -2,43 +2,43 @@ include_directories(Include) list(APPEND SOURCE - udf_info/alloc.cpp - udf_info/dirtree.cpp - udf_info/extent.cpp - udf_info/mount.cpp - udf_info/phys_eject.cpp - udf_info/physical.cpp - udf_info/remap.cpp - udf_info/udf_info.cpp - cleanup.cpp - close.cpp - create.cpp - devcntrl.cpp - dircntrl.cpp - env_spec.cpp - fastio.cpp - fileinfo.cpp - flush.cpp - fscntrl.cpp - lockctrl.cpp - mem.cpp - misc.cpp - namesup.cpp - prefxsup.cpp - pnp.cpp - read.cpp - secursup.cpp - shutdown.cpp - sys_spec.cpp - udf_dbg.cpp - udfinit.cpp - unload.cpp - verfysup.cpp - volinfo.cpp - write.cpp - strucsup.cpp - filobsup.cpp - udfdata.cpp + udf_info/alloc.c + udf_info/dirtree.c + udf_info/extent.c + udf_info/mount.c + udf_info/phys_eject.c + udf_info/physical.c + udf_info/remap.c + udf_info/udf_info.c + cleanup.c + close.c + create.c + devcntrl.c + dircntrl.c + env_spec.c + fastio.c + fileinfo.c + flush.c + fscntrl.c + lockctrl.c + mem.c + misc.c + namesup.c + prefxsup.c + pnp.c + read.c + secursup.c + shutdown.c + sys_spec.c + udf_dbg.c + udfinit.c + unload.c + verfysup.c + volinfo.c + write.c + strucsup.c + filobsup.c + udfdata.c udffs.h) add_library(udfs MODULE ${SOURCE} udffs.rc) diff --git a/drivers/filesystems/udfs/Include/Sys_spec_lib.cpp b/drivers/filesystems/udfs/Include/Sys_spec_lib.c similarity index 99% rename from drivers/filesystems/udfs/Include/Sys_spec_lib.cpp rename to drivers/filesystems/udfs/Include/Sys_spec_lib.c index b740b6a8a9e73..b56ed59d687a6 100644 --- a/drivers/filesystems/udfs/Include/Sys_spec_lib.cpp +++ b/drivers/filesystems/udfs/Include/Sys_spec_lib.c @@ -150,10 +150,10 @@ UDFAttributesToUDF( IN ULONG NTAttr ) { - PULONG attr; //permissions - PUSHORT Flags; - PUCHAR Type; - PUCHAR FCharact; + PULONG attr = NULL; //permissions + PUSHORT Flags = NULL; + PUCHAR Type = NULL; + PUCHAR FCharact = NULL; NTAttr &= UDF_VALID_FILE_ATTRIBUTES; @@ -240,7 +240,7 @@ UDFFileDirInfoToNT( PEXTENDED_FILE_ENTRY ExFileEntry; USHORT Ident; BOOLEAN ReadSizes = FALSE; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; PFCB Fcb; UDFPrint(("@=%#x, FileDirNdx %x\n", &Vcb, FileDirNdx)); @@ -575,7 +575,7 @@ UDFDoesOSAllowFileToBeTargetForRename__( IN PUDF_FILE_INFO FileInfo ) { - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; if (UDFIsADirectory(FileInfo)) return STATUS_ACCESS_DENIED; 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 96% rename from drivers/filesystems/udfs/Include/mem_tools.cpp rename to drivers/filesystems/udfs/Include/mem_tools.c index 7b9a8bf8ea499..3eda665b30971 100644 --- a/drivers/filesystems/udfs/Include/mem_tools.cpp +++ b/drivers/filesystems/udfs/Include/mem_tools.c @@ -6,25 +6,12 @@ #ifdef MY_USE_INTERNAL_MEMMANAGER -#ifdef _X86_ - __inline VOID DbgTouch(IN PVOID addr) { - __asm { - mov eax,addr - mov al,[byte ptr eax] - } + volatile UCHAR a = ((volatile UCHAR*)addr)[0]; + (void)a; } -#else // NO X86 optimization , use generic C/C++ - -__inline VOID DbgTouch(IN PVOID addr) -{ - UCHAR a = ((PUCHAR)addr)[0]; -} - -#endif // _X86_ - //MEM_ALLOC_DESC Allocs[MY_HEAP_MAX_BLOCKS]; MEM_FRAME_ALLOC_DESC FrameList[MY_HEAP_MAX_FRAMES]; @@ -39,7 +26,7 @@ InitLockMemoryManager() { KeInitializeSpinLock(&FrameLock); return STATUS_SUCCESS; } -#define DeinitLockMemoryManager() {NOTHING;} +#define DeinitLockMemoryManager() ((void)0) #else //MEM_LOCK_BY_SPINLOCK ERESOURCE FrameLock; #define LockMemoryManager() ExAcquireResourceExclusiveLite(&FrameLock, TRUE) @@ -47,15 +34,15 @@ ERESOURCE FrameLock; #define InitLockMemoryManager() ExInitializeResourceLite(&FrameLock) #define DeinitLockMemoryManager() ExDeleteResourceLite(&FrameLock) #endif //MEM_LOCK_BY_SPINLOCK -ULONG FrameCount; -ULONG LastFrame; +ULONG FrameCount = 0; +ULONG LastFrame = 0; BOOLEAN MyMemInitialized = FALSE; #define MyAllocIsFrameFree(FrameList, i) \ (!(FrameList[i].LastUsed || FrameList[i].FirstFree)) #ifdef UDF_DBG -ULONG MemTotalAllocated; +ULONG MemTotalAllocated = 0; PCHAR BreakAddr; VOID @@ -64,7 +51,7 @@ MyAllocDumpDescr( ULONG i ) { - BOOLEAN Used; + BOOLEAN Used = FALSE; Used = (Allocs[i].Len & MY_HEAP_FLAG_USED) ? TRUE : FALSE; UDFPrint(("block %x \t%s addr %x len %x \t", i, Used ? "used" : "free", Allocs[i].Addr, (Allocs[i].Len) & MY_HEAP_FLAG_LEN_MASK)); @@ -93,11 +80,11 @@ MyAllocDumpFrame( ULONG Frame ) { - ULONG i; + ULONG i = 0; PMEM_ALLOC_DESC Allocs; Allocs = FrameList[Frame].Frame; ULONG k=0; - BOOLEAN Used; + BOOLEAN Used = FALSE; #ifdef DUMP_MEM_FRAMES if (!MyDumpMem) #endif //DUMP_MEM_FRAMES @@ -132,7 +119,7 @@ MyAllocDumpFrames( VOID ) { - ULONG i; + ULONG i = 0; for(i=0;i> 1; @@ -933,7 +920,7 @@ MyAllocInit(VOID) VOID MyAllocRelease(VOID) { - ULONG i; + ULONG i = 0; PMEM_ALLOC_DESC Allocs; if (!MyMemInitialized) diff --git a/drivers/filesystems/udfs/Include/mem_tools.h b/drivers/filesystems/udfs/Include/mem_tools.h index fa06ad9708fb5..c240fdce60bca 100644 --- a/drivers/filesystems/udfs/Include/mem_tools.h +++ b/drivers/filesystems/udfs/Include/mem_tools.h @@ -198,13 +198,13 @@ VOID inline MyFreePool__(PVOID addr) { // ULONG i; newaddr = (PCHAR)addr; if (!newaddr) { - __asm int 3; + __debugbreak(); return; } /* for(i=0; iextLength; i++, RelocExtent++) { - ULONG _ReadBytes; + ULONG _ReadBytes = 0; rLba = RelocExtent->extLocation; if (rLba >= (Vcb->CDR_Mode ? Vcb->NWA : Vcb->LastLBA + 1)) { RtlZeroMemory(Buffer, _ReadBytes = RelocExtent->extLength); @@ -437,7 +437,7 @@ UDFPrepareForWriteOperation( { #ifdef _UDF_STRUCTURES_H_ if (Vcb->BSBM_Bitmap) { - ULONG i; + ULONG i = 0; for(i=0; iBSBM_Bitmap), Lba+i)) { UDFPrint(("W: Known BB @ %#x\n", Lba)); @@ -485,15 +485,15 @@ UDFDetermineVolumeLayout( PULONG SessionEndLba ) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; CDROM_TOC_LARGE* toc = NULL; CDROM_TOC_SESSION_DATA* LastSes = NULL; - ULONG LocalTrackCount; - ULONG TocEntry; + ULONG LocalTrackCount = 0; + ULONG TocEntry = 0; void* TempBuffer = NULL; - ULONG OldTrkNum; - ULONG TrkNum; - ULONG ReadBytes; + ULONG OldTrkNum = 0; + ULONG TrkNum = 0; + ULONG ReadBytes = 0; SIZE_T i, len; *SessionStartLba = 0; @@ -790,20 +790,20 @@ UDFGetBlockSize( ) { NTSTATUS RC = STATUS_SUCCESS; - DISK_GEOMETRY_EX DiskGeometryEx; + DISK_GEOMETRY DiskGeometry; PARTITION_INFORMATION PartitionInfo; if (UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) { UDFPrint(("UDFGetBlockSize: HDD\n")); - RC = UDFPhSendIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,DeviceObject, - 0,NULL, - &DiskGeometryEx,sizeof(DISK_GEOMETRY_EX), + RC = UDFPhSendIOCTL(IOCTL_DISK_GET_DRIVE_GEOMETRY,DeviceObject, + NULL,0, + &DiskGeometry,sizeof(DISK_GEOMETRY), 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)) { @@ -817,9 +817,9 @@ UDFGetBlockSize( try_return(RC = STATUS_UNRECOGNIZED_VOLUME); } } else { - RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX,DeviceObject, - &DiskGeometryEx,sizeof(DISK_GEOMETRY_EX), - &DiskGeometryEx,sizeof(DISK_GEOMETRY_EX), + RC = UDFPhSendIOCTL(IOCTL_CDROM_GET_DRIVE_GEOMETRY,DeviceObject, + NULL,0, + &DiskGeometry,sizeof(DISK_GEOMETRY), TRUE,NULL ); if (RC == STATUS_DEVICE_NOT_READY) { @@ -829,18 +829,33 @@ UDFGetBlockSize( } } + /* Initialize SectorSize/SectorShift from the device geometry if not already set. + * This is required in the verify path where NewVcb is zero-initialized: + * UDFDetermineVolumeLayout allocates a buffer of Vcb->SectorSize bytes, and + * the disk-path LastLBA calculation shifts by Vcb->SectorShift, so both must + * be valid before either calculation is performed. */ + if (!Vcb->SectorSize) { + ULONG BytesPerSector = DiskGeometry.Geometry.BytesPerSector; + if (!BytesPerSector) { + /* Fallback: 2048 for optical media, 512 for HDD */ + BytesPerSector = (UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK) ? 512 : 2048; + } + Vcb->SectorSize = BytesPerSector; + Vcb->SectorShift = UDFHighBit(BytesPerSector); + } + if ( UDFGetDevType(DeviceObject) == FILE_DEVICE_DISK || FALSE) { Vcb->FirstLBA=0;//(ULONG)(PartitionInfo->StartingOffset.QuadPart >> Vcb->BlockSizeBits); Vcb->LastPossibleLBA = - Vcb->LastLBA = (uint32)(DiskGeometryEx.DiskSize.QuadPart >> Vcb->SectorShift)/* + Vcb->FirstLBA*/ - 1; + Vcb->LastLBA = (uint32)(DiskGeometry.DiskSize.QuadPart >> Vcb->SectorShift)/* + Vcb->FirstLBA*/ - 1; } else { Vcb->FirstLBA=0; if (NT_SUCCESS(RC)) { - Vcb->LastLBA = (uint32)(DiskGeometryEx.Geometry.Cylinders.QuadPart * - DiskGeometryEx.Geometry.TracksPerCylinder * - DiskGeometryEx.Geometry.SectorsPerTrack - 1); + Vcb->LastLBA = (uint32)(DiskGeometry.Geometry.Cylinders.QuadPart * + DiskGeometry.Geometry.TracksPerCylinder * + DiskGeometry.Geometry.SectorsPerTrack - 1); if (Vcb->LastLBA == 0x7fffffff) { ASSERT(FALSE); } @@ -911,8 +926,8 @@ UDFGetDiskInfo( try_return(RC); } - ULONG SessionStart; - ULONG SessionEnd; + ULONG SessionStart = 0; + ULONG SessionEnd = 0; RC = UDFDetermineVolumeLayout(IrpContext, DeviceObject, Vcb, &SessionStart, &SessionEnd); @@ -976,7 +991,7 @@ try_exit: NOTHING; UDFPrint(("UDF: Last LBA in last session: %x\n",Vcb->LastLBA)); UDFPrint(("UDF: First writable LBA (NWA) in last session: %x\n",Vcb->NWA)); UDFPrint(("UDF: Last available LBA beyond end of last session: %x\n",Vcb->LastPossibleLBA)); - UDFPrint(("UDF: blocks per frame: %x\n",1 << Vcb->WCacheBlocksPerFrameSh)); + UDFPrint(("UDF: blocks per frame: %x\n", Vcb->WriteBlockSize >> Vcb->SectorShift)); UDFPrint(("UDF: Flags: %s%s\n", Vcb->VcbState & UDF_VCB_FLAGS_RAW_DISK ? "RAW " : "", Vcb->VcbState & VCB_STATE_VOLUME_READ_ONLY ? "R/O " : "WR " @@ -1006,7 +1021,7 @@ UDFPrepareForReadOperation( #ifdef _UDF_STRUCTURES_H_ if (Vcb->BSBM_Bitmap) { - ULONG i; + ULONG i = 0; for(i=0; iBSBM_Bitmap), Lba+i)) { UDFPrint(("R: Known BB @ %#x\n", Lba)); @@ -1036,7 +1051,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() /* @@ -1056,8 +1071,8 @@ UDFReadInSector( ) { int8* tmp_buff; - NTSTATUS status; - ULONG _ReadBytes; + NTSTATUS status = STATUS_SUCCESS; + ULONG _ReadBytes = 0; (*ReadBytes) = 0; @@ -1095,9 +1110,8 @@ UDFReadData( { uint32 i, l, Lba, BS=Vcb->SectorSize; uint32 BSh=Vcb->SectorShift; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; ULONG _ReadBytes = 0; - uint32 to_read; (*ReadBytes) = 0; if (!Length) return STATUS_SUCCESS; @@ -1117,17 +1131,16 @@ UDFReadData( } // read sector_size-aligned part i = Length >> BSh; - while(i) { - to_read = min(i, 64); - status = UDFReadSectors(IrpContext, Vcb, Translate, Lba, to_read, Direct, Buffer, &_ReadBytes); + if (i) { + status = UDFReadSectors(IrpContext, Vcb, Translate, Lba, i, Direct, Buffer, &_ReadBytes); (*ReadBytes) += _ReadBytes; if (!NT_SUCCESS(status)) { return status; } - Buffer += to_read<Modified || (Vcb->IntegrityType == INTEGRITY_TYPE_CLOSE)) { UDFSetModified(Vcb); @@ -1167,7 +1180,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; @@ -1187,9 +1200,9 @@ UDFWriteInSector( ) { int8* tmp_buff; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; SIZE_T _WrittenBytes; - ULONG ReadBytes; + ULONG ReadBytes = 0; if (!Vcb->Modified) { UDFSetModified(Vcb); @@ -1252,7 +1265,7 @@ UDFWriteData( { uint32 i, l, Lba, BS=Vcb->SectorSize; uint32 BSh=Vcb->SectorShift; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; SIZE_T _WrittenBytes; (*WrittenBytes) = 0; @@ -1286,4 +1299,4 @@ UDFWriteData( (*WrittenBytes) += _WrittenBytes; return status; -} // end UDFWriteData() +} // end UDFWriteData() \ No newline at end of file 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 97% rename from drivers/filesystems/udfs/Include/regtools.cpp rename to drivers/filesystems/udfs/Include/regtools.c index 1b75c0c07eb3e..d8a227074c64f 100644 --- a/drivers/filesystems/udfs/Include/regtools.cpp +++ b/drivers/filesystems/udfs/Include/regtools.c @@ -17,7 +17,7 @@ RegTGetKeyHandle( { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING NameString; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; //UDFPrint(("RegTGetKeyHandle: h=%x, %S\n", hRootKey, KeyName)); @@ -107,8 +107,8 @@ RegTGetDwordValue( UNICODE_STRING NameString; PKEY_VALUE_PARTIAL_INFORMATION ValInfo; #endif //WIN_32_MODE - ULONG len; - NTSTATUS status; + ULONG len = 0; + NTSTATUS status = STATUS_SUCCESS; HKEY hKey; BOOLEAN retval = FALSE; BOOLEAN free_h = FALSE; @@ -198,8 +198,8 @@ RegTGetStringValue( UNICODE_STRING NameString; PKEY_VALUE_PARTIAL_INFORMATION ValInfo; #endif //USER_MODE - ULONG len; - NTSTATUS status; + ULONG len = 0; + NTSTATUS status = STATUS_SUCCESS; HKEY hKey; BOOLEAN retval = FALSE; BOOLEAN free_h = FALSE; diff --git a/drivers/filesystems/udfs/Include/string_lib.cpp b/drivers/filesystems/udfs/Include/string_lib.c similarity index 73% rename from drivers/filesystems/udfs/Include/string_lib.cpp rename to drivers/filesystems/udfs/Include/string_lib.c index 1750feb27ff16..2e6e4e8afa7c4 100644 --- a/drivers/filesystems/udfs/Include/string_lib.cpp +++ b/drivers/filesystems/udfs/Include/string_lib.c @@ -12,7 +12,7 @@ MyRtlCompareMemory( ULONG len ) { - ULONG i; + ULONG i = 0; for(i=0; iLength != s2->Length) return (-1); i = memcmp(s1->Buffer, s2->Buffer, (s1->Length) ? (s1->Length) : (s2->Length)); @@ -65,34 +65,14 @@ RtlAppendUnicodeToString( ) { PWCHAR tmp; - USHORT i; - -#ifdef _X86_ - - __asm push ebx - __asm push esi - __asm xor ebx,ebx - __asm mov esi,Str2 -Scan_1: - __asm cmp [word ptr esi+ebx],0 - __asm je EO_Scan - __asm add ebx,2 - __asm jmp Scan_1 -EO_Scan: - __asm mov i,bx - __asm pop esi - __asm pop ebx - -#else // NO X86 optimization, use generic C/C++ + ULONG i; i=0; - while(Str2[i]) { + while(Str2[i] && i < (MAXUSHORT / sizeof(WCHAR))) { i++; } i *= sizeof(WCHAR); -#endif // _X86_ - tmp = Str1->Buffer; ASSERT(Str1->MaximumLength); if ((Str1->Length+i+sizeof(WCHAR)) > Str1->MaximumLength) { @@ -102,13 +82,13 @@ RtlAppendUnicodeToString( memcpy(tmp2, tmp, Str1->MaximumLength); ExFreePool(tmp); tmp = tmp2; - Str1->MaximumLength = STRING_BUFFER_ALIGN(i + sizeof(WCHAR))*2; + Str1->MaximumLength = (USHORT)(STRING_BUFFER_ALIGN(i + sizeof(WCHAR))*2); Str1->Buffer = tmp; } RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2, i); i+=Str1->Length; tmp[(i / sizeof(WCHAR))] = 0; - Str1->Length = i; + Str1->Length = (USHORT)i; return STATUS_SUCCESS; @@ -126,35 +106,16 @@ MyInitUnicodeString( ) { - USHORT i; - -#ifdef _X86_ - - __asm push ebx - __asm push esi - __asm xor ebx,ebx - __asm mov esi,Str2 -Scan_1: - __asm cmp [word ptr esi+ebx],0 - __asm je EO_Scan - __asm add ebx,2 - __asm jmp Scan_1 -EO_Scan: - __asm mov i,bx - __asm pop esi - __asm pop ebx - -#else // NO X86 optimization, use generic C/C++ + ULONG i; i=0; - while(Str2[i]) { + while(Str2[i] && i < (MAXUSHORT / sizeof(WCHAR))) { i++; } i *= sizeof(WCHAR); -#endif // _X86_ - - Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = i) + sizeof(WCHAR)); + Str1->Length = (USHORT)i; + Str1->MaximumLength = (USHORT)STRING_BUFFER_ALIGN(i + sizeof(WCHAR)); Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); if (!Str1->Buffer) return STATUS_INSUFFICIENT_RESOURCES; 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/cleanup.cpp b/drivers/filesystems/udfs/cleanup.c similarity index 56% rename from drivers/filesystems/udfs/cleanup.cpp rename to drivers/filesystems/udfs/cleanup.c index 4a42b7da33427..2946cb3f193a4 100644 --- a/drivers/filesystems/udfs/cleanup.cpp +++ b/drivers/filesystems/udfs/cleanup.c @@ -26,6 +26,15 @@ UDFAutoUnlock ( IN PVCB Vcb ); +NTSTATUS +UDFCloseFileInfoChain( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN PUDF_FILE_INFO fi, + IN ULONG TreeLength, + IN BOOLEAN VcbAcquired + ); + /************************************************************************* * * Function: UDFCommonCleanup() @@ -50,6 +59,7 @@ UDFCommonCleanup( { IO_STATUS_BLOCK IoStatus; NTSTATUS RC = STATUS_SUCCESS; + NTSTATUS RC2 = STATUS_SUCCESS; PFILE_OBJECT FileObject = NULL; PFCB Fcb = NULL; PCCB Ccb = NULL; @@ -77,13 +87,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) { @@ -152,8 +162,10 @@ UDFCommonCleanup( if (FileObject->Flags & FO_CACHE_SUPPORTED) { // we've cached close - InterlockedDecrement((PLONG)&Fcb->CachedOpenHandleCount); + InterlockedDecrement(&Fcb->CachedOpenHandleCount); } + ASSERT(Fcb->FcbCleanup <= (Fcb->FcbReference-1)); + MmPrint((" CcUninitializeCacheMap()\n")); CcUninitializeCacheMap(FileObject, NULL, NULL); @@ -171,29 +183,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); + InterlockedDecrement(&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,141 +237,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)) { - - Fcb->FcbState &= ~UDF_FCB_DELETE_ON_CLOSE; - + // 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; - DeleteAttempted = TRUE; + // Make system to issue last Close request + // for our Target ... - // 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 + UDFFspClose(Fcb->Vcb); +#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; + 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.AllocationSize.QuadPart = + Fcb->Header.FileSize.QuadPart = + Fcb->Header.ValidDataLength.QuadPart = 0; + if (CcIsFileCached(FileObject)) { + CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); } - // 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. - - // 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; - } + UDFReleaseResource(&Fcb->FcbNonpaged->FcbPagingIoResource); + } + } - // Flush file. It is required by UDFUnlinkFile__() - RC = UDFFlushFile__(IrpContext, Vcb, NextFileInfo); - if (!NT_SUCCESS(RC)) { - AdPrint(("Error flushing file !!!\n")); - } +#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 - // 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; - } + NextFileInfo = Fcb->FileInfo; - } else { + // do we need to delete it now ? + if ( (Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) && + !(Fcb->FcbCleanup)) { - // 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; + // 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; + } + } else + if (lc <= 1) { + // Synchronize here with paging IO + BOOLEAN AcquiredPagingIo = FALSE; + 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); } } + // 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; - 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); + // 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 { - // Delete discarded (e.g. non-empty directory) — notify modification +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; + } +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)) { + UDFNotifyReportChange( IrpContext, Vcb, NextFileInfo->Fcb, + FILE_NOTIFY_CHANGE_STREAM_NAME, + FILE_ACTION_REMOVED_STREAM, + Ccb->Lcb, FileObject); + } else { 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); + UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_REMOVED, + Ccb->Lcb, FileObject); } - - } else if (Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) { - - // DELETE_ON_CLOSE is set but FcbCleanup > 0 (other handles still open) + } else + if (Fcb->FcbState & UDF_FCB_DELETE_ON_CLOSE) { +DiscardDelete: 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) | @@ -387,10 +440,11 @@ UDFCommonCleanup( // handles later. We ignore any I/O errors from the flush. // We shall not flush deleted files RC = STATUS_SUCCESS; - if ( LastNonCached - || - (!Fcb->FcbCleanup && - !ForcedCleanUp) ) { + if (( LastNonCached + || + (!Fcb->FcbCleanup && + !ForcedCleanUp) ) && + Fcb->FcbNonpaged->SegmentObject.SharedCacheMap) { LONGLONG OldFileSize, NewFileSize; @@ -422,7 +476,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 @@ -437,7 +491,7 @@ UDFCommonCleanup( KeQuerySystemTime((PLARGE_INTEGER)&NtTime); // Check if we should set ARCHIVE bit & LastWriteTime if (FileObject->Flags & FO_FILE_MODIFIED) { - ULONG Attr; + ULONG Attr = 0; PDIR_INDEX_ITEM DirNdx; DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo), NextFileInfo->Index); ASSERT(DirNdx); @@ -509,19 +563,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,19 +574,31 @@ 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, 0xFFFF /* walk entire chain */, TRUE); + if (NT_SUCCESS(RC)) + RC = RC2; + + // Decrement the LCB open reference count that was incremented in + // UDFCommonCreate. Without this, Lcb->Reference stays non-zero after + // the handle is closed, and UDFSetRenameInfo incorrectly treats the + // file as still open (StaleLcb->Reference != 0), returning + // STATUS_ACCESS_DENIED for every rename targeting it. + if (Ccb->Lcb) { + UDFReleasePrefix(IrpContext, Ccb->Lcb); } Ccb->Flags |= UDF_CCB_CLEANED; @@ -564,15 +617,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 +649,86 @@ 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 = STATUS_SUCCESS; + + // 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); + // Note: FcbReference may be less than fi->RefCount for intermediate + // directories opened during path traversal without a CCB (FcbReference=0, + // fi->RefCount=1 from UDFReferenceFile__). Do not assert FcbReference here. + RC2 = UDFCloseFile__(IrpContext, Vcb, fi); + if (!NT_SUCCESS(RC2)) + RC = RC2; + 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 99% rename from drivers/filesystems/udfs/close.cpp rename to drivers/filesystems/udfs/close.c index 88b74886c080c..77564a4927e56 100644 --- a/drivers/filesystems/udfs/close.cpp +++ b/drivers/filesystems/udfs/close.c @@ -168,6 +168,7 @@ UDFCommonClose( try_return(RC = STATUS_SUCCESS); } + if ((Vcb->VcbCleanup == 0) && (Vcb->VcbCondition != VcbMounted)) { @@ -470,7 +471,7 @@ Return Value: --*/ { - BOOLEAN RemovedFcb; + BOOLEAN RemovedFcb = FALSE; PAGED_CODE(); @@ -560,7 +561,7 @@ Return Value: THREAD_CONTEXT ThreadContext = {0}; PFCB Fcb; - ULONG UserReference; + ULONG UserReference = 0; ULONG VcbHoldCount = 0; PVCB CurrentVcb = NULL; diff --git a/drivers/filesystems/udfs/create.cpp b/drivers/filesystems/udfs/create.c similarity index 99% rename from drivers/filesystems/udfs/create.cpp rename to drivers/filesystems/udfs/create.c index 8518dcf82256f..2d244f54a1237 100644 --- a/drivers/filesystems/udfs/create.cpp +++ b/drivers/filesystems/udfs/create.c @@ -128,6 +128,7 @@ try_exit: NOTHING; } // end UDFSupersedeOrOverwriteFile() + /************************************************************************* * * Function: UDFOpenExistingFcb() @@ -254,7 +255,8 @@ UDFOpenExistingFcb( if (FlagOn(Options, FILE_NO_INTERMEDIATE_BUFFERING) && !((*PtrNewFcb)->CachedOpenHandleCount) && - ((*PtrNewFcb)->FcbNonpaged->SegmentObject.DataSectionObject) ) { + ((*PtrNewFcb)->FcbNonpaged->SegmentObject.DataSectionObject) && + ((*PtrNewFcb)->FcbNonpaged->SegmentObject.SharedCacheMap) ) { // If this is a non-cached open, and there are no open cached // handles, but there is still a data section, attempt a flush // and purge operation to avoid cache coherency overhead later. @@ -997,6 +999,7 @@ try_exit: NOTHING; * *************************************************************************/ static + VOID UDFNormalizeStreamSuffix( IN PIRP_CONTEXT IrpContext, @@ -1020,6 +1023,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 +1034,7 @@ UDFNormalizeStreamSuffix( } } + /************************************************************************* * * Function: UDFCommonCreate() @@ -1289,6 +1294,8 @@ UDFCommonCreate( _SEH2_TRY { + + // Verify that the Vcb is not in an unusable condition. This routine // will raise if not usable. @@ -1360,15 +1367,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 +1390,9 @@ UDFCommonCreate( FALSE, // VcbLocked FILE_OPENED); // DesiredInformation + try_return(Status); + } if (UDFIllegalFcbAccess(Vcb, DesiredAccess)) { @@ -1406,10 +1419,12 @@ UDFCommonCreate( try_return(Status = STATUS_ACCESS_DENIED); } + try_return(Status = UDFOpenObjectByFileId(IrpContext, IrpSp, Vcb, &CurrentFcb)); + } // @@ -1504,7 +1519,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 +1863,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 +1882,7 @@ UDFCommonCreate( &NewFileInfo, &PtrNewFcb); if (NT_SUCCESS(Status)) { LastGoodFileInfo = NewFileInfo; + } else { // FCB setup failed — close stream dir and exit UDFCloseFile__(IrpContext, Vcb, StreamDirInfo); @@ -1983,7 +2002,7 @@ UDFCommonCreate( if ((Status != STATUS_FILE_IS_A_DIRECTORY) && (Status != STATUS_NOT_A_DIRECTORY) && (Status != STATUS_ACCESS_DENIED)) { - UDFFlushFile__(IrpContext, Vcb, NewFileInfo); + UDFFlushFile__(IrpContext, Vcb, NewFileInfo, 0); UDFUnlinkFile__(IrpContext, Vcb, NewFileInfo, TRUE); } // UDFCloseFile__ is handled by the finally block. @@ -2027,9 +2046,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, @@ -2070,7 +2091,7 @@ UDFCommonCreate( (Status != STATUS_FILE_IS_A_DIRECTORY) && (Status != STATUS_NOT_A_DIRECTORY) && (Status != STATUS_ACCESS_DENIED)) { - UDFFlushFile__(IrpContext, Vcb, NewFileInfo); + UDFFlushFile__(IrpContext, Vcb, NewFileInfo, 0); UDFUnlinkFile__(IrpContext, Vcb, NewFileInfo, TRUE); } try_return(Status); @@ -2079,8 +2100,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 +2182,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); } @@ -2183,7 +2208,7 @@ UDFCommonCreate( if ((Status != STATUS_FILE_IS_A_DIRECTORY) && (Status != STATUS_NOT_A_DIRECTORY) && (Status != STATUS_ACCESS_DENIED)) { - UDFFlushFile__(IrpContext, Vcb, NewFileInfo); + UDFFlushFile__(IrpContext, Vcb, NewFileInfo, 0); UDFUnlinkFile__(IrpContext, Vcb, NewFileInfo, TRUE); } UDFCloseFile__(IrpContext, Vcb, NewFileInfo); @@ -2211,6 +2236,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 +2270,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)) { @@ -2278,7 +2309,7 @@ UDFCommonCreate( (Status != STATUS_FILE_IS_A_DIRECTORY) && (Status != STATUS_NOT_A_DIRECTORY) && (Status != STATUS_ACCESS_DENIED)) { - UDFFlushFile__(IrpContext, Vcb, NewFileInfo); + UDFFlushFile__(IrpContext, Vcb, NewFileInfo, 0); UDFUnlinkFile__(IrpContext, Vcb, NewFileInfo, TRUE); } if (NewFileInfo) { @@ -2372,8 +2403,10 @@ try_exit: NOTHING; if (NT_SUCCESS(Status) && PtrNewFcb) { + if (DeleteOnClose) { ASSERT(!(PtrNewFcb->FcbState & UDF_FCB_ROOT_DIRECTORY)); + } if (StreamOpen) { @@ -2465,13 +2498,20 @@ try_exit: NOTHING; // // Teardown partial FCB structures. - // Protect PreviousFcb from deletion via FcbReference bump — + // CurrentFcb is always the exclusively-held FCB — use it directly. + // Protect PreviousFcb from deletion via FcbReference bump: // TeardownStructures walks parent chain and may free parents. // + // Note: CurrentFcb may differ from LastGoodFileInfo->Fcb when + // UDFOpenObjectFromDirContext advances CurrentFcb to the final + // component FCB in step 4 before PerformUserOpen fails. + // - ASSERT(!LastGoodFileInfo || !LastGoodFileInfo->Fcb || CurrentFcb == LastGoodFileInfo->Fcb); - - if (Vcb && (PtrNewFcb != Vcb->RootIndexFcb) && LastGoodFileInfo) { + // Guard against tearing down the root index FCB: use CurrentFcb + // (the exclusively-locked FCB we are about to tear down) rather + // than PtrNewFcb (the output of a successful open, which may be + // NULL or different from CurrentFcb in the error path). + if (Vcb && CurrentFcb && (CurrentFcb != Vcb->RootIndexFcb)) { BOOLEAN ProtectedPreviousFcb = FALSE; if (PreviousFcb && PreviousFcb != CurrentFcb) { @@ -2482,7 +2522,7 @@ try_exit: NOTHING; } BOOLEAN RemovedFcb = FALSE; - UDFTeardownStructures(IrpContext, LastGoodFileInfo->Fcb, FALSE, &RemovedFcb); + UDFTeardownStructures(IrpContext, CurrentFcb, FALSE, &RemovedFcb); if (RemovedFcb) { if (PreviousFcb == CurrentFcb) { @@ -2497,8 +2537,6 @@ try_exit: NOTHING; UDFUnlockVcb(IrpContext, Vcb); } - } else { - ASSERT(!LastGoodFileInfo); } } @@ -2790,7 +2828,7 @@ UDFCompleteFcbOpen( // Flush the volume and make sure all of the user references // are gone. - Status = UDFFlushVolume(IrpContext, Vcb); + Status = UDFFlushVolume(IrpContext, Vcb, 0); if (!NT_SUCCESS(Status)) { @@ -2832,6 +2870,7 @@ UDFCompleteFcbOpen( if (!(Ccb = UDFCreateCcb())) { + return STATUS_INSUFFICIENT_RESOURCES; } @@ -2839,6 +2878,7 @@ UDFCompleteFcbOpen( _SEH2_TRY { + if (AddedAccess) { ClearFlag(DesiredAccess, AddedAccess); @@ -2998,7 +3038,7 @@ UDFCompleteFcbOpen( IrpSp->FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; } else { IrpSp->FileObject->Flags |= FO_CACHE_SUPPORTED; - InterlockedIncrement((PLONG)&Fcb->CachedOpenHandleCount); + InterlockedIncrement(&Fcb->CachedOpenHandleCount); } } else if (TypeOfOpen == UserVolumeOpen) { @@ -3018,6 +3058,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 +3067,7 @@ UDFCompleteFcbOpen( UDFLockVcb(IrpContext, Fcb->Vcb); } + // Cleanup counts: Fcb->FcbCleanup++; Fcb->Vcb->VcbCleanup++; @@ -3042,7 +3084,7 @@ UDFCompleteFcbOpen( Fcb->Vcb->VcbUserReference++; // Increment LCB reference count. - // This reference will be decremented in cleanup.cpp. + // This reference will be decremented in cleanup.c (UDFCommonCleanup). if (Ccb->Lcb) { Ccb->Lcb->Reference++; } diff --git a/drivers/filesystems/udfs/devcntrl.cpp b/drivers/filesystems/udfs/devcntrl.c similarity index 93% rename from drivers/filesystems/udfs/devcntrl.cpp rename to drivers/filesystems/udfs/devcntrl.c index dd0bb0a651baf..adb9cff4e497a 100644 --- a/drivers/filesystems/udfs/devcntrl.cpp +++ b/drivers/filesystems/udfs/devcntrl.c @@ -96,16 +96,24 @@ UdfIsVolumeModifyingScsiOp( NTSTATUS UDFCommonDevControl(PIRP_CONTEXT IrpContext, PIRP Irp) { + BOOLEAN FcbAcquired = FALSE; BOOLEAN DeviceAcquired = FALSE; BOOLEAN IsOpticalWriteRModeActive = FALSE; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); + BOOLEAN CanWait = FALSE; PCDB Cdb = NULL; PVCB Vcb; PFCB Fcb; PCCB Ccb; - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; TYPE_OF_OPEN TypeOfOpen; - ULONG IoControlCode; + ULONG IoControlCode = 0; + + PAGED_CODE(); + + UDFPrint(("UDFCommonDevControl\n")); + UDFPrint(("Irp = %p\n", Irp)); + UDFPrint(("MinorFunction = %08lx\n", IrpSp->MinorFunction)); PAGED_CODE(); @@ -127,10 +135,13 @@ UDFCommonDevControl(PIRP_CONTEXT IrpContext, PIRP Irp) IsOpticalWriteRModeActive = TRUE; } + CanWait = FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); + if (TypeOfOpen == UserFileOpen) { UDF_CHECK_PAGING_IO_RESOURCE(Fcb); - UDFAcquireFcbShared(IrpContext, Fcb, FALSE); + UDFAcquireResourceShared(&Fcb->FcbNonpaged->FcbResource, CanWait); + FcbAcquired = TRUE; _SEH2_TRY { @@ -173,7 +184,10 @@ UDFCommonDevControl(PIRP_CONTEXT IrpContext, PIRP Irp) if (DeviceAcquired) UDFReleaseDevice(IrpContext, Vcb, NULL); - UDFReleaseFcb(IrpContext, Fcb); + if (FcbAcquired) { + UDF_CHECK_PAGING_IO_RESOURCE(Fcb); + UDFReleaseResource(&Fcb->FcbNonpaged->FcbResource); + } } _SEH2_END; return Status; @@ -218,7 +232,7 @@ UDFCommonDevControl(PIRP_CONTEXT IrpContext, PIRP Irp) if (!FlagOn(Vcb->VcbState, VCB_STATE_PNP_NOTIFICATION)) { - UDFAcquireVcbExclusive(IrpContext, Vcb, FALSE); + UDFAcquireResourceExclusive(&Vcb->VcbResource, CanWait); if (Vcb->VcbCondition == VcbMounted && FALSE /*IsWritableOpticalMedia()*/) { @@ -233,7 +247,7 @@ UDFCommonDevControl(PIRP_CONTEXT IrpContext, PIRP Irp) } } - UDFReleaseVcb(IrpContext, Vcb); + UDFReleaseResource(&(Vcb->VcbResource)); } break; diff --git a/drivers/filesystems/udfs/dircntrl.cpp b/drivers/filesystems/udfs/dircntrl.c similarity index 97% rename from drivers/filesystems/udfs/dircntrl.cpp rename to drivers/filesystems/udfs/dircntrl.c index c9b2f7d62cf64..b936ba42ba371 100644 --- a/drivers/filesystems/udfs/dircntrl.cpp +++ b/drivers/filesystems/udfs/dircntrl.c @@ -156,9 +156,9 @@ UDFQueryDirectory( BOOLEAN FirstTimeQuery = FALSE; LONG NextMatch = 0; LONG PrevMatch = -1; - ULONG CurrentOffset; - ULONG BaseLength; - ULONG FileNameBytes; + ULONG CurrentOffset = 0; + ULONG BaseLength = 0; + ULONG FileNameBytes = 0; ULONG Information = 0; ULONG LastOffset = 0; BOOLEAN AtLeastOneFound = FALSE; @@ -168,7 +168,7 @@ UDFQueryDirectory( PFILE_BOTH_DIR_INFORMATION BothDirInformation = NULL; // Pointer in callers buffer PFILE_NAMES_INFORMATION NamesInfo; PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo = NULL; - ULONG BytesRemainingInBuffer; + ULONG BytesRemainingInBuffer = 0; PHASH_ENTRY cur_hashes = NULL; PDIR_INDEX_ITEM DirNdx; // do some pre-init... @@ -279,7 +279,10 @@ UDFQueryDirectory( // check whether we need to store this search pattern in // the CCB. if (Ccb->DirectorySearchPattern) { - MyFreePool__(Ccb->DirectorySearchPattern->Buffer); + if (Ccb->DirectorySearchPattern->Buffer) { + MyFreePool__(Ccb->DirectorySearchPattern->Buffer); + Ccb->DirectorySearchPattern->Buffer = NULL; + } MyFreePool__(Ccb->DirectorySearchPattern); Ccb->DirectorySearchPattern = NULL; } @@ -297,6 +300,8 @@ UDFQueryDirectory( Ccb->DirectorySearchPattern->MaximumLength = PtrSearchPattern->MaximumLength; Ccb->DirectorySearchPattern->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool,PtrSearchPattern->MaximumLength); if (!(Ccb->DirectorySearchPattern->Buffer)) { + MyFreePool__(Ccb->DirectorySearchPattern); + Ccb->DirectorySearchPattern = NULL; try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } RtlCopyMemory(Ccb->DirectorySearchPattern->Buffer,PtrSearchPattern->Buffer, diff --git a/drivers/filesystems/udfs/env_spec.c b/drivers/filesystems/udfs/env_spec.c new file mode 100644 index 0000000000000..75a771a92e889 --- /dev/null +++ b/drivers/filesystems/udfs/env_spec.c @@ -0,0 +1,797 @@ +//////////////////////////////////////////////////////////////////// +// 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: Env_Spec.cpp +* +* Module: UDF File System Driver (Kernel mode execution only) +* +* Description: +* Contains environment-secific code to handle physical +* operations: read, write and device IOCTLS +* +*************************************************************************/ + +#include "udffs.h" +// define the file specific bug-check id +#define UDF_BUG_CHECK_ID UDF_FILE_ENV_SPEC + +// Maximum size of a single NonPagedPool I/O chunk (1 MB). +// Splitting large transfers into chunks allows them to succeed on systems +// with limited RAM (e.g. 64 MB), where a single large NonPagedPool allocation +// or a single MmProbeAndLockPages call over the full buffer would fail. +#define UDF_MAX_IO_CHUNK_SIZE (1024 * 1024) + +#ifdef DBG +ULONG UDF_SIMULATE_WRITES=0; +#endif //DBG + +/* + + */ +NTSTATUS +NTAPI +UDFAsyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + UDFPrint(("UDFAsyncCompletionRoutine ctx=%x\n", Contxt)); + PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt; + PMDL Mdl, NextMdl; + + Context->IosbToUse = Irp->IoStatus; +#if 1 + // Unlock pages that are described by MDL (if any). + // MDLs built with MmBuildMdlForNonPagedPool have MDL_SOURCE_IS_NONPAGED_POOL + // set; those pages were never locked so MmUnlockPages must NOT be called on + // them (it would decrement PFN reference counts that were never incremented, + // causing PFN_LIST_CORRUPT / bugcheck 0x4E with Arg1=7). + Mdl = Irp->MdlAddress; + while(Mdl) { + MmPrint((" Unlock MDL=%x\n", Mdl)); + if (!(Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL)) { + MmUnlockPages(Mdl); + } + Mdl = Mdl->Next; + } + // ... and free MDL + Mdl = Irp->MdlAddress; + while(Mdl) { + MmPrint((" Free MDL=%x\n", Mdl)); + NextMdl = Mdl->Next; + IoFreeMdl(Mdl); + Mdl = NextMdl; + } + Irp->MdlAddress = NULL; + IoFreeIrp(Irp); + + KeSetEvent( &(Context->event), 0, FALSE ); + + return STATUS_MORE_PROCESSING_REQUIRED; +#else + KeSetEvent( &(Context->event), 0, FALSE ); + + return STATUS_SUCCESS; +#endif +} // end UDFAsyncCompletionRoutine() + +NTSTATUS +NTAPI +UDFSyncCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + UDFPrint(("UDFSyncCompletionRoutine ctx=%x\n", Contxt)); + PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt; + + Context->IosbToUse = Irp->IoStatus; + //KeSetEvent( &(Context->event), 0, FALSE ); + + return STATUS_SUCCESS; +} // end UDFSyncCompletionRoutine() + +/* +NTSTATUS +UDFSyncCompletionRoutine2( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Contxt + ) +{ + UDFPrint(("UDFSyncCompletionRoutine2\n")); + PKEVENT SyncEvent = (PKEVENT)Contxt; + + KeSetEvent( SyncEvent, 0, FALSE ); + + return STATUS_SUCCESS; +} // end UDFSyncCompletionRoutine2() +*/ + +/* + + Function: UDFPhReadSynchronous() + + Description: + UDFFSD will invoke this rotine to read physical device synchronously/asynchronously + + Expected Interrupt Level (for execution) : + + <= APC_LEVEL (MmProbeAndLockPages requires IRQL <= APC_LEVEL) + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +UDFPhReadSynchronous( + PIRP_CONTEXT IrpContext, + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG ByteCount, + LONGLONG Offset, + PULONG ReadBytes, + ULONG Flags + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + LARGE_INTEGER ROffset; + + (*ReadBytes) = 0; + + // MmProbeAndLockPages requires IRQL <= APC_LEVEL. + if (KeGetCurrentIrql() > APC_LEVEL) { + UDFPrint((" UDFPhReadSynchronous: called above APC_LEVEL\n")); + ASSERT(FALSE); + return STATUS_INVALID_DEVICE_STATE; + } + + if (!(Flags & PH_TMP_BUFFER)) { + // Non-TMP path: issue I/O in NonPagedPool chunks so that large transfers + // (e.g. >= 64 MB) succeed on systems with limited RAM. Each chunk is at + // most UDF_MAX_IO_CHUNK_SIZE bytes, which can always be satisfied by a + // small NonPagedPool allocation. MmBuildMdlForNonPagedPool is used so + // that MmProbeAndLockPages (which could fail under memory pressure) is + // never called on the full transfer buffer. + ULONG BytesLeft = ByteCount; + ULONG BytesDone = 0; + + while (BytesLeft > 0) { + ULONG ChunkSize = min(BytesLeft, UDF_MAX_IO_CHUNK_SIZE); + PVOID ChunkBuf = DbgAllocatePoolWithTag(NonPagedPool, ChunkSize, 'bNWD'); + if (!ChunkBuf) { + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + PUDF_PH_CALL_CONTEXT ChunkCtx = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__(NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT)); + if (!ChunkCtx) { + DbgFreePool(ChunkBuf); + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + KeInitializeEvent(&ChunkCtx->event, NotificationEvent, FALSE); + + ROffset.QuadPart = Offset + (LONGLONG)BytesDone; + + // Use MmCreateMdl + MmBuildMdlForNonPagedPool: no page-locking is + // needed for NonPagedPool, so this path works at any memory pressure. + PMDL ChunkMdl = MmCreateMdl(NULL, ChunkBuf, ChunkSize); + if (!ChunkMdl) { + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + MmBuildMdlForNonPagedPool(ChunkMdl); + + PIRP ChunkIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!ChunkIrp) { + IoFreeMdl(ChunkMdl); + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + ChunkIrp->MdlAddress = ChunkMdl; + ChunkIrp->UserIosb = &ChunkCtx->IosbToUse; + ChunkIrp->UserEvent = NULL; + ChunkIrp->RequestorMode = KernelMode; + ChunkIrp->Tail.Overlay.Thread = PsGetCurrentThread(); + IoSetCompletionRoutine(ChunkIrp, &UDFAsyncCompletionRoutine, ChunkCtx, TRUE, TRUE, TRUE); + + // Setup the next IRP stack location. + PIO_STACK_LOCATION IrpSp = IoGetNextIrpStackLocation(ChunkIrp); + IrpSp->MajorFunction = IRP_MJ_READ; + IrpSp->Parameters.Read.Length = ChunkSize; + IrpSp->Parameters.Read.ByteOffset = ROffset; + + if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { + SetFlag(IrpSp->Flags, SL_WRITE_THROUGH); + } + SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); + + RC = IoCallDriver(DeviceObject, ChunkIrp); + // ChunkIrp and ChunkMdl are freed by UDFAsyncCompletionRoutine. + + if (RC == STATUS_PENDING) { + DbgWaitForSingleObject(&ChunkCtx->event, NULL); + RC = ChunkCtx->IosbToUse.Status; + if (RC == STATUS_DATA_OVERRUN) RC = STATUS_SUCCESS; + } + + if (NT_SUCCESS(RC)) { + ULONG ChunkRead = (ULONG)ChunkCtx->IosbToUse.Information; + RtlCopyMemory((PUCHAR)Buffer + BytesDone, ChunkBuf, ChunkRead); + *ReadBytes += ChunkRead; + BytesDone += ChunkRead; + BytesLeft -= ChunkRead; + + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + + // Short read: stop iterating. + if (ChunkRead < ChunkSize) break; + } else { + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + break; + } + } + + return RC; + } + + // PH_TMP_BUFFER path: Buffer is already a NonPagedPool buffer from the caller. + // Use a single IRP for the whole transfer (these are always small, e.g. one sector). + PVOID IoBuf = Buffer; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); + if (!Context) { + UDFPrint((" !Context\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + // Create notification event object to be used to signal the request completion. + KeInitializeEvent(&(Context->event), NotificationEvent, FALSE); + + { + // Use MmCreateMdl instead of IoAllocateMdl so that large buffers + // (> ~64 MB) are not rejected on Windows XP/Server 2003, where + // IoAllocateMdl returns NULL when the MDL size exceeds MAXUSHORT. + // MmProbeAndLockPages (like IoBuildAsynchronousFsdRequest does) sets + // MDL_PAGES_LOCKED without MDL_SOURCE_IS_NONPAGED_POOL, making + // MmUnlockPages safe in the async completion routine. + PMDL Mdl = MmCreateMdl(NULL, IoBuf, ByteCount); + if (!Mdl) { + UDFPrint((" !Mdl\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + NTSTATUS LockStatus = STATUS_SUCCESS; + _SEH2_TRY { + // IoWriteAccess: for READ we write data from disk into the buffer. + MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + LockStatus = _SEH2_GetExceptionCode(); + } _SEH2_END; + if (!NT_SUCCESS(LockStatus)) { + UDFPrint((" !MmProbeAndLockPages read\n")); + IoFreeMdl(Mdl); + try_return(RC = LockStatus); + } + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) { + UDFPrint((" !irp\n")); + MmUnlockPages(Mdl); + IoFreeMdl(Mdl); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + Irp->MdlAddress = Mdl; + Irp->UserIosb = &(Context->IosbToUse); + Irp->UserEvent = NULL; + Irp->RequestorMode = KernelMode; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", Irp->MdlAddress, Context)); + IoSetCompletionRoutine(Irp, &UDFAsyncCompletionRoutine, + Context, TRUE, TRUE, TRUE); + } + + // Setup the next IRP stack location in the associated Irp for the disk + // driver beneath us. + + ROffset.QuadPart = Offset; + IrpSp = IoGetNextIrpStackLocation(Irp); + IrpSp->MajorFunction = IRP_MJ_READ; + IrpSp->Parameters.Read.Length = ByteCount; + IrpSp->Parameters.Read.ByteOffset = ROffset; + + // If this Irp is the result of a WriteThough operation, + // tell the device to write it through. + + if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { + + SetFlag(IrpSp->Flags, SL_WRITE_THROUGH); + } + + SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); + + RC = IoCallDriver(DeviceObject, Irp); + + if (RC == STATUS_PENDING) { + DbgWaitForSingleObject(&(Context->event), NULL); + if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { + RC = STATUS_SUCCESS; + } + } + if (NT_SUCCESS(RC)) { + (*ReadBytes) = Context->IosbToUse.Information; + } + +try_exit: NOTHING; + + if (Context) MyFreePool__(Context); + + return(RC); +} // end UDFPhReadSynchronous() + + +/* + + Function: UDFPhWriteSynchronous() + + Description: + UDFFSD will invoke this rotine to write physical device synchronously + + Expected Interrupt Level (for execution) : + + <= APC_LEVEL (MmProbeAndLockPages requires IRQL <= APC_LEVEL) + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +UDFPhWriteSynchronous( + PDEVICE_OBJECT DeviceObject, // the physical device object + PVOID Buffer, + ULONG ByteCount, + LONGLONG Offset, + PSIZE_T WrittenBytes, + ULONG Flags + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + LARGE_INTEGER ROffset; + +#ifdef DBG + if (UDF_SIMULATE_WRITES) { +/* FIXME ReactOS + If this function is to force a read from the bufffer to simulate any segfaults, then it makes sense. + Else, this forloop is useless. + UCHAR a; + for(ULONG i=0; i APC_LEVEL) { + UDFPrint((" UDFPhWriteSynchronous: called above APC_LEVEL\n")); + ASSERT(FALSE); + return STATUS_INVALID_DEVICE_STATE; + } + + if (!(Flags & PH_TMP_BUFFER)) { + // Non-TMP path: issue I/O in NonPagedPool chunks so that large transfers + // (e.g. >= 64 MB) succeed on systems with limited RAM. Each chunk is at + // most UDF_MAX_IO_CHUNK_SIZE bytes, which can always be satisfied by a + // small NonPagedPool allocation. MmBuildMdlForNonPagedPool is used so + // that MmProbeAndLockPages (which could fail under memory pressure) is + // never called on the full transfer buffer. + ULONG BytesLeft = ByteCount; + ULONG BytesDone = 0; + + while (BytesLeft > 0) { + ULONG ChunkSize = min(BytesLeft, UDF_MAX_IO_CHUNK_SIZE); + PVOID ChunkBuf = DbgAllocatePoolWithTag(NonPagedPool, ChunkSize, 'bNWD'); + if (!ChunkBuf) { + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + RtlCopyMemory(ChunkBuf, (PUCHAR)Buffer + BytesDone, ChunkSize); + + PUDF_PH_CALL_CONTEXT ChunkCtx = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__(NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT)); + if (!ChunkCtx) { + DbgFreePool(ChunkBuf); + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + KeInitializeEvent(&ChunkCtx->event, NotificationEvent, FALSE); + + ROffset.QuadPart = Offset + (LONGLONG)BytesDone; + + // Use MmCreateMdl + MmBuildMdlForNonPagedPool: no page-locking is + // needed for NonPagedPool, so this path works at any memory pressure. + PMDL ChunkMdl = MmCreateMdl(NULL, ChunkBuf, ChunkSize); + if (!ChunkMdl) { + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + MmBuildMdlForNonPagedPool(ChunkMdl); + + PIRP ChunkIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!ChunkIrp) { + IoFreeMdl(ChunkMdl); + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + RC = STATUS_INSUFFICIENT_RESOURCES; + break; + } + ChunkIrp->MdlAddress = ChunkMdl; + ChunkIrp->UserIosb = &ChunkCtx->IosbToUse; + ChunkIrp->UserEvent = NULL; + ChunkIrp->RequestorMode = KernelMode; + ChunkIrp->Tail.Overlay.Thread = PsGetCurrentThread(); + IoSetCompletionRoutine(ChunkIrp, &UDFAsyncCompletionRoutine, ChunkCtx, TRUE, TRUE, TRUE); + + // Setup the next IRP stack location. + PIO_STACK_LOCATION IrpSp = IoGetNextIrpStackLocation(ChunkIrp); + IrpSp->MajorFunction = IRP_MJ_WRITE; + IrpSp->Parameters.Write.Length = ChunkSize; + IrpSp->Parameters.Write.ByteOffset = ROffset; + SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); + + RC = IoCallDriver(DeviceObject, ChunkIrp); + // ChunkIrp and ChunkMdl are freed by UDFAsyncCompletionRoutine. + + if (RC == STATUS_PENDING) { + DbgWaitForSingleObject(&ChunkCtx->event, NULL); + RC = ChunkCtx->IosbToUse.Status; + if (RC == STATUS_DATA_OVERRUN) RC = STATUS_SUCCESS; + } + + if (NT_SUCCESS(RC)) { + ULONG ChunkWritten = (ULONG)ChunkCtx->IosbToUse.Information; + *WrittenBytes += ChunkWritten; + BytesDone += ChunkWritten; + BytesLeft -= ChunkWritten; + + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + + // Short write: stop iterating. + if (ChunkWritten < ChunkSize) break; + } else { + MyFreePool__(ChunkCtx); + DbgFreePool(ChunkBuf); + break; + } + } + + if (!NT_SUCCESS(RC)) { + UDFPrint(("WriteError\n")); + } + return RC; + } + + // PH_TMP_BUFFER path: Buffer is already a NonPagedPool buffer from the caller. + // Use a single IRP for the whole transfer (these are always small, e.g. one sector). + PVOID IoBuf = Buffer; + ROffset.QuadPart = Offset; + PIRP irp; + PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); + if (!Context) try_return (RC = STATUS_INSUFFICIENT_RESOURCES); + // Create notification event object to be used to signal the request completion. + KeInitializeEvent(&(Context->event), NotificationEvent, FALSE); + + { + // Use MmCreateMdl instead of IoAllocateMdl so that large buffers + // (> ~64 MB) are not rejected on Windows XP/Server 2003, where + // IoAllocateMdl returns NULL when the MDL size exceeds MAXUSHORT. + // MmProbeAndLockPages (like IoBuildAsynchronousFsdRequest does) sets + // MDL_PAGES_LOCKED without MDL_SOURCE_IS_NONPAGED_POOL, making + // MmUnlockPages safe in the async completion routine. + PMDL Mdl = MmCreateMdl(NULL, IoBuf, ByteCount); + if (!Mdl) { + UDFPrint((" !Mdl\n")); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + NTSTATUS LockStatus = STATUS_SUCCESS; + _SEH2_TRY { + // IoReadAccess: for WRITE we read data from the buffer to send to disk. + MmProbeAndLockPages(Mdl, KernelMode, IoReadAccess); + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + LockStatus = _SEH2_GetExceptionCode(); + } _SEH2_END; + if (!NT_SUCCESS(LockStatus)) { + UDFPrint((" !MmProbeAndLockPages write\n")); + IoFreeMdl(Mdl); + try_return(RC = LockStatus); + } + irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!irp) { + UDFPrint((" !irp\n")); + MmUnlockPages(Mdl); + IoFreeMdl(Mdl); + try_return(RC = STATUS_INSUFFICIENT_RESOURCES); + } + irp->MdlAddress = Mdl; + irp->UserIosb = &(Context->IosbToUse); + irp->UserEvent = NULL; + irp->RequestorMode = KernelMode; + irp->Tail.Overlay.Thread = PsGetCurrentThread(); + MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); + IoSetCompletionRoutine(irp, &UDFAsyncCompletionRoutine, + Context, TRUE, TRUE, TRUE); + } + + PIO_STACK_LOCATION IrpSp = IoGetNextIrpStackLocation(irp); + IrpSp->MajorFunction = IRP_MJ_WRITE; + IrpSp->Parameters.Write.Length = ByteCount; + IrpSp->Parameters.Write.ByteOffset = ROffset; + SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); + RC = IoCallDriver(DeviceObject, irp); + + if (RC == STATUS_PENDING) { + DbgWaitForSingleObject(&(Context->event), NULL); + if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { + RC = STATUS_SUCCESS; + } + } + if (NT_SUCCESS(RC)) { + (*WrittenBytes) = Context->IosbToUse.Information; + } + +try_exit: NOTHING; + + if (Context) MyFreePool__(Context); + if (!NT_SUCCESS(RC)) { + UDFPrint(("WriteError\n")); + } + + return(RC); +} // end UDFPhWriteSynchronous() + +NTSTATUS +NTAPI +UDFTSendIOCTL( + IN ULONG IoControlCode, + IN PVCB Vcb, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PIO_STATUS_BLOCK Iosb OPTIONAL + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + BOOLEAN Acquired = FALSE; + + Acquired = UDFAcquireResourceExclusiveWithCheck(&(Vcb->IoResource)); + + _SEH2_TRY { + + RC = UDFPhSendIOCTL(IoControlCode, + Vcb->TargetDeviceObject, + InputBuffer , + InputBufferLength, + OutputBuffer , + OutputBufferLength, + OverrideVerify, + Iosb + ); + + } _SEH2_FINALLY { + if (Acquired) + UDFReleaseResource(&(Vcb->IoResource)); + } _SEH2_END; + + return RC; +} // end UDFTSendIOCTL() + +/* + + Function: UDFPhSendIOCTL() + + Description: + UDF FSD will invoke this rotine to send IOCTL's to physical + device + + Return Value: STATUS_SUCCESS/Error + +*/ +NTSTATUS +NTAPI +UDFPhSendIOCTL( + IN ULONG IoControlCode, + IN PDEVICE_OBJECT DeviceObject, + IN PVOID InputBuffer , + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer , + IN ULONG OutputBufferLength, + IN BOOLEAN OverrideVerify, + OUT PIO_STATUS_BLOCK Iosb OPTIONAL + ) +{ + NTSTATUS RC = STATUS_SUCCESS; + PIRP irp; + PUDF_PH_CALL_CONTEXT Context; + LARGE_INTEGER timeout; + + UDFPrint(("UDFPhDevIOCTL: Code %8x \n",IoControlCode)); + + Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); + if (!Context) return STATUS_INSUFFICIENT_RESOURCES; + // Check if the user gave us an Iosb. + + // Create notification event object to be used to signal the request completion. + KeInitializeEvent(&(Context->event), NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer , + InputBufferLength, OutputBuffer, OutputBufferLength,FALSE,&(Context->event),&(Context->IosbToUse)); + + if (!irp) try_return (RC = STATUS_INSUFFICIENT_RESOURCES); + MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); +/* + if (KeGetCurrentIrql() > PASSIVE_LEVEL) { + UDFPrint(("Setting completion routine\n")); + IoSetCompletionRoutine( irp, &UDFSyncCompletionRoutine, + Context, TRUE, TRUE, TRUE ); + } +*/ + if (OverrideVerify) { + (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; + } + + RC = IoCallDriver(DeviceObject, irp); + + if (RC == STATUS_PENDING) { + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + UDFPrint(("Enter wait state on evt %x\n", Context)); + + if (KeGetCurrentIrql() > PASSIVE_LEVEL) { + timeout.QuadPart = -1000; + UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); + RC = DbgWaitForSingleObject(&(Context->event), &timeout); + while(RC == STATUS_TIMEOUT) { + timeout.QuadPart *= 2; + UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); + RC = DbgWaitForSingleObject(&(Context->event), &timeout); + } + + } else { + DbgWaitForSingleObject(&(Context->event), NULL); + } + if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { + RC = STATUS_SUCCESS; + } + UDFPrint(("Exit wait state on evt %x, status %8.8x\n", Context, RC)); +/* if (Iosb) { + (*Iosb) = Context->IosbToUse; + }*/ + } else { + UDFPrint(("No wait completion on evt %x\n", Context)); +/* if (Iosb) { + (*Iosb) = irp->IoStatus; + }*/ + } + + if (Iosb) { + (*Iosb) = Context->IosbToUse; + } + +try_exit: NOTHING; + + if (Context) MyFreePool__(Context); + return(RC); +} // end UDFPhSendIOCTL() + +VOID +UDFNotifyReportChange( + PIRP_CONTEXT IrpContext, + PVCB Vcb, + PFCB Fcb, + ULONG Filter, + ULONG Action, + PLCB Lcb, + PFILE_OBJECT FileObject + ) +{ + USHORT TargetNameOffset = 0; + UNICODE_STRING FullPath; + BOOLEAN PathAllocated = FALSE; + WCHAR RootChar; + + FullPath.Buffer = NULL; + FullPath.Length = 0; + FullPath.MaximumLength = 0; + + // + // Acquire FcbResource shared for the duration of the notify. + // Protects LCB chain and name buffers from concurrent teardown. + // + UDFAcquireFcbShared(IrpContext, Fcb, FALSE); + + _SEH2_TRY { + + // If no LCB provided, find first valid (non-deleted) one + if (!Lcb) { + if (!IsListEmpty(&Fcb->ParentLcbQueue)) { + PLIST_ENTRY ListEntry = Fcb->ParentLcbQueue.Flink; + while (ListEntry != &Fcb->ParentLcbQueue) { + PLCB CandidateLcb = CONTAINING_RECORD(ListEntry, LCB, ChildFcbLinks); + if (!(CandidateLcb->Flags & UDF_LCB_FLAG_LINK_DELETED)) { + Lcb = CandidateLcb; + break; + } + ListEntry = ListEntry->Flink; + } + } + } + + // + // Build the full target name. Prefer FileObject->FileName (stable + // pointer, does not depend on LCB chain state). Fall back to + // building from LCB chain. + // + if (FileObject && FileObject->FileName.Buffer && + FileObject->FileName.Length > 0) { + FullPath = FileObject->FileName; + } else if (Lcb) { + NTSTATUS Status = UDFBuildFullPathFromLcb(NULL, Lcb, &FullPath, FALSE); + if (NT_SUCCESS(Status)) { + PathAllocated = TRUE; + } + } + + // Fallback to root + if (!FullPath.Buffer || FullPath.Length == 0) { + RootChar = L'\\'; + FullPath.Buffer = &RootChar; + FullPath.Length = sizeof(WCHAR); + FullPath.MaximumLength = sizeof(WCHAR); + PathAllocated = FALSE; + Lcb = NULL; + } + + // TargetNameOffset: byte offset within FullPath to the final name component + if (Lcb && Lcb->ExactCaseLinkName.Length > 0 && + FullPath.Length > Lcb->ExactCaseLinkName.Length) { + TargetNameOffset = FullPath.Length - Lcb->ExactCaseLinkName.Length; + } + + FsRtlNotifyFullReportChange(Vcb->NotifySync, + &Vcb->NextNotifyIRP, + (PSTRING)&FullPath, + TargetNameOffset, + NULL, + NULL, + Filter, + Action, + NULL); + + } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { + NOTHING; + } _SEH2_END; + + UDFReleaseFcb(IrpContext, Fcb); + + if (PathAllocated && FullPath.Buffer) { + ExFreePool(FullPath.Buffer); + } + +} + diff --git a/drivers/filesystems/udfs/env_spec.cpp b/drivers/filesystems/udfs/env_spec.cpp deleted file mode 100644 index 52e1cb5382576..0000000000000 --- a/drivers/filesystems/udfs/env_spec.cpp +++ /dev/null @@ -1,560 +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: Env_Spec.cpp -* -* Module: UDF File System Driver (Kernel mode execution only) -* -* Description: -* Contains environment-secific code to handle physical -* operations: read, write and device IOCTLS -* -*************************************************************************/ - -#include "udffs.h" -// define the file specific bug-check id -#define UDF_BUG_CHECK_ID UDF_FILE_ENV_SPEC - -#ifdef DBG -ULONG UDF_SIMULATE_WRITES=0; -#endif //DBG - -/* - - */ -NTSTATUS -NTAPI -UDFAsyncCompletionRoutine( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PVOID Contxt - ) -{ - UDFPrint(("UDFAsyncCompletionRoutine ctx=%x\n", Contxt)); - PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt; - PMDL Mdl, NextMdl; - - Context->IosbToUse = Irp->IoStatus; -#if 1 - // Unlock pages that are described by MDL (if any)... - Mdl = Irp->MdlAddress; - while(Mdl) { - MmPrint((" Unlock MDL=%x\n", Mdl)); - MmUnlockPages(Mdl); - Mdl = Mdl->Next; - } - // ... and free MDL - Mdl = Irp->MdlAddress; - while(Mdl) { - MmPrint((" Free MDL=%x\n", Mdl)); - NextMdl = Mdl->Next; - IoFreeMdl(Mdl); - Mdl = NextMdl; - } - Irp->MdlAddress = NULL; - IoFreeIrp(Irp); - - KeSetEvent( &(Context->event), 0, FALSE ); - - return STATUS_MORE_PROCESSING_REQUIRED; -#else - KeSetEvent( &(Context->event), 0, FALSE ); - - return STATUS_SUCCESS; -#endif -} // end UDFAsyncCompletionRoutine() - -NTSTATUS -NTAPI -UDFSyncCompletionRoutine( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PVOID Contxt - ) -{ - UDFPrint(("UDFSyncCompletionRoutine ctx=%x\n", Contxt)); - PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt; - - Context->IosbToUse = Irp->IoStatus; - //KeSetEvent( &(Context->event), 0, FALSE ); - - return STATUS_SUCCESS; -} // end UDFSyncCompletionRoutine() - -/* -NTSTATUS -UDFSyncCompletionRoutine2( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp, - IN PVOID Contxt - ) -{ - UDFPrint(("UDFSyncCompletionRoutine2\n")); - PKEVENT SyncEvent = (PKEVENT)Contxt; - - KeSetEvent( SyncEvent, 0, FALSE ); - - return STATUS_SUCCESS; -} // end UDFSyncCompletionRoutine2() -*/ - -/* - - Function: UDFPhReadSynchronous() - - Description: - UDFFSD will invoke this rotine to read physical device synchronously/asynchronously - - Expected Interrupt Level (for execution) : - - <= IRQL_DISPATCH_LEVEL - - Return Value: STATUS_SUCCESS/Error - -*/ -NTSTATUS -UDFPhReadSynchronous( - PIRP_CONTEXT IrpContext, - PDEVICE_OBJECT DeviceObject, // the physical device object - PVOID Buffer, - ULONG ByteCount, - LONGLONG Offset, - PULONG ReadBytes, - ULONG Flags - ) -{ - NTSTATUS RC = STATUS_SUCCESS; - LARGE_INTEGER ROffset; - PUDF_PH_CALL_CONTEXT Context; - PIRP Irp; - PIO_STACK_LOCATION IrpSp; - KIRQL CurIrql = KeGetCurrentIrql(); - PVOID IoBuf = NULL; - PVCB Vcb = NULL; - - ROffset.QuadPart = Offset; - (*ReadBytes) = 0; -/* - // DEBUG !!! - Flags |= PH_TMP_BUFFER; -*/ - if (Flags & PH_TMP_BUFFER) { - IoBuf = Buffer; - } else { - IoBuf = DbgAllocatePoolWithTag(NonPagedPool, ByteCount, 'bNWD'); - } - if (!IoBuf) { - UDFPrint((" !IoBuf\n")); - return STATUS_INSUFFICIENT_RESOURCES; - } - Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); - if (!Context) { - UDFPrint((" !Context\n")); - try_return(RC = STATUS_INSUFFICIENT_RESOURCES); - } - // Create notification event object to be used to signal the request completion. - KeInitializeEvent(&(Context->event), NotificationEvent, FALSE); - - if (TRUE || CurIrql > PASSIVE_LEVEL) { - Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf, - ByteCount, &ROffset, &(Context->IosbToUse) ); - if (!Irp) { - UDFPrint((" !irp Async\n")); - try_return(RC = STATUS_INSUFFICIENT_RESOURCES); - } - MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", Irp->MdlAddress, Context)); - IoSetCompletionRoutine(Irp, &UDFAsyncCompletionRoutine, - Context, TRUE, TRUE, TRUE ); - } else { - Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf, - ByteCount, &ROffset, &(Context->event), &(Context->IosbToUse) ); - if (!Irp) { - UDFPrint((" !irp Sync\n")); - try_return(RC = STATUS_INSUFFICIENT_RESOURCES); - } - MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", Irp->MdlAddress, Context)); - } - - // Setup the next IRP stack location in the associated Irp for the disk - // driver beneath us. - - IrpSp = IoGetNextIrpStackLocation(Irp); - - // If this Irp is the result of a WriteThough operation, - // tell the device to write it through. - - if (FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) { - - SetFlag(IrpSp->Flags, SL_WRITE_THROUGH); - } - - SetFlag(IrpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME); - - RC = IoCallDriver(DeviceObject, Irp); - - if (RC == STATUS_PENDING) { - DbgWaitForSingleObject(&(Context->event), NULL); - if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { - RC = STATUS_SUCCESS; - } -// *ReadBytes = Context->IosbToUse.Information; - } else { -// *ReadBytes = irp->IoStatus.Information; - } - if (NT_SUCCESS(RC)) { - (*ReadBytes) = Context->IosbToUse.Information; - } - if (!(Flags & PH_TMP_BUFFER)) { - RtlCopyMemory(Buffer, IoBuf, *ReadBytes); - } - -try_exit: NOTHING; - - if (Context) MyFreePool__(Context); - if (IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf); - - return(RC); -} // end UDFPhReadSynchronous() - - -/* - - Function: UDFPhWriteSynchronous() - - Description: - UDFFSD will invoke this rotine to write physical device synchronously - - Expected Interrupt Level (for execution) : - - <= IRQL_DISPATCH_LEVEL - - Return Value: STATUS_SUCCESS/Error - -*/ -NTSTATUS -UDFPhWriteSynchronous( - PDEVICE_OBJECT DeviceObject, // the physical device object - PVOID Buffer, - ULONG ByteCount, - LONGLONG Offset, - PSIZE_T WrittenBytes, - ULONG Flags - ) -{ - NTSTATUS RC = STATUS_SUCCESS; - LARGE_INTEGER ROffset; - PUDF_PH_CALL_CONTEXT Context = NULL; - PIRP irp; - KIRQL CurIrql = KeGetCurrentIrql(); - PVOID IoBuf = NULL; - - PVCB Vcb = NULL; - -#ifdef DBG - if (UDF_SIMULATE_WRITES) { -/* FIXME ReactOS - If this function is to force a read from the bufffer to simulate any segfaults, then it makes sense. - Else, this forloop is useless. - UCHAR a; - for(ULONG i=0; ievent), NotificationEvent, FALSE); - - if (TRUE || CurIrql > PASSIVE_LEVEL) { - irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf, - ByteCount, &ROffset, &(Context->IosbToUse) ); - if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); - MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); - IoSetCompletionRoutine( irp, &UDFAsyncCompletionRoutine, - Context, TRUE, TRUE, TRUE ); - } else { - irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf, - ByteCount, &ROffset, &(Context->event), &(Context->IosbToUse) ); - if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); - MmPrint((" Alloc Irp MDL=%x\n, ctx=%x", irp->MdlAddress, Context)); - } - - (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; - RC = IoCallDriver(DeviceObject, irp); - - if (RC == STATUS_PENDING) { - DbgWaitForSingleObject(&(Context->event), NULL); - if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { - RC = STATUS_SUCCESS; - } -// *WrittenBytes = Context->IosbToUse.Information; - } else { -// *WrittenBytes = irp->IoStatus.Information; - } - if (NT_SUCCESS(RC)) { - (*WrittenBytes) = Context->IosbToUse.Information; - } - -try_exit: NOTHING; - - if (Context) MyFreePool__(Context); - if (IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf); - if (!NT_SUCCESS(RC)) { - UDFPrint(("WriteError\n")); - } - - return(RC); -} // end UDFPhWriteSynchronous() - -NTSTATUS -NTAPI -UDFTSendIOCTL( - IN ULONG IoControlCode, - IN PVCB Vcb, - IN PVOID InputBuffer , - IN ULONG InputBufferLength, - OUT PVOID OutputBuffer , - IN ULONG OutputBufferLength, - IN BOOLEAN OverrideVerify, - OUT PIO_STATUS_BLOCK Iosb OPTIONAL - ) -{ - NTSTATUS RC = STATUS_SUCCESS; - BOOLEAN Acquired; - - Acquired = UDFAcquireResourceExclusiveWithCheck(&(Vcb->IoResource)); - - _SEH2_TRY { - - RC = UDFPhSendIOCTL(IoControlCode, - Vcb->TargetDeviceObject, - InputBuffer , - InputBufferLength, - OutputBuffer , - OutputBufferLength, - OverrideVerify, - Iosb - ); - - } _SEH2_FINALLY { - if (Acquired) - UDFReleaseResource(&(Vcb->IoResource)); - } _SEH2_END; - - return RC; -} // end UDFTSendIOCTL() - -/* - - Function: UDFPhSendIOCTL() - - Description: - UDF FSD will invoke this rotine to send IOCTL's to physical - device - - Return Value: STATUS_SUCCESS/Error - -*/ -NTSTATUS -NTAPI -UDFPhSendIOCTL( - IN ULONG IoControlCode, - IN PDEVICE_OBJECT DeviceObject, - IN PVOID InputBuffer , - IN ULONG InputBufferLength, - OUT PVOID OutputBuffer , - IN ULONG OutputBufferLength, - IN BOOLEAN OverrideVerify, - OUT PIO_STATUS_BLOCK Iosb OPTIONAL - ) -{ - NTSTATUS RC = STATUS_SUCCESS; - PIRP irp; - PUDF_PH_CALL_CONTEXT Context; - LARGE_INTEGER timeout; - - UDFPrint(("UDFPhDevIOCTL: Code %8x \n",IoControlCode)); - - Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); - if (!Context) return STATUS_INSUFFICIENT_RESOURCES; - // Check if the user gave us an Iosb. - - // Create notification event object to be used to signal the request completion. - KeInitializeEvent(&(Context->event), NotificationEvent, FALSE); - - irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer , - InputBufferLength, OutputBuffer, OutputBufferLength,FALSE,&(Context->event),&(Context->IosbToUse)); - - if (!irp) try_return (RC = STATUS_INSUFFICIENT_RESOURCES); - MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); -/* - if (KeGetCurrentIrql() > PASSIVE_LEVEL) { - UDFPrint(("Setting completion routine\n")); - IoSetCompletionRoutine( irp, &UDFSyncCompletionRoutine, - Context, TRUE, TRUE, TRUE ); - } -*/ - if (OverrideVerify) { - (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; - } - - RC = IoCallDriver(DeviceObject, irp); - - if (RC == STATUS_PENDING) { - ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); - UDFPrint(("Enter wait state on evt %x\n", Context)); - - if (KeGetCurrentIrql() > PASSIVE_LEVEL) { - timeout.QuadPart = -1000; - UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); - RC = DbgWaitForSingleObject(&(Context->event), &timeout); - while(RC == STATUS_TIMEOUT) { - timeout.QuadPart *= 2; - UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); - RC = DbgWaitForSingleObject(&(Context->event), &timeout); - } - - } else { - DbgWaitForSingleObject(&(Context->event), NULL); - } - if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { - RC = STATUS_SUCCESS; - } - UDFPrint(("Exit wait state on evt %x, status %8.8x\n", Context, RC)); -/* if (Iosb) { - (*Iosb) = Context->IosbToUse; - }*/ - } else { - UDFPrint(("No wait completion on evt %x\n", Context)); -/* if (Iosb) { - (*Iosb) = irp->IoStatus; - }*/ - } - - if (Iosb) { - (*Iosb) = Context->IosbToUse; - } - -try_exit: NOTHING; - - if (Context) MyFreePool__(Context); - return(RC); -} // end UDFPhSendIOCTL() - -VOID -UDFNotifyReportChange( - PIRP_CONTEXT IrpContext, - PVCB Vcb, - PFCB Fcb, - ULONG Filter, - ULONG Action, - PLCB Lcb, - PFILE_OBJECT FileObject - ) -{ - USHORT TargetNameOffset = 0; - UNICODE_STRING FullPath; - BOOLEAN PathAllocated = FALSE; - WCHAR RootChar; - - FullPath.Buffer = NULL; - FullPath.Length = 0; - FullPath.MaximumLength = 0; - - // - // Acquire FcbResource shared for the duration of the notify. - // Protects LCB chain and name buffers from concurrent teardown. - // - UDFAcquireFcbShared(IrpContext, Fcb, FALSE); - - _SEH2_TRY { - - // If no LCB provided, find first valid (non-deleted) one - if (!Lcb) { - if (!IsListEmpty(&Fcb->ParentLcbQueue)) { - PLIST_ENTRY ListEntry = Fcb->ParentLcbQueue.Flink; - while (ListEntry != &Fcb->ParentLcbQueue) { - PLCB CandidateLcb = CONTAINING_RECORD(ListEntry, LCB, ChildFcbLinks); - if (!(CandidateLcb->Flags & UDF_LCB_FLAG_LINK_DELETED)) { - Lcb = CandidateLcb; - break; - } - ListEntry = ListEntry->Flink; - } - } - } - - // - // Build the full target name. Prefer FileObject->FileName (stable - // pointer, does not depend on LCB chain state). Fall back to - // building from LCB chain. - // - if (FileObject && FileObject->FileName.Buffer && - FileObject->FileName.Length > 0) { - FullPath = FileObject->FileName; - } else if (Lcb) { - NTSTATUS Status = UDFBuildFullPathFromLcb(NULL, Lcb, &FullPath, FALSE); - if (NT_SUCCESS(Status)) { - PathAllocated = TRUE; - } - } - - // Fallback to root - if (!FullPath.Buffer || FullPath.Length == 0) { - RootChar = L'\\'; - FullPath.Buffer = &RootChar; - FullPath.Length = sizeof(WCHAR); - FullPath.MaximumLength = sizeof(WCHAR); - PathAllocated = FALSE; - Lcb = NULL; - } - - // TargetNameOffset: byte offset within FullPath to the final name component - if (Lcb && Lcb->ExactCaseLinkName.Length > 0 && - FullPath.Length > Lcb->ExactCaseLinkName.Length) { - TargetNameOffset = FullPath.Length - Lcb->ExactCaseLinkName.Length; - } - - FsRtlNotifyFullReportChange(Vcb->NotifySync, - &Vcb->NextNotifyIRP, - (PSTRING)&FullPath, - TargetNameOffset, - NULL, - NULL, - Filter, - Action, - NULL); - - } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { - NOTHING; - } _SEH2_END; - - UDFReleaseFcb(IrpContext, Fcb); - - if (PathAllocated && FullPath.Buffer) { - ExFreePool(FullPath.Buffer); - } -} - diff --git a/drivers/filesystems/udfs/fastio.cpp b/drivers/filesystems/udfs/fastio.c similarity index 99% rename from drivers/filesystems/udfs/fastio.cpp rename to drivers/filesystems/udfs/fastio.c index 9bdbac17b3f40..caf6f8dcf6672 100644 --- a/drivers/filesystems/udfs/fastio.cpp +++ b/drivers/filesystems/udfs/fastio.c @@ -899,7 +899,7 @@ UDFFastIoAcqModWrite( // For embedded data files, acquire exclusive since data shares sector with metadata // For normal files, shared is enough - BOOLEAN Acquired; + BOOLEAN Acquired = FALSE; if (Fcb->FcbState & UDF_FCB_EMBEDDED_DATA) { Acquired = UDFAcquireResourceExclusive(&Fcb->FcbNonpaged->FcbResource, FALSE); } else { diff --git a/drivers/filesystems/udfs/fileinfo.cpp b/drivers/filesystems/udfs/fileinfo.c similarity index 97% rename from drivers/filesystems/udfs/fileinfo.cpp rename to drivers/filesystems/udfs/fileinfo.c index 92fcd88eaf98e..6db7393bf33ab 100644 --- a/drivers/filesystems/udfs/fileinfo.cpp +++ b/drivers/filesystems/udfs/fileinfo.c @@ -123,6 +123,24 @@ UDFCommonQueryInfo( case FileAlternateNameInformation: Status = UDFGetAltNameInformation(Fcb, (PFILE_NAME_INFORMATION)Buffer, &Length); break; + case FileAttributeTagInformation: + { + PFILE_ATTRIBUTE_TAG_INFORMATION TagInfo = (PFILE_ATTRIBUTE_TAG_INFORMATION)Buffer; + + if (Length < (LONG)sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) { + Status = STATUS_BUFFER_TOO_SMALL; + break; + } + + TagInfo->FileAttributes = Fcb->FileAttributes; + if (!TagInfo->FileAttributes) { + TagInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL; + } + // UDF does not support reparse points + TagInfo->ReparseTag = 0; + Length -= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION); + } + break; //TODO: impl // case FileCompressionInformation: // // Status = UDFGetCompressionInformation(...); @@ -1468,7 +1486,8 @@ UDFSetAllocationInfo( // Yes. Do the FSD specific stuff i.e. increase reserved // space on disk. - if (((LONGLONG)UDFGetFreeSpace(Vcb) << Vcb->SectorShift) < Buffer->AllocationSize.QuadPart) { + if (((LONGLONG)UDFGetFreeSpace(Vcb) << Vcb->SectorShift) < + (Buffer->AllocationSize.QuadPart - Fcb->Header.AllocationSize.QuadPart)) { try_return(RC = STATUS_DISK_FULL); } // RC = STATUS_SUCCESS; @@ -1683,12 +1702,12 @@ UDFSetEndOfFileInfo( // reference file to pretend that it is opened UDFReferenceFile__(Fcb->FileInfo); - InterlockedIncrement((PLONG)&Fcb->FcbReference); + InterlockedIncrement(&Fcb->FcbReference); // perform resize operation RC = UDFResizeFile__(IrpContext, Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart); // dereference file UDFCloseFile__(IrpContext, Vcb, Fcb->FileInfo); - InterlockedDecrement((PLONG)&Fcb->FcbReference); + InterlockedDecrement(&Fcb->FcbReference); // update values in NtReqFcb Fcb->Header.FileSize.QuadPart = // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = @@ -1713,12 +1732,12 @@ UDFSetEndOfFileInfo( // Perform directory entry modifications. Release any on-disk // space we may need to in the process. UDFReferenceFile__(Fcb->FileInfo); - InterlockedIncrement((PLONG)&Fcb->FcbReference); + InterlockedIncrement(&Fcb->FcbReference); // perform resize operation RC = UDFResizeFile__(IrpContext, Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart); // dereference file UDFCloseFile__(IrpContext, Vcb, Fcb->FileInfo); - InterlockedDecrement((PLONG)&Fcb->FcbReference); + InterlockedDecrement(&Fcb->FcbReference); ModifiedAllocSize = TRUE; TruncatedFile = TRUE; @@ -1840,17 +1859,20 @@ 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); + + InterlockedIncrement(&Vcb->VcbReference); (*SingleDir) = ((Dir1 == Dir2) && (Dir1->Fcb)); if (!(*SingleDir) || (UDFGetFileLinkCount(File1) != 1)) { - InterlockedDecrement((PLONG)&Vcb->VcbReference); + InterlockedDecrement(&Vcb->VcbReference); } else { - InterlockedDecrement((PLONG)&Vcb->VcbReference); + InterlockedDecrement(&Vcb->VcbReference); + // Child-first lock ordering // File1 (child) first, Dir1 (parent) second @@ -1858,6 +1880,7 @@ UDFPrepareForRenameMoveLink( UDFAcquireFcbExclusive(IrpContext, File1->Fcb, TRUE); (*AcquiredFcb1) = TRUE; + UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb); UDFAcquireFcbExclusive(IrpContext, Dir1->Fcb, TRUE); (*AcquiredDir1) = TRUE; @@ -1865,61 +1888,6 @@ UDFPrepareForRenameMoveLink( 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 */ @@ -2109,12 +2077,6 @@ UDFSetRenameInfo( } } - // check if the source file is in use - if (Fcb->FcbCleanup > 1) { - - try_return (RC = STATUS_ACCESS_DENIED); - } - ASSERT(Fcb->FcbCleanup); ASSERT(!Fcb->IrpContextLite); @@ -2122,12 +2084,6 @@ UDFSetRenameInfo( 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 renaming to stream name - only allowed for streams if (!TargetFileObject && NewName.Length >= sizeof(WCHAR) && NewName.Buffer[0] == L':') { @@ -2141,8 +2097,8 @@ UDFSetRenameInfo( // 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). + // data stays intact: UDF files are addressed by physical ICB location, + // so moving a directory does not invalidate open handles to files inside. { // Note: With LCB model, FcbReference may not always be >= RefCount @@ -2284,6 +2240,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 +2249,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 +2265,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/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 95% rename from drivers/filesystems/udfs/flush.cpp rename to drivers/filesystems/udfs/flush.c index 65240f50e2a7e..ddd6d90a60332 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,25 +168,26 @@ 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; } if (!_SEH2_AbnormalTermination()) { - NTSTATUS DriverStatus; + NTSTATUS DriverStatus = STATUS_SUCCESS; // Get the next stack location, and copy over the stack location @@ -266,7 +267,8 @@ UDFFlushAFile( // Flush File _SEH2_TRY { if ((Fcb->CachedOpenHandleCount || !Fcb->FcbCleanup) && - Fcb->FcbNonpaged->SegmentObject.DataSectionObject) { + Fcb->FcbNonpaged->SegmentObject.DataSectionObject && + Fcb->FcbNonpaged->SegmentObject.SharedCacheMap) { if (!(Fcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) && (Fcb->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED)) { @@ -304,7 +306,7 @@ UDFFlushAFile( _SEH2_TRY { if (SetArchive && (Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) { - ULONG Attr; + ULONG Attr = 0; PDIR_INDEX_ITEM DirNdx; DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index); // Archive bit @@ -626,7 +628,7 @@ Return Value: { KEVENT Event; - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION NextIrpSp; PAGED_CODE(); diff --git a/drivers/filesystems/udfs/fscntrl.cpp b/drivers/filesystems/udfs/fscntrl.c similarity index 97% rename from drivers/filesystems/udfs/fscntrl.cpp rename to drivers/filesystems/udfs/fscntrl.c index 74982610e6a43..8d6c14e9eb5b0 100644 --- a/drivers/filesystems/udfs/fscntrl.cpp +++ b/drivers/filesystems/udfs/fscntrl.c @@ -49,7 +49,7 @@ UDFCommonFsControl( PIRP Irp ) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PAGED_CODE(); @@ -108,7 +108,7 @@ UDFUserFsCtrlRequest( PIRP Irp ) { - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); // Case on the control code. @@ -277,7 +277,7 @@ UDFMountVolume( IN PIRP Irp ) { - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PDEVICE_OBJECT DeviceObjectWeTalkTo = IrpSp->Parameters.MountVolume.DeviceObject; PVPB Vpb = IrpSp->Parameters.MountVolume.Vpb; @@ -288,15 +288,16 @@ UDFMountVolume( DEVICE_TYPE FsDeviceType; BOOLEAN RestoreDoVerify = FALSE; BOOLEAN RemovableMedia = TRUE; - BOOLEAN SetDoVerifyOnFail; + BOOLEAN SetDoVerifyOnFail = FALSE; BOOLEAN VcbAcquired = FALSE; BOOLEAN DeviceNotTouched = TRUE; DISK_GEOMETRY DiskGeometry; + PDEVICE_OBJECT RealDevice; ASSERT(IrpSp); UDFPrint(("\n !!! UDFMountVolume\n")); - auto RealDevice = Vpb->RealDevice; + RealDevice = Vpb->RealDevice; SetDoVerifyOnFail = UDFRealDevNeedsVerify(RealDevice); @@ -471,7 +472,7 @@ UDFMountVolume( // but simply cleanup and return error, Vcb->VcbReference // will be decremented during cleanup. Thus anyway it must // stay 1 unchanged here - //InterlockedDecrement((PLONG)&Vcb->VcbReference); + //InterlockedDecrement(&Vcb->VcbReference); UDFCloseResidual(IrpContext, Vcb); Vcb->VcbReference = 1; @@ -525,7 +526,7 @@ try_exit: NOTHING; } // Make sure there is no Vcb since it could go away if (Vcb->VcbReference) - InterlockedDecrement((PLONG)&Vcb->VcbReference); + InterlockedDecrement(&Vcb->VcbReference); // This procedure will also delete the volume device object if (UDFDismountVcb(IrpContext, Vcb, FALSE)) { UDFReleaseResource( &(Vcb->VcbResource) ); @@ -575,7 +576,7 @@ UDFCloseResidual( { // Deinitialize Non-alloc file if (Vcb->VcbReference) - InterlockedDecrement((PLONG)&Vcb->VcbReference); + InterlockedDecrement(&Vcb->VcbReference); UDFPrint(("UDFCloseResidual: NonAllocFileInfo %x\n", Vcb->NonAllocFileInfo)); if (Vcb->NonAllocFileInfo) { UDFCloseFile__(IrpContext, Vcb, Vcb->NonAllocFileInfo); @@ -650,7 +651,7 @@ UDFCloseResidual( } // Remove root FCB reference in vcb if (Vcb->VcbReference) - InterlockedDecrement((PLONG)&Vcb->VcbReference); + InterlockedDecrement(&Vcb->VcbReference); Vcb->RootIndexFcb = NULL; } } // end UDFCloseResidual() @@ -669,16 +670,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 +692,7 @@ UDFCleanupVCB( } #endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS if (Vcb->FSBM_OldBitmap) { - DbgFreePool(Vcb->FSBM_OldBitmap); + UDFFreeChunked(Vcb->FSBM_OldBitmap); Vcb->FSBM_OldBitmap = NULL; } @@ -886,7 +890,7 @@ UDFLockVolume( IN PIRP Irp ) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PVCB Vcb; PFCB Fcb; PCCB Ccb; @@ -981,7 +985,7 @@ Return Value: --*/ { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; KIRQL SavedIrql; NTSTATUS FinalStatus = (FileObject? STATUS_ACCESS_DENIED: STATUS_DEVICE_BUSY); ULONG RemainingUserReferences = (FileObject? 1: 0); @@ -997,7 +1001,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 ); // @@ -1071,7 +1075,7 @@ UDFUnlockVolume( IN PIRP Irp ) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PVCB Vcb; PFCB Fcb; @@ -1135,7 +1139,7 @@ UDFDismountVolume( IN PIRP Irp ) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; KIRQL SavedIrql; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); @@ -1181,7 +1185,7 @@ UDFDismountVolume( } else { - UDFFlushVolume(IrpContext, Vcb); + UDFFlushVolume(IrpContext, Vcb, 0); // Invalidate the volume right now. // @@ -1261,16 +1265,16 @@ UDFGetVolumeBitmap( PFCB Fcb; PCCB Ccb; PVCB Vcb = IrpContext->Vcb; - ULONG BytesToCopy; - ULONG TotalClusters; - ULONG StartingCluster; - ULONG DesiredClusters; - ULONG InputBufferLength; - ULONG OutputBufferLength; + ULONG BytesToCopy = 0; + ULONG TotalClusters = 0; + ULONG StartingCluster = 0; + ULONG DesiredClusters = 0; + ULONG InputBufferLength = 0; + ULONG OutputBufferLength = 0; LARGE_INTEGER StartingLcn; PVOLUME_BITMAP_BUFFER OutputBuffer; ULONG i, lim; - PULONG FSBM; + PULONG FSBM = NULL; BOOLEAN VcbAcquired = FALSE; ASSERT_VCB(Vcb); @@ -1411,13 +1415,13 @@ UDFGetRetrievalPointers( IN PIRP Irp ) { - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PUDF_FILE_INFO FileInfo; - ULONG InputBufferLength; - ULONG OutputBufferLength; + ULONG InputBufferLength = 0; + ULONG OutputBufferLength = 0; PRETRIEVAL_POINTERS_BUFFER OutputBuffer; PSTARTING_VCN_INPUT_BUFFER InputBuffer; @@ -1431,10 +1435,10 @@ UDFGetRetrievalPointers( TYPE_OF_OPEN TypeOfOpen; PEXTENT_MAP SubMapping = NULL; - ULONG SubExtInfoSz; - ULONG i; - ULONG LBS; - ULONG LBSh; + ULONG SubExtInfoSz = 0; + ULONG i = 0; + ULONG LBS = 0; + ULONG LBSh = 0; UDFPrint(("UDFGetRetrievalPointers\n")); @@ -1572,7 +1576,7 @@ UDFIsVolumeDirty( IN PIRP Irp ) { - PULONG VolumeState; + PULONG VolumeState = NULL; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PCCB Ccb; PFCB Fcb; @@ -1663,7 +1667,7 @@ UDFInvalidateVolumes( IN PIRP Irp ) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); UDFPrint(("UDFInvalidateVolumes\n")); @@ -1807,7 +1811,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 100% rename from drivers/filesystems/udfs/lockctrl.cpp rename to drivers/filesystems/udfs/lockctrl.c diff --git a/drivers/filesystems/udfs/mem.cpp b/drivers/filesystems/udfs/mem.c similarity index 93% rename from drivers/filesystems/udfs/mem.cpp rename to drivers/filesystems/udfs/mem.c index 072602c852327..301ead0d8ba72 100644 --- a/drivers/filesystems/udfs/mem.cpp +++ b/drivers/filesystems/udfs/mem.c @@ -8,4 +8,4 @@ // define the file specific bug-check id #define UDF_BUG_CHECK_ID UDF_FILE_MEM -#include "Include/mem_tools.cpp" +#include "Include/mem_tools.c" diff --git a/drivers/filesystems/udfs/misc.cpp b/drivers/filesystems/udfs/misc.c similarity index 98% rename from drivers/filesystems/udfs/misc.cpp rename to drivers/filesystems/udfs/misc.c index 75765fe90ce48..3d98abd3a47d4 100644 --- a/drivers/filesystems/udfs/misc.cpp +++ b/drivers/filesystems/udfs/misc.c @@ -60,7 +60,7 @@ UDFExceptionFilter( PEXCEPTION_POINTERS ExceptionPointer ) { - NTSTATUS ExceptionCode; + NTSTATUS ExceptionCode = STATUS_SUCCESS; ASSERT_OPTIONAL_IRP_CONTEXT(IrpContext); @@ -188,7 +188,7 @@ UDFProcessException( } else if ((ExceptionCode == STATUS_VERIFY_REQUIRED) && FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_TOP_LEVEL) && - KeAreAllApcsDisabled()) { + (KeGetCurrentIrql() >= APC_LEVEL)) { ExceptionCode = UDFFsdPostRequest(IrpContext, Irp); } @@ -501,7 +501,7 @@ UDFCreateIrpContext( } // TODO: fix - if (false && IrpSp->FileObject != NULL) { + if (FALSE && IrpSp->FileObject != NULL) { PFILE_OBJECT FileObject = IrpSp->FileObject; @@ -733,7 +733,7 @@ Return Value: { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - BOOLEAN RemovedFcb; + BOOLEAN RemovedFcb = FALSE; PAGED_CODE(); @@ -967,7 +967,7 @@ UDFFspDispatch( { THREAD_CONTEXT ThreadContext = { 0 }; PIRP_CONTEXT IrpContext = (PIRP_CONTEXT)Context; - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PIRP Irp = IrpContext->Irp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); @@ -1486,8 +1486,8 @@ UDFSetModified( IN PVCB Vcb ) { - if (InterlockedIncrement((PLONG) & (Vcb->Modified)) & 0x80000000) - Vcb->Modified = 2; + if (InterlockedIncrement(&Vcb->Modified) & 0x80000000) + InterlockedExchange(&Vcb->Modified, 2); } // end UDFSetModified() VOID @@ -1495,7 +1495,7 @@ UDFPreClrModified( IN PVCB Vcb ) { - Vcb->Modified = 1; + InterlockedExchange(&Vcb->Modified, 1); } // end UDFPreClrModified() VOID @@ -1504,7 +1504,7 @@ UDFClrModified( ) { UDFPrint(("ClrModified\n")); - InterlockedDecrement((PLONG)&Vcb->Modified); + InterlockedDecrement(&Vcb->Modified); } // end UDFClrModified() NTSTATUS @@ -1524,7 +1524,10 @@ UDFToggleMediaEjectDisable ( } else { - Vcb->VcbState ^= UDF_VCB_FLAGS_MEDIA_LOCKED; + if (PreventRemoval) + InterlockedOr((volatile LONG*)&Vcb->VcbState, UDF_VCB_FLAGS_MEDIA_LOCKED); + else + InterlockedAnd((volatile LONG*)&Vcb->VcbState, ~UDF_VCB_FLAGS_MEDIA_LOCKED); } Prevent.PreventMediaRemoval = PreventRemoval; @@ -1742,7 +1745,7 @@ Return Value: { BOOLEAN Wait = FALSE; - BOOLEAN Acquired; + BOOLEAN Acquired = FALSE; PAGED_CODE(); // We look first at the IgnoreWait flag, next at the flag in the Irp @@ -1867,5 +1870,5 @@ UDFWaitForIoAtEof( return TRUE; } -#include "Include/regtools.cpp" +#include "Include/regtools.c" diff --git a/drivers/filesystems/udfs/namesup.cpp b/drivers/filesystems/udfs/namesup.c similarity index 100% rename from drivers/filesystems/udfs/namesup.cpp rename to drivers/filesystems/udfs/namesup.c diff --git a/drivers/filesystems/udfs/pnp.cpp b/drivers/filesystems/udfs/pnp.c similarity index 99% rename from drivers/filesystems/udfs/pnp.cpp rename to drivers/filesystems/udfs/pnp.c index 55b1e02f0eeb3..1569d5312da4d 100644 --- a/drivers/filesystems/udfs/pnp.cpp +++ b/drivers/filesystems/udfs/pnp.c @@ -228,7 +228,7 @@ Return Value: --*/ { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; KEVENT Event; BOOLEAN VcbPresent = TRUE; @@ -399,7 +399,7 @@ Return Value: --*/ { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; KEVENT Event; BOOLEAN VcbPresent = TRUE; @@ -542,7 +542,7 @@ Return Value: --*/ { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; KEVENT Event; BOOLEAN VcbPresent = TRUE; @@ -660,7 +660,7 @@ Return Value: --*/ { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); diff --git a/drivers/filesystems/udfs/prefxsup.cpp b/drivers/filesystems/udfs/prefxsup.c similarity index 99% rename from drivers/filesystems/udfs/prefxsup.cpp rename to drivers/filesystems/udfs/prefxsup.c index 5bc2a4ff3aeda..7c1b0223a243d 100644 --- a/drivers/filesystems/udfs/prefxsup.cpp +++ b/drivers/filesystems/udfs/prefxsup.c @@ -577,7 +577,7 @@ UDFAcquirePrefix( // Increment parent refs immediately after LCB creation. // These will be decremented in UDFTeardownStructures when LCB is removed. // - InterlockedIncrement((PLONG)&ParentFcb->FcbReference); + InterlockedIncrement(&ParentFcb->FcbReference); if (ParentFcb->FileInfo) { UDFReferenceFile__(ParentFcb->FileInfo); } @@ -609,7 +609,7 @@ UDFReleasePrefix( ASSERT(Lcb->NodeIdentifier.NodeTypeCode == UDF_NODE_TYPE_LCB); ASSERT(Lcb->Reference > 0); - InterlockedDecrement((PLONG)&Lcb->Reference); + InterlockedDecrement(&Lcb->Reference); } // end UDFReleasePrefix() @@ -899,7 +899,7 @@ UDFReleasePrefixImmediate( // // Decrement reference // - NewRef = InterlockedDecrement((PLONG)&Lcb->Reference); + NewRef = InterlockedDecrement(&Lcb->Reference); if (NewRef > 0) { // @@ -925,7 +925,7 @@ UDFReleasePrefixImmediate( // if (ParentFcb) { ASSERT(ParentFcb->FcbReference > 0); - InterlockedDecrement((PLONG)&ParentFcb->FcbReference); + InterlockedDecrement(&ParentFcb->FcbReference); // // Close parent's FileInfo if requested @@ -1314,14 +1314,14 @@ UDFRenameMovePrefix( // Adjust reference counts if (OldParentFcb) { ASSERT(OldParentFcb->FcbReference > 0); - InterlockedDecrement((PLONG)&OldParentFcb->FcbReference); + InterlockedDecrement(&OldParentFcb->FcbReference); if (OldParentFileInfo && OldParentFcb->Vcb) { UDFCloseFile__(IrpContext, OldParentFcb->Vcb, OldParentFileInfo); } } - InterlockedIncrement((PLONG)&NewParentFcb->FcbReference); + InterlockedIncrement(&NewParentFcb->FcbReference); if (NewParentFcb->FileInfo) { UDFReferenceFile__(NewParentFcb->FileInfo); diff --git a/drivers/filesystems/udfs/protos.h b/drivers/filesystems/udfs/protos.h index acaa3cd52b8b4..49a5910c31ab0 100644 --- a/drivers/filesystems/udfs/protos.h +++ b/drivers/filesystems/udfs/protos.h @@ -445,11 +445,6 @@ UDFSetEndOfFileInfo( IN PFILE_END_OF_FILE_INFORMATION PtrBuffer ); -BOOLEAN -UDFCheckDirOpenHandles( - IN PFCB DirectoryFcb - ); - NTSTATUS UDFSetRenameInfo( IN PIRP_CONTEXT IrpContext, @@ -512,7 +507,7 @@ ULONG UDFFlushAFile( IN PFCB Fcb, IN PCCB Ccb, OUT PIO_STATUS_BLOCK PtrIoStatus, - IN ULONG FlushFlags = 0 + IN ULONG FlushFlags ); ULONG @@ -521,14 +516,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 +533,7 @@ PVOID Context); extern BOOLEAN UDFFlushIsBreaking( IN PVCB Vcb, -IN ULONG FlushFlags = 0); +IN ULONG FlushFlags); extern VOID UDFFlushTryBreak( IN PVCB Vcb); @@ -693,6 +688,8 @@ UDFFastUnlockAllByKey( * Prototypes for the file misc.cpp *************************************************************************/ + + _IRQL_requires_max_(APC_LEVEL) __drv_dispatchType(DRIVER_DISPATCH) __drv_dispatchType(IRP_MJ_CREATE) @@ -868,6 +865,8 @@ UDFInsertFcbIntoTable( _In_ PFCB Fcb ); + + _Ret_valid_ PIRP_CONTEXT UDFCreateIrpContext( _In_ PIRP Irp, @@ -925,7 +924,7 @@ UDFReadRegKeys( extern ULONG UDFGetRegParameter( IN PVCB Vcb, IN PCWSTR Name, - IN ULONG DefValue = 0); + IN ULONG DefValue); VOID UDFDeleteVCB( @@ -1047,7 +1046,7 @@ UDFCommonShutdown( /************************************************************************* * Prototypes for the file UDFinit.cpp *************************************************************************/ -extern "C" NTSTATUS NTAPI DriverEntry( +NTSTATUS NTAPI DriverEntry( PDRIVER_OBJECT DriverObject, // created by the I/O sub-system PUNICODE_STRING RegistryPath); // path to the registry key @@ -1337,6 +1336,8 @@ enum TYPE_OF_ACQUIRE { }; +typedef enum TYPE_OF_ACQUIRE TYPE_OF_ACQUIRE; + _Requires_lock_held_(_Global_critical_region_) _When_(Type == AcquireExclusive && return != FALSE, _Acquires_exclusive_lock_(*Resource)) _When_(Type == AcquireShared && return != FALSE, _Acquires_shared_lock_(*Resource)) @@ -1380,10 +1381,13 @@ UDFAcquireResource( #define UDFAcquirePagingIoExclusive(IC,F) \ UDFAcquireResource((IC), (F)->Header.PagingIoResource, FALSE, AcquireExclusive) +#define UDFAcquirePagingIoShared(IC,F) \ + UDFAcquireResource((IC), (F)->Header.PagingIoResource, FALSE, AcquireShared) + #define UDFReleasePagingIo(IC,F) \ ExReleaseResourceLite((F)->Header.PagingIoResource) -inline +static inline ULONG UDFHighBit( ULONG Word @@ -1407,7 +1411,7 @@ UDFHighBit( #define SectorSize(V) ((V)->SectorSize) -inline +static inline ULONG SectorAlign( PVCB Vcb, @@ -1417,7 +1421,7 @@ SectorAlign( return (Length + (Vcb->SectorSize - 1)) & ~(Vcb->SectorSize - 1); } -inline +static inline ULONGLONG LlSectorAlign( PVCB Vcb, @@ -1439,7 +1443,7 @@ UDFSetThreadContext( (IC)->ThreadContext = NULL -inline +static inline BOOLEAN UdfIsExtendedFESupported( _In_ PVCB Vcb ) @@ -1447,7 +1451,7 @@ BOOLEAN UdfIsExtendedFESupported( return Vcb->NSRDesc == VRS_NSR03_FOUND; } -inline +static inline BOOLEAN UDFIsStreamsSupported( _In_ PVCB Vcb ) diff --git a/drivers/filesystems/udfs/read.cpp b/drivers/filesystems/udfs/read.c similarity index 94% rename from drivers/filesystems/udfs/read.cpp rename to drivers/filesystems/udfs/read.c index c920331dee579..ff88dcd36e288 100644 --- a/drivers/filesystems/udfs/read.cpp +++ b/drivers/filesystems/udfs/read.c @@ -56,8 +56,8 @@ UDFCommonRead( PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); LONGLONG StartingOffset; LONGLONG ByteRange; - ULONG ReadLength; - ULONG ByteCount; + ULONG ReadLength = 0; + ULONG ByteCount = 0; ULONG NumberBytesRead = 0; LONGLONG FileSize; TYPE_OF_OPEN TypeOfOpen; @@ -66,12 +66,13 @@ UDFCommonRead( PVCB Vcb = NULL; BOOLEAN VcbAcquired = FALSE; BOOLEAN FcbAcquired = FALSE; + BOOLEAN PagingIoResourceAcquired = FALSE; PVOID SystemBuffer = NULL; - BOOLEAN Wait; - BOOLEAN PagingIo; - BOOLEAN NonCachedIo; - BOOLEAN SynchronousIo; + BOOLEAN Wait = FALSE; + BOOLEAN PagingIo = FALSE; + BOOLEAN NonCachedIo = FALSE; + BOOLEAN SynchronousIo = FALSE; // Read request byte range visualization: // @@ -154,9 +155,16 @@ UDFCommonRead( // Acquire the appropriate FCB resource shared if (PagingIo) { - + // Don't offload jobs when doing paging IO - otherwise this can lead to + // deadlocks in CcCopyRead. + Wait = TRUE; UDFAcquireFcbSharedStarveExclusive(IrpContext, Fcb, FALSE); FcbAcquired = TRUE; + // Acquire PagingIo resource shared to serialize with writes that hold + // it exclusively while modifying the extent mapping (UDFResizeExtent). + // This prevents a use-after-free when iterating DataLoc.Mapping. + UDFAcquirePagingIoShared(IrpContext, Fcb); + PagingIoResourceAcquired = TRUE; } else { @@ -309,6 +317,7 @@ UDFCommonRead( Status = UDFReadFile__(IrpContext, Vcb, Fcb->FileInfo, StartingOffset, ByteCount, FALSE, (PCHAR)SystemBuffer, &NumberBytesRead); + /* // AFAIU, CacheManager wants this: if (!NT_SUCCESS(RC)) { NumberBytesRead = 0; @@ -406,6 +415,9 @@ try_exit: NOTHING; } _SEH2_FINALLY { + if (PagingIoResourceAcquired) { + UDFReleasePagingIo(IrpContext, Fcb); + } if (FcbAcquired) { UDFReleaseFcb(IrpContext, Fcb); @@ -523,9 +535,11 @@ UDFLockUserBuffer( // Is a MDL already present in the IRP if (!IrpContext->Irp->MdlAddress) { - // This will place allocated Mdl to Irp - if (!(Mdl = IoAllocateMdl(IrpContext->Irp->UserBuffer, BufferLength, FALSE, FALSE, IrpContext->Irp))) { - + // Use MmCreateMdl instead of IoAllocateMdl so that large buffers + // (> ~64 MB) are not rejected on Windows XP/Server 2003, where + // IoAllocateMdl returns NULL when the MDL size exceeds MAXUSHORT. + Mdl = MmCreateMdl(NULL, IrpContext->Irp->UserBuffer, BufferLength); + if (!Mdl) { return(RC = STATUS_INSUFFICIENT_RESOURCES); } @@ -542,10 +556,13 @@ UDFLockUserBuffer( } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { IoFreeMdl(Mdl); - IrpContext->Irp->MdlAddress = NULL; RC = STATUS_INVALID_USER_BUFFER; } _SEH2_END; + + if (NT_SUCCESS(RC)) { + IrpContext->Irp->MdlAddress = Mdl; + } } return(RC); diff --git a/drivers/filesystems/udfs/secursup.cpp b/drivers/filesystems/udfs/secursup.c similarity index 99% rename from drivers/filesystems/udfs/secursup.cpp rename to drivers/filesystems/udfs/secursup.c index 8328d7599e110..94484697ef2b8 100644 --- a/drivers/filesystems/udfs/secursup.cpp +++ b/drivers/filesystems/udfs/secursup.c @@ -29,7 +29,7 @@ UDFCheckAccessRights( USHORT ShareAccess ) { - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; BOOLEAN ROCheck = FALSE; // Check attr compatibility diff --git a/drivers/filesystems/udfs/shutdown.cpp b/drivers/filesystems/udfs/shutdown.c similarity index 97% rename from drivers/filesystems/udfs/shutdown.cpp rename to drivers/filesystems/udfs/shutdown.c index 93dd97b067f36..ab0c904500a6b 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, @@ -173,14 +173,13 @@ UDFCommonShutdown( IoUnregisterFileSystem(UdfData.UDFDeviceObject_CD); if (UdfData.UDFDeviceObject_CD) { IoDeleteDevice(UdfData.UDFDeviceObject_CD); - UdfData.UDFDeviceObject_CD = NULL; } IoUnregisterFileSystem(UdfData.UDFDeviceObject_HDD); if (UdfData.UDFDeviceObject_HDD) { IoDeleteDevice(UdfData.UDFDeviceObject_HDD); - 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.c similarity index 97% rename from drivers/filesystems/udfs/strucsup.cpp rename to drivers/filesystems/udfs/strucsup.c index 6e746f30fc8a4..3395822747ed8 100644 --- a/drivers/filesystems/udfs/strucsup.cpp +++ b/drivers/filesystems/udfs/strucsup.c @@ -144,6 +144,7 @@ Return Value: ExInitializeResourceLite(&FcbNonpaged->FcbPagingIoResource); ExInitializeResourceLite(&FcbNonpaged->FcbResource); + ExInitializeResourceLite(&FcbNonpaged->CcbListResource); ExInitializeFastMutex(&FcbNonpaged->FcbMutex); ExInitializeFastMutex(&FcbNonpaged->AdvancedFcbHeaderMutex); ExInitializeFastMutex(&FcbNonpaged->FcbFastMutex); @@ -175,11 +176,23 @@ Return Value: { PAGED_CODE(); - + UNREFERENCED_PARAMETER(IrpContext); - + + // Acquire each resource exclusively to drain any active holders before + // calling ExDeleteResourceLite. Freeing a pool block that still contains + // an active ERESOURCE triggers Driver Verifier bugcheck 0xC4/0xD2. + ExAcquireResourceExclusiveLite(&FcbNonpaged->FcbPagingIoResource, TRUE); + ExReleaseResourceLite(&FcbNonpaged->FcbPagingIoResource); + + ExAcquireResourceExclusiveLite(&FcbNonpaged->FcbResource, TRUE); + ExReleaseResourceLite(&FcbNonpaged->FcbResource); + ExDeleteResourceLite(&FcbNonpaged->FcbResource); ExDeleteResourceLite(&FcbNonpaged->FcbPagingIoResource); + ExDeleteResourceLite(&FcbNonpaged->CcbListResource); + + UDFDeallocateFcbNonpaged(FcbNonpaged); @@ -293,8 +306,8 @@ Return Value: if (Vcb != NULL) { - InterlockedDecrement( (LONG*)&Vcb->VcbReference ); - InterlockedDecrement( (LONG*)&Vcb->VcbUserReference ); + InterlockedDecrement(&Vcb->VcbReference ); + InterlockedDecrement(&Vcb->VcbUserReference ); } return; @@ -458,7 +471,7 @@ UDFTeardownStructures( if (ParentFcb->FileInfo) { UDFCloseFile__(IrpContext, Vcb, ParentFcb->FileInfo); } - InterlockedDecrement((PLONG)&ParentFcb->FcbReference); + InterlockedDecrement(&ParentFcb->FcbReference); UDFUnlockVcb(IrpContext, Vcb); } @@ -510,14 +523,14 @@ UDFTeardownStructures( // no more references... current file/dir MUST DIE!!! if (Delete) { UDFReferenceFile__(CurrentFcb->FileInfo); - UDFFlushFile__(IrpContext, Vcb, CurrentFcb->FileInfo); + UDFFlushFile__(IrpContext, Vcb, CurrentFcb->FileInfo, 0); 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); + UDFFlushFile__(IrpContext, Vcb, CurrentFcb->FileInfo, 0); } else { // File is already deleted - clear Modified flags without flushing to disk. @@ -765,7 +778,7 @@ Return Value: { PFCB NewFcb; - BOOLEAN LocalFcbExisted; + BOOLEAN LocalFcbExisted = FALSE; PAGED_CODE(); @@ -902,10 +915,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 +1091,7 @@ UDFInitializeVCB( ExInitializeResourceLite(&Vcb->VcbResource); ExInitializeResourceLite(&Vcb->BitMapResource1); + ExInitializeResourceLite(&Vcb->DlocResource); ExInitializeResourceLite(&Vcb->DlocResource2); ExInitializeResourceLite(&Vcb->FlushResource); @@ -1162,6 +1178,7 @@ UDFInitializeVCB( // TRUE, // We will use pinned access. // &(UDFGlobalData.CacheMgrCallBacks), Vcb); + Vcb->SectorSize = DiskGeometry->BytesPerSector; Vcb->SectorShift = UDFHighBit(DiskGeometry->BytesPerSector); Vcb->MediaChangeCount = MediaChangeCount; @@ -1175,17 +1192,19 @@ UDFInitializeVCB( } _SEH2_END; } // end UDFInitializeVCB() + + NTSTATUS UDFCompleteMount( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb ) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING LocalPath; ULONG LastSector = 0; BOOLEAN UnlockVcb = FALSE; - FILE_ID FileId{}; + FILE_ID FileId = { 0 }; PAGED_CODE(); @@ -1274,7 +1293,7 @@ UDFCompleteMount( UDFInsertFcbIntoTable(IrpContext, Vcb->RootIndexFcb); // this is a part of UDF_RESIDUAL_REFERENCE - InterlockedIncrement((PLONG)&Vcb->VcbReference); + InterlockedIncrement(&Vcb->VcbReference); Vcb->RootIndexFcb->FcbCleanup = 1; Vcb->RootIndexFcb->FcbReference = 1; @@ -1305,7 +1324,7 @@ UDFCompleteMount( // Open Unallocatable space stream // Generally, it should be placed in SystemStreamDirectory, but some // stupid apps think that RootDirectory is much better place.... :(( - LocalPath = RTL_CONSTANT_STRING(UDF_FN_NON_ALLOCATABLE); + RtlInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE); Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->RootIndexFcb->FileInfo, &Vcb->NonAllocFileInfo, NULL); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { @@ -1314,7 +1333,7 @@ UDFCompleteMount( UDFCleanUpFile__(Vcb, Vcb->NonAllocFileInfo); Vcb->NonAllocFileInfo = NULL; // this was a part of UDF_RESIDUAL_REFERENCE - InterlockedDecrement((PLONG)&Vcb->VcbReference); + InterlockedDecrement(&Vcb->VcbReference); unwind_1: // UDFCloseResidual() will clean up everything @@ -1328,7 +1347,7 @@ UDFCompleteMount( UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; } else { /* try to read Non-allocatable from alternate locations */ - LocalPath = RTL_CONSTANT_STRING(UDF_FN_NON_ALLOCATABLE_2); + RtlInitUnicodeString(&LocalPath, UDF_FN_NON_ALLOCATABLE_2); Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->RootIndexFcb->FileInfo, &(Vcb->NonAllocFileInfo), NULL); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { goto unwind_1; @@ -1338,7 +1357,7 @@ UDFCompleteMount( UDFDirIndex(UDFGetDirIndexByFileInfo(Vcb->NonAllocFileInfo), Vcb->NonAllocFileInfo->Index)->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; } else if (Vcb->SysSDirFileInfo) { - LocalPath = RTL_CONSTANT_STRING(UDF_SN_NON_ALLOCATABLE); + RtlInitUnicodeString(&LocalPath, UDF_SN_NON_ALLOCATABLE); Status = UDFOpenFile__(IrpContext, Vcb, FALSE, TRUE, &LocalPath, Vcb->SysSDirFileInfo , &(Vcb->NonAllocFileInfo), NULL); if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { goto unwind_1; @@ -1357,7 +1376,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); @@ -1383,7 +1402,7 @@ UDFCompleteMount( UDFPreClrModified(Vcb); UDFClrModified(Vcb); // this is a part of UDF_RESIDUAL_REFERENCE - InterlockedIncrement((PLONG)&Vcb->VcbReference); + InterlockedIncrement(&Vcb->VcbReference); // Start initializing the fields contained in the Header. diff --git a/drivers/filesystems/udfs/struct.h b/drivers/filesystems/udfs/struct.h index 74c032224266d..f7ac37d663539 100644 --- a/drivers/filesystems/udfs/struct.h +++ b/drivers/filesystems/udfs/struct.h @@ -31,6 +31,9 @@ /************************************************************************** include udf related structures *here* (because we need definition of Fcb) **************************************************************************/ +/* FCB is defined later in this file; pre-declare it so udf_rel.h can use FCB* */ +struct FCB; +typedef struct FCB FCB; #include "udf_info/udf_rel.h" struct IRP_CONTEXT_LITE; @@ -38,6 +41,22 @@ struct IO_CONTEXT; struct IRP_CONTEXT; struct LCB; +/* C typedef aliases – allow plain name usage without the 'struct' keyword */ +typedef struct IRP_CONTEXT_LITE IRP_CONTEXT_LITE; +typedef struct IO_CONTEXT IO_CONTEXT; +typedef struct IRP_CONTEXT IRP_CONTEXT; +typedef struct LCB LCB; +typedef struct UDFIdentifier UDFIdentifier; +typedef struct UDFObjectName UDFObjectName; +typedef struct CCB CCB; +typedef struct FCB_NONPAGED FCB_NONPAGED; +typedef struct FCB_DATA FCB_DATA; +typedef struct FCB_INDEX FCB_INDEX; +typedef struct FCB FCB; +typedef struct VCB VCB; +typedef struct VOLUME_DEVICE_OBJECT VOLUME_DEVICE_OBJECT; +typedef struct THREAD_CONTEXT THREAD_CONTEXT; + /************************************************************************** every structure has a node type, and a node size associated with it. The node type serves as a signature field. The size is used for @@ -48,8 +67,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 +86,7 @@ struct UDFObjectName { // an absolute pathname of the object is stored below UNICODE_STRING ObjectName; }; -using PtrUDFObjectName = UDFObjectName*; +typedef UDFObjectName* PtrUDFObjectName; /************************************************************************** Each file open instance is represented by a context control block. @@ -107,7 +125,7 @@ struct CCB { PUNICODE_STRING DirectorySearchPattern; HASH_ENTRY hashes; }; -using PCCB = CCB*; +typedef CCB* PCCB; #define CCB_FLAG_IGNORE_CASE (0x00000004) // the CCB has had an IRP_MJ_CLEANUP issued on it. we must @@ -151,6 +169,8 @@ struct FCB_NONPAGED { ERESOURCE FcbPagingIoResource; + ERESOURCE CcbListResource; + // This is the FastMutex for this Fcb. FAST_MUTEX FcbMutex; @@ -165,7 +185,7 @@ struct FCB_NONPAGED { FAST_MUTEX FcbFastMutex; }; -using PFCB_NONPAGED = FCB_NONPAGED*; +typedef FCB_NONPAGED* PFCB_NONPAGED; /************************************************************************** each open file/directory/volume is represented by a file control block. @@ -206,11 +226,11 @@ using PFCB_NONPAGED = FCB_NONPAGED*; /***************************************************/ struct FCB_DATA { - + UCHAR Placeholder; }; struct FCB_INDEX { - + UCHAR Placeholder; }; struct FCB { @@ -245,10 +265,10 @@ struct FCB { // But when we have mapped data, we can receive no IRP_MJ_CLOSE // In this case OpenHandleCount may reach zero, but ReferenceCount may // be non-zero. - ULONG FcbReference; - ULONG FcbCleanup; - ULONG CachedOpenHandleCount; - ULONG FcbUserReference; + LONG FcbReference; + LONG FcbCleanup; + LONG CachedOpenHandleCount; + LONG FcbUserReference; // State flags for this Fcb. @@ -312,7 +332,7 @@ struct FCB { FCB_INDEX FcbIndex; }; }; -using PFCB = FCB*; +typedef FCB* PFCB; #define SIZEOF_FCB_DATA \ (FIELD_OFFSET(FCB, FcbType) + sizeof(FCB_DATA)) @@ -355,7 +375,7 @@ using PFCB = FCB*; **************************************************************************/ -enum UDFFSD_MEDIA_TYPE { +typedef enum UDFFSD_MEDIA_TYPE { MediaUnknown = 0, MediaHdd, MediaCdr, @@ -365,7 +385,7 @@ enum UDFFSD_MEDIA_TYPE { MediaFloppy, MediaDvdr, MediaDvdrw -}; +} UDFFSD_MEDIA_TYPE; //*************************************************************************** // LCB (Link Control Block) @@ -398,7 +418,7 @@ struct LCB { ULONGLONG InitialOffset; // +0x38 Initial offset // Reference count (incremented by CCB, decremented on cleanup) - ULONG Reference; // +0x40 Reference count + LONG Reference; // +0x40 Reference count // LCB flags ULONG Flags; // +0x44 LCB flags @@ -439,7 +459,7 @@ struct LCB { UNICODE_STRING FileName; // +0xE8 File name }; -using PLCB = LCB*; +typedef LCB* PLCB; // LCB Flags #define UDF_LCB_FLAG_POOL_ALLOCATED 0x00000001 // Allocated from pool (not lookaside) @@ -465,14 +485,14 @@ using PLCB = LCB*; // VCB (Volume Control Block) //*************************************************************************** -enum VCB_CONDITION { +typedef enum VCB_CONDITION { VcbNotMounted = 0, VcbMountInProgress, VcbMounted, VcbInvalid, VcbDismountInProgress -}; +} VCB_CONDITION; struct VCB { @@ -481,11 +501,11 @@ struct VCB { // Condition flag for the Vcb. VCB_CONDITION VcbCondition; - ULONG VcbCleanup; - ULONG VcbReference; - ULONG VcbUserReference; - ULONG VcbResidualReference; - ULONG VcbResidualUserReference; + LONG VcbCleanup; + LONG VcbReference; + LONG VcbUserReference; + LONG VcbResidualReference; + LONG VcbResidualUserReference; ERESOURCE FlushResource; // Link into queue of Vcb's in the CdData structure. We will create a union with @@ -653,12 +673,12 @@ struct VCB { uint16 minUDFWriteRev; uint16 maxUDFWriteRev; // file/dir counters for Mac OS - uint32 numFiles; - uint32 numDirs; + LONG numFiles; + LONG numDirs; // VAT uint32 InitVatCount; uint32 VatCount; - uint32* Vat; + PCHAR Vat; uint32 VatPartNdx; PUDF_FILE_INFO VatFileInfo; // sparing table @@ -684,6 +704,7 @@ struct VCB { PCHAR FSBM_OldBitmap; // 0 - free, 1 - used ULONG BitmapModified; + ULONG BitmapSearchHint; // LBA hint for next free space search (roving pointer) PCHAR BSBM_Bitmap; // 0 - normal, 1 - bad-block // pointers to Volume Descriptor Sequences @@ -692,7 +713,7 @@ struct VCB { ULONG VDS2; ULONG VDS2_Len; - ULONG Modified; + LONG Modified; // System Stream Dir PUDF_FILE_INFO SysSDirFileInfo; @@ -727,8 +748,6 @@ struct VCB { uint32 CompatFlags; - // Fcb table. Synchronized with FcbTableMutex. - RTL_GENERIC_TABLE FcbTable; // Preallocated VPB for swapout, so we are not forced to consider @@ -736,7 +755,7 @@ struct VCB { PVPB SwapVpb; }; -using PVCB = VCB*; +typedef VCB* PVCB; // One for root #define UDFS_BASE_RESIDUAL_REFERENCE (4)//(6) @@ -810,7 +829,7 @@ struct THREAD_CONTEXT { // will store the IrpContext for the request in this stack location. IRP_CONTEXT* TopLevelIrpContext; }; -using PTHREAD_CONTEXT = THREAD_CONTEXT*; +typedef THREAD_CONTEXT* PTHREAD_CONTEXT; /************************************************************************** The IRP context encapsulates the current request. This structure is @@ -854,7 +873,7 @@ struct IRP_CONTEXT { VCB* Vcb; }; -using PIRP_CONTEXT = IRP_CONTEXT*; +typedef IRP_CONTEXT* PIRP_CONTEXT; #define IRP_CONTEXT_FLAG_ON_STACK (0x00000001) #define IRP_CONTEXT_FLAG_MORE_PROCESSING (0x00000002) @@ -919,7 +938,7 @@ struct IRP_CONTEXT_LITE { // Real device object. This represents the physical device closest to the media. PDEVICE_OBJECT RealDevice; }; -using PIRP_CONTEXT_LITE = IRP_CONTEXT_LITE*; +typedef IRP_CONTEXT_LITE* PIRP_CONTEXT_LITE; /************************************************************************** we will store all of our global variables in one structure. diff --git a/drivers/filesystems/udfs/sys_spec.cpp b/drivers/filesystems/udfs/sys_spec.c similarity index 95% rename from drivers/filesystems/udfs/sys_spec.cpp rename to drivers/filesystems/udfs/sys_spec.c index e9a11ab152817..df66b8c66f22e 100644 --- a/drivers/filesystems/udfs/sys_spec.cpp +++ b/drivers/filesystems/udfs/sys_spec.c @@ -20,6 +20,6 @@ // define the file specific bug-check id #define UDF_BUG_CHECK_ID UDF_FILE_SYS_SPEC -#include "Include/Sys_spec_lib.cpp" +#include "Include/Sys_spec_lib.c" //#include "Include/tools.cpp" diff --git a/drivers/filesystems/udfs/udf_dbg.cpp b/drivers/filesystems/udfs/udf_dbg.c similarity index 99% rename from drivers/filesystems/udfs/udf_dbg.cpp rename to drivers/filesystems/udfs/udf_dbg.c index 0d16f8280a41e..547252df0c8b8 100644 --- a/drivers/filesystems/udfs/udf_dbg.cpp +++ b/drivers/filesystems/udfs/udf_dbg.c @@ -134,7 +134,7 @@ DbgWaitForSingleObject_( PLARGE_INTEGER to; LARGE_INTEGER dto; // LARGE_INTEGER cto; - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; ULONG c = 20; dto.QuadPart = -5LL*1000000LL*10LL; // 5 sec diff --git a/drivers/filesystems/udfs/udf_dbg.h b/drivers/filesystems/udfs/udf_dbg.h index 63fc430bc3c83..476876991c723 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, ... ); @@ -61,13 +61,13 @@ #ifdef USE_KD_PRINT #define KdPrint(_x_) DbgPrint _x_ #else - #define KdPrint(a) {NOTHING;} + #define KdPrint(a) ((void)0) #endif //USE_KD_PRINT #ifdef USE_MM_PRINT #define MmPrint(_x_) DbgPrint _x_ #else - #define MmPrint(_x_) {NOTHING;} + #define MmPrint(_x_) ((void)0) #endif //USE_MM_PRINT #ifdef USE_TIME_PRINT @@ -80,29 +80,29 @@ #ifdef USE_AD_PRINT #define AdPrint(_x_) {DbgPrint("Thrd:%x:",PsGetCurrentThread());DbgPrint _x_;} #else - #define AdPrint(_x_) {NOTHING;} + #define AdPrint(_x_) ((void)0) #endif #ifdef USE_TH_PRINT #define ThPrint(_x_) {DbgPrint("Thrd:%x:",PsGetCurrentThread());DbgPrint _x_;} #else - #define ThPrint(_x_) {NOTHING;} + #define ThPrint(_x_) ((void)0) #endif #ifdef UDF_DUMP_EXTENT #define ExtPrint(_x_) KdPrint(_x_) #else - #define ExtPrint(_x_) {NOTHING;} + #define ExtPrint(_x_) ((void)0) #endif #else // defined UDF_DBG || defined PRINT_ALWAYS - #define MmPrint(_x_) {NOTHING;} - #define TmPrint(_x_) {NOTHING;} - #define PerfPrint(_x_) {NOTHING;} - #define AdPrint(_x_) {NOTHING;} - #define ThPrint(_x_) {NOTHING;} - #define ExtPrint(_x_) {NOTHING;} + #define MmPrint(_x_) ((void)0) + #define TmPrint(_x_) ((void)0) + #define PerfPrint(_x_) ((void)0) + #define AdPrint(_x_) ((void)0) + #define ThPrint(_x_) ((void)0) + #define ExtPrint(_x_) ((void)0) #endif // defined UDF_DBG || defined PRINT_ALWAYS @@ -120,24 +120,18 @@ DbgWaitForSingleObject_( #ifdef UDF_DBG -#ifdef _X86_ -// This is an illegal use of INT3 -#define UDFBreakPoint() { __asm int 3 } -#else // _X86_ - -#define UDFBreakPoint() DbgBreakPoint() -#endif // _X86_ +#define UDFBreakPoint() __debugbreak() #ifdef BRUTE #define BrutePoint() UDFBreakPoint() #else -#define BrutePoint() {} +#define BrutePoint() ((void)0) #endif // BRUTE #ifdef CHECK_REF_COUNTS #define ASSERT_REF(_a_) ASSERT(_a_) #else -#define ASSERT_REF(_a_) {NOTHING;} +#define ASSERT_REF(_a_) ((void)0) #endif //CHECK_REF_COUNTS #ifdef TRACK_SYS_ALLOCS @@ -186,29 +180,15 @@ VOID DebugFreePool(PVOID addr); } #else -#define ValidateFileInfo(fi) {} +#define ValidateFileInfo(fi) ((void)0) #endif -#if defined (_X86_) && defined (_MSC_VER) - -__inline VOID UDFTouch(IN PVOID addr) -{ - __asm { - mov eax,addr - mov al,[byte ptr eax] - } -} - -#else // NO X86 optimization , use generic C/C++ - __inline VOID UDFTouch(IN PVOID addr) { - UCHAR a = ((PUCHAR)addr)[0]; - a = a; + UCHAR a = *((volatile UCHAR*)addr); + UNREFERENCED_PARAMETER(a); } -#endif // _X86_ - #else // UDF_DBG #define DbgAllocatePool(x,y) ExAllocatePoolWithTag(x,y,'Fnwd') @@ -219,13 +199,13 @@ __inline VOID UDFTouch(IN PVOID addr) #define DbgCopyMemory(d, s, l) RtlCopyMemory(d, s, l) #define DbgCompareMemory(d, s, l) RtlCompareMemory(d, s, l) -#define ASSERT_REF(_a_) {NOTHING;} +#define ASSERT_REF(_a_) ((void)0) -#define UDFBreakPoint() {} -#define BrutePoint() {} -#define ValidateFileInfo(fi) {} +#define UDFBreakPoint() ((void)0) +#define BrutePoint() ((void)0) +#define ValidateFileInfo(fi) ((void)0) -#define UDFTouch(addr) {} +#define UDFTouch(addr) ((void)0) #endif // UDF_DBG @@ -245,7 +225,7 @@ if ((a)!=NULL) { \ #else -#define KdDump(a,b) {} +#define KdDump(a,b) ((void)0) #endif // UDF_DBG diff --git a/drivers/filesystems/udfs/udf_info/alloc.cpp b/drivers/filesystems/udfs/udf_info/alloc.c similarity index 71% rename from drivers/filesystems/udfs/udf_info/alloc.cpp rename to drivers/filesystems/udfs/udf_info/alloc.c index 530d6b168767e..18b48ef289a5b 100644 --- a/drivers/filesystems/udfs/udf_info/alloc.cpp +++ b/drivers/filesystems/udfs/udf_info/alloc.c @@ -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 */ + + ASSERT((bit == 0) || (bit == 1)); + + while (i < Lim) { + ULONG byteIdx = (ULONG)(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++; + } } } } @@ -408,6 +467,7 @@ UDFCheckSpaceAllocation_( uint32 i=0; uint32 lba, j, len, BS, BSh; BOOLEAN asUsed = (asXXX == AS_USED); + uint32* BitmapPtr = (uint32*)(Vcb->FSBM_Bitmap); if (!Map) return; @@ -468,39 +528,56 @@ UDFCheckSpaceAllocation_( len = Vcb->LastPossibleLBA - lba; } - // mark frag as XXX (see asUsed parameter) - if (asUsed) { + // --- SPEED OPTIMIZATION: Word-at-a-time verification --- + // Instead of bit-by-bit, we check 32 blocks per CPU instruction. + j = 0; + while (j < len) { + // Fast Path: Check 32 blocks if aligned on a 32-bit boundary + if (((lba + j) & 31) == 0 && (len - j) >= 32) { + uint32 CurrentWord = BitmapPtr[(lba + j) >> 5]; + + if (asUsed) { + // In UDF, 0 = Used. We expect the whole word to be 0x00000000. + if (CurrentWord == 0) { + j += 32; + continue; + } + } else { + // In UDF, 1 = Free. We expect the whole word to be 0xFFFFFFFF. + if (CurrentWord == 0xFFFFFFFF) { + j += 32; + continue; + } + } + // If the word check fails, we fall through to the bit-checker below + // to identify exactly which block is inconsistent. + } - ASSERT(len); - for(j=0;j Vcb->LastPossibleLBA) { + // Fallback: Individual bit check (for tails or if an inconsistency is found) + if (asUsed) { + if (lba + j > Vcb->LastPossibleLBA) { BrutePoint(); - AdPrint(("USED Mapping covers block(s) beyond media @%x\n",lba+j)); break; } - if (!UDFGetUsedBit(Vcb->FSBM_Bitmap, lba+j)) { + if (!UDFGetUsedBit(Vcb->FSBM_Bitmap, lba + j)) { BrutePoint(); - AdPrint(("USED Mapping covers FREE block(s) @%x\n",lba+j)); + AdPrint(("USED Mapping covers FREE block @ %x\n", lba + j)); break; } - } - - } else { - - ASSERT(len); - for(j=0;j Vcb->LastPossibleLBA) { + } else { + if (lba + j > Vcb->LastPossibleLBA) { BrutePoint(); - AdPrint(("USED Mapping covers block(s) beyond media @%x\n",lba+j)); break; } - if (!UDFGetFreeBit(Vcb->FSBM_Bitmap, lba+j)) { + if (!UDFGetFreeBit(Vcb->FSBM_Bitmap, lba + j)) { BrutePoint(); - AdPrint(("FREE Mapping covers USED block(s) @%x\n",lba+j)); + AdPrint(("FREE Mapping covers USED block @ %x\n", lba + j)); break; } } + j++; } + // --- END OPTIMIZATION --- i++; } @@ -515,15 +592,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() /* @@ -546,7 +625,7 @@ UDFMarkSpaceAsXXXNoProtect_( uint32 root; BOOLEAN asUsed = (asXXX == AS_USED || (asXXX & AS_BAD)); #ifdef UDF_TRACK_ONDISK_ALLOCATION - BOOLEAN bit_before, bit_after; + BOOLEAN bit_before = FALSE, bit_after = FALSE; #endif //UDF_TRACK_ONDISK_ALLOCATION UDF_CHECK_BITMAP_RESOURCE(Vcb); @@ -603,40 +682,30 @@ UDFMarkSpaceAsXXXNoProtect_( bit_after = UDFGetBit(Vcb->FSBM_Bitmap, lba+len); #endif //UDF_TRACK_ONDISK_ALLOCATION - // mark frag as XXX (see asUsed parameter) + // --- SPEED OPTIMIZATION START --- + // Instead of bit-loops, we use the optimized SetBits/FreeBits + // which should ideally be mapped to RtlFillMemory for large spans. if (asUsed) { -/* for(j=0;jFSBM_Bitmap, lba+j); - }*/ ASSERT(len); + // Fast Path: If we are marking a large span as used (bits = 1) + // UDFSetUsedBits handles the bit-shifting logic. UDFSetUsedBits(Vcb->FSBM_Bitmap, lba, len); -#ifdef UDF_TRACK_ONDISK_ALLOCATION - for(j=0;jFSBM_Bitmap, lba+j)); - } -#endif //UDF_TRACK_ONDISK_ALLOCATION + // VAT handling (This loop is slow but only runs for UDF 1.50/Vat-based media) if (Vcb->Vat) { - // 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); } } } } else { -/* for(j=0;jFSBM_Bitmap, lba+j); - }*/ ASSERT(len); + // Fast Path: Mark space as free (bits = 0) UDFSetFreeBits(Vcb->FSBM_Bitmap, lba, len); -#ifdef UDF_TRACK_ONDISK_ALLOCATION - for(j=0;jFSBM_Bitmap, lba+j)); - } -#endif //UDF_TRACK_ONDISK_ALLOCATION + if (asXXX & AS_BAD) { UDFSetBits(Vcb->BSBM_Bitmap, lba, len); } @@ -645,25 +714,19 @@ UDFMarkSpaceAsXXXNoProtect_( if (asXXX & AS_DISCARDED) { UDFUnmapRange(Vcb, lba, len); } + if (Vcb->Vat) { - // mark logical blocks in VAT as free - // 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 - // prevent writes there + + // Optimization for the Map itself Map[i].extLength = (len << BSh) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30); Map[i].extLocation = 0; } - -#ifdef UDF_TRACK_ONDISK_ALLOCATION - if (lba) - ASSERT(bit_before == UDFGetBit(Vcb->FSBM_Bitmap, lba-1)); - ASSERT(bit_after == UDFGetBit(Vcb->FSBM_Bitmap, lba+len)); -#endif //UDF_TRACK_ONDISK_ALLOCATION + // --- SPEED OPTIMIZATION END --- i++; } @@ -725,6 +788,7 @@ UDFAllocFreeExtent_( EXTENT_AD Ext; PEXTENT_MAP Map = NULL; uint32 len, LBS, BSh, blen; + uint32 EffectiveSearchStart; LBS = Vcb->SectorSize; BSh = Vcb->SectorShift; @@ -740,11 +804,31 @@ UDFAllocFreeExtent_( if (blen > (SearchLim - SearchStart)) { goto no_free_space_err; } + + // Use the bitmap search hint for allocation locality: start near the last + // allocation to avoid scanning already-used space at the start of the partition. + // The hint is only valid when it falls within [SearchStart, SearchLim); any + // out-of-range value is silently ignored and the full range is scanned instead. + EffectiveSearchStart = SearchStart; + if (Vcb->BitmapSearchHint >= SearchStart && Vcb->BitmapSearchHint < SearchLim) { + EffectiveSearchStart = Vcb->BitmapSearchHint; + AdPrint((" BitmapSearchHint applied: hint @%x, effective start @%x\n", + Vcb->BitmapSearchHint, EffectiveSearchStart)); + } + // walk through the free space bitmap & find a single extent or a set of // frags giving in sum the Length specified while(blen) { - Ext.extLocation = UDFFindMinSuitableExtent(Vcb, blen, SearchStart, - SearchLim, &len, AllocFlags); + Ext.extLocation = UDFFindMinSuitableExtent(Vcb, blen, EffectiveSearchStart, + SearchLim, &len, AllocFlags); + if (!len && EffectiveSearchStart > SearchStart) { + // Nothing found from the hint onward; fall back to a full-range search + AdPrint((" BitmapSearchHint: no free space from @%x, falling back to full scan from @%x\n", + EffectiveSearchStart, SearchStart)); + EffectiveSearchStart = SearchStart; + Ext.extLocation = UDFFindMinSuitableExtent(Vcb, blen, SearchStart, + SearchLim, &len, AllocFlags); + } if (len >= blen) { // complete search @@ -755,6 +839,9 @@ UDFAllocFreeExtent_( // probably we have the opportunity to do it Ext.extLength = len<Mapping, AS_DISCARDED); // free UDFMarkBadSpaceAsUsed(Vcb, Ext.extLocation, Ext.extLength >> BSh); // bad -> bad+used - // roll back + // Advance past the bad blocks and roll back the length + EffectiveSearchStart = Ext.extLocation + (Ext.extLength >> BSh); + if (EffectiveSearchStart > SearchLim) + EffectiveSearchStart = SearchLim; blen += Ext.extLength>>BSh; continue; } } + // Advance the search position past the just-allocated extent + EffectiveSearchStart = Ext.extLocation + (Ext.extLength >> BSh); + if (EffectiveSearchStart > SearchLim) + EffectiveSearchStart = SearchLim; + Ext.extLength |= EXTENT_NOT_RECORDED_ALLOCATED << 30; if (!(ExtInfo->Mapping)) { // create new @@ -818,6 +913,13 @@ UDFAllocFreeExtent_( return STATUS_INSUFFICIENT_RESOURCES; } } + // Persist the search position for future allocations (success path only; + // failure paths all return before reaching here via no_free_space_err). + // Clamp to SearchLim so an out-of-range hint is silently ignored next call. + if (EffectiveSearchStart > SearchLim) + EffectiveSearchStart = SearchLim; + AdPrint((" BitmapSearchHint updated: @%x -> @%x\n", Vcb->BitmapSearchHint, EffectiveSearchStart)); + Vcb->BitmapSearchHint = EffectiveSearchStart; UDFReleaseResource(&(Vcb->BitMapResource1)); ExtInfo->Length = Length; return STATUS_SUCCESS; @@ -833,15 +935,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() @@ -857,13 +979,12 @@ UDFGetFreeSpace( if (!Vcb->CDR_Mode) { for(i=0;iPartitionMaps;i++) { -/* lim = UDFPartEnd(Vcb,i); - for(j=UDFPartStart(Vcb,i); jPartitions[i].AccessType < PARTITION_ACCESS_WO) + continue; s += UDFGetPartFreeSpace(Vcb, i); } } else { diff --git a/drivers/filesystems/udfs/udf_info/dirtree.cpp b/drivers/filesystems/udfs/udf_info/dirtree.c similarity index 99% rename from drivers/filesystems/udfs/udf_info/dirtree.cpp rename to drivers/filesystems/udfs/udf_info/dirtree.c index e4ed3534956e4..0781210004644 100644 --- a/drivers/filesystems/udfs/udf_info/dirtree.cpp +++ b/drivers/filesystems/udfs/udf_info/dirtree.c @@ -102,8 +102,8 @@ UDFDirIndexFree( uint32 k; PDIR_INDEX_ITEM* FrameList; - FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1); if (!hDirNdx) return; + FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1); for(k=0; kFrameCount; k++, FrameList++) { if (*FrameList) MyFreePool__(*FrameList); } @@ -398,9 +398,11 @@ UDFBuildHashEntry( UName.MaximumLength = Name->Length; UName.Buffer = (PWCHAR)FsRtlAllocatePoolWithTag(NonPagedPool, UName.MaximumLength, TAG_FILE_NAME); - RtlUpcaseUnicodeString(&UName, Name, FALSE); - hashes->hLfn = crc32((uint8*)(UName.Buffer), UName.Length); - ExFreePoolWithTag(UName.Buffer, TAG_FILE_NAME); + if (UName.Buffer) { + RtlUpcaseUnicodeString(&UName, Name, FALSE); + hashes->hLfn = crc32((uint8*)(UName.Buffer), UName.Length); + ExFreePoolWithTag(UName.Buffer, TAG_FILE_NAME); + } } if (Mask & HASH_DOS) { @@ -685,6 +687,8 @@ UDFIndexDirectory( } // end UDFIndexDirectory() + + /* This routine rebuilds tags for all entries from Dir. */ diff --git a/drivers/filesystems/udfs/udf_info/ecma_167.h b/drivers/filesystems/udfs/udf_info/ecma_167.h index 6ca06a7c47fc2..9351f214fb160 100644 --- a/drivers/filesystems/udfs/udf_info/ecma_167.h +++ b/drivers/filesystems/udfs/udf_info/ecma_167.h @@ -772,5 +772,22 @@ typedef EXTENDED_FILE_ENTRY ExtendedFileEntry; #pragma pack(pop) +typedef struct VolStructDesc VolStructDesc; +typedef struct BeginningExtendedAreaDesc BeginningExtendedAreaDesc; +typedef struct TerminatingExtendedAreaDesc TerminatingExtendedAreaDesc; +typedef struct PrimaryVolDesc PrimaryVolDesc; +typedef struct AnchorVolDescPtr AnchorVolDescPtr; +typedef struct VolDescPtr VolDescPtr; +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 LogicalVolHeaderDesc LogicalVolHeaderDesc; + #endif /* __ECMA_167_H__ */ diff --git a/drivers/filesystems/udfs/udf_info/extent.cpp b/drivers/filesystems/udfs/udf_info/extent.c similarity index 99% rename from drivers/filesystems/udfs/udf_info/extent.cpp rename to drivers/filesystems/udfs/udf_info/extent.c index f76d82b4577c0..0c3daf0a5d5ad 100644 --- a/drivers/filesystems/udfs/udf_info/extent.cpp +++ b/drivers/filesystems/udfs/udf_info/extent.c @@ -338,7 +338,7 @@ UDFShortAllocDescToMapping( // record information about this frag locAddr.logicalBlockNum = AllocDesc->extPosition; - AllocExt.extLength = len; + AllocExt.extLength = (len + Vcb->SectorSize - 1) & ~(Vcb->SectorSize - 1); AllocExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr); if (AllocExt.extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address\n")); @@ -498,7 +498,7 @@ UDFLongAllocDescToMapping( return NULL; } // record information about this frag - AllocExt.extLength = len; + AllocExt.extLength = (len + Vcb->SectorSize - 1) & ~(Vcb->SectorSize - 1); AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); if (AllocExt.extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address\n")); @@ -635,7 +635,7 @@ UDFExtAllocDescToMapping( return NULL; } // record information about this frag - AllocExt.extLength = len; + AllocExt.extLength = (len + Vcb->SectorSize - 1) & ~(Vcb->SectorSize - 1); AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)); if (AllocExt.extLocation == LBA_OUT_OF_EXTENT) { UDFPrint(("bad address\n")); @@ -1324,6 +1324,8 @@ UDFBuildExtAllocDescs( } // end UDFBuildExtAllocDescs()*/ + + NTSTATUS UDFInitAllocationCache( IN PVCB Vcb, @@ -1519,7 +1521,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); @@ -1573,7 +1577,7 @@ UDFMarkAllocatedAsRecorded( (i == ((UDFGetMappingLength(Extent) / sizeof(EXTENT_MAP)) - 2)) && TRUE) { // make optimization for sequentially written files - Extent[i-1].extLength += Extent[i].extLength; + Extent[i-1].extLength += Extent[i].extLength & UDF_EXTENT_LENGTH_MASK; Extent[i].extLocation = 0; Extent[i].extLength = 0; } else { diff --git a/drivers/filesystems/udfs/udf_info/mount.cpp b/drivers/filesystems/udfs/udf_info/mount.c similarity index 92% rename from drivers/filesystems/udfs/udf_info/mount.cpp rename to drivers/filesystems/udfs/udf_info/mount.c index 62fa4048fc624..45d672c236036 100644 --- a/drivers/filesystems/udfs/udf_info/mount.cpp +++ b/drivers/filesystems/udfs/udf_info/mount.c @@ -57,14 +57,14 @@ UDFPrepareXSpaceBitmap( IN OUT uint32* XSl ) { - uint32 BS, j, LBS; + uint32 j, LBS; uint32 plen; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; EXTENT_MAP TmpExt; lb_addr locAddr; int8* _XSBM; uint16 Ident; - ULONG ReadBytes; + ULONG ReadBytes = 0; uint32 RefPartNum; if (!(XSpaceBitmap->extLength)) { @@ -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; iSparingTableModified) return STATUS_SUCCESS; @@ -616,6 +639,8 @@ UDFUpdateLogicalVol( status = UDFUpdateSparingTable(IrpContext, Vcb); + + lvd = (LogicalVolDesc*)MyAllocatePool__(NonPagedPool, max(Vcb->SectorSize, sizeof(LogicalVolDesc)) ); if (!lvd) { @@ -679,7 +704,7 @@ UDFUpdateVDS( IN uint32 flags ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; int8* Buf = (int8*)DbgAllocatePool(NonPagedPool,Vcb->SectorSize); UDF_VDS_RECORD vds[VDS_POS_LENGTH]; uint32 i,j; @@ -813,7 +838,7 @@ UDFUpdateVolIdent( { #define CUR_IDENT_SZ (sizeof(pvoldesc->volIdent)) PrimaryVolDesc* pvoldesc = (PrimaryVolDesc*)MyAllocatePool__(NonPagedPool, max(Vcb->SectorSize, sizeof(PrimaryVolDesc)) ); - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; dstring CS0[CUR_IDENT_SZ]; uint16 ident; SIZE_T WrittenBytes; @@ -911,7 +936,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 @@ -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: @@ -1013,7 +1038,7 @@ UDFFindAnchorVolumeDescriptor( uint16 ident; uint32 i; uint32 LastBlock; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; int8* Buf = (int8*)MyAllocatePool__(NonPagedPool, ROUND_TO_PAGES(SectorAlign(Vcb, sizeof(AnchorVolDescPtr)))); @@ -1086,9 +1111,9 @@ UDFFindVRS( uint32 offset; uint32 retStat = 0; uint32 BeginOffset = Vcb->FirstLBA; - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; int8* buffer = (int8*)MyAllocatePool__(NonPagedPool,Vcb->SectorSize); - ULONG ReadBytes; + ULONG ReadBytes = 0; if (!buffer) return 0; // Relative to First LBA in Last Session @@ -1619,15 +1644,14 @@ 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; + NTSTATUS status = STATUS_SUCCESS; uint16 Ident; uint32 flags; SIZE_T Length; - ULONG ReadBytes; - BOOLEAN bit_set; + ULONG ReadBytes = 0; + BOOLEAN bit_set = FALSE; UDF_CHECK_BITMAP_RESOURCE(Vcb); UDFPrint(("UDFAddXSpaceBitmap: at block=%x, partition=%d\n", @@ -1638,11 +1662,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 +1681,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++; + } + 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; } - i++; + 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,15 +1758,13 @@ UDFVerifyXSpaceBitmap( ) { int8* tmp; -// int8* tmp_bm; -// uint32 i, l2, k, lim, j, lim2; uint32 lba; lb_addr locAddr; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint16 Ident; uint32 flags; uint32 Length; - ULONG ReadBytes; + ULONG ReadBytes = 0; // BOOLEAN bit_set; UDF_CHECK_BITMAP_RESOURCE(Vcb); @@ -1718,7 +1775,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 +1794,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; @@ -1798,7 +1820,7 @@ UDFDelXSpaceBitmap( int8* tmp, tmp_bm; uint32 i, lim, j; lb_addr locAddr; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint16 Ident; uint32 flags; uint32 Length; @@ -1853,7 +1875,7 @@ UDFVerifyFreeSpaceBitmap( IN uint32 Lba // UnallocSpaceDesc ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint32 i, l; uint16 Ident; int8* AllocDesc; @@ -1949,7 +1971,7 @@ UDFBuildFreeSpaceBitmap( IN uint32 Lba // UnallocSpaceDesc ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint32 i, l; uint16 Ident; int8* AllocDesc; @@ -1959,10 +1981,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)); @@ -2068,7 +2095,7 @@ UDFLoadPartDesc( { PartitionDesc *p = (PartitionDesc *)Buf; uint32 i; - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; BOOLEAN Found = FALSE; UDFPrint(("UDF: Pard Descr:\n")); UDFPrint((" volDescSeqNum = %x\n", p->volDescSeqNum)); @@ -2169,7 +2196,7 @@ UDFVerifyPartDesc( { PartitionDesc *p = (PartitionDesc *)Buf; uint32 i; - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; BOOLEAN Found = FALSE; UDFPrint(("UDF: Verify Part Descr:\n")); UDFPrint((" volDescSeqNum = %x\n", p->volDescSeqNum)); @@ -2284,7 +2311,7 @@ UDFReadVDS( IN int8* Buf ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; GenericDesc* gd; BOOLEAN done=FALSE; uint32 vdsn; @@ -2724,13 +2751,14 @@ UDFFindLastFileSet( IN OUT PFILE_SET_DESC FileSetDesc ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint32 relLocExt = Addr->logicalBlockNum; uint32 locExt = UDFPartLbaToPhys(Vcb, Addr); uint16 Ident; uint32 relPrevExt, prevExt; - relPrevExt, prevExt = NULL; + relPrevExt = 0; + prevExt = 0; FileSetDesc->nextExt.extLength = 1; // ;) // walk through FileSet chain // we've just pre-init'd extent length to read 1st FileSet @@ -2768,14 +2796,14 @@ UDFLoadSparingTable( { PSPARING_MAP RelocMap; PSPARING_MAP NewRelocMap; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint32 i=0, BC, BC2; PSPARING_TABLE SparTable; uint32 TabSize, NewSize; - ULONG ReadBytes; + ULONG ReadBytes = 0; uint32 SparTableLoc; uint32 n,m; - BOOLEAN merged; + BOOLEAN merged = FALSE; Vcb->SparingCountFree = -1; @@ -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/osta_misc.h b/drivers/filesystems/udfs/udf_info/osta_misc.h index f9813bfb321c7..c8628fba514c0 100644 --- a/drivers/filesystems/udfs/udf_info/osta_misc.h +++ b/drivers/filesystems/udfs/udf_info/osta_misc.h @@ -350,4 +350,11 @@ typedef UID_MAPPING_TABLE* PUID_MAPPING_TABLE; #pragma pack(pop) +typedef struct LogicalVolIntegrityDescImpUse LogicalVolIntegrityDescImpUse; +typedef struct ImpUseVolDescImpUse ImpUseVolDescImpUse; +typedef struct UdfPartitionMap2 UdfPartitionMap2; +typedef struct VirtualAllocationTable15 VirtualAllocationTable15; +typedef struct VirtualAllocationTable20 VirtualAllocationTable20; +typedef struct FidADImpUse FidADImpUse; + #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 96% rename from drivers/filesystems/udfs/udf_info/remap.cpp rename to drivers/filesystems/udfs/udf_info/remap.c index 72a4079b07021..6361daace6f51 100644 --- a/drivers/filesystems/udfs/udf_info/remap.cpp +++ b/drivers/filesystems/udfs/udf_info/remap.c @@ -29,8 +29,8 @@ UDFCheckArea( ) { uint8* buff; - NTSTATUS RC; - ULONG ReadBytes; + NTSTATUS RC = STATUS_SUCCESS; + ULONG ReadBytes = 0; uint32 i, d; BOOLEAN ext_ok = TRUE; EXTENT_MAP Map[2]; @@ -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.c similarity index 96% rename from drivers/filesystems/udfs/udf_info/udf_info.cpp rename to drivers/filesystems/udfs/udf_info/udf_info.c index e9556aa93de31..d67f04de8977a 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.cpp +++ b/drivers/filesystems/udfs/udf_info/udf_info.c @@ -18,31 +18,16 @@ #define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO -#ifdef _X86_ -static const int8 valid_char_arr[] = - {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, - 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, - 1,0,1,0, 0,0,0,0, 0,0,1,1, 1,0,0,1, - 0,0,0,0, 0,0,0,0, 0,0,1,1, 1,1,1,1, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // @ABCDE.... - 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,0, // ....Z[/]^_ - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // `abcde.... - 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,1, // ....z{|}~ - - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; -#else // NO X86 optimization , use generic C/C++ static const char valid_char_arr[] = {"*/:?\"<>|\\"}; -#endif // _X86_ #define DOS_CRC_MODULUS 41 #define hexChar crcChar + +// Minimum number of sectors to pre-allocate for a new directory data extent. +// Amortises per-sector cold-write spikes across many file additions. +// The effective pre-allocation is max(2*t, UDF_DIR_PREALLOC_MIN_SECTORS * +// SectorSize) rounded up to a WriteBlockSize boundary. +#define UDF_DIR_PREALLOC_MIN_SECTORS 8 static const char crcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@"; /* Used to convert hex digits to ASCII for readability. */ @@ -286,7 +271,7 @@ UDFReadFileEntry( IN OUT uint16* Ident ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; if (!NT_SUCCESS(status = UDFReadTagged(IrpContext, Vcb, (int8*)FileEntry, UDFPartLbaToPhys(Vcb,&(Icb->extLocation)), @@ -352,7 +337,7 @@ UDFIsIllegalChar( IN PUDF_FILE_INFO FileInfo ) { - BOOLEAN KeepIntact; + BOOLEAN KeepIntact = FALSE; KeepIntact = (FileInfo && (FileInfo->Index < 2)); UDFDOSName(Vcb, DosName, UdfName, KeepIntact); @@ -916,7 +901,7 @@ UDFBuildFileEntry( ) { PFILE_ENTRY FileEntry; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; // EntityID* eID; uint32 l; EXTENT_INFO _FEExtInfo; @@ -1549,10 +1534,10 @@ UDFWriteFile__( ) { int64 t, elen; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; int8* OldInIcb = NULL; ValidateFileInfo(FileInfo); - ULONG ReadBytes; + ULONG ReadBytes = 0; SIZE_T _WrittenBytes; PUDF_DATALOC_INFO Dloc; // unwind staff @@ -1587,7 +1572,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 +1599,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", @@ -1623,8 +1612,16 @@ UDFWriteFile__( WasInIcb ? "In-Icb" : "", Vcb->LowFreeSpace ? "LowSpace" : "")); if (UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) { + // Pre-allocate directory data extents in larger chunks to amortise + // per-sector cold-write spikes across many file additions. + // The pre-allocation size is at least UDF_DIR_PREALLOC_MIN_SECTORS + // sectors (safety net for small WriteBlockSize configurations) and + // is always rounded up to a full WriteBlockSize boundary. + uint64 prealloc = max((uint64)t * 2, + (uint64)Vcb->SectorSize * UDF_DIR_PREALLOC_MIN_SECTORS); + prealloc = (prealloc + Vcb->WriteBlockSize - 1) & ~(ULONGLONG)(Vcb->WriteBlockSize - 1); 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, prealloc, FALSE, &(Dloc->DataLoc)); if (NT_SUCCESS(status)) { AdPrint((" preallocated space for Dir\n")); FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED; @@ -1681,7 +1678,9 @@ UDFWriteFile__( return status; UDFSetFileSize(FileInfo, t); Dloc->DataLoc.Modified = TRUE; + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + return STATUS_SUCCESS; } // end UDFWriteFile__() @@ -1705,8 +1704,8 @@ UDFUnlinkFile__( PDIR_INDEX_HDR hDirNdx; PDIR_INDEX_HDR hCurDirNdx; PDIR_INDEX_ITEM DirNdx; - NTSTATUS status; - BOOLEAN IsSDir; + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN IsSDir = FALSE; AdPrint(("UDFUnlinkFile__:\n")); if (!FileInfo) return STATUS_SUCCESS; @@ -1815,7 +1814,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 +1825,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 +1839,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 +1860,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 @@ -1874,7 +1873,7 @@ UDFUnlinkFile__( UDFDecFileLinkCount(FileInfo->ParentFile); } // flush file - UDFFlushFile__(IrpContext, Vcb, FileInfo); + UDFFlushFile__(IrpContext, Vcb, FileInfo, 0); UDFUnlinkDloc(Vcb, Dloc); // free allocation UDFFreeFileAllocation(Vcb, DirInfo, FileInfo); @@ -1894,7 +1893,7 @@ UDFUnlinkAllFilesInDir( PDIR_INDEX_HDR hCurDirNdx; PDIR_INDEX_ITEM CurDirNdx; PUDF_FILE_INFO FileInfo; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint_di i; hCurDirNdx = DirInfo->Dloc->DirIndex; @@ -1929,7 +1928,7 @@ UDFUnlinkAllFilesInDir( return status; } - UDFFlushFile__(IrpContext, Vcb, FileInfo); + UDFFlushFile__(IrpContext, Vcb, FileInfo, 0); AdPrint((" ")); UDFUnlinkFile__(IrpContext, Vcb, FileInfo, TRUE); UDFCloseFile__(IrpContext, Vcb, FileInfo); @@ -1959,7 +1958,7 @@ UDFOpenFile__( IN uint_di* IndexToOpen ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint_di i=0; EXTENT_AD FEExt; uint16 Ident; @@ -1967,7 +1966,7 @@ UDFOpenFile__( PDIR_INDEX_ITEM DirNdx; PUDF_FILE_INFO FileInfo; PUDF_FILE_INFO ParFileInfo; - ULONG ReadBytes; + ULONG ReadBytes = 0; *_FileInfo = NULL; if (!hDirNdx) return STATUS_NOT_A_DIRECTORY; @@ -2298,7 +2297,7 @@ UDFOpenRootFile__( ) { uint32 RootLBA; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; // uint32 PartNum = RootLoc->partitionReferenceNum; uint32 LBS = Vcb->SectorSize; uint16 Ident; @@ -2380,8 +2379,8 @@ UDFCleanUpFile__( { PUDF_DATALOC_INFO Dloc; uint32 lc = 0; - BOOLEAN IsASDir; - BOOLEAN KeepDloc; + BOOLEAN IsASDir = FALSE; + BOOLEAN KeepDloc = FALSE; PDIR_INDEX_ITEM DirNdx = NULL, DirNdx2; BOOLEAN Parallel = FALSE; BOOLEAN Linked = FALSE; @@ -2604,24 +2603,31 @@ UDFCleanUpFile__( } #endif //UDF_TRACK_ONDISK_ALLOCATION if (FileInfo->Dloc->DirIndex) { + PDIR_INDEX_HDR tmpDirIndex; uint_di i; - for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) { + tmpDirIndex = Dloc->DirIndex; + Dloc->DirIndex = NULL; + for(i=2; (DirNdx = UDFDirIndex(tmpDirIndex,i)); i++) { ASSERT(!DirNdx->FileInfo); - if (DirNdx->FName.Buffer) + if (DirNdx->FName.Buffer) { MyFreePool__(DirNdx->FName.Buffer); + DirNdx->FName.Buffer = NULL; + } } - UDFDirIndexFree(Dloc->DirIndex); - Dloc->DirIndex = NULL; + UDFDirIndexFree(tmpDirIndex); #ifdef UDF_TRACK_ONDISK_ALLOCATION UDFIndexDirectory(Vcb, FileInfo); if (FileInfo->Dloc->DirIndex) { - for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) { + tmpDirIndex = Dloc->DirIndex; + Dloc->DirIndex = NULL; + for(i=2; (DirNdx = UDFDirIndex(tmpDirIndex,i)); i++) { ASSERT(!DirNdx->FileInfo); - if (DirNdx->FName.Buffer) + if (DirNdx->FName.Buffer) { MyFreePool__(DirNdx->FName.Buffer); + DirNdx->FName.Buffer = NULL; + } } - UDFDirIndexFree(Dloc->DirIndex); - Dloc->DirIndex = NULL; + UDFDirIndexFree(tmpDirIndex); } #endif //UDF_TRACK_ONDISK_ALLOCATION } @@ -2752,7 +2758,7 @@ UDFCreateFile__( { uint32 l, d; uint_di i, j; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; LONG_AD FEicb; UDF_DIR_SCAN_CONTEXT ScanContext; PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; @@ -2761,7 +2767,7 @@ UDFCreateFile__( PUDF_FILE_INFO FileInfo; *_FileInfo = NULL; BOOLEAN undel = FALSE; - ULONG ReadBytes; + ULONG ReadBytes = 0; SIZE_T WrittenBytes; // BOOLEAN PackDir = FALSE; BOOLEAN FEAllocated = FALSE; @@ -3000,8 +3006,15 @@ UDFCreateFile__( FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; FileInfo->Dloc->DataLoc.Modified = TRUE; FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; - // zero sector for FileEntry + // Mark the FE sector as newly allocated so that UDFFlushFE writes the + // full sector (FE content + zero padding) in a single call instead of + // the previous two-step sequence (explicit zero-write here followed by + // a read-modify-write inside UDFWriteInSector). CDR media still needs + // the explicit zero-write because UDFFlushFE skips the padded path in + // that mode. if (!Vcb->CDR_Mode) { + FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_NEW_SECTOR; + } else { status = UDFWriteData(IrpContext, Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->SectorShift, LBS, FALSE, Vcb->ZBuffer, &WrittenBytes); if (!NT_SUCCESS(status)) { UDFFlushFI(IrpContext, Vcb, FileInfo, PartNum); @@ -3131,7 +3144,7 @@ UDFPadLastSector( PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array SIZE_T to_write, WrittenBytes; uint32 Lba, sect_offs, flags; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; // Length should not be zero int64 Offset = ExtInfo->Length + ExtInfo->Offset; // data is sector-size-aligned, we needn't any padding @@ -3185,7 +3198,7 @@ UDFCloseFile__( return STATUS_SUCCESS; } PUDF_FILE_INFO DirInfo = FileInfo->ParentFile; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint32 PartNum; if (FileInfo->RefCount) { InterlockedDecrement((PLONG)&FileInfo->RefCount); @@ -3344,7 +3357,7 @@ UDFRenameMoveFile__( ) { PUDF_FILE_INFO FileInfo2; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; PDIR_INDEX_ITEM DirNdx1; PDIR_INDEX_ITEM DirNdx2; uint_di i,j; @@ -3485,7 +3498,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); @@ -3572,7 +3585,7 @@ UDFRecordDirectory__( IN OUT PUDF_FILE_INFO DirInfo // source (opened) ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; LONG_AD FEicb; UDF_FILE_INFO FileInfo; UDF_DATALOC_INFO Dloc; @@ -3584,6 +3597,8 @@ UDFRecordDirectory__( // validate DirInfo ValidateFileInfo(DirInfo); + AdPrint(("UDFRecordDirectory__: FE @%x\n", + DirInfo->Dloc ? DirInfo->Dloc->FELoc.Mapping[0].extLocation : 0)); if (DirInfo->ParentFile && UDFIsAStreamDir(DirInfo->ParentFile)) return STATUS_ACCESS_DENIED; // file should be empty @@ -3610,6 +3625,7 @@ UDFRecordDirectory__( lba = DirInfo->Dloc->FELoc.Mapping[0].extLocation; ASSERT(lba); PartNum = UDFGetRefPartNumByPhysLba(Vcb, lba); + AdPrint((" lba %x, PartNum %x\n", lba, PartNum)); FEicb.extLength = Vcb->SectorSize; FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, lba); FEicb.extLocation.partitionReferenceNum = (uint16)PartNum; @@ -3628,16 +3644,38 @@ UDFRecordDirectory__( Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen), FEicb.extLocation.logicalBlockNum, 0); FileInfo.Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; // for metadata // flush + AdPrint((" writing parent FID, len %x\n", FileInfo.FileIdentLen)); 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 (!NT_SUCCESS(status)) { + AdPrint((" UDFWriteFile__ failed %x\n", status)); + return status; + } + AdPrint((" UDFWriteFile__ OK, written %x bytes\n", (ULONG)WrittenBytes)); if (CurDirNdx) CurDirNdx->FileCharacteristics = DirInfo->FileIdent->fileCharacteristics; - return UDFIndexDirectory(IrpContext, Vcb, DirInfo); + AdPrint((" calling UDFIndexDirectory\n")); + status = UDFIndexDirectory(IrpContext, Vcb, DirInfo); + if (!NT_SUCCESS(status)) { + AdPrint((" UDFIndexDirectory failed %x\n", status)); + return status; + } + AdPrint((" UDFIndexDirectory OK, calling UDFFlushFE\n")); + // The FE was already written by UDFCreateFile__'s UDFFlushFE as a regular + // empty file. UDFWriteFile__ above modified DataLoc (new allocation, + // non-zero informationLength) and the in-memory FE now has + // fileType = UDF_FILE_TYPE_DIRECTORY. Flush the FE now so that the + // on-disk copy is consistent; without this a crash before close would + // leave a corrupt regular-empty-file FE on disk. + status = UDFFlushFE(IrpContext, Vcb, DirInfo, PartNum); + AdPrint(("UDFRecordDirectory__: done, status %x\n", status)); + return status; } // end UDFRecordDirectory__() /* @@ -3651,9 +3689,9 @@ UDFResizeFile__( IN int64 NewLength ) { - ULONG ReadBytes; + ULONG ReadBytes = 0; SIZE_T WrittenBytes; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint32 PartNum; int8* OldInIcb = NULL; PEXTENT_MAP NewMap; @@ -3733,10 +3771,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 +3808,10 @@ UDFResizeFile__( UDFSetFileSize(FileInfo, NewLength); } + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + return status; } // end UDFResizeFile__() @@ -3784,11 +3826,11 @@ UDFLoadVAT( ) { lb_addr VatFELoc; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; PUDF_FILE_INFO VatFileInfo; uint32 len, i=0, j, to_read; uint32 Offset, hdrOffset; - ULONG ReadBytes; + ULONG ReadBytes = 0; uint32 root; uint16 PartNum; // uint32 VatFirstLba = 0; @@ -3897,7 +3939,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 +3966,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 +3974,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); } } @@ -3971,7 +4013,7 @@ UDFReadFileEA( ) { PFILE_ENTRY FileEntry; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; if (FileDirNdx->FileInfo) { FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry); @@ -4056,7 +4098,7 @@ UDFFlushFE( ) { int8* NewAllocDescs; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; SIZE_T WrittenBytes; uint16 AllocMode; uint32 lba; @@ -4090,7 +4132,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 +4164,9 @@ UDFFlushFE( ASSERT(UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping) == 0); } else { + ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); + } #endif // UDF_DBG } @@ -4180,10 +4226,46 @@ UDFFlushFE( UDFPhysLbaToPart(Vcb, PartNum, lba), 0); } } - status = UDFWriteExtent( - IrpContext, - Vcb, &FileInfo->Dloc->FELoc, 0, (uint32)(FileInfo->Dloc->FELoc.Length), FALSE, - (int8 *)(FileInfo->Dloc->FileEntry), &WrittenBytes); + // Write the FE to disk. When the FE sector was freshly allocated in + // this file-creation call (UDF_FE_FLAG_NEW_SECTOR is set), write the + // full sector as a single zero-padded buffer. This replaces the + // previous three-step sequence (zero-write the sector in + // UDFCreateFile__, then read-before-write inside UDFWriteInSector when + // the FE is smaller than a full sector) with a single write I/O. + { + BOOLEAN newSector = !!(FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_NEW_SECTOR); + uint32 feLen = (uint32)(FileInfo->Dloc->FELoc.Length); + uint32 LBS_fe = Vcb->SectorSize; + FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_NEW_SECTOR; + + if (newSector && feLen < LBS_fe) { + // Allocate a sector-sized staging buffer, copy the FE into the + // beginning, and zero-fill the rest so the trailing bytes are + // clean without a separate read-modify-write. + int8* padBuf = (int8*)MyAllocatePool__(NonPagedPool, LBS_fe); + if (padBuf) { + RtlCopyMemory(padBuf, FileInfo->Dloc->FileEntry, feLen); + RtlZeroMemory(padBuf + feLen, LBS_fe - feLen); + SIZE_T _wb = 0; + status = UDFWriteData(IrpContext, Vcb, TRUE, + ((int64)lba) << Vcb->SectorShift, LBS_fe, FALSE, padBuf, &_wb); + WrittenBytes = _wb; + MyFreePool__(padBuf); + } else { + // Pool exhausted; fall through to the regular path which + // may do a read-modify-write but is always correct. + status = UDFWriteExtent( + IrpContext, + Vcb, &FileInfo->Dloc->FELoc, 0, feLen, FALSE, + (int8 *)(FileInfo->Dloc->FileEntry), &WrittenBytes); + } + } else { + status = UDFWriteExtent( + IrpContext, + Vcb, &FileInfo->Dloc->FELoc, 0, feLen, FALSE, + (int8 *)(FileInfo->Dloc->FileEntry), &WrittenBytes); + } + } if (!NT_SUCCESS(status)) { UDFPrint((" FlushFE: UDFWriteExtent(2) failed (%x)\n", status)); if (status == STATUS_DEVICE_DATA_ERROR) { @@ -4263,7 +4345,7 @@ UDFFlushFI( { PUDF_FILE_INFO DirInfo = FileInfo->ParentFile; PDIR_INDEX_ITEM DirNdx; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; SIZE_T WrittenBytes; // use WrittenBytes variable to store LBA of FI to be recorded #define lba WrittenBytes @@ -4334,7 +4416,7 @@ UDFFlushFile__( ValidateFileInfo(FileInfo); if (!FileInfo) return STATUS_SUCCESS; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; uint32 PartNum; ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); @@ -4579,17 +4661,17 @@ UDFReadTagged( uint16 *Ident ) { - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; tag* PTag = (tag*)Buf; // icbtag* Icb = (icbtag*)(Buf+1); uint8 checksum; unsigned int i; - ULONG ReadBytes; + ULONG ReadBytes = 0; int8* tb; // Read the block if (Block == 0xFFFFFFFF) - return NULL; + return STATUS_INVALID_PARAMETER; _SEH2_TRY { RC = UDFReadSectors(IrpContext, Vcb, FALSE, Block, 1, FALSE, Buf, &ReadBytes); @@ -4668,7 +4750,7 @@ UDFHardLinkFile__( ) { PUDF_FILE_INFO FileInfo2; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; PDIR_INDEX_ITEM DirNdx1; PDIR_INDEX_ITEM DirNdx2; uint_di i; @@ -4823,7 +4905,7 @@ UDFCreateRootFile__( OUT PUDF_FILE_INFO* _FileInfo ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; LONG_AD FEicb; PUDF_FILE_INFO FileInfo; *_FileInfo = NULL; @@ -4882,7 +4964,7 @@ UDFCreateStreamDir__( // any pointers ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; PUDF_FILE_INFO SDirInfo; uint16 Ident; @@ -4968,7 +5050,7 @@ UDFOpenStreamDir__( // any pointers ) { - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; PUDF_FILE_INFO SDirInfo; PUDF_FILE_INFO ParSDirInfo; uint16 Ident; @@ -5040,8 +5122,8 @@ UDFRecordVAT( uint32 to_read; uint32 hdrOffset, hdrOffsetNew; uint32 hdrLen; - NTSTATUS status; - ULONG ReadBytes; + NTSTATUS status = STATUS_SUCCESS; + ULONG ReadBytes = 0; SIZE_T WrittenBytes; uint32 len; uint16 PartNdx = (uint16)Vcb->VatPartNdx; @@ -5062,7 +5144,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 +5263,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 = @@ -5193,7 +5277,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; } @@ -5203,7 +5287,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; } @@ -5299,7 +5385,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; @@ -5339,7 +5425,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() @@ -5358,8 +5444,8 @@ UDFConvertFEToExtended( PEXTENDED_FILE_ENTRY ExFileEntry; PFILE_ENTRY FileEntry; uint32 Length, NewLength, l; - NTSTATUS status; - ULONG ReadBytes; + NTSTATUS status = STATUS_SUCCESS; + ULONG ReadBytes = 0; SIZE_T WrittenBytes; if (!FileInfo) return STATUS_INVALID_PARAMETER; @@ -5466,7 +5552,7 @@ UDFPretendFileDeleted__( { AdPrint(("UDFPretendFileDeleted__:\n")); - NTSTATUS RC; + NTSTATUS RC = STATUS_SUCCESS; PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo); if (!hDirNdx) return STATUS_CANNOT_DELETE; PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index); diff --git a/drivers/filesystems/udfs/udf_info/udf_info.h b/drivers/filesystems/udfs/udf_info/udf_info.h index d68b0d6437f3f..4951f793d136b 100644 --- a/drivers/filesystems/udfs/udf_info/udf_info.h +++ b/drivers/filesystems/udfs/udf_info/udf_info.h @@ -160,8 +160,8 @@ UDFShortAllocDescToMapping( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN uint32 PartNum, - IN PLONG_AD AllocDesc, - IN uint32 AllocDescLength, + IN PSHORT_AD AllocDescs, + IN uint32 AllocDescsLength, IN uint32 SubCallCount, OUT PEXTENT_INFO AllocLoc ); @@ -182,7 +182,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 @@ -1023,7 +1023,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 @@ -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/udf_info/udf_rel.h b/drivers/filesystems/udfs/udf_info/udf_rel.h index cefcb3b8c2d0c..5ee2ef1c3e34f 100644 --- a/drivers/filesystems/udfs/udf_info/udf_rel.h +++ b/drivers/filesystems/udfs/udf_info/udf_rel.h @@ -325,6 +325,10 @@ typedef struct _UDF_DATALOC_INFO { #define UDF_FE_FLAG_IS_DEL_SDIR (0x20) /// Dloc is being initialized, don't touch it now #define UDF_FE_FLAG_UNDER_INIT (0x40) +/// FE sector is freshly allocated; UDFFlushFE must write it zero-padded +/// to the full sector size to avoid a separate zero-init write followed by +/// a read-modify-write. Cleared by UDFFlushFE after the padded write. +#define UDF_FE_FLAG_NEW_SECTOR (0x80) #define UDF_FILE_INFO_MT PagedPool diff --git a/drivers/filesystems/udfs/udfdata.cpp b/drivers/filesystems/udfs/udfdata.c similarity index 99% rename from drivers/filesystems/udfs/udfdata.cpp rename to drivers/filesystems/udfs/udfdata.c index d1674b7727e54..ee60b53dcf61a 100644 --- a/drivers/filesystems/udfs/udfdata.cpp +++ b/drivers/filesystems/udfs/udfdata.c @@ -76,13 +76,13 @@ Return Value: { THREAD_CONTEXT ThreadContext = {0}; PIRP_CONTEXT IrpContext = NULL; - BOOLEAN Wait; + BOOLEAN Wait = FALSE; #ifdef UDF_SANITY PVOID PreviousTopLevel; #endif - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; #if DBG diff --git a/drivers/filesystems/udfs/udffs.h b/drivers/filesystems/udfs/udffs.h index 272046b907e62..371fd0ad79cf4 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 @@ -91,6 +88,11 @@ typedef FILE_ID *PFILE_ID; #undef MdlMappingNoExecute #define MdlMappingNoExecute 0 #define NonPagedPoolNx NonPagedPool +// POOL_NX_ALLOCATION (0x200) is a Windows 8+ flag not recognized on XP-based +// systems. Passing it to ExInitialize*LookasideList would result in an invalid +// pool type on Windows XP / POSReady 2009. +#undef POOL_NX_ALLOCATION +#define POOL_NX_ALLOCATION 0 #endif // #define NDEBUG @@ -98,6 +100,8 @@ typedef FILE_ID *PFILE_ID; #define UDF_DBG #endif +//#define BRUTE + #define VALIDATE_STRUCTURES // the following include files should be in the inc sub-dir associated with this driver @@ -117,6 +121,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 +188,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.c similarity index 97% rename from drivers/filesystems/udfs/udfinit.cpp rename to drivers/filesystems/udfs/udfinit.c index 657034565142c..8f92b303b284b 100644 --- a/drivers/filesystems/udfs/udfinit.cpp +++ b/drivers/filesystems/udfs/udfinit.c @@ -210,8 +210,11 @@ DriverEntry( FilterCallbacks.PreAcquireForSectionSynchronization = UDFFilterCallbackAcquireForCreateSection; RC = FsRtlRegisterFileSystemFilterCallbacks(DriverObject, &FilterCallbacks); - if (!NT_SUCCESS(RC)) - try_return(RC); + if (!NT_SUCCESS(RC)) { + // On Windows XP, this call may fail. Treat as non-fatal. + UDFPrint(("UDF: FsRtlRegisterFileSystemFilterCallbacks failed with %x, continuing\n", RC)); + RC = STATUS_SUCCESS; + } UDFPrint(("UDF: Create CD dev obj\n")); if (!NT_SUCCESS(RC = UDFCreateFsDeviceObject(UDF_FS_NAME_CD, @@ -234,11 +237,13 @@ DriverEntry( if (UdfData.UDFDeviceObject_CD) { UDFPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem() for CD\n")); IoRegisterFileSystem(UdfData.UDFDeviceObject_CD); + ObReferenceObject(UdfData.UDFDeviceObject_CD); } if (UdfData.UDFDeviceObject_HDD) { UDFPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem() for HDD\n")); IoRegisterFileSystem(UdfData.UDFDeviceObject_HDD); + ObReferenceObject(UdfData.UDFDeviceObject_HDD); } RC = STATUS_SUCCESS; @@ -270,6 +275,7 @@ DriverEntry( IoDeleteDevice(UdfData.UDFDeviceObject_HDD); UdfData.UDFDeviceObject_HDD = NULL; } + } } _SEH2_END; diff --git a/drivers/filesystems/udfs/udfs_reg.inf b/drivers/filesystems/udfs/udfs_reg.inf index 2822dbdce371c..532ecdcdbf918 100644 --- a/drivers/filesystems/udfs/udfs_reg.inf +++ b/drivers/filesystems/udfs/udfs_reg.inf @@ -1,7 +1,7 @@ ; UDF Filesystem driver [AddReg] HKLM,"SYSTEM\CurrentControlSet\Services\Udfs","ErrorControl",0x00010001,0x00000001 -HKLM,"SYSTEM\CurrentControlSet\Services\Udfs","Group",0x00000000,"File System" +HKLM,"SYSTEM\CurrentControlSet\Services\Udfs","Group",0x00000000,"Boot File System" HKLM,"SYSTEM\CurrentControlSet\Services\Udfs","ImagePath",0x00020000,"system32\drivers\udfs.sys" -HKLM,"SYSTEM\CurrentControlSet\Services\Udfs","Start",0x00010001,0x00000001 +HKLM,"SYSTEM\CurrentControlSet\Services\Udfs","Start",0x00010001,0x00000003 HKLM,"SYSTEM\CurrentControlSet\Services\Udfs","Type",0x00010001,0x00000002 diff --git a/drivers/filesystems/udfs/unload.c b/drivers/filesystems/udfs/unload.c new file mode 100644 index 0000000000000..c1ffae1967529 --- /dev/null +++ b/drivers/filesystems/udfs/unload.c @@ -0,0 +1,24 @@ +//////////////////////////////////////////////////////////////////// +// 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. +//////////////////////////////////////////////////////////////////// +#include "udffs.h" + +VOID +NTAPI +UDFDriverUnload( + IN PDRIVER_OBJECT DriverObject + ) +{ + UDFPrint(("UDF: Unloading!!\n")); + + // Release the object references we took in DriverEntry after + // IoRegisterFileSystem, matching Fastfat's FatUnload pattern. + if (UdfData.UDFDeviceObject_CD) { + ObDereferenceObject(UdfData.UDFDeviceObject_CD); + } + if (UdfData.UDFDeviceObject_HDD) { + ObDereferenceObject(UdfData.UDFDeviceObject_HDD); + } +} diff --git a/drivers/filesystems/udfs/unload.cpp b/drivers/filesystems/udfs/unload.cpp deleted file mode 100644 index 33dc5a5d16d57..0000000000000 --- a/drivers/filesystems/udfs/unload.cpp +++ /dev/null @@ -1,53 +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. -//////////////////////////////////////////////////////////////////// -#include "udffs.h" - -VOID -NTAPI -UDFDriverUnload( - IN PDRIVER_OBJECT DriverObject - ) -{ -// UNICODE_STRING uniWin32NameString; - LARGE_INTEGER delay; - - // - // All *THIS* driver needs to do is to delete the device object and the - // symbolic link between our device name and the Win32 visible name. - // - // Almost every other driver ever written would need to do a - // significant amount of work here deallocating stuff. - // - - UDFPrint( ("UDF: Unloading!!\n") ); - - // prevent mount oparations - UdfData.Flags |= UDF_DATA_FLAGS_SHUTDOWN; - - // wait for all volumes to be dismounted - delay.QuadPart = 10*1000*1000*10; - while(TRUE) { - UDFPrint(("Poll...\n")); - KeDelayExecutionThread(KernelMode, FALSE, &delay); - } - - // Create counted string version of our Win32 device name. - - -// RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME ); - - - // Delete the link from our device name to a name in the Win32 namespace. - - -// IoDeleteSymbolicLink( &uniWin32NameString ); - - - // Finally delete our device object - - -// IoDeleteDevice( DriverObject->DeviceObject ); -} 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..5111b0da8a420 100644 --- a/drivers/filesystems/udfs/verfysup.cpp +++ b/drivers/filesystems/udfs/verfysup.c @@ -89,7 +89,7 @@ UDFVerifyVcb( IO_STATUS_BLOCK Iosb; ULONG MediaChangeCount = 0; BOOLEAN ForceVerify = FALSE; - BOOLEAN DevMarkedForVerify; + BOOLEAN DevMarkedForVerify = FALSE; ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->VcbResource) || ExIsResourceAcquiredSharedLite(&Vcb->VcbResource)); @@ -263,7 +263,7 @@ UDFVerifyVolume( PVCB NewVcb = NULL; IO_STATUS_BLOCK Iosb; ULONG MediaChangeCount = 0; - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; BOOLEAN ReleaseVcb = FALSE; PAGED_CODE(); @@ -736,7 +736,7 @@ UDFDismountVcb( BOOLEAN VcbPresent = TRUE; KIRQL SavedIrql; - BOOLEAN FinalReference; + BOOLEAN FinalReference = FALSE; ASSERT_EXCLUSIVE_CDDATA; ASSERT_EXCLUSIVE_VCB(Vcb); diff --git a/drivers/filesystems/udfs/volinfo.cpp b/drivers/filesystems/udfs/volinfo.c similarity index 99% rename from drivers/filesystems/udfs/volinfo.cpp rename to drivers/filesystems/udfs/volinfo.c index c6ab4d3da9bf9..b5a39cbcf73f8 100644 --- a/drivers/filesystems/udfs/volinfo.cpp +++ b/drivers/filesystems/udfs/volinfo.c @@ -91,7 +91,7 @@ UDFCommonQueryVolInfo( { NTSTATUS Status = STATUS_INVALID_PARAMETER; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); - ULONG Length; + ULONG Length = 0; PVCB Vcb; TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; @@ -206,8 +206,8 @@ UDFQueryFsVolumeInfo( IN OUT PULONG Length ) { - ULONG BytesToCopy; - NTSTATUS Status; + ULONG BytesToCopy = 0; + NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); @@ -403,11 +403,11 @@ UDFQueryFsAttributeInfo( IN OUT PULONG Length ) { - ULONG BytesToCopy; + ULONG BytesToCopy = 0; NTSTATUS Status = STATUS_SUCCESS; PCWSTR FsTypeTitle; - ULONG FsTypeTitleLen; + ULONG FsTypeTitleLen = 0; PAGED_CODE(); UDFPrint((" UDFQueryFsAttributeInfo: \n")); @@ -464,7 +464,7 @@ UDFCommonSetVolInfo( { NTSTATUS Status = STATUS_INVALID_PARAMETER; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - ULONG Length; + ULONG Length = 0; FS_INFORMATION_CLASS FsInformationClass; PVOID Buffer; TYPE_OF_OPEN TypeOfOpen; diff --git a/drivers/filesystems/udfs/write.cpp b/drivers/filesystems/udfs/write.c similarity index 97% rename from drivers/filesystems/udfs/write.cpp rename to drivers/filesystems/udfs/write.c index 076e5a6cbe305..d98faefab4b1c 100644 --- a/drivers/filesystems/udfs/write.cpp +++ b/drivers/filesystems/udfs/write.c @@ -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 @@ -225,7 +237,7 @@ UDFCommonWrite( // 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); } @@ -330,6 +342,9 @@ UDFCommonWrite( // Acquire the appropriate FCB resource if (PagingIo) { + // Don't offload jobs when doing paging IO - otherwise this can lead to + // deadlocks in CcCopyWrite. + Wait = TRUE; // For PagingIo: FcbResource already acquired by UDFAcqLazyWrite/UDFFastIoAcqModWrite // callback before this function is called @@ -397,7 +412,7 @@ UDFCommonWrite( !RecursiveWriteThrough && !IsLazyWriteThread) { - BOOLEAN ExtendFS; + BOOLEAN ExtendFS = FALSE; ExtendFS = (StartingOffset + TruncatedLength > Fcb->Header.FileSize.QuadPart); @@ -408,7 +423,9 @@ UDFCommonWrite( try_return(Status = STATUS_PENDING); // CanWait = TRUE; + UDFAcquirePagingIoExclusive(IrpContext, Fcb); + PagingIoResourceAcquired = TRUE; if (ExtendFS) { @@ -428,8 +445,15 @@ UDFCommonWrite( } } - UDFReleasePagingIo(IrpContext, Fcb); - PagingIoResourceAcquired = FALSE; + // For cached I/O, release now so that CcCopyWrite-triggered + // paging reads (which acquire PagingIoResource shared) do + // not deadlock against our exclusive hold. + // For non-cached I/O, keep it held through UDFWriteFile__ to + // protect against concurrent paging reads seeing a freed mapping. + if (!NonCachedIo) { + UDFReleasePagingIo(IrpContext, Fcb); + PagingIoResourceAcquired = FALSE; + } if (CcIsFileCached(FileObject)) { if (ExtendFS) { @@ -560,7 +584,7 @@ UDFCommonWrite( // Send the request to lower level drivers if (!Wait) { - UDFPrint(("UDFCommonWrite: Post physical write %x bytes at %x\n", TruncatedLength, StartingOffset.LowPart)); + UDFPrint(("UDFCommonWrite: Post physical write %x bytes at %x\n", TruncatedLength, (ULONG)StartingOffset)); try_return(Status = STATUS_PENDING); } @@ -577,6 +601,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 +613,7 @@ UDFCommonWrite( PagingIoResourceAcquired = TRUE; } + Status = UDFWriteFile__(IrpContext, Vcb, Fcb->FileInfo, StartingOffset, TruncatedLength, FALSE, (PCHAR)SystemBuffer, &NumberBytesWritten); @@ -652,6 +678,7 @@ try_exit: NOTHING; // Release any resources acquired here ... if (PagingIoResourceAcquired) { + UDFReleasePagingIo(IrpContext, Fcb); } @@ -661,6 +688,7 @@ try_exit: NOTHING; if (VcbAcquired) { UDFReleaseVcb(IrpContext, Vcb); + } } _SEH2_END; // end of "__finally" processing @@ -732,9 +760,9 @@ UDFPurgeCacheEx_( PFILE_OBJECT FileObject ) { - ULONG Off_l; + ULONG Off_l = 0; #ifdef USE_CcCopyWrite_TO_ZERO - ULONG PgLen; + ULONG PgLen = 0; #endif //USE_CcCopyWrite_TO_ZERO // We'll just purge cache section here, @@ -897,7 +925,7 @@ UDFZeroData ( LARGE_INTEGER ZeroStart = {0,0}; LARGE_INTEGER BeyondZeroEnd = {0,0}; - BOOLEAN Finished; + BOOLEAN Finished = FALSE; PAGED_CODE();