reactos/drivers/filesystems/udfs/udf_info/mount.cpp

3063 lines
108 KiB
C++

////////////////////////////////////////////////////////////////////
// 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;
uint32 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;
uint32 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<<Vcb->LB2B_Bits;
// if we have some bad bits, mark corresponding area as BAD
if(bad_bm) {
for(i=pstart; i<pend; i++) {
if(UDFGetBadBit(bad_bm, i)) {
// TODO: would be nice to add these blocks to unallocatable space
UDFSetUsedBits(new_bm, i & ~(d-1), d);
}
}
}
j=0;
for(i=pstart; i<pend; i+=d) {
if(UDFGetUsedBit(old_bm, i) && UDFGetFreeBit(new_bm, i)) {
// sector was deallocated during last session
if(USBM) UDFSetFreeBit(upart_bm, j);
if(FSBM) UDFSetFreeBit(fpart_bm, j);
} else if(UDFGetUsedBit(new_bm, i)) {
// allocated
if(USBM) UDFSetUsedBit(upart_bm, j);
if(FSBM) UDFSetUsedBit(fpart_bm, j);
}
j++;
}
// flush updates
if(USBM) {
status = UDFWriteExtent(Vcb, &USBMExtInfo, 0, USl, FALSE, USBM, &WrittenBytes);
DbgFreePool(USBM);
MyFreePool__(USBMExtInfo.Mapping);
}
if(FSBM) {
status2 = UDFWriteExtent(Vcb, &FSBMExtInfo, 0, FSl, FALSE, FSBM, &WrittenBytes);
DbgFreePool(FSBM);
MyFreePool__(FSBMExtInfo.Mapping);
} else {
status2 = status;
}
}
if(!OS_SUCCESS(status))
return status;
return status2;
} // end UDFUpdateXSpaceBitmaps()
/*
This routine updates Partition Desc & associated data structures
*/
OSSTATUS
UDFUpdatePartDesc(
PVCB Vcb,
int8* Buf
)
{
PartitionDesc *p = (PartitionDesc *)Buf;
uint32 i; // PartNdx
tag* PTag;
uint32 WrittenBytes;
for(i=0; i<Vcb->PartitionMaps; 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;
uint32 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;
uint32 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; i<lvid->numOfPartitions; 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;
uint32 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;i<Vcb->SparingCount;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;i<Vcb->SparingCount;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;i<Vcb->SparingTableCount;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; n<SparTable->reallocationTableLen; n++) {
for(m=0; m<Vcb->SparingCount; 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;
uint32 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; i<VDS_POS_LENGTH; i++) {
if (vds[i].block) {
status = UDFReadTagged(Vcb, Buf, vds[i].block, vds[i].block, &ident);
if(OS_SUCCESS(status) && (i == VDS_POS_PARTITION_DESC)) {
// load partition descriptor(s)
int8* Buf2 = (int8*)DbgAllocatePool(NonPagedPool,Vcb->BlockSize);
if (!Buf2) {
DbgFreePool(Buf);
return STATUS_INSUFFICIENT_RESOURCES;
}
for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++) {
UDFReadTagged(Vcb,Buf2, j, j, &ident);
if (ident == TID_UNALLOC_SPACE_DESC)
// This implememtation doesn't support USD ;) recording
// So, we'll make'em blank, but record all bitmaps
UDFUpdateUSpaceDesc(Vcb,Buf2);
}
DbgFreePool(Buf2);
break;
}
}
}*/
for (i=0; i<VDS_POS_LENGTH; i++) {
if (vds[i].block) {
status = UDFReadTagged(Vcb, Buf, vds[i].block, vds[i].block, &ident);
if(!OS_SUCCESS(status))
continue;
// update XBMs
if(i == VDS_POS_PARTITION_DESC) {
if(!(flags & 1))
continue;
// update partition descriptor(s)
int8* Buf2 = (int8*)DbgAllocatePool(NonPagedPool,Vcb->BlockSize);
if (!Buf2) {
DbgFreePool(Buf);
return STATUS_INSUFFICIENT_RESOURCES;
}
UDFUpdatePartDesc(Vcb,Buf);
for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++) {
UDFReadTagged(Vcb,Buf2, j, j, &ident);
if (ident == TID_PARTITION_DESC)
UDFUpdatePartDesc(Vcb,Buf2);
}
DbgFreePool(Buf2);
// continue;
} else
// update Vol Ident Desc
if(i == VDS_POS_LOGICAL_VOL_DESC) {
status = UDFUpdateLogicalVol(Vcb, vds[VDS_POS_LOGICAL_VOL_DESC], &(Vcb->VolIdent));
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;
uint32 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;
uint32 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; i<pend; i++) {
if(!UDFGetBadBit(bad_bm, i))
continue;
// add BAD blocks to unallocatable space
// if the block is already in NonAllocatable, ignore it
if(UDFLocateLbaInExtent(Vcb, DataLoc->Mapping, 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<<Vcb->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; i<sizeof(Vcb->Anchor)/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);
uint32 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;
uint32 _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;
i<Vcb->PartitionMaps && offset<lvd->mapTableLength;
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;
uint32 Length;
uint32 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)<<Vcb->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)) && (i<lim);) {
// expand LBlocks to Sectors...
l2 = l << Vcb->LB2B_Bits;
// ...and mark them
if(bm_type == UDF_FSPACE_BM) {
bit_set = UDFGetFreeBit(tmp_bm, j);
for(k=0;(k<l2) && (i<lim);k++) {
if(bit_set) {
// FREE block
UDFSetFreeBit(Vcb->FSBM_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;(k<l2) && (i<lim);k++) {
if(bit_set) {
// ZERO block
UDFSetZeroBit(Vcb->ZSBM_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(;i<lim;i++) {
UDFSetUsedBit(Vcb->FSBM_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;
uint32 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)<<Vcb->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)) && (i<lim);) {
// expand LBlocks to Sectors...
l2 = l << Vcb->LB2B_Bits;
// ...and mark them
if(bm_type == UDF_FSPACE_BM) {
bit_set = UDFGetFreeBit(tmp_bm, j);
for(k=0;(k<l2) && (i<lim);k++) {
if(bit_set) {
// FREE block
UDFSetFreeBit(Vcb->FSBM_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;(k<l2) && (i<lim);k++) {
if(bit_set) {
// ZERO block
UDFSetZeroBit(Vcb->ZSBM_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(;i<lim;i++) {
UDFSetUsedBit(Vcb->FSBM_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;
uint32 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)<<Vcb->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(;i<lim;i++) {
if(UDFGetUsedBit(tmp_bm, j)) UDFSetFreeBit(Vcb->FSBM_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(;i<lim;i++) {
// UDFSetUsedBit(Vcb->FSBM_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; i<Vcb->PartitionMaps; 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; i<Vcb->PartitionMaps; 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; i<VDS_POS_LENGTH; i++)
{
if(vds[i].block)
{
if(!OS_SUCCESS(RC = UDFReadTagged(Vcb, Buf, vds[i].block, vds[i].block, &ident)))
try_return(RC);
UDFRegisterFsStructure(Vcb, vds[i].block, Vcb->BlockSize);
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; j<vds[VDS_POS_TERMINATING_DESC].block; j++)
{
RC = UDFReadTagged(Vcb,Buf2, j, j, &ident);
if(!OS_SUCCESS(RC)) try_return(RC);
UDFRegisterFsStructure(Vcb, j, Vcb->BlockSize);
// 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; i<VDS_POS_LENGTH; i++)
{
if(vds[i].block)
{
if(!OS_SUCCESS(RC = UDFReadTagged(Vcb, Buf, vds[i].block, vds[i].block, &ident)))
try_return(RC);
UDFRegisterFsStructure(Vcb, vds[i].block, Vcb->BlockSize);
/* 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; j<vds[VDS_POS_TERMINATING_DESC].block; j++)
{
RC = UDFReadTagged(Vcb,Buf2, j, j, &ident);
if(!OS_SUCCESS(RC)) try_return(RC);
UDFRegisterFsStructure(Vcb, j, Vcb->BlockSize);
// 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; j<Vcb->BadSeqLocIndex; 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; i<MAX_ANCHOR_LOCATIONS; i++)
{
if(Vcb->Anchor[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;
uint32 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;i<PartMap->numSparingTables;i++) {
// read (next) table
SparTableLoc = ((uint32*)(PartMap+1))[i];
for(n=0; n<Vcb->SparingTableCount; 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<<Vcb->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; j<SparTable->reallocationTableLen; 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; n<SparTable->reallocationTableLen; n++) {
merged = TRUE;
for(m=0; m<Vcb->SparingCount; 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; i<Length/4; i++) {
if(tmp[i]) return FALSE;
}
return TRUE;
#endif // _X86_
} // end UDFCheckZeroBuf()
/*
check if this is an UDF-formatted disk
*/
OSSTATUS
UDFGetDiskInfoAndVerify(
IN PDEVICE_OBJECT DeviceObject, // the target device object
IN PVCB Vcb // Volume control block from this DevObj
)
{
OSSTATUS RC = STATUS_UNRECOGNIZED_VOLUME;
uint32 NSRDesc;
lb_addr fileset;
PFILE_SET_DESC FileSetDesc = NULL;
int8* Buf = NULL;
uint32 ReadBytes;
UDFPrint(("UDFGetDiskInfoAndVerify\n"));
_SEH2_TRY {
if(!UDFFindAnchor(Vcb)) {
if(Vcb->FsDeviceType == 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()