//////////////////////////////////////////////////////////////////// // 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. //////////////////////////////////////////////////////////////////// /* Module name: mount.cpp Abstract: This file contains filesystem-specific routines responsible for Mount/Umount */ #include "udf.h" /* FIXME */ #ifdef XCHG_DD #undef XCHG_DD #endif #define XCHG_DD(a,b) \ { \ ULONG _temp_; \ PULONG _from_, _to_; \ _from_ = ((PULONG)&(b)); \ _to_ = ((PULONG)&(a)); \ _temp_ = *_from_; \ *_from_ = *_to_; \ *_to_ = _temp_; \ } #define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_MOUNT OSSTATUS __fastcall UDFSetDstring( IN PUNICODE_STRING UName, IN dstring* Dest, IN uint32 Length ); #ifndef UDF_READ_ONLY_BUILD /* This routine loads specified bitmap. It is also allocate space if the bitmap is not allocated. */ OSSTATUS UDFPrepareXSpaceBitmap( IN PVCB Vcb, IN OUT PSHORT_AD XSpaceBitmap, IN OUT PEXTENT_INFO XSBMExtInfo, IN OUT int8** XSBM, IN OUT uint32* XSl ) { uint32 BS, j, LBS; uint32 plen; OSSTATUS status; EXTENT_MAP TmpExt; lb_addr locAddr; int8* _XSBM; uint16 Ident; SIZE_T ReadBytes; uint32 PartNum; if(!(XSpaceBitmap->extLength)) { *XSl = 0; *XSBM = NULL; return STATUS_SUCCESS; } PartNum = UDFGetPartNumByPartNdx(Vcb, Vcb->PartitionMaps-1); locAddr.partitionReferenceNum = (uint16)PartNum; plen = UDFPartStart(Vcb, PartNum) + UDFPartLen(Vcb, PartNum); BS = Vcb->BlockSize; LBS = Vcb->LBlockSize; *XSl = sizeof(SPACE_BITMAP_DESC) + ((plen+7)>>3); _XSBM = (int8*)DbgAllocatePool(NonPagedPool, (*XSl + BS - 1) & ~(BS-1) ); *XSBM = _XSBM; switch (XSpaceBitmap->extLength >> 30) { case EXTENT_RECORDED_ALLOCATED: { locAddr.logicalBlockNum = XSpaceBitmap->extPosition; *XSl = min(XSpaceBitmap->extLength, *XSl); TmpExt.extLength = XSpaceBitmap->extLength = *XSl; TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr); if(TmpExt.extLocation == LBA_OUT_OF_EXTENT) { BrutePoint(); } XSBMExtInfo->Mapping = UDFExtentToMapping(&TmpExt); XSBMExtInfo->Offset = 0; XSBMExtInfo->Length = *XSl; break; } case EXTENT_NEXT_EXTENT_ALLOCDESC: case EXTENT_NOT_RECORDED_NOT_ALLOCATED: { // allocate space for bitmap if(!OS_SUCCESS(status = UDFAllocFreeExtent(Vcb, *XSl, UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), XSBMExtInfo, EXTENT_FLAG_ALLOC_SEQUENTIAL) )) return status; if(XSBMExtInfo->Mapping[1].extLength) { UDFPrint(("Can't allocate space for Freed Space bitmap\n")); *XSl = 0; } else { *XSl = (uint32)(XSBMExtInfo->Length); XSpaceBitmap->extPosition = UDFPhysLbaToPart(Vcb, PartNum, XSBMExtInfo->Mapping[0].extLocation); } break; } case EXTENT_NOT_RECORDED_ALLOCATED: { // record Alloc-Not-Rec locAddr.logicalBlockNum = XSpaceBitmap->extPosition; *XSl = min((XSpaceBitmap->extLength & UDF_EXTENT_LENGTH_MASK), *XSl); TmpExt.extLength = XSpaceBitmap->extLength = *XSl; TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr); if(TmpExt.extLocation == LBA_OUT_OF_EXTENT) { BrutePoint(); } XSBMExtInfo->Mapping = UDFExtentToMapping(&TmpExt); XSBMExtInfo->Offset = 0; XSBMExtInfo->Length = *XSl; break; } } if(!_XSBM) { BrutePoint(); return STATUS_INSUFFICIENT_RESOURCES; } switch (XSpaceBitmap->extLength >> 30) { case EXTENT_RECORDED_ALLOCATED: { // read descriptor & bitmap if((!OS_SUCCESS(status = UDFReadTagged(Vcb, *XSBM, (j = TmpExt.extLocation), locAddr.logicalBlockNum, &Ident))) || (Ident != TID_SPACE_BITMAP_DESC) || (!OS_SUCCESS(status = UDFReadExtent(Vcb, XSBMExtInfo, 0, *XSl, FALSE, *XSBM, &ReadBytes))) ) { if(OS_SUCCESS(status)) { BrutePoint(); status = STATUS_FILE_CORRUPT_ERROR; } if(XSBMExtInfo->Mapping) { MyFreePool__(XSBMExtInfo->Mapping); XSBMExtInfo->Mapping = NULL; } DbgFreePool(*XSBM); *XSl = 0; *XSBM = NULL; return status; } else { // BrutePoint(); } return STATUS_SUCCESS; } #if 0 case EXTENT_NEXT_EXTENT_ALLOCDESC: case EXTENT_NOT_RECORDED_NOT_ALLOCATED: case EXTENT_NOT_RECORDED_ALLOCATED: { break; } #endif } PSPACE_BITMAP_DESC XSDesc = (PSPACE_BITMAP_DESC)(*XSBM); XSpaceBitmap->extLength = (*XSl + LBS -1) & ~(LBS-1); RtlZeroMemory(*XSBM, *XSl); XSDesc->descTag.tagIdent = TID_SPACE_BITMAP_DESC; UDFSetUpTag(Vcb, &(XSDesc->descTag), 0, XSpaceBitmap->extPosition); XSDesc->numOfBits = plen; XSDesc->numOfBytes = (*XSl)-sizeof(SPACE_BITMAP_DESC); return STATUS_SUCCESS; } // end UDFPrepareXSpaceBitmap() /* This routine updates Freed & Unallocated space bitmaps */ OSSTATUS UDFUpdateXSpaceBitmaps( IN PVCB Vcb, IN uint32 PartNum, IN PPARTITION_HEADER_DESC phd // partition header pointing to Bitmaps ) { uint32 i,j,d; uint32 plen, pstart, pend; int8* bad_bm; int8* old_bm; int8* new_bm; int8* fpart_bm; int8* upart_bm; OSSTATUS status, status2; int8* USBM=NULL; int8* FSBM=NULL; uint32 USl, FSl; EXTENT_INFO FSBMExtInfo, USBMExtInfo; // lb_addr locAddr; SIZE_T WrittenBytes; UDF_CHECK_BITMAP_RESOURCE(Vcb); plen = UDFPartLen(Vcb, PartNum); // locAddr.partitionReferenceNum = (uint16)PartNum; // prepare bitmaps for updating status = UDFPrepareXSpaceBitmap(Vcb, &(phd->unallocatedSpaceBitmap), &USBMExtInfo, &USBM, &USl); status2 = UDFPrepareXSpaceBitmap(Vcb, &(phd->freedSpaceBitmap), &FSBMExtInfo, &FSBM, &FSl); if(!OS_SUCCESS(status) || !OS_SUCCESS(status2)) { BrutePoint(); } pstart = UDFPartStart(Vcb, PartNum); new_bm = Vcb->FSBM_Bitmap; old_bm = Vcb->FSBM_OldBitmap; bad_bm = Vcb->BSBM_Bitmap; if((status == STATUS_INSUFFICIENT_RESOURCES) || (status2 == STATUS_INSUFFICIENT_RESOURCES)) { // try to recover insufficient resources if(USl && USBMExtInfo.Mapping) { USl -= sizeof(SPACE_BITMAP_DESC); status = UDFWriteExtent(Vcb, &USBMExtInfo, sizeof(SPACE_BITMAP_DESC), USl, FALSE, new_bm, &WrittenBytes); #ifdef UDF_DBG } else { UDFPrint(("Can't update USBM\n")); #endif // UDF_DBG } if(USBMExtInfo.Mapping) MyFreePool__(USBMExtInfo.Mapping); if(FSl && FSBMExtInfo.Mapping) { FSl -= sizeof(SPACE_BITMAP_DESC); status2 = UDFWriteExtent(Vcb, &FSBMExtInfo, sizeof(SPACE_BITMAP_DESC), FSl, FALSE, new_bm, &WrittenBytes); } else { status2 = status; UDFPrint(("Can't update FSBM\n")); } 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); pend = min(pstart + plen, Vcb->FSBM_BitCount); d=1<LB2B_Bits; // if we have some bad bits, mark corresponding area as BAD if(bad_bm) { for(i=pstart; iPartitionMaps; i++) { if((UDFGetPartNumByPartNdx(Vcb,i) == p->partitionNumber) && (!strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR02) || !strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR03))) { PPARTITION_HEADER_DESC phd; phd = (PPARTITION_HEADER_DESC)(p->partitionContentsUse); #ifdef UDF_DBG if(phd->unallocatedSpaceTable.extLength) { // rebuild unallocatedSpaceTable UDFPrint(("unallocatedSpaceTable (part %d)\n", i)); } if(phd->freedSpaceTable.extLength) { // rebuild freedSpaceTable UDFPrint(("freedSpaceTable (part %d)\n", i)); } #endif // UDF_DBG UDFUpdateXSpaceBitmaps(Vcb, p->partitionNumber, phd); PTag = (tag*)Buf; UDFSetUpTag(Vcb, PTag, PTag->descCRCLength, PTag->tagLocation); UDFWriteSectors(Vcb, TRUE, PTag->tagLocation, 1, FALSE, Buf, &WrittenBytes); } } return STATUS_SUCCESS; } // end UDFUpdatePartDesc() /* This routine blanks Unalloc Space Desc *//* OSSTATUS UDFUpdateUSpaceDesc( IN PVCB Vcb, int8* Buf ) { PUNALLOC_SPACE_DESC usd; SIZE_T WrittenBytes; usd = (PUNALLOC_SPACE_DESC)Buf; usd->numAllocDescs = 0; RtlZeroMemory(Buf+sizeof(UNALLOC_SPACE_DESC), Vcb->BlockSize - sizeof(UNALLOC_SPACE_DESC)); UDFSetUpTag(Vcb, &(usd->descTag), 0, usd->descTag.tagLocation); UDFWriteSectors(Vcb, TRUE, usd->descTag.tagLocation, 1, FALSE, Buf, &WrittenBytes); return STATUS_SUCCESS; }*/ /* update Logical volume integrity descriptor */ OSSTATUS UDFUpdateLogicalVolInt( PVCB Vcb, BOOLEAN Close ) { OSSTATUS RC = STATUS_SUCCESS; uint32 i, len; SIZE_T WrittenBytes; // uint32 lvid_count = 0; uint32 pSize; tag* PTag; LogicalVolIntegrityDesc *lvid; LogicalVolIntegrityDescImpUse* LVID_iUse; LogicalVolHeaderDesc* LVID_hd; uint32* partFreeSpace; BOOLEAN equal = FALSE; if(Vcb->CDR_Mode) return STATUS_SUCCESS; if(!Vcb->LVid) { return STATUS_UNSUCCESSFUL; } UDFPrint(("UDF: Updating LVID @%x (%x)\n", Vcb->LVid_loc.extLocation, Vcb->LVid_loc.extLength)); len = max(Vcb->LVid_loc.extLength, Vcb->BlockSize); lvid = Vcb->LVid; if(lvid->descTag.tagSerialNum > UDF_LVID_TTL) { // TODO: allocate space for new LVID } LVID_iUse = UDFGetLVIDiUse(Vcb); if((LVID_iUse->minUDFReadRev == Vcb->minUDFReadRev) && (LVID_iUse->minUDFWriteRev == Vcb->minUDFWriteRev) && (LVID_iUse->maxUDFWriteRev == Vcb->maxUDFWriteRev) && (LVID_iUse->numFiles == Vcb->numFiles) && (LVID_iUse->numDirs == Vcb->numDirs)) equal = TRUE; LVID_iUse->minUDFReadRev = Vcb->minUDFReadRev; LVID_iUse->minUDFWriteRev = Vcb->minUDFWriteRev; LVID_iUse->maxUDFWriteRev = Vcb->maxUDFWriteRev; LVID_iUse->numFiles = Vcb->numFiles; LVID_iUse->numDirs = Vcb->numDirs; #if 0 UDFSetEntityID_imp(&(LVID_iUse->impIdent), UDF_ID_DEVELOPER); #endif if(Close){ UDFPrint(("UDF: Opening LVID\n")); lvid->integrityType = INTEGRITY_TYPE_CLOSE; } else { UDFPrint(("UDF: Closing LVID\n")); lvid->integrityType = INTEGRITY_TYPE_OPEN; } equal = equal && (Vcb->IntegrityType == lvid->integrityType); // update Free Space Table partFreeSpace = (uint32*)(lvid+1); for(i=0; inumOfPartitions; i++) { pSize = UDFGetPartFreeSpace(Vcb, i) >> Vcb->LB2B_Bits; equal = equal && (partFreeSpace[i] == pSize); partFreeSpace[i] = pSize; } // Update LVID Header Descriptor LVID_hd = (LogicalVolHeaderDesc*)&(lvid->logicalVolContentsUse); equal = equal && (LVID_hd->uniqueID == Vcb->NextUniqueId); LVID_hd->uniqueID = Vcb->NextUniqueId; if(equal) { UDFPrint(("UDF: equal Ids\n")); return STATUS_SUCCESS; } PTag = &(lvid->descTag); lvid->lengthOfImpUse = sizeof(LogicalVolIntegrityDescImpUse); UDFSetUpTag(Vcb, PTag, sizeof(LogicalVolIntegrityDesc) + sizeof(uint32)*2*lvid->numOfPartitions + sizeof(LogicalVolIntegrityDescImpUse), PTag->tagLocation); Vcb->IntegrityType = INTEGRITY_TYPE_OPEN; // make happy auto-dirty RC = UDFWriteSectors(Vcb, TRUE, PTag->tagLocation, len >> Vcb->BlockSizeBits, FALSE, (int8*)(lvid), &WrittenBytes); WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, PTag->tagLocation, len >> Vcb->BlockSizeBits); // update it here to prevent recursion Vcb->IntegrityType = lvid->integrityType; return RC; } // end UDFUpdateLogicalVolInt() /* This routine reads all sparing tables & stores them in contiguos memory space */ OSSTATUS UDFUpdateSparingTable( IN PVCB Vcb ) { PSPARING_MAP RelocMap; // PSPARING_MAP NewRelocMap; OSSTATUS status = STATUS_SUCCESS; OSSTATUS status2 = STATUS_SUCCESS; uint32 i=0, BC, BC2; PSPARING_TABLE SparTable; SIZE_T ReadBytes; // uint32 n,m; // BOOLEAN merged; BOOLEAN sorted; UDFPrint(("UDF: Updating Sparable Part Map:\n")); if(!Vcb->SparingTableModified) return STATUS_SUCCESS; if(!Vcb->SparingTable) return STATUS_SUCCESS; BC = (Vcb->SparingTableLength >> Vcb->BlockSizeBits) + 1; SparTable = (PSPARING_TABLE)MyAllocatePool__(NonPagedPool, BC*Vcb->BlockSize); if(!SparTable) return STATUS_INSUFFICIENT_RESOURCES; // if a part of Sparing Table is already loaded, // update it with data from another one RelocMap = Vcb->SparingTable; // sort sparing table //merged = FALSE; do { sorted = FALSE; for(i=1;iSparingCount;i++) { if(RelocMap[i-1].origLocation > RelocMap[i].origLocation) { XCHG_DD(RelocMap[i-1].origLocation, RelocMap[i].origLocation); swp_loc: XCHG_DD(RelocMap[i-1].mappedLocation, RelocMap[i].mappedLocation); //merged = TRUE; sorted = TRUE; } else if(RelocMap[i-1].origLocation == SPARING_LOC_AVAILABLE && RelocMap[i].origLocation == SPARING_LOC_AVAILABLE && RelocMap[i-1].mappedLocation > RelocMap[i].mappedLocation) { goto swp_loc; } } } while(sorted); for(i=0;iSparingCount;i++) { UDFPrint((" @%x -> %x \n", RelocMap[i].origLocation, RelocMap[i].mappedLocation)); } Vcb->SparingTableModified = FALSE; // if(!merged) { // UDFPrint((" sparing table unchanged\n")); // MyFreePool__(SparTable); // return STATUS_SUCCESS; // } // walk through all available Sparing Tables for(i=0;iSparingTableCount;i++) { // read (next) table UDFPrint((" sparing table @%x\n", Vcb->SparingTableLoc[i])); status = UDFReadSectors(Vcb, FALSE, Vcb->SparingTableLoc[i], 1, FALSE, (int8*)SparTable, &ReadBytes); // tag should be set to TID_UNUSED_DESC if(OS_SUCCESS(status) && (SparTable->descTag.tagIdent == TID_UNUSED_DESC)) { BC2 = ((sizeof(SPARING_TABLE) + SparTable->reallocationTableLen*sizeof(SparingEntry) + Vcb->BlockSize-1) >> Vcb->BlockSizeBits); if(BC2 > BC) { UDFPrint((" sizeSparingTable @%x too long: %x > %x\n", Vcb->SparingTableLoc[i], BC2, BC )); continue; } status = UDFReadSectors(Vcb, FALSE, Vcb->SparingTableLoc[i], BC2, FALSE, (int8*)SparTable, &ReadBytes); if(!OS_SUCCESS(status)) { UDFPrint((" Error reading sizeSparingTable @%x (%x)\n", Vcb->SparingTableLoc[i], BC2 )); continue; } BC2 = ((sizeof(SPARING_TABLE) + Vcb->SparingCount*sizeof(SparingEntry) + Vcb->BlockSize-1) >> Vcb->BlockSizeBits); if(BC2 > BC) { UDFPrint((" new sizeSparingTable @%x too long: %x > %x\n", Vcb->SparingTableLoc[i], BC2, BC )); continue; } SparTable->reallocationTableLen = (USHORT)Vcb->SparingCount; RtlCopyMemory((SparTable+1), RelocMap, Vcb->SparingCount*sizeof(SparingEntry)); /* merged = FALSE; NewRelocMap = (PSPARING_MAP)(SparTable+1); for(n=0; nreallocationTableLen; n++) { for(m=0; mSparingCount; m++) { if(RelocMap[m].mappedLocation == NewRelocMap[n].mappedLocation) { if(RelocMap[m].origLocation != NewRelocMap[n].origLocation) { UDFPrint((" update @%x (%x) -> @%x (%x)\n", NewRelocMap[m].origLocation, NewRelocMap[m].mappedLocation, RelocMap[m].origLocation, RelocMap[m].mappedLocation)); merged = TRUE; } } } } */ // if(merged) { UDFPrint(("UDF: record updated\n")); status = UDFWriteSectors(Vcb, FALSE, Vcb->SparingTableLoc[i], BC2, FALSE, (int8*)SparTable, &ReadBytes); if(!OS_SUCCESS(status)) { if(!OS_SUCCESS(status2)) { status2 = status; } // } } } } MyFreePool__(SparTable); if(!OS_SUCCESS(status2)) { status = status2; } return status; } // end UDFUpdateSparingTable() /* update Logical volume descriptor */ OSSTATUS UDFUpdateLogicalVol( IN PVCB Vcb, IN UDF_VDS_RECORD Lba, IN PUNICODE_STRING VolIdent ) { LogicalVolDesc* lvd = NULL; #define CUR_IDENT_SZ (sizeof(lvd->logicalVolIdent)) dstring CS0[CUR_IDENT_SZ]; uint16 ident; SIZE_T WrittenBytes; OSSTATUS status = STATUS_SUCCESS; // OSSTATUS status2 = STATUS_SUCCESS; status = UDFUpdateSparingTable(Vcb); if(!(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_VLABEL)) { goto Err_SetVI; } lvd = (LogicalVolDesc*)MyAllocatePool__(NonPagedPool, max(Vcb->BlockSize, sizeof(LogicalVolDesc)) ); if(!lvd) { status = STATUS_INSUFFICIENT_RESOURCES; goto Err_SetVI; } UDFPrint(("UDF: Updating LVD @%x (%x)\n", Lba.block, Vcb->BlockSize)); status = UDFSetDstring(&(Vcb->VolIdent), (dstring*)&CS0, CUR_IDENT_SZ); if(!OS_SUCCESS(status)) { if(status == STATUS_INVALID_PARAMETER) { status = STATUS_INVALID_VOLUME_LABEL; } goto Err_SetVI; } if(!Lba.block) { status = STATUS_INVALID_PARAMETER; goto Err_SetVI; } status = UDFReadTagged(Vcb, (int8*)lvd, Lba.block, Lba.block, &ident); if(!OS_SUCCESS(status)) goto Err_SetVI; if(ident != TID_LOGICAL_VOL_DESC) { status = STATUS_FILE_CORRUPT_ERROR; goto Err_SetVI; } if(RtlCompareMemory(lvd->logicalVolIdent, CS0, CUR_IDENT_SZ) == CUR_IDENT_SZ) { // no changes UDFPrint(("UDF: equal VolIds\n")); status = STATUS_SUCCESS; goto Err_SetVI; } RtlCopyMemory(lvd->logicalVolIdent, CS0, CUR_IDENT_SZ); lvd->descTag.tagSerialNum --; UDFSetUpTag(Vcb, (tag*)lvd, lvd->descTag.descCRCLength, Lba.block); status = UDFWriteSectors(Vcb, TRUE, Lba.block, 1, FALSE, (int8*)lvd, &WrittenBytes); Err_SetVI: if(lvd) MyFreePool__(lvd); #undef CUR_IDENT_SZ //#endif //0 return status; } // end UDFUpdateLogicalVol() /* This routine updates volume descriptor sequence */ OSSTATUS UDFUpdateVDS( IN PVCB Vcb, IN uint32 block, IN uint32 lastblock, IN uint32 flags ) { OSSTATUS status; int8* Buf = (int8*)DbgAllocatePool(NonPagedPool,Vcb->LBlockSize); UDF_VDS_RECORD vds[VDS_POS_LENGTH]; uint32 i,j; uint16 ident; if (!Buf) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory(vds, sizeof(UDF_VDS_RECORD) * VDS_POS_LENGTH); if(!OS_SUCCESS(status = UDFReadVDS(Vcb, block, lastblock, (PUDF_VDS_RECORD)&vds, Buf))) { DbgFreePool(Buf); return status; } /* // update USD (if any) for (i=0; iBlockSize); if (!Buf2) { DbgFreePool(Buf); return STATUS_INSUFFICIENT_RESOURCES; } for (j=vds[i].block+1; jBlockSize); if (!Buf2) { DbgFreePool(Buf); return STATUS_INSUFFICIENT_RESOURCES; } UDFUpdatePartDesc(Vcb,Buf); for (j=vds[i].block+1; jVolIdent)); if(!OS_SUCCESS(status)) continue; } } } DbgFreePool(Buf); return status; } // end UDFUpdateVDS() #endif //UDF_READ_ONLY_BUILD OSSTATUS __fastcall UDFSetDstring( IN PUNICODE_STRING UName, IN dstring* Dest, IN uint32 Length ) { uint8* CS0; SIZE_T len = Length-1; UDFCompressUnicode(UName, &CS0, &len); if(!CS0) return STATUS_INSUFFICIENT_RESOURCES; if(len > Length-1) { MyFreePool__(CS0); return STATUS_INVALID_PARAMETER; } RtlCopyMemory(Dest, CS0, len); MyFreePool__(CS0); if(len < Length-1) RtlZeroMemory(Dest+len, Length-1-len); Dest[Length-1] = (uint8)len; return TRUE; } // end UDFSetDstring() void __fastcall UDFGetDstring( IN OUT PUNICODE_STRING UName, IN dstring* Dest, IN uint32 Length ) { uint32 len = Dest[Length-1]; UDFDecompressUnicode(UName, Dest, len, NULL); return; } // end UDFGetDstring() #ifndef UDF_READ_ONLY_BUILD /* This routine updates Volume Label & some other features stored in VolIdentDesc */ OSSTATUS UDFUpdateVolIdent( IN PVCB Vcb, IN UDF_VDS_RECORD Lba, IN PUNICODE_STRING VolIdent ) { #define CUR_IDENT_SZ (sizeof(pvoldesc->volIdent)) PrimaryVolDesc* pvoldesc = (PrimaryVolDesc*)MyAllocatePool__(NonPagedPool, max(Vcb->BlockSize, sizeof(PrimaryVolDesc)) ); OSSTATUS status; dstring CS0[CUR_IDENT_SZ]; uint16 ident; SIZE_T WrittenBytes; if(!pvoldesc) return STATUS_INSUFFICIENT_RESOURCES; UDFPrint(("UDF: Updating PVD @%x (%x)\n", Lba.block, Vcb->BlockSize)); status = UDFSetDstring(&(Vcb->VolIdent), (dstring*)&CS0, CUR_IDENT_SZ); if(!OS_SUCCESS(status)) { if(status == STATUS_INVALID_PARAMETER) { status = STATUS_INVALID_VOLUME_LABEL; } goto Err_SetVI; } if(!Lba.block) { status = STATUS_INVALID_PARAMETER; goto Err_SetVI; } status = UDFReadTagged(Vcb, (int8*)pvoldesc, Lba.block, Lba.block, &ident); if(!OS_SUCCESS(status)) goto Err_SetVI; if(ident != TID_PRIMARY_VOL_DESC) { status = STATUS_FILE_CORRUPT_ERROR; goto Err_SetVI; } if(RtlCompareMemory(pvoldesc->volIdent, CS0, CUR_IDENT_SZ) == CUR_IDENT_SZ) { // no changes status = STATUS_SUCCESS; goto Err_SetVI; } RtlCopyMemory(pvoldesc->volIdent, CS0, CUR_IDENT_SZ); pvoldesc->descTag.tagSerialNum --; UDFSetUpTag(Vcb, (tag*)pvoldesc, pvoldesc->descTag.descCRCLength, Lba.block); status = UDFWriteSectors(Vcb, TRUE, Lba.block, 1, FALSE, (int8*)pvoldesc, &WrittenBytes); Err_SetVI: MyFreePool__(pvoldesc); return status; #undef CUR_IDENT_SZ } // end UDFUpdateVolIdent() #endif //UDF_READ_ONLY_BUILD OSSTATUS UDFUpdateNonAllocated( IN PVCB Vcb ) { uint32 PartNum; uint32 i; uint32 plen, pstart, pend; int8* bad_bm; EXTENT_AD Ext; PEXTENT_MAP Map = NULL; PEXTENT_INFO DataLoc; UDFPrint(("UDFUpdateNonAllocated:\n")); if(!Vcb->NonAllocFileInfo) { return STATUS_SUCCESS; } if(!(bad_bm = Vcb->BSBM_Bitmap)) { return STATUS_SUCCESS; } DataLoc = &(Vcb->NonAllocFileInfo->Dloc->DataLoc); ASSERT(!DataLoc->Offset); if(Vcb->NonAllocFileInfo->Dloc->DataLoc.Offset) { UDFPrint(("NonAllocFileInfo in IN_ICB mode !!!\n")); return STATUS_SUCCESS; } PartNum = UDFGetPartNumByPhysLba(Vcb, Vcb->NonAllocFileInfo->Dloc->FELoc.Mapping[0].extLocation); pstart = UDFPartStart(Vcb, PartNum); plen = UDFPartLen(Vcb, PartNum); pend = min(pstart + plen, Vcb->FSBM_BitCount); //BrutePoint(); for(i=pstart; iMapping, i) != LBA_OUT_OF_EXTENT) { UDFPrint(("lba %#x is already in NonAllocFileInfo\n", i)); continue; } UDFPrint(("add lba %#x to NonAllocFileInfo\n", i)); DataLoc->Modified = TRUE; Ext.extLength = Vcb->LBlockSize; // align lba on LogicalBlock boundary Ext.extLocation = i & ~((1<LB2B_Bits) - 1); Map = UDFExtentToMapping(&Ext); DataLoc->Mapping = UDFMergeMappings(DataLoc->Mapping, Map); } UDFPackMapping(Vcb, DataLoc); DataLoc->Length = UDFGetExtentLength(DataLoc->Mapping); UDFFlushFile__(Vcb, Vcb->NonAllocFileInfo); // ensure that BAD space is marked as USED UDFMarkSpaceAsXXX(Vcb, 0, &(DataLoc->Mapping[0]), AS_USED); // mark as used UDFPrint(("UDFUpdateNonAllocated: done\n")); return STATUS_SUCCESS; } // end UDFUpdateNonAllocated() /* This routine rebuilds & flushes all system areas */ OSSTATUS UDFUmount__( IN PVCB Vcb ) { #ifndef UDF_READ_ONLY_BUILD uint32 flags = 0; if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) || !Vcb->Modified) return STATUS_SUCCESS; // prevent discarding metadata Vcb->VCBFlags |= UDF_VCB_ASSUME_ALL_USED; if(Vcb->CDR_Mode) { // flush internal cache if(WCacheGetWriteBlockCount__(&(Vcb->FastCache)) >= (Vcb->WriteBlockSize >> Vcb->BlockSizeBits) ) WCacheFlushAll__(&(Vcb->FastCache), Vcb); // record VAT return UDFRecordVAT(Vcb); } UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_FE); UDFFlushAllCachedAllocations(Vcb, UDF_PREALLOC_CLASS_DIR); if(Vcb->VerifyOnWrite) { UDFPrint(("UDF: Flushing cache for verify\n")); //WCacheFlushAll__(&(Vcb->FastCache), Vcb); WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA); UDFVFlush(Vcb); } // synchronize BAD Block bitmap and NonAllocatable UDFUpdateNonAllocated(Vcb); UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE); // RAM mode #ifdef UDF_DBG if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)))) UDFPrint(("Error updating VolIdent (1)\n")); if(!OS_SUCCESS(UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent)))) UDFPrint(("Error updating VolIdent (2)\n")); #else UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr, &(Vcb->VolIdent)); UDFUpdateVolIdent(Vcb, Vcb->PVolDescAddr2, &(Vcb->VolIdent)); #endif // UDF_DBG 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)) { flags &= ~1; } else { flags |= 1; } #ifdef UDF_DBG if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags))) UDFPrint(("Error updating Main VDS\n")); if(!OS_SUCCESS(UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags))) UDFPrint(("Error updating Reserve VDS\n")); #else UDFUpdateVDS(Vcb, Vcb->VDS1, Vcb->VDS1 + Vcb->VDS1_Len, flags); UDFUpdateVDS(Vcb, Vcb->VDS2, Vcb->VDS2 + Vcb->VDS2_Len, flags); #endif // UDF_DBG // Update Integrity Desc if any if(Vcb->LVid && Vcb->origIntegrityType == INTEGRITY_TYPE_CLOSE) { UDFUpdateLogicalVolInt(Vcb, TRUE); } if(flags & 1) RtlCopyMemory(Vcb->FSBM_OldBitmap, Vcb->FSBM_Bitmap, Vcb->FSBM_ByteCount); //skip_update_bitmap: Vcb->VCBFlags &= ~UDF_VCB_ASSUME_ALL_USED; UDFReleaseResource(&(Vcb->BitMapResource1)); #endif //UDF_READ_ONLY_BUILD return STATUS_SUCCESS; } // end UDFUmount__() /*************************************************************************/ /* Find an anchor volume descriptor. The UDFGetDiskInfoAndVerify() will invoke this routine to find & check Anchor Volume Descriptors on the target device */ lba_t UDFFindAnchor( PVCB Vcb // Volume control block ) { // OSSTATUS RC = STATUS_SUCCESS; uint16 ident; uint32 i; uint32 LastBlock; OSSTATUS status; int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); BOOLEAN MRW_candidate; BOOLEAN IsMRW = (Vcb->MRWStatus != 0); if(!Buf) return 0; UDFPrint(("UDFFindAnchor\n")); // init probable locations... RtlZeroMemory(&(Vcb->Anchor), sizeof(Vcb->Anchor)); Vcb->Anchor[0] = 256 + Vcb->FirstLBALastSes; Vcb->Anchor[1] = 512 + Vcb->FirstLBALastSes; Vcb->Anchor[2] = 256 + Vcb->TrackMap[Vcb->LastTrackNum].FirstLba; Vcb->Anchor[3] = 512 + Vcb->TrackMap[Vcb->LastTrackNum].FirstLba; Vcb->Anchor[4] = Vcb->LastLBA - 256; Vcb->Anchor[5] = Vcb->LastLBA - 256 + 1; Vcb->Anchor[6] = Vcb->LastLBA - 256 - 2; // vat locations Vcb->Anchor[7] = Vcb->LastLBA - 2; Vcb->Anchor[8] = Vcb->LastLBA; Vcb->Anchor[9] = Vcb->LastLBA - 512; // Vcb->Anchor[7] = Vcb->LastLBA - 256 - 7; // Vcb->Anchor[8] = Vcb->LastLBA - 512 - 2; // Vcb->Anchor[9] = Vcb->LastLBA - 512 - 7; LastBlock = 0; // ... and check them for (i=0; iAnchor)/sizeof(int); i++) { if(Vcb->Anchor[i] > Vcb->LastLBA) Vcb->Anchor[i] = 0; MRW_candidate = FALSE; if(Vcb->Anchor[i]) { UDFPrint(("check Anchor %x\n", Vcb->Anchor[i])); if(!OS_SUCCESS(status = UDFReadTagged(Vcb,Buf, Vcb->Anchor[i], Vcb->Anchor[i], &ident))) { // Fucking MRW... if(!IsMRW && (i<2) && (Vcb->CompatFlags & UDF_VCB_IC_MRW_ADDR_PROBLEM)) { if(OS_SUCCESS(status = UDFReadTagged(Vcb,Buf, Vcb->Anchor[i]+MRW_DMA_OFFSET, Vcb->Anchor[i], &ident))) { // do MRW workaround..... UDFPrint(("UDF: looks like we have MRW....\n")); MRW_candidate = TRUE; goto MRW_workaround; } } Vcb->Anchor[i] = 0; if(status == STATUS_NONEXISTENT_SECTOR) { UDFPrint(("UDF: disk seems to be incomplete\n")); break; } } else { MRW_workaround: if((ident != TID_ANCHOR_VOL_DESC_PTR) && ((i<6) || (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY))) { Vcb->Anchor[i] = 0; } else { UDFPrint(("UDF: Found AVD at %x (point %d)\n",Vcb->Anchor[i], i)); if(!LastBlock) LastBlock = Vcb->LastLBA; if(MRW_candidate) { UDFPrint(("UDF: looks like we _*really*_ have MRW....\n")); IsMRW = TRUE; ASSERT(Vcb->LastReadTrack == 1); Vcb->TrackMap[Vcb->LastReadTrack].Flags |= TrackMap_FixMRWAddressing; WCachePurgeAll__(&(Vcb->FastCache), Vcb); UDFPrint(("UDF: MRW on non-MRW drive => ReadOnly")); Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; UDFRegisterFsStructure(Vcb, Vcb->Anchor[i], Vcb->BlockSize); } } } } } UDFPrint(("UDF: -----------------\nUDF: Last block %x\n",LastBlock)); MyFreePool__(Buf); return LastBlock; } // end UDFFindAnchor() /* Look for Volume recognition sequence */ uint32 UDFFindVRS( PVCB Vcb ) { VolStructDesc *vsd = NULL; uint32 offset; uint32 retStat = 0; uint32 BeginOffset = Vcb->FirstLBA; OSSTATUS RC; int8* buffer = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); SIZE_T ReadBytes; if(!buffer) return 0; // Relative to First LBA in Last Session offset = Vcb->FirstLBA + 0x10; UDFPrint(("UDFFindVRS:\n")); // Process the sequence (if applicable) for (;(offset-BeginOffset <=0x20); offset ++) { // Read a block RC = UDFReadSectors(Vcb, FALSE, offset, 1, FALSE, buffer, &ReadBytes); if(!OS_SUCCESS(RC)) continue; // Look for ISO descriptors vsd = (VolStructDesc *)(buffer); if(vsd->stdIdent[0]) { if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_CD001, STD_ID_LEN)) { retStat |= VRS_ISO9660_FOUND; switch (vsd->structType) { case 0: UDFPrint(("UDF: ISO9660 Boot Record found\n")); break; case 1: UDFPrint(("UDF: ISO9660 Primary Volume Descriptor found\n")); break; case 2: UDFPrint(("UDF: ISO9660 Supplementary Volume Descriptor found\n")); break; case 3: UDFPrint(("UDF: ISO9660 Volume Partition Descriptor found\n")); break; case 255: UDFPrint(("UDF: ISO9660 Volume Descriptor Set Terminator found\n")); break; default: UDFPrint(("UDF: ISO9660 VRS (%u) found\n", vsd->structType)); break; } } else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_BEA01, STD_ID_LEN)) { UDFPrint(("UDF: BEA01 Found\n")); } else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_TEA01, STD_ID_LEN)) { UDFPrint(("UDF: TEA01 Found\n")); break; } else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_NSR02, STD_ID_LEN)) { retStat |= VRS_NSR02_FOUND; UDFPrint(("UDF: NSR02 Found\n")); break; } else if(!strncmp((int8*)(&vsd->stdIdent), STD_ID_NSR03, STD_ID_LEN)) { retStat |= VRS_NSR03_FOUND; UDFPrint(("UDF: NSR03 Found\n")); break; } } } MyFreePool__(buffer); return retStat; } // end UDFFindVRS() /* process Primary volume descriptor */ void UDFLoadPVolDesc( PVCB Vcb, int8* Buf // pointer to buffer containing PVD ) { PrimaryVolDesc *pvoldesc; // OSSTATUS RC = STATUS_SUCCESS; pvoldesc = (PrimaryVolDesc *)Buf; UDFPrint(("UDF: PrimaryVolDesc:\n")); UDFPrint(("volDescSeqNum = %d\n", pvoldesc->volDescSeqNum)); UDFPrint(("primaryVolDescNum = %d\n", pvoldesc->primaryVolDescNum)); // remember recording time... Vcb->VolCreationTime = UDFTimeToNT(&(pvoldesc->recordingDateAndTime)); // ...VolIdent... #define CUR_IDENT_SZ (sizeof(pvoldesc->volIdent)) if (Vcb->VolIdent.Buffer) { MyFreePool__(Vcb->VolIdent.Buffer); } UDFGetDstring(&(Vcb->VolIdent), (dstring*)&(pvoldesc->volIdent), CUR_IDENT_SZ); #undef CUR_IDENT_SZ UDFPrint(("volIdent[] = '%ws'\n", Vcb->VolIdent.Buffer)); #ifdef UDF_DBG UDFPrint(("volSeqNum = %d\n", pvoldesc->volSeqNum)); UDFPrint(("maxVolSeqNum = %d\n", pvoldesc->maxVolSeqNum)); UDFPrint(("interchangeLvl = %d\n", pvoldesc->interchangeLvl)); UDFPrint(("maxInterchangeLvl = %d\n", pvoldesc->maxInterchangeLvl)); UDFPrint(("charSetList = %d\n", pvoldesc->charSetList)); UDFPrint(("maxCharSetList = %d\n", pvoldesc->maxCharSetList)); // ...& just print VolSetIdent UNICODE_STRING instr; #define CUR_IDENT_SZ (sizeof(pvoldesc->volSetIdent)) UDFGetDstring(&instr, (dstring*)&(pvoldesc->volSetIdent), CUR_IDENT_SZ); #undef CUR_IDENT_SZ UDFPrint(("volSetIdent[] = '%ws'\n", instr.Buffer)); // UDFPrint(("maxInterchangeLvl = %d\n", pvoldesc->maxInterchangeLvl)); UDFPrint(("flags = %x\n", pvoldesc->flags)); if(instr.Buffer) MyFreePool__(instr.Buffer); #endif // UDF_DBG } // end UDFLoadPVolDesc() /* load Logical volume integrity descriptor */ OSSTATUS UDFLoadLogicalVolInt( PDEVICE_OBJECT DeviceObject, PVCB Vcb, extent_ad loc ) { OSSTATUS RC = STATUS_SUCCESS; uint32 len; SIZE_T _ReadBytes; int8* Buf = NULL; uint16 ident; LogicalVolIntegrityDescImpUse* LVID_iUse; LogicalVolHeaderDesc* LVID_hd; extent_ad last_loc; BOOLEAN read_last = FALSE; uint32 lvid_count = 0; ASSERT(!Vcb->LVid); if(Vcb->LVid) { MyFreePool__(Vcb->LVid); Vcb->LVid = NULL; } // walk through all sectors inside LogicalVolumeIntegrityDesc while(loc.extLength) { UDFPrint(("UDF: Reading LVID @%x (%x)\n", loc.extLocation, loc.extLength)); len = max(loc.extLength, Vcb->BlockSize); Buf = (int8*)MyAllocatePool__(NonPagedPool,len); if(!Buf) return STATUS_INSUFFICIENT_RESOURCES; RC = UDFReadTagged(Vcb,Buf, loc.extLocation, loc.extLocation, &ident); if(!OS_SUCCESS(RC)) { exit_with_err: UDFPrint(("UDF: Reading LVID @%x (%x) failed.\n", loc.extLocation, loc.extLength)); switch(Vcb->PartitialDamagedVolumeAction) { case UDF_PART_DAMAGED_RO: UDFPrint(("UDF: Switch to r/o mode.\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_MEDIA_DEFECT_RO; RC = STATUS_SUCCESS; break; case UDF_PART_DAMAGED_NO: UDFPrint(("UDF: Switch to raw mount mode, return UNRECOGNIZED_VOLUME.\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; //RC = STATUS_WRONG_VOLUME; break; case UDF_PART_DAMAGED_RW: default: UDFPrint(("UDF: Keep r/w mode for your own risk.\n")); RC = STATUS_SUCCESS; // asume we have INTEGRITY_TYPE_CLOSE Vcb->IntegrityType = INTEGRITY_TYPE_CLOSE; break; } MyFreePool__(Buf); return RC; } UDFRegisterFsStructure(Vcb, loc.extLocation, len); // handle Terminal Entry if(ident == TID_TERMINAL_ENTRY) { read_last = TRUE; MyFreePool__(Buf); Vcb->LVid = NULL; loc = last_loc; continue; } else if(ident != TID_LOGICAL_VOL_INTEGRITY_DESC) { RC = STATUS_DISK_CORRUPT_ERROR; goto exit_with_err; } Vcb->LVid = (LogicalVolIntegrityDesc *)Buf; RC = UDFReadData(Vcb, TRUE, ((uint64)(loc.extLocation)) << Vcb->BlockSizeBits, len, FALSE, Buf, &_ReadBytes); // update info if( !read_last && Vcb->LVid->nextIntegrityExt.extLength) { // go to next LVID last_loc = loc; loc = Vcb->LVid->nextIntegrityExt; Vcb->LVid = NULL; lvid_count++; if(lvid_count > UDF_MAX_LVID_CHAIN_LENGTH) { RC = STATUS_DISK_CORRUPT_ERROR; goto exit_with_err; } MyFreePool__(Buf); continue; } // process last LVID Vcb->origIntegrityType = Vcb->IntegrityType = Vcb->LVid->integrityType; Vcb->LVid_loc = loc; LVID_iUse = UDFGetLVIDiUse(Vcb); UDFPrint(("UDF: Last LVID:\n")); UDFPrint((" minR: %x\n",LVID_iUse->minUDFReadRev )); UDFPrint((" minW: %x\n",LVID_iUse->minUDFWriteRev)); UDFPrint((" maxW: %x\n",LVID_iUse->maxUDFWriteRev)); UDFPrint((" Type: %s\n",!Vcb->IntegrityType ? "Open" : "Close")); Vcb->minUDFReadRev = LVID_iUse->minUDFReadRev; Vcb->minUDFWriteRev = LVID_iUse->minUDFWriteRev; Vcb->maxUDFWriteRev = LVID_iUse->maxUDFWriteRev; Vcb->numFiles = LVID_iUse->numFiles; Vcb->numDirs = LVID_iUse->numDirs; UDFPrint((" nFiles: %x\n",Vcb->numFiles )); UDFPrint((" nDirs: %x\n",Vcb->numDirs )); // Check if we can understand this format if(Vcb->minUDFReadRev > UDF_MAX_READ_REVISION) RC = STATUS_UNRECOGNIZED_VOLUME; // Check if we know how to write here if(Vcb->minUDFWriteRev > UDF_MAX_WRITE_REVISION) { UDFPrint((" Target FS requires: %x Revision => ReadOnly\n",Vcb->minUDFWriteRev)); Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_NEW_FS_RO; } LVID_hd = (LogicalVolHeaderDesc*)&(Vcb->LVid->logicalVolContentsUse); Vcb->NextUniqueId = LVID_hd->uniqueID; UDFPrint((" Next FID: %x\n",Vcb->NextUniqueId)); break; } return RC; } // end UDFLoadLogicalVolInt() /* load Logical volume descriptor */ OSSTATUS UDFLoadLogicalVol( PDEVICE_OBJECT DeviceObject, PVCB Vcb, int8* Buf, lb_addr *fileset ) { LogicalVolDesc *lvd = (LogicalVolDesc *)Buf; uint16 i, offset; uint8 type; OSSTATUS status = STATUS_SUCCESS; UDFPrint(("UDF: LogicalVolDesc\n")); // Validate partition map counter if(!(Vcb->Partitions)) { Vcb->PartitionMaps = lvd->numPartitionMaps; Vcb->Partitions = (PUDFPartMap)MyAllocatePool__(NonPagedPool, sizeof(UDFPartMap) * Vcb->PartitionMaps ); if(!Vcb->Partitions) return STATUS_INSUFFICIENT_RESOURCES; } else { if(Vcb->PartitionMaps != lvd->numPartitionMaps) return STATUS_DISK_CORRUPT_ERROR; } UDFPrint(("UDF: volDescSeqNum = %x\n", lvd->volDescSeqNum)); // Get logical block size (may be different from physical) Vcb->LBlockSize = lvd->logicalBlockSize; // Get current UDF revision // Get Read-Only flags UDFReadEntityID_Domain(Vcb, &(lvd->domainIdent)); if(Vcb->LBlockSize < Vcb->BlockSize) return STATUS_DISK_CORRUPT_ERROR; switch(Vcb->LBlockSize) { case 512: Vcb->LBlockSizeBits = 9; break; case 1024: Vcb->LBlockSizeBits = 10; break; case 2048: Vcb->LBlockSizeBits = 11; break; case 4096: Vcb->LBlockSizeBits = 12; break; case 8192: Vcb->LBlockSizeBits = 13; break; case 16384: Vcb->LBlockSizeBits = 14; break; case 32768: Vcb->LBlockSizeBits = 15; break; case 65536: Vcb->LBlockSizeBits = 16; break; default: UDFPrint(("UDF: Bad block size (%ld)\n", Vcb->LBlockSize)); return STATUS_DISK_CORRUPT_ERROR; } UDFPrint(("UDF: logical block size (%ld)\n", Vcb->LBlockSize)); Vcb->LB2B_Bits = Vcb->LBlockSizeBits - Vcb->BlockSizeBits; UDFPrint(("UDF: mapTableLength = %x\n", lvd->mapTableLength)); UDFPrint(("UDF: numPartitionMaps = %x\n", lvd->numPartitionMaps)); // walk through all available part maps for (i=0,offset=0; iPartitionMaps && offsetmapTableLength; i++,offset+=((GenericPartitionMap *)( ((uint8*)(lvd+1))+offset) )->partitionMapLength) { GenericPartitionMap* gpm = (GenericPartitionMap *)(((uint8*)(lvd+1))+offset); type = gpm->partitionMapType; UDFPrint(("Partition (%d) type %x, len %x\n", i, type, gpm->partitionMapLength)); if(type == PARTITION_MAP_TYPE_1) { GenericPartitionMap1 *gpm1 = (GenericPartitionMap1 *)(((uint8*)(lvd+1))+offset); Vcb->Partitions[i].PartitionType = UDF_TYPE1_MAP15; Vcb->Partitions[i].VolumeSeqNum = gpm1->volSeqNum; Vcb->Partitions[i].PartitionNum = gpm1->partitionNum; status = STATUS_SUCCESS; } else if(type == PARTITION_MAP_TYPE_2) { UdfPartitionMap2* upm2 = (UdfPartitionMap2 *)(((uint8*)(lvd+1))+offset); if(!strncmp((int8*)&(upm2->partIdent.ident), UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) { UDFIdentSuffix* udfis = (UDFIdentSuffix*)&(upm2->partIdent.identSuffix); if( (udfis->currentRev == 0x0150)/* || (Vcb->CurrentUDFRev == 0x0150)*/ ) { UDFPrint(("Found VAT 1.50\n")); Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP15; } else if( (udfis->currentRev == 0x0200) || (udfis->currentRev == 0x0201) /*|| (Vcb->CurrentUDFRev == 0x0200) || (Vcb->CurrentUDFRev == 0x0201)*/ ) { UDFPrint(("Found VAT 2.00\n")); Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP20; } status = STATUS_SUCCESS; } else if(!strncmp((int8*)&(upm2->partIdent.ident), UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { UDFPrint(("Load sparing table\n")); PSPARABLE_PARTITION_MAP spm = (PSPARABLE_PARTITION_MAP)(((uint8*)(lvd+1))+offset); Vcb->Partitions[i].PartitionType = UDF_SPARABLE_MAP15; status = UDFLoadSparingTable(Vcb, spm); } else if(!strncmp((int8*)&(upm2->partIdent.ident), UDF_ID_METADATA, strlen(UDF_ID_METADATA))) { UDFPrint(("Found metadata partition\n")); // PMETADATA_PARTITION_MAP mpm = (PMETADATA_PARTITION_MAP)(((uint8*)(lvd+1))+offset); Vcb->Partitions[i].PartitionType = UDF_METADATA_MAP25; //status = UDFLoadSparingTable(Vcb, spm); } else { UDFPrint(("Unknown ident: %s\n", upm2->partIdent.ident)); continue; } Vcb->Partitions[i].VolumeSeqNum = upm2->volSeqNum; Vcb->Partitions[i].PartitionNum = upm2->partitionNum; } } if(fileset) { // remember FileSet location long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]); *fileset = (la->extLocation); UDFPrint(("FileSet found in LogicalVolDesc at block=%x, partition=%d\n", fileset->logicalBlockNum, fileset->partitionReferenceNum)); } if(OS_SUCCESS(status)) { // load Integrity Desc if any if(lvd->integritySeqExt.extLength) status = UDFLoadLogicalVolInt(DeviceObject,Vcb,lvd->integritySeqExt); } return status; } // end UDFLoadLogicalVol() OSSTATUS UDFLoadBogusLogicalVol( PDEVICE_OBJECT DeviceObject, PVCB Vcb, int8* Buf, lb_addr *fileset ) { // LogicalVolDesc *lvd = (LogicalVolDesc *)Buf; UDFPrint(("UDF: Bogus LogicalVolDesc\n")); // Validate partition map counter if(!(Vcb->Partitions)) { Vcb->PartitionMaps = 1; Vcb->Partitions = (PUDFPartMap)MyAllocatePool__(NonPagedPool, sizeof(UDFPartMap) * Vcb->PartitionMaps ); if(!Vcb->Partitions) return STATUS_INSUFFICIENT_RESOURCES; } else { if(Vcb->PartitionMaps != 1) return STATUS_DISK_CORRUPT_ERROR; } UDFPrint(("UDF: volDescSeqNum = %x\n", 0)); // Get logical block size (may be different from physical) Vcb->LBlockSize = 2048; // Get current UDF revision // Get Read-Only flags // UDFReadEntityID_Domain(Vcb, &(lvd->domainIdent)); if(Vcb->LBlockSize < Vcb->BlockSize) return STATUS_DISK_CORRUPT_ERROR; Vcb->LBlockSizeBits = 11; UDFPrint(("UDF: logical block size (%ld)\n", Vcb->LBlockSize)); Vcb->LB2B_Bits = Vcb->LBlockSizeBits - Vcb->BlockSizeBits; UDFPrint(("UDF: mapTableLength = %x\n", 0)); UDFPrint(("UDF: numPartitionMaps = %x\n", 0)); // if(CDRW) { Vcb->Partitions[0].PartitionType = UDF_TYPE1_MAP15; Vcb->Partitions[0].VolumeSeqNum = 0; Vcb->Partitions[0].PartitionNum = 0; /* } else if(CDR) if() UDFPrint(("Found VAT 1.50\n")); Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP15; } else UDFPrint(("Found VAT 2.00\n")); Vcb->Partitions[i].PartitionType = UDF_VIRTUAL_MAP20; } } } */ if(fileset) { // remember FileSet location // long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]); fileset->logicalBlockNum = 0; fileset->partitionReferenceNum = 0; UDFPrint(("FileSet found in LogicalVolDesc at block=%x, partition=%d\n", fileset->logicalBlockNum, fileset->partitionReferenceNum)); } return STATUS_SUCCESS; } // end UDFLoadBogusLogicalVol() /* This routine adds given Bitmap to existing one */ OSSTATUS UDFAddXSpaceBitmap( IN PVCB Vcb, IN uint32 PartNum, IN PSHORT_AD bm, IN ULONG bm_type ) { int8* tmp; int8* tmp_bm; uint32 i, lim, j, lba, l, lim2, l2, k; lb_addr locAddr; OSSTATUS status; uint16 Ident; uint32 flags; SIZE_T Length; SIZE_T ReadBytes; BOOLEAN bit_set; UDF_CHECK_BITMAP_RESOURCE(Vcb); UDFPrint(("UDFAddXSpaceBitmap: at block=%x, partition=%d\n", bm->extPosition, PartNum)); if(!(Length = (bm->extLength & UDF_EXTENT_LENGTH_MASK))) return STATUS_SUCCESS; i=UDFPartStart(Vcb, PartNum); flags = bm->extLength >> 30; if(!flags /*|| flags == EXTENT_NOT_RECORDED_ALLOCATED*/) { tmp = (int8*)DbgAllocatePool(NonPagedPool, max(Length, Vcb->BlockSize)); if(!tmp) return STATUS_INSUFFICIENT_RESOURCES; locAddr.partitionReferenceNum = (uint16)PartNum; locAddr.logicalBlockNum = bm->extPosition; // read header of the Bitmap if(!OS_SUCCESS(status = UDFReadTagged(Vcb, tmp, lba = UDFPartLbaToPhys(Vcb, &(locAddr)), locAddr.logicalBlockNum, &Ident)) ) { err_addxsbm_1: DbgFreePool(tmp); return status; } if(Ident != TID_SPACE_BITMAP_DESC) { status = STATUS_DISK_CORRUPT_ERROR; goto err_addxsbm_1; } UDFRegisterFsStructure(Vcb, lba, Vcb->BlockSize); // read the whole Bitmap if(!OS_SUCCESS(status = UDFReadData(Vcb, FALSE, ((uint64)lba)<BlockSizeBits, Length, FALSE, tmp, &ReadBytes))) goto err_addxsbm_1; UDFRegisterFsStructure(Vcb, lba, Length); 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[PartNum].PartitionRoot; lim = i + Vcb->Partitions[PartNum].PartitionLen; for(;iFSBM_Bitmap, i); }*/ } return STATUS_SUCCESS; } // end UDFAddXSpaceBitmap() /* This routine adds given Bitmap to existing one */ OSSTATUS UDFVerifyXSpaceBitmap( IN PVCB Vcb, IN uint32 PartNum, IN PSHORT_AD bm, IN ULONG bm_type ) { int8* tmp; // int8* tmp_bm; // uint32 i, l2, k, lim, j, lim2; uint32 lba; lb_addr locAddr; OSSTATUS status; uint16 Ident; uint32 flags; uint32 Length; SIZE_T ReadBytes; // BOOLEAN bit_set; UDF_CHECK_BITMAP_RESOURCE(Vcb); UDFPrint((" UDFVerifyXSpaceBitmap: part %x\n", PartNum)); if(!(Length = (bm->extLength & UDF_EXTENT_LENGTH_MASK))) return STATUS_SUCCESS; // i=UDFPartStart(Vcb, PartNum); flags = bm->extLength >> 30; if(!flags /*|| flags == EXTENT_NOT_RECORDED_ALLOCATED*/) { tmp = (int8*)DbgAllocatePool(NonPagedPool, max(Length, Vcb->BlockSize)); if(!tmp) return STATUS_INSUFFICIENT_RESOURCES; locAddr.partitionReferenceNum = (uint16)PartNum; locAddr.logicalBlockNum = bm->extPosition; // read header of the Bitmap if(!OS_SUCCESS(status = UDFReadTagged(Vcb, tmp, lba = UDFPartLbaToPhys(Vcb, &(locAddr)), locAddr.logicalBlockNum, &Ident)) ) { err_vfyxsbm_1: DbgFreePool(tmp); return status; } UDFPrint((" BM Lba %x\n", lba)); if(Ident != TID_SPACE_BITMAP_DESC) { status = STATUS_DISK_CORRUPT_ERROR; goto err_vfyxsbm_1; } // read the whole Bitmap if(!OS_SUCCESS(status = UDFReadData(Vcb, FALSE, ((uint64)lba)<BlockSizeBits, Length, FALSE, tmp, &ReadBytes))) goto err_vfyxsbm_1; UDFRegisterFsStructure(Vcb, lba, Length); // 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[PartNum].PartitionRoot; lim = i + Vcb->Partitions[PartNum].PartitionLen; for(;iFSBM_Bitmap, i); }*/ } return STATUS_SUCCESS; } // end UDFVerifyXSpaceBitmap() /* This routine subtracts given Bitmap to existing one */ /*OSSTATUS UDFDelXSpaceBitmap( IN PVCB Vcb, IN uint32 PartNum, IN PSHORT_AD bm ) { int8* tmp, tmp_bm; uint32 i, lim, j; lb_addr locAddr; OSSTATUS status; uint16 Ident; uint32 flags; uint32 Length; SIZE_T ReadBytes; if(!(Length = (bm->extLength & UDF_EXTENT_LENGTH_MASK))) return STATUS_SUCCESS; i=0; flags = bm->extLength >> 30; if(!flags || flags == EXTENT_NOT_RECORDED_ALLOCATED) { tmp = (int8*)MyAllocatePool__(NonPagedPool, Length); if(!tmp) return STATUS_INSUFFICIENT_RESOURCES; locAddr.partitionReferenceNum = (uint16)PartNum; locAddr.logicalBlockNum = bm->extPosition; if((!OS_SUCCESS(status = UDFReadTagged(Vcb, tmp, (j = UDFPartLbaToPhys(Vcb, &(locAddr))), locAddr.logicalBlockNum, &Ident))) || (Ident != TID_SPACE_BITMAP_DESC) ) { MyFreePool__(tmp); return status; } if(!OS_SUCCESS(status = UDFReadData(Vcb, FALSE, ((uint64)j)<BlockSizeBits, Length, FALSE, tmp, &ReadBytes))) { MyFreePool__(tmp); return status; } lim = i + ((PSPACE_BITMAP_DESC)tmp)->numOfBits; tmp_bm = tmp + sizeof(SPACE_BITMAP_DESC); j = 0; for(;iFSBM_Bitmap, i); j++; } MyFreePool__(tmp); // } else if((bm->extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) { // i=Vcb->Partitions[PartNum].PartitionRoot; // lim = i + Vcb->Partitions[PartNum].PartitionLen; // for(;iFSBM_Bitmap, i); // } } return STATUS_SUCCESS; } // end UDFDelXSpaceBitmap() */ /* This routine verifues FreeSpaceBitmap (internal) according to media parameters & input data */ OSSTATUS UDFVerifyFreeSpaceBitmap( IN PVCB Vcb, IN uint32 PartNdx, IN PPARTITION_HEADER_DESC phd, // partition header pointing to Bitmaps IN uint32 Lba // UnallocSpaceDesc ) { OSSTATUS status; uint32 i, l; uint16 Ident; int8* AllocDesc; PEXTENT_MAP Extent; lb_addr locAddr; uint32 PartNum; PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx); UDFPrint(("UDFVerifyFreeSpaceBitmap:\n")); // read info for partition header (if any) if(phd) { // read unallocated Bitmap if(!OS_SUCCESS(status = UDFVerifyXSpaceBitmap(Vcb, PartNum, &(phd->unallocatedSpaceBitmap), UDF_FSPACE_BM))) return status; // read freed Bitmap if(!OS_SUCCESS(status = UDFVerifyXSpaceBitmap(Vcb, PartNum, &(phd->freedSpaceBitmap), UDF_ZSPACE_BM))) return status; } // read UnallocatedSpaceDesc & convert to Bitmap if(Lba) { UDFPrint((" Lba @%x\n", Lba)); if(!(AllocDesc = (int8*)MyAllocatePool__(NonPagedPool, Vcb->LBlockSize + sizeof(EXTENT_AD) ))) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory(((int8*)AllocDesc) + Vcb->LBlockSize, sizeof(EXTENT_AD)); if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, l = (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { MyFreePool__(AllocDesc); return status; } UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); RtlCopyMemory((int8*)Extent, AllocDesc+sizeof(UNALLOC_SPACE_DESC), (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ); locAddr.partitionReferenceNum = (uint16)PartNum; // read extent is recorded with relative addresses // so, we should convert it to suitable form for(i=0; Extent[i].extLength; i++) { locAddr.logicalBlockNum = Extent[i].extLocation; Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr); if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { BrutePoint(); MyFreePool__(AllocDesc); return STATUS_DISK_CORRUPT_ERROR; } if((Extent[i].extLocation >> 30) == EXTENT_NEXT_EXTENT_ALLOCDESC) { // load continuation Lba = Extent[i].extLocation & UDF_EXTENT_LENGTH_MASK; if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { MyFreePool__(AllocDesc); return status; } if(Ident == TID_UNALLOC_SPACE_DESC) { UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); if(!(l = MyReallocPool__((int8*)Extent, l, (int8**)&Extent, i*sizeof(EXTENT_MAP)))) { MyFreePool__(Extent); MyFreePool__(AllocDesc); return STATUS_INSUFFICIENT_RESOURCES; } Extent[i].extLength = Extent[i].extLocation = 0; Extent = UDFMergeMappings(Extent, (PEXTENT_MAP)(AllocDesc+sizeof(UNALLOC_SPACE_DESC)) ); #ifdef UDF_DBG } else { UDFPrint(("Broken unallocated space descriptor sequence\n")); #endif // UDF_DBG } } } // UDFMarkSpaceAsXXX(Vcb, (-1), Extent, AS_USED); // mark as used MyFreePool__(Extent); MyFreePool__(AllocDesc); status = STATUS_SUCCESS; } return status; } // end UDFBuildFreeSpaceBitmap() /* This routine builds FreeSpaceBitmap (internal) according to media parameters & input data */ OSSTATUS UDFBuildFreeSpaceBitmap( IN PVCB Vcb, IN uint32 PartNdx, IN PPARTITION_HEADER_DESC phd, // partition header pointing to Bitmaps IN uint32 Lba // UnallocSpaceDesc ) { OSSTATUS status; uint32 i, l; uint16 Ident; int8* AllocDesc; PEXTENT_MAP Extent; lb_addr locAddr; uint32 PartNum; PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx); 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; Vcb->ZSBM_Bitmap = (int8*)DbgAllocatePool(NonPagedPool, (i = (Vcb->LastPossibleLBA+1+7)>>3) ); if(!(Vcb->ZSBM_Bitmap)) { #ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS free_fsbm: #endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS MyFreePool__(Vcb->FSBM_Bitmap); Vcb->FSBM_Bitmap = NULL; return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(Vcb->FSBM_Bitmap, i); RtlZeroMemory(Vcb->ZSBM_Bitmap, i); #ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS Vcb->FSBM_Bitmap_owners = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32)); if(!(Vcb->FSBM_Bitmap_owners)) { MyFreePool__(Vcb->ZSBM_Bitmap); Vcb->ZSBM_Bitmap = NULL; goto free_fsbm; } RtlFillMemory(Vcb->FSBM_Bitmap_owners, (Vcb->LastPossibleLBA+1)*sizeof(uint32), 0xff); #endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS Vcb->FSBM_ByteCount = i; Vcb->FSBM_BitCount = Vcb->LastPossibleLBA+1; } // read info for partition header (if any) if(phd) { // read unallocated Bitmap if(!OS_SUCCESS(status = UDFAddXSpaceBitmap(Vcb, PartNum, &(phd->unallocatedSpaceBitmap), UDF_FSPACE_BM))) return status; // read freed Bitmap if(!OS_SUCCESS(status = UDFAddXSpaceBitmap(Vcb, PartNum, &(phd->freedSpaceBitmap), UDF_ZSPACE_BM))) return status; } // read UnallocatedSpaceDesc & convert to Bitmap if(Lba) { if(!(AllocDesc = (int8*)MyAllocatePool__(NonPagedPool, Vcb->LBlockSize + sizeof(EXTENT_AD) ))) return STATUS_INSUFFICIENT_RESOURCES; RtlZeroMemory(((int8*)AllocDesc) + Vcb->LBlockSize, sizeof(EXTENT_AD)); if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, l = (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { MyFreePool__(AllocDesc); return status; } UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); RtlCopyMemory((int8*)Extent, AllocDesc+sizeof(UNALLOC_SPACE_DESC), (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ); locAddr.partitionReferenceNum = (uint16)PartNum; // read extent is recorded with relative addresses // so, we should convert it to suitable form for(i=0; Extent[i].extLength; i++) { locAddr.logicalBlockNum = Extent[i].extLocation; Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr); if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) { BrutePoint(); MyFreePool__(AllocDesc); return STATUS_DISK_CORRUPT_ERROR; } if((Extent[i].extLocation >> 30) == EXTENT_NEXT_EXTENT_ALLOCDESC) { // load continuation Lba = Extent[i].extLocation & UDF_EXTENT_LENGTH_MASK; if(!OS_SUCCESS(status = UDFReadTagged(Vcb, AllocDesc, Lba, Lba, &Ident)) || !(Extent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, (((PUNALLOC_SPACE_DESC)AllocDesc)->numAllocDescs+1) * sizeof(EXTENT_AD) ))) { MyFreePool__(AllocDesc); return status; } if(Ident == TID_UNALLOC_SPACE_DESC) { UDFRegisterFsStructure(Vcb, Lba, Vcb->BlockSize); if(!(l = MyReallocPool__((int8*)Extent, l, (int8**)&Extent, i*sizeof(EXTENT_MAP)))) { MyFreePool__(Extent); MyFreePool__(AllocDesc); return STATUS_INSUFFICIENT_RESOURCES; } Extent[i].extLength = Extent[i].extLocation = 0; Extent = UDFMergeMappings(Extent, (PEXTENT_MAP)(AllocDesc+sizeof(UNALLOC_SPACE_DESC)) ); #ifdef UDF_DBG } else { UDFPrint(("Broken unallocated space descriptor sequence\n")); #endif // UDF_DBG } } } UDFMarkSpaceAsXXX(Vcb, (-1), Extent, AS_USED); // mark as used MyFreePool__(Extent); MyFreePool__(AllocDesc); } return status; } // end UDFVerifyFreeSpaceBitmap() /* process Partition descriptor */ OSSTATUS UDFLoadPartDesc( PVCB Vcb, int8* Buf ) { PartitionDesc *p = (PartitionDesc *)Buf; uint32 i; OSSTATUS RC; BOOLEAN Found = FALSE; UDFPrint(("UDF: Pard Descr:\n")); UDFPrint((" volDescSeqNum = %x\n", p->volDescSeqNum)); UDFPrint((" partitionFlags = %x\n", p->partitionFlags)); UDFPrint((" partitionNumber = %x\n", p->partitionNumber)); UDFPrint((" accessType = %x\n", p->accessType)); UDFPrint((" partitionStartingLocation = %x\n", p->partitionStartingLocation)); UDFPrint((" partitionLength = %x\n", p->partitionLength)); // There is nothing interesting to comment here // Just look at Names & Messages.... for (i=0; iPartitionMaps; i++) { UDFPrint(("Searching map: (%d == %d)\n", Vcb->Partitions[i].PartitionNum, (p->partitionNumber) )); if(Vcb->Partitions[i].PartitionNum == (p->partitionNumber)) { Found = TRUE; Vcb->Partitions[i].PartitionRoot = p->partitionStartingLocation + Vcb->FirstLBA; Vcb->Partitions[i].PartitionLen = p->partitionLength; Vcb->Partitions[i].UspaceBitmap = 0xFFFFFFFF; Vcb->Partitions[i].FspaceBitmap = 0xFFFFFFFF; Vcb->Partitions[i].AccessType = p->accessType; UDFPrint(("Access mode %x\n", p->accessType)); if(p->accessType == PARTITION_ACCESS_WO) { Vcb->CDR_Mode = TRUE; // Vcb->Partitions[i].PartitionLen = Vcb->LastPossibleLBA - p->partitionStartingLocation; } else if(p->accessType < PARTITION_ACCESS_WO) { // Soft-read-only volume UDFPrint(("Soft Read-only volume\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_PART_RO; } else if(p->accessType > PARTITION_ACCESS_MAX_KNOWN) { return STATUS_UNRECOGNIZED_MEDIA; } if(!strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR02) || !strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR03)) { PPARTITION_HEADER_DESC phd; phd = (PPARTITION_HEADER_DESC)(p->partitionContentsUse); #ifdef UDF_DBG if(phd->unallocatedSpaceTable.extLength) UDFPrint(("unallocatedSpaceTable (part %d)\n", i)); #endif // UDF_DBG if(phd->unallocatedSpaceBitmap.extLength) { Vcb->Partitions[i].UspaceBitmap = phd->unallocatedSpaceBitmap.extPosition; UDFPrint(("unallocatedSpaceBitmap (part %d) @ %x\n", i, Vcb->Partitions[i].UspaceBitmap )); } #ifdef UDF_DBG if(phd->partitionIntegrityTable.extLength) UDFPrint(("partitionIntegrityTable (part %d)\n", i)); if(phd->freedSpaceTable.extLength) UDFPrint(("freedSpaceTable (part %d)\n", i)); #endif // UDF_DBG if(phd->freedSpaceBitmap.extLength) { Vcb->Partitions[i].FspaceBitmap = phd->freedSpaceBitmap.extPosition; UDFPrint(("freedSpaceBitmap (part %d)\n", i)); } RC = UDFBuildFreeSpaceBitmap(Vcb, i, phd, 0); //Vcb->Modified = FALSE; UDFPreClrModified(Vcb); UDFClrModified(Vcb); if(!OS_SUCCESS(RC)) return RC; if ((Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP15) || (Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP20)) { RC = UDFLoadVAT(Vcb, i); if(!OS_SUCCESS(RC)) return RC; WCacheFlushAll__(&(Vcb->FastCache), Vcb); WCacheSetMode__(&(Vcb->FastCache), WCACHE_MODE_R); Vcb->LastModifiedTrack = 0; } } } } #ifdef UDF_DBG if(!Found) { UDFPrint(("Partition (%d) not found in partition map\n", (p->partitionNumber) )); } else { UDFPrint(("Partition (%d:%d type %x) starts at physical %x, length %x\n", p->partitionNumber, i-1, Vcb->Partitions[i-1].PartitionType, Vcb->Partitions[i-1].PartitionRoot, Vcb->Partitions[i-1].PartitionLen)); } #endif // UDF_DBG return STATUS_SUCCESS; } // end UDFLoadPartDesc() /* process Partition descriptor */ OSSTATUS UDFVerifyPartDesc( PVCB Vcb, int8* Buf ) { PartitionDesc *p = (PartitionDesc *)Buf; uint32 i; OSSTATUS RC; BOOLEAN Found = FALSE; UDFPrint(("UDF: Verify Part Descr:\n")); UDFPrint((" volDescSeqNum = %x\n", p->volDescSeqNum)); UDFPrint((" partitionFlags = %x\n", p->partitionFlags)); UDFPrint((" partitionNumber = %x\n", p->partitionNumber)); UDFPrint((" accessType = %x\n", p->accessType)); UDFPrint((" partitionStartingLocation = %x\n", p->partitionStartingLocation)); UDFPrint((" partitionLength = %x\n", p->partitionLength)); // There is nothing interesting to comment here // Just look at Names & Messages.... for (i=0; iPartitionMaps; i++) { UDFPrint(("Searching map: (%d == %d)\n", Vcb->Partitions[i].PartitionNum, (p->partitionNumber) )); if(Vcb->Partitions[i].PartitionNum == (p->partitionNumber)) { Found = TRUE; if(Vcb->Partitions[i].PartitionRoot != p->partitionStartingLocation + Vcb->FirstLBA) return STATUS_DISK_CORRUPT_ERROR; if(Vcb->Partitions[i].PartitionLen != min(p->partitionLength, Vcb->LastPossibleLBA - Vcb->Partitions[i].PartitionRoot)) /* sectors */ return STATUS_DISK_CORRUPT_ERROR; // Vcb->Partitions[i].UspaceBitmap = 0xFFFFFFFF; // Vcb->Partitions[i].FspaceBitmap = 0xFFFFFFFF; if(Vcb->Partitions[i].AccessType != p->accessType) return STATUS_DISK_CORRUPT_ERROR; UDFPrint(("Access mode %x\n", p->accessType)); if(p->accessType == PARTITION_ACCESS_WO) { if(Vcb->CDR_Mode != TRUE) return STATUS_DISK_CORRUPT_ERROR; // Vcb->Partitions[i].PartitionLen = Vcb->LastPossibleLBA - p->partitionStartingLocation; } else if(p->accessType < PARTITION_ACCESS_WO) { // Soft-read-only volume UDFPrint(("Soft Read-only volume\n")); if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) return STATUS_DISK_CORRUPT_ERROR; } else if(p->accessType > PARTITION_ACCESS_MAX_KNOWN) { return STATUS_UNRECOGNIZED_MEDIA; } if(!strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR02) || !strcmp((int8*)&(p->partitionContents.ident), PARTITION_CONTENTS_NSR03)) { PPARTITION_HEADER_DESC phd; phd = (PPARTITION_HEADER_DESC)(p->partitionContentsUse); #ifdef UDF_DBG if(phd->unallocatedSpaceTable.extLength) UDFPrint(("unallocatedSpaceTable (part %d)\n", i)); #endif // UDF_DBG if(phd->unallocatedSpaceBitmap.extLength) { if(Vcb->Partitions[i].UspaceBitmap == phd->unallocatedSpaceBitmap.extPosition) { UDFPrint(("Warning: both USpaceBitmaps have same location\n")); } UDFPrint(("unallocatedSpaceBitmap (part %d) @ %x\n", i, Vcb->Partitions[i].UspaceBitmap )); } #ifdef UDF_DBG if(phd->partitionIntegrityTable.extLength) UDFPrint(("partitionIntegrityTable (part %d)\n", i)); if(phd->freedSpaceTable.extLength) UDFPrint(("freedSpaceTable (part %d)\n", i)); #endif // UDF_DBG if(phd->freedSpaceBitmap.extLength) { if(Vcb->Partitions[i].FspaceBitmap == phd->freedSpaceBitmap.extPosition) { UDFPrint(("Warning: both FSpaceBitmaps have same location\n")); } UDFPrint(("freedSpaceBitmap (part %d)\n", i)); } RC = UDFVerifyFreeSpaceBitmap(Vcb, i, phd, 0); //Vcb->Modified = FALSE; //UDFPreClrModified(Vcb); //UDFClrModified(Vcb); if(!OS_SUCCESS(RC)) return RC; if ((Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP15) || (Vcb->Partitions[i].PartitionType == UDF_VIRTUAL_MAP20)) { /* RC = UDFLoadVAT(Vcb, i); if(!OS_SUCCESS(RC)) return RC; WCacheFlushAll__(&(Vcb->FastCache), Vcb); WCacheSetMode__(&(Vcb->FastCache), WCACHE_MODE_R); Vcb->LastModifiedTrack = 0;*/ } } } } #ifdef UDF_DBG if(!Found) { UDFPrint(("Partition (%d) not found in partition map\n", (p->partitionNumber) )); } else { UDFPrint(("Partition (%d:%d type %x) starts at physical %x, length %x\n", p->partitionNumber, i-1, Vcb->Partitions[i-1].PartitionType, Vcb->Partitions[i-1].PartitionRoot, Vcb->Partitions[i-1].PartitionLen)); } #endif // UDF_DBG return STATUS_SUCCESS; } // end UDFVerifyPartDesc() /* This routine scans VDS & fills special array with Desc locations */ OSSTATUS UDFReadVDS( IN PVCB Vcb, IN uint32 block, IN uint32 lastblock, IN PUDF_VDS_RECORD vds, IN int8* Buf ) { OSSTATUS status; GenericDesc* gd; BOOLEAN done=FALSE; uint32 vdsn; uint16 ident; UDFPrint(("UDF: Read VDS (%x - %x)\n", block, lastblock )); // Read the main descriptor sequence for (;(!done && block <= lastblock); block++) { status = UDFReadTagged(Vcb, Buf, block, block, &ident); if(!OS_SUCCESS(status)) return status; UDFRegisterFsStructure(Vcb, block, Vcb->BlockSize); // Process each descriptor (ISO 13346 3/8.3-8.4) gd = (struct GenericDesc *)Buf; vdsn = gd->volDescSeqNum; UDFPrint(("LBA %x, Ident = %x, vdsn = %x\n", block, ident, vdsn )); switch (ident) { case TID_PRIMARY_VOL_DESC: // ISO 13346 3/10.1 if(vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) { vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn; vds[VDS_POS_PRIMARY_VOL_DESC].block = block; } break; case TID_VOL_DESC_PTR: // ISO 13346 3/10.3 struct VolDescPtr* pVDP; if(vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) { vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn; vds[VDS_POS_VOL_DESC_PTR].block = block; vds[VDS_POS_RECURSION_COUNTER].volDescSeqNum++; if(vds[VDS_POS_RECURSION_COUNTER].volDescSeqNum > MAX_VDS_PARTS) { UDFPrint(("too long multipart VDS -> abort\n")); return STATUS_DISK_CORRUPT_ERROR; } pVDP = (struct VolDescPtr*)Buf; UDFPrint(("multipart VDS...\n")); return UDFReadVDS(Vcb, pVDP->nextVolDescSeqExt.extLocation, pVDP->nextVolDescSeqExt.extLocation + (pVDP->nextVolDescSeqExt.extLocation >> Vcb->BlockSizeBits), vds, Buf); } break; case TID_IMP_USE_VOL_DESC: // ISO 13346 3/10.4 if(vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) { vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn; vds[VDS_POS_IMP_USE_VOL_DESC].block = block; } break; case TID_PARTITION_DESC: // ISO 13346 3/10.5 if(!vds[VDS_POS_PARTITION_DESC].block) vds[VDS_POS_PARTITION_DESC].block = block; break; case TID_LOGICAL_VOL_DESC: // ISO 13346 3/10.6 case TID_ADAPTEC_LOGICAL_VOL_DESC: // Adaptec Compressed UDF extesion if(vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) { vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn; vds[VDS_POS_LOGICAL_VOL_DESC].block = block; } break; case TID_UNALLOC_SPACE_DESC: // ISO 13346 3/10.8 if(vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) { vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn; vds[VDS_POS_UNALLOC_SPACE_DESC].block = block; } break; case TID_TERMINATING_DESC: // ISO 13346 3/10.9 vds[VDS_POS_TERMINATING_DESC].block = block; done = TRUE; break; } } return STATUS_SUCCESS; } // UDFReadVDS() OSSTATUS UDFLoadImpUseVolDesc( IN PVCB Vcb, int8* Buf ) { #ifdef UDF_DBG ImpUseVolDesc* iuvd = (ImpUseVolDesc*)Buf; ImpUseVolDescImpUse* iuvdiu = (ImpUseVolDescImpUse*)&(iuvd->impUse); UDFPrint(("UDF: Imp Use Vol Desc:\n")); UDFPrint((" volDescSeqNum = %x\n", iuvd->volDescSeqNum)); UDFPrint(("UDF: Imp Use Vol Desc Imp Use:\n")); KdDump(iuvdiu, sizeof(ImpUseVolDescImpUse)); #endif return STATUS_SUCCESS; } // UDFLoadImpUseVolDesc() OSSTATUS UDFLoadUnallocatedSpaceDesc( IN PVCB Vcb, int8* Buf ) { UDFPrint(("UDF: Unallocated Space Desc:\n")); // UnallocatedSpaceDesc* usd = (UnallocatedSpaceDesc*)Buf; return STATUS_SUCCESS; } // UDFLoadImpUseVolDesc() /* Process a main/reserve volume descriptor sequence. */ OSSTATUS UDFProcessSequence( IN PDEVICE_OBJECT DeviceObject, IN PVCB Vcb, IN uint32 block, IN uint32 lastblock, OUT lb_addr *fileset ) { OSSTATUS RC = STATUS_SUCCESS; int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); UDF_VDS_RECORD vds[VDS_POS_LENGTH]; // GenericDesc *gd; uint32 i,j; uint16 ident; int8* Buf2 = NULL; _SEH2_TRY { if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); RtlZeroMemory(vds, sizeof(UDF_VDS_RECORD) * VDS_POS_LENGTH); if(!OS_SUCCESS(RC = UDFReadVDS(Vcb, block, lastblock, (PUDF_VDS_RECORD)&vds, Buf))) try_return(RC); // walk through Vol Desc Sequence according to locations gained by // UDFReadVDS() & do some procesing for each one // It is very simple dispath routine... for (i=0; iBlockSize); if(i == VDS_POS_PRIMARY_VOL_DESC) { UDFLoadPVolDesc(Vcb,Buf); if(!Vcb->PVolDescAddr.block) { Vcb->PVolDescAddr = vds[i]; } else { Vcb->PVolDescAddr2 = vds[i]; } } else if(i == VDS_POS_LOGICAL_VOL_DESC) { RC = UDFLoadLogicalVol(DeviceObject,Vcb, Buf, fileset); if(!OS_SUCCESS(RC)) try_return(RC); } else if(i == VDS_POS_IMP_USE_VOL_DESC) { UDFLoadImpUseVolDesc(Vcb, Buf); } else if(i == VDS_POS_UNALLOC_SPACE_DESC) { UDFLoadUnallocatedSpaceDesc(Vcb, Buf); } else if(i == VDS_POS_PARTITION_DESC) { Buf2 = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); if(!Buf2) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); RC = UDFLoadPartDesc(Vcb,Buf); if(!OS_SUCCESS(RC)) try_return(RC); for (j=vds[i].block+1; jBlockSize); // gd = (struct GenericDesc *)Buf2; if(ident == TID_PARTITION_DESC) { RC = UDFLoadPartDesc(Vcb,Buf2); if(!OS_SUCCESS(RC)) try_return(RC); } else if(ident == TID_UNALLOC_SPACE_DESC) { RC = UDFBuildFreeSpaceBitmap(Vcb,0,NULL,j); //Vcb->Modified = FALSE; UDFPreClrModified(Vcb); UDFClrModified(Vcb); if(!OS_SUCCESS(RC)) try_return(RC); } } MyFreePool__(Buf2); Buf2 = NULL; } } else { if(i == VDS_POS_LOGICAL_VOL_DESC) { RC = UDFLoadBogusLogicalVol(DeviceObject,Vcb, Buf, fileset); if(!OS_SUCCESS(RC)) try_return(RC); } } } try_exit: NOTHING; } _SEH2_FINALLY { if(Buf) MyFreePool__(Buf); if(Buf2) MyFreePool__(Buf2); } _SEH2_END; return RC; } // end UDFProcessSequence() /* Verifies a main/reserve volume descriptor sequence. */ OSSTATUS UDFVerifySequence( IN PDEVICE_OBJECT DeviceObject, IN PVCB Vcb, IN uint32 block, IN uint32 lastblock, OUT lb_addr *fileset ) { OSSTATUS RC = STATUS_SUCCESS; int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); UDF_VDS_RECORD vds[VDS_POS_LENGTH]; // GenericDesc *gd; uint32 i,j; uint16 ident; int8* Buf2 = NULL; _SEH2_TRY { if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); if(!block) try_return (RC = STATUS_SUCCESS); RtlZeroMemory(vds, sizeof(UDF_VDS_RECORD) * VDS_POS_LENGTH); if(!OS_SUCCESS(RC = UDFReadVDS(Vcb, block, lastblock, (PUDF_VDS_RECORD)&vds, Buf))) try_return(RC); for (i=0; iBlockSize); /* if(i == VDS_POS_PRIMARY_VOL_DESC) UDFLoadPVolDesc(Vcb,Buf); else if(i == VDS_POS_LOGICAL_VOL_DESC) { RC = UDFLoadLogicalVol(DeviceObject,Vcb, Buf, fileset); if(!OS_SUCCESS(RC)) try_return(RC); } else*/ if(i == VDS_POS_PARTITION_DESC) { Buf2 = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); if(!Buf2) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); RC = UDFVerifyPartDesc(Vcb,Buf); if(!OS_SUCCESS(RC)) try_return(RC); for (j=vds[i].block+1; jBlockSize); // gd = (struct GenericDesc *)Buf2; if(ident == TID_PARTITION_DESC) { RC = UDFVerifyPartDesc(Vcb,Buf2); if(!OS_SUCCESS(RC)) try_return(RC); } else if(ident == TID_UNALLOC_SPACE_DESC) { RC = UDFVerifyFreeSpaceBitmap(Vcb,0,NULL,j); Vcb->Modified = FALSE; if(!OS_SUCCESS(RC)) try_return(RC); } } MyFreePool__(Buf2); Buf2 = NULL; } } } try_exit: NOTHING; } _SEH2_FINALLY { if(Buf) MyFreePool__(Buf); if(Buf2) MyFreePool__(Buf2); } _SEH2_END; return RC; } // end UDFVerifySequence() /* remember some useful info about FileSet & RootDir location */ void UDFLoadFileset( IN PVCB Vcb, IN PFILE_SET_DESC fset, OUT lb_addr *root, OUT lb_addr *sysstream ) { *root = fset->rootDirectoryICB.extLocation; Vcb->SerialNumber = fset->descTag.tagSerialNum; UDFPrint(("Rootdir at block=%x, partition=%d\n", root->logicalBlockNum, root->partitionReferenceNum)); if(sysstream) { *sysstream = fset->streamDirectoryICB.extLocation; UDFPrint(("SysStream at block=%x, partition=%d\n", sysstream->logicalBlockNum, sysstream->partitionReferenceNum)); } #define CUR_IDENT_SZ (sizeof(fset->logicalVolIdent)) if (Vcb->VolIdent.Buffer) { MyFreePool__(Vcb->VolIdent.Buffer); } UDFGetDstring(&(Vcb->VolIdent), (dstring*)&(fset->logicalVolIdent), CUR_IDENT_SZ); #undef CUR_IDENT_SZ UDFPrint(("volIdent[] = '%ws'\n", Vcb->VolIdent.Buffer)); // Get current UDF revision // Get Read-Only flags UDFReadEntityID_Domain(Vcb, &(fset->domainIdent)); } // end UDFLoadFileset() OSSTATUS UDFIsCachedBadSequence( IN PVCB Vcb, IN uint32 Lba ) { ULONG j; OSSTATUS RC = STATUS_SUCCESS; // Check if it is known bad sequence for(j=0; jBadSeqLocIndex; j++) { if(Vcb->BadSeqLoc[j] == Lba) { RC = Vcb->BadSeqStatus[j]; break; } } return RC; } // end UDFIsCachedBadSequence() VOID UDFRememberBadSequence( IN PVCB Vcb, IN uint32 Lba, IN OSSTATUS RC ) { int j; if(!OS_SUCCESS(UDFIsCachedBadSequence(Vcb, Lba))) return; // Remenber bad sequence j = Vcb->BadSeqLocIndex; Vcb->BadSeqLocIndex++; Vcb->BadSeqLoc[j] = Lba; Vcb->BadSeqStatus[j] = RC; } // end UDFRememberBadSequence() /* load partition info */ OSSTATUS UDFLoadPartition( IN PDEVICE_OBJECT DeviceObject, IN PVCB Vcb, OUT lb_addr *fileset ) { OSSTATUS RC = STATUS_UNRECOGNIZED_VOLUME; OSSTATUS RC2 = STATUS_UNRECOGNIZED_VOLUME; AnchorVolDescPtr *anchor; uint16 ident; int8* Buf = (int8*)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); uint32 main_s, main_e; uint32 reserve_s, reserve_e; int i; if(!Buf) return STATUS_INSUFFICIENT_RESOURCES; // walk through all available Anchors & load data for (i=0; iAnchor[i] && (OS_SUCCESS(UDFReadTagged(Vcb, Buf, Vcb->Anchor[i], Vcb->Anchor[i] - Vcb->FirstLBA, &ident)))) { anchor = (AnchorVolDescPtr *)Buf; // Locate the main sequence main_s = ( anchor->mainVolDescSeqExt.extLocation ); main_e = ( anchor->mainVolDescSeqExt.extLength ); main_e = main_e >> Vcb->BlockSizeBits; main_e += main_s; // Locate the reserve sequence reserve_s = (anchor->reserveVolDescSeqExt.extLocation); reserve_e = (anchor->reserveVolDescSeqExt.extLength); reserve_e = reserve_e >> Vcb->BlockSizeBits; reserve_e += reserve_s; // Check if it is known bad sequence RC = UDFIsCachedBadSequence(Vcb, main_s); if(OS_SUCCESS(RC)) { // Process the main & reserve sequences // responsible for finding the PartitionDesc(s) UDFPrint(("-----------------------------------\n")); UDFPrint(("UDF: Main sequence:\n")); RC = UDFProcessSequence(DeviceObject, Vcb, main_s, main_e, fileset); } if(!OS_SUCCESS(RC)) { // Remenber bad sequence UDFRememberBadSequence(Vcb, main_s, RC); UDFPrint(("-----------------------------------\n")); UDFPrint(("UDF: Main sequence failed.\n")); UDFPrint(("UDF: Reserve sequence\n")); if(Vcb->LVid) MyFreePool__(Vcb->LVid); Vcb->LVid = NULL; RC2 = UDFIsCachedBadSequence(Vcb, reserve_s); if(OS_SUCCESS(RC2)) { RC2 = UDFProcessSequence(DeviceObject, Vcb, reserve_s, reserve_e, fileset); } if(OS_SUCCESS(RC2)) { UDFPrint(("-----------------------------------\n")); Vcb->VDS2_Len = reserve_e - reserve_s; Vcb->VDS2 = reserve_s; RC = STATUS_SUCCESS; // Vcb is already Zero-filled // Vcb->VDS1_Len = 0; // Vcb->VDS1 = 0; break; } else { // This is also bad sequence. Remenber it too UDFRememberBadSequence(Vcb, reserve_s, RC); } } else { // remember these values for umount__ Vcb->VDS1_Len = main_e - main_s; Vcb->VDS1 = main_s; /* if(Vcb->LVid) MyFreePool__(Vcb->LVid); Vcb->LVid = NULL;*/ if(OS_SUCCESS(UDFVerifySequence(DeviceObject, Vcb, reserve_s, reserve_e, fileset))) { UDFPrint(("-----------------------------------\n")); Vcb->VDS2_Len = reserve_e - reserve_s; Vcb->VDS2 = reserve_s; break; } else { UDFPrint(("UDF: Reserve sequence verification failed.\n")); switch(Vcb->PartitialDamagedVolumeAction) { case UDF_PART_DAMAGED_RO: UDFPrint(("UDF: Switch to r/o mode.\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; break; case UDF_PART_DAMAGED_NO: UDFPrint(("UDF: Switch to raw mount mode, return UNRECOGNIZED_VOLUME.\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; RC = STATUS_WRONG_VOLUME; break; case UDF_PART_DAMAGED_RW: default: UDFPrint(("UDF: Keep r/w mode for your own risk.\n")); break; } } break; } } } if(Vcb->SparingCount && (Vcb->NoFreeRelocationSpaceVolumeAction != UDF_PART_DAMAGED_RW)) { UDFPrint(("UDF: No free Sparing Entries -> Switch to r/o mode.\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; } if(i == sizeof(Vcb->Anchor)/sizeof(int)) { UDFPrint(("No Anchor block found\n")); RC = STATUS_UNRECOGNIZED_VOLUME; #ifdef UDF_DBG } else { UDFPrint(("Using anchor in block %x\n", Vcb->Anchor[i])); #endif // UDF_DBG } MyFreePool__(Buf); return RC; } // end UDFLoadPartition() /* This routine scans FileSet sequence & returns pointer to last valid FileSet */ OSSTATUS UDFFindLastFileSet( IN PVCB Vcb, IN lb_addr *Addr, // Addr for the 1st FileSet IN OUT PFILE_SET_DESC FileSetDesc ) { OSSTATUS status; uint32 relLocExt = Addr->logicalBlockNum; uint32 locExt = UDFPartLbaToPhys(Vcb, Addr); uint16 Ident; uint32 relPrevExt, prevExt; relPrevExt, prevExt = NULL; FileSetDesc->nextExt.extLength = 1; // ;) // walk through FileSet chain // we've just pre-init'd extent length to read 1st FileSet while(FileSetDesc->nextExt.extLength) { status = UDFReadTagged(Vcb, (int8*)FileSetDesc, locExt, relLocExt, &Ident); if(!OS_SUCCESS(status)) { FileSetDesc->nextExt.extLength = 0; return status; } UDFRegisterFsStructure(Vcb, locExt, Vcb->BlockSize); if((locExt == LBA_OUT_OF_EXTENT) || (Ident != TID_FILE_SET_DESC)) { // try to read previous FileSet if(!prevExt) return STATUS_UNRECOGNIZED_VOLUME; status = UDFReadTagged(Vcb, (int8*)FileSetDesc, prevExt, relLocExt, &Ident); if(OS_SUCCESS(status)) { UDFRegisterFsStructure(Vcb, prevExt, Vcb->BlockSize); } return status; } prevExt = locExt; relPrevExt = relLocExt; locExt = UDFPartLbaToPhys(Vcb, &(FileSetDesc->nextExt.extLocation)); } return STATUS_SUCCESS; } // end UDFFindLastFileSet() /* This routine reads all sparing tables & stores them in contiguos memory space */ OSSTATUS UDFLoadSparingTable( IN PVCB Vcb, IN PSPARABLE_PARTITION_MAP PartMap ) { PSPARING_MAP RelocMap; PSPARING_MAP NewRelocMap; OSSTATUS status; uint32 i=0, BC, BC2; PSPARING_TABLE SparTable; uint32 TabSize, NewSize; SIZE_T ReadBytes; uint32 SparTableLoc; #ifdef UDF_TRACK_FS_STRUCTURES uint32 j; #endif //UDF_TRACK_FS_STRUCTURES uint32 n,m; BOOLEAN merged; Vcb->SparingCountFree = -1; UDFPrint(("UDF: Sparable Part Map:\n")); Vcb->SparingTableLength = PartMap->sizeSparingTable; BC = (PartMap->sizeSparingTable >> Vcb->BlockSizeBits) + 1; UDFPrint((" partitionMapType = %x\n", PartMap->partitionMapType)); UDFPrint((" partitionMapLength = %x\n", PartMap->partitionMapLength)); UDFPrint((" volSeqNum = %x\n", PartMap->volSeqNum)); UDFPrint((" partitionNum = %x\n", PartMap->partitionNum)); UDFPrint((" packetLength = %x\n", PartMap->packetLength)); UDFPrint((" numSparingTables = %x\n", PartMap->numSparingTables)); UDFPrint((" sizeSparingTable = %x\n", PartMap->sizeSparingTable)); SparTable = (PSPARING_TABLE)MyAllocatePool__(NonPagedPool, BC*Vcb->BlockSize); if(!SparTable) return STATUS_INSUFFICIENT_RESOURCES; if(Vcb->SparingTable) { // if a part of Sparing Table is already loaded, // update it with data from another one RelocMap = Vcb->SparingTable; TabSize = Vcb->SparingCount * sizeof(SPARING_ENTRY); } else { // do some init to load first part of Sparing Table RelocMap = (PSPARING_MAP)MyAllocatePool__(NonPagedPool, RELOC_MAP_GRAN); if(!RelocMap) { MyFreePool__(SparTable); return STATUS_INSUFFICIENT_RESOURCES; } TabSize = RELOC_MAP_GRAN; Vcb->SparingBlockSize = PartMap->packetLength; } // walk through all available Sparing Tables for(i=0;inumSparingTables;i++) { // read (next) table SparTableLoc = ((uint32*)(PartMap+1))[i]; for(n=0; nSparingTableCount; n++) { if(Vcb->SparingTableLoc[i] == SparTableLoc) { UDFPrint((" already processed @%x\n", SparTableLoc )); continue; } } status = UDFReadSectors(Vcb, FALSE, SparTableLoc, 1, FALSE, (int8*)SparTable, &ReadBytes); // tag should be set to TID_UNUSED_DESC if(OS_SUCCESS(status) && (SparTable->descTag.tagIdent == TID_UNUSED_DESC)) { UDFRegisterFsStructure(Vcb, SparTableLoc, Vcb->BlockSize); BC2 = ((sizeof(SPARING_TABLE) + SparTable->reallocationTableLen*sizeof(SparingEntry) + Vcb->BlockSize-1) >> Vcb->BlockSizeBits); if(BC2 > BC) { UDFPrint((" sizeSparingTable @%x too long: %x > %x\n", SparTableLoc, BC2, BC )); continue; } status = UDFReadSectors(Vcb, FALSE, SparTableLoc, BC2, FALSE, (int8*)SparTable, &ReadBytes); UDFRegisterFsStructure(Vcb, SparTableLoc, BC2<BlockSizeBits); if(!OS_SUCCESS(status)) { UDFPrint((" Error reading sizeSparingTable @%x (%x)\n", SparTableLoc, BC2 )); continue; } // process sparing table NewSize = sizeof(SparingEntry)*SparTable->reallocationTableLen; TabSize = MyReallocPool__((int8*)RelocMap, TabSize, (int8**)&RelocMap, TabSize+NewSize); if(!TabSize) { MyFreePool__(SparTable); return STATUS_INSUFFICIENT_RESOURCES; } #ifdef UDF_TRACK_FS_STRUCTURES for(j=0; jreallocationTableLen; j++) { UDFRegisterFsStructure(Vcb, ((SparingEntry*)(SparTable+1))[j].mappedLocation, Vcb->WriteBlockSize); } #endif //UDF_TRACK_FS_STRUCTURES Vcb->SparingTableLoc[Vcb->SparingTableCount] = SparTableLoc; Vcb->SparingTableCount++; NewRelocMap = (PSPARING_MAP)(SparTable+1); for(n=0; nreallocationTableLen; n++) { merged = TRUE; for(m=0; mSparingCount; m++) { if(RelocMap[m].mappedLocation == NewRelocMap[n].mappedLocation) { UDFPrint((" dup @%x (%x) vs @%x (%x)\n", RelocMap[m].origLocation, RelocMap[m].mappedLocation, NewRelocMap[m].origLocation, NewRelocMap[m].mappedLocation)); merged = FALSE; } if((RelocMap[m].origLocation == NewRelocMap[n].origLocation) && (RelocMap[m].mappedLocation != NewRelocMap[n].mappedLocation) && (RelocMap[m].origLocation != SPARING_LOC_AVAILABLE) && (RelocMap[m].origLocation != SPARING_LOC_CORRUPTED)) { UDFPrint((" conflict @%x (%x) vs @%x (%x)\n", RelocMap[m].origLocation, RelocMap[m].mappedLocation, NewRelocMap[n].origLocation, NewRelocMap[n].mappedLocation)); merged = FALSE; } } if(merged) { RelocMap[Vcb->SparingCount] = NewRelocMap[n]; UDFPrint((" reloc %x -> %x\n", RelocMap[Vcb->SparingCount].origLocation, RelocMap[Vcb->SparingCount].mappedLocation)); Vcb->SparingCount++; if(RelocMap[Vcb->SparingCount].origLocation == SPARING_LOC_AVAILABLE) { Vcb->NoFreeRelocationSpaceVolumeAction = UDF_PART_DAMAGED_RW; } } } /* RtlCopyMemory((int8*)(RelocMap+Vcb->SparingCount), (int8*)(SparTable+1), NewSize); Vcb->SparingCount += NewSize/sizeof(SPARING_ENTRY); */ if(Vcb->SparingTableCount >= MAX_SPARING_TABLE_LOCATIONS) { UDFPrint((" too many Sparing Tables\n")); break; } } } Vcb->SparingTable = RelocMap; MyFreePool__(SparTable); return STATUS_SUCCESS; } // end UDFLoadSparingTable() /* This routine checks if buffer is ZERO-filled */ BOOLEAN UDFCheckZeroBuf( IN int8* Buf, IN uint32 Length ) { #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) BOOLEAN RC = FALSE; uint32 len = Length; __asm push ecx __asm push edi __asm mov ecx,len __asm mov edi,Buf __asm xor eax,eax __asm shr ecx,2 __asm repe scasd __asm jne short not_all_zeros __asm mov RC,1 not_all_zeros: __asm pop edi __asm pop ecx return RC; #else // _X86_ uint32* tmp = (uint32*)Buf; uint32 i; for(i=0; iFsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) { // check if this disc is mountable for CDFS UDFPrint((" FILE_DEVICE_CD_ROM_FILE_SYSTEM\n")); check_NSR: NSRDesc = UDFFindVRS(Vcb); if(!(NSRDesc & VRS_ISO9660_FOUND)) { // no CDFS VRS found UDFPrint(("UDFGetDiskInfoAndVerify: no CDFS VRS found\n")); if(!Vcb->TrackMap[Vcb->LastTrackNum].LastLba && !Vcb->TrackMap[Vcb->FirstTrackNum].LastLba) { // such a stupid method of Audio-CD detection... UDFPrint(("UDFGetDiskInfoAndVerify: set UDF_VCB_FLAGS_RAW_DISK\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK; } } Vcb->NSRDesc = NSRDesc; Buf = (int8*)MyAllocatePool__(NonPagedPool, 0x10000); if(!Buf) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); RC = UDFReadData(Vcb, FALSE, 0, 0x10000, FALSE, Buf, &ReadBytes); if(!OS_SUCCESS(RC)) try_return(RC = STATUS_UNRECOGNIZED_VOLUME); RC = STATUS_UNRECOGNIZED_VOLUME; if(!UDFCheckZeroBuf(Buf,0x10000)) { UDFPrint(("UDFGetDiskInfoAndVerify: possible FS detected, remove UDF_VCB_FLAGS_RAW_DISK\n")); Vcb->VCBFlags &= ~UDF_VCB_FLAGS_RAW_DISK; } MyFreePool__(Buf); Buf = NULL; } try_return(RC = STATUS_UNRECOGNIZED_VOLUME); } RC = UDFLoadPartition(DeviceObject,Vcb,&fileset); if(!OS_SUCCESS(RC)) { if(RC == STATUS_UNRECOGNIZED_VOLUME) { UDFPrint(("UDFGetDiskInfoAndVerify: check NSR presence\n")); goto check_NSR; } try_return(RC); } FileSetDesc = (PFILE_SET_DESC)MyAllocatePool__(NonPagedPool,Vcb->BlockSize); if(!FileSetDesc) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); RC = UDFFindLastFileSet(Vcb,&fileset,FileSetDesc); if(!OS_SUCCESS(RC)) try_return(RC); 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); try_exit: NOTHING; } _SEH2_FINALLY { if(FileSetDesc) MyFreePool__(FileSetDesc); if(Buf) MyFreePool__(Buf); } _SEH2_END; return(RC); } // end UDFGetDiskInfoAndVerify()