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

3428 lines
131 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:
extent.cpp
Abstract:
This file contains filesystem-specific routines
responsible for extent & mapping management
*/
#include "udf.h"
#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_EXTENT
/*
This routine converts offset in extent to Lba & returns offset in the 1st
sector & bytes before end of block.
Here we assume no references to AllocDescs
*/
uint32
UDFExtentOffsetToLba(
IN PVCB Vcb,
IN PEXTENT_MAP Extent, // Extent array
IN int64 Offset, // offset in extent
OUT uint32* SectorOffset,
OUT uint32* AvailLength, // available data in this block
OUT uint32* Flags,
OUT uint32* Index
)
{
uint32 j=0, l, d, BSh = Vcb->BlockSizeBits;
uint32 Offs;
uint32 i=0, BOffset; // block nums
BOffset = (uint32)(Offset >> BSh);
// scan extent table for suitable range (frag)
ExtPrint(("ExtLen %x\n", Extent->extLength));
while(i+(d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK)) >> BSh) <= BOffset) {
if(!l) {
if(Index) (*Index) = j-1;
if(Flags) {
Extent--;
(*Flags) = (Extent->extLength >> 30);
}
return LBA_OUT_OF_EXTENT;
}
if(!d)
break;
i += d; //frag offset
j++; // frag index
Extent++;
}
BOffset -= i;
Offs = (*((uint32*)&Offset)) - (i << BSh); // offset in frag
if(SectorOffset)
(*SectorOffset) = Offs & (Vcb->BlockSize-1);// offset in 1st Lba
if(AvailLength)
(*AvailLength) = l - Offs;// bytes to EO frag
if(Flags)
(*Flags) = (Extent->extLength >> 30);
if(Index)
(*Index) = j;
ASSERT(((Extent->extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation);
return Extent->extLocation + BOffset;// 1st Lba
} // end UDFExtentOffsetToLba()
uint32
UDFNextExtentToLba(
IN PVCB Vcb,
IN PEXTENT_MAP Extent, // Extent array
OUT uint32* AvailLength, // available data in this block
OUT uint32* Flags,
OUT uint32* Index
)
{
// uint32 Lba;
uint32 l;
// uint32 d;
// scan extent table for suitable range (frag)
// d = (l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK));
l = (Extent->extLength & UDF_EXTENT_LENGTH_MASK);
if(!l) {
(*Index) = -1;
Extent--;
(*Flags) = (Extent->extLength >> 30);
return LBA_OUT_OF_EXTENT;
}
(*Index) = 0;
(*AvailLength) = l;// bytes to EO frag
(*Flags) = (Extent->extLength >> 30);
ASSERT(((*Flags) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) || Extent->extLocation);
return Extent->extLocation;// 1st Lba
} // end UDFNextExtentToLba()
/*
This routine locates frag containing specified Lba in extent
*/
ULONG
UDFLocateLbaInExtent(
IN PVCB Vcb,
IN PEXTENT_MAP Extent, // Extent array
IN lba_t lba
)
{
uint32 l, BSh = Vcb->BlockSizeBits;
uint32 i=0;
while((l = ((Extent->extLength & UDF_EXTENT_LENGTH_MASK) >> BSh))) {
if(Extent->extLocation >= lba &&
Extent->extLocation+l < lba) {
return i;
}
i++; //frag offset
Extent++;
}
return LBA_OUT_OF_EXTENT;// index of item in extent, containing out Lba
} // end UDFLocateLbaInExtent()
/*
This routine calculates total length of specified extent.
Here we assume no references to AllocDescs
*/
int64
UDFGetExtentLength(
IN PEXTENT_MAP Extent // Extent array
)
{
if(!Extent) return 0;
int64 i=0;
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
__asm push ebx
__asm push ecx
__asm push esi
__asm lea ebx,i
__asm mov esi,Extent
__asm xor ecx,ecx
While_1:
__asm mov eax,[esi+ecx*8] // Extent[j].extLength
__asm and eax,UDF_EXTENT_LENGTH_MASK
__asm jz EO_While
__asm add [ebx],eax
__asm adc [ebx+4],0
__asm inc ecx
__asm jmp While_1
EO_While:;
__asm pop esi
__asm pop ecx
__asm pop ebx
#else // NO X86 optimization , use generic C/C++
while(Extent->extLength) {
i += (Extent->extLength & UDF_EXTENT_LENGTH_MASK);
Extent++;
}
#endif // _X86_
return i;
} // UDFGetExtentLength()
/*
This routine appends Zero-terminator to single Extent-entry.
Such operation makes it compatible with other internal routines
*/
PEXTENT_MAP
__fastcall
UDFExtentToMapping_(
IN PEXTENT_AD Extent
#ifdef UDF_TRACK_EXTENT_TO_MAPPING
,IN ULONG src,
IN ULONG line
#endif //UDF_TRACK_EXTENT_TO_MAPPING
)
{
PEXTENT_MAP Map;
#ifdef UDF_TRACK_EXTENT_TO_MAPPING
#define UDF_EXT_MAP_MULT 4
#else //UDF_TRACK_EXTENT_TO_MAPPING
#define UDF_EXT_MAP_MULT 2
#endif //UDF_TRACK_EXTENT_TO_MAPPING
Map = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDF_EXT_MAP_MULT *
sizeof(EXTENT_MAP), MEM_EXTMAP_TAG);
if(!Map) return NULL;
RtlZeroMemory((int8*)(Map+1), sizeof(EXTENT_MAP));
Map[0].extLength = Extent->extLength;
Map[0].extLocation = Extent->extLocation;
#ifdef UDF_TRACK_EXTENT_TO_MAPPING
Map[2].extLength = src;
Map[2].extLocation = line;
#endif //UDF_TRACK_EXTENT_TO_MAPPING
return Map;
} // end UDFExtentToMapping()
/*
This routine calculates file mapping length (in bytes) including
ZERO-terminator
*/
uint32
UDFGetMappingLength(
IN PEXTENT_MAP Extent
)
{
if(!Extent) return 0;
uint32 i=0;
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
__asm push ebx
__asm mov ebx,Extent
__asm xor eax,eax
While_1:
__asm mov ecx,[ebx+eax*8]
__asm jecxz EO_While
__asm inc eax
__asm jmp While_1
EO_While:
__asm inc eax
__asm shl eax,3
__asm mov i,eax
__asm pop ebx
#else // NO X86 optimization , use generic C/C++
while(Extent->extLength) {
i++;
Extent++;
}
i++;
i*=sizeof(EXTENT_MAP);
#endif // _X86_
return i; // i*sizeof(EXTENT_MAP)
} // end UDFGetMappingLength()
/*
This routine merges 2 sequencial file mappings
*/
PEXTENT_MAP
__fastcall
UDFMergeMappings(
IN PEXTENT_MAP Extent,
IN PEXTENT_MAP Extent2
)
{
PEXTENT_MAP NewExt;
uint32 len, len2;
len = UDFGetMappingLength(Extent);
len2 = UDFGetMappingLength(Extent2);
ASSERT(len2 && len);
if(!len2) {
return Extent;
}
if(MyReallocPool__((int8*)Extent, len, (int8**)(&NewExt), len+len2-sizeof(EXTENT_MAP))) {
RtlCopyMemory(((int8*)NewExt)+len-sizeof(EXTENT_MAP), (int8*)Extent2, len2);
} else {
ExtPrint(("UDFMergeMappings failed\n"));
BrutePoint();
}
return NewExt;
} // end UDFMergeMappings()
/*
This routine builds file mapping according to ShortAllocDesc (SHORT_AD)
array
*/
PEXTENT_MAP
UDFShortAllocDescToMapping(
IN PVCB Vcb,
IN uint32 PartNum,
IN PSHORT_AD AllocDesc,
IN uint32 AllocDescLength,
IN uint32 SubCallCount,
OUT PEXTENT_INFO AllocLoc
)
{
uint32 i, lim, l, len, type;
// uint32 BSh;
PEXTENT_MAP Extent, Extent2, AllocMap;
EXTENT_AD AllocExt;
PALLOC_EXT_DESC NextAllocDesc;
lb_addr locAddr;
uint32 ReadBytes;
EXTENT_INFO NextAllocLoc;
BOOLEAN w2k_compat = FALSE;
ExtPrint(("UDFShortAllocDescToMapping: len=%x\n", AllocDescLength));
if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL;
locAddr.partitionReferenceNum = (uint16)PartNum;
// BSh = Vcb->BlockSizeBits;
l = ((lim = (AllocDescLength/sizeof(SHORT_AD))) + 1 ) * sizeof(EXTENT_AD);
Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG);
if(!Extent) return NULL;
NextAllocLoc.Offset = 0;
for(i=0;i<lim;i++) {
type = AllocDesc[i].extLength >> 30;
len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK;
ExtPrint(("ShExt: type %x, loc %x, len %x\n", type, AllocDesc[i].extPosition, len));
if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) {
// read next frag of allocation descriptors if encountered
if(len < sizeof(ALLOC_EXT_DESC)) {
MyFreePool__(Extent);
return NULL;
}
NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG);
if(!NextAllocDesc) {
MyFreePool__(Extent);
return NULL;
}
// record information about this frag
locAddr.logicalBlockNum = AllocDesc[i].extPosition;
AllocExt.extLength = len;
AllocExt.extLocation = UDFPartLbaToPhys(Vcb, &locAddr);
if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) {
UDFPrint(("bad address\n"));
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
NextAllocLoc.Mapping =
AllocMap = UDFExtentToMapping(&AllocExt);
NextAllocLoc.Length = len;
if(!AllocMap) {
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap);
if(!AllocLoc->Mapping ||
// read this frag
!OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc,
0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes)))
{
MyFreePool__(AllocMap);
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
MyFreePool__(AllocMap);
// check integrity
if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) ||
(NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) {
UDFPrint(("Integrity check failed\n"));
UDFPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent));
UDFPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs));
UDFPrint(("len = %x\n", len));
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
// perform recursive call to obtain mapping
NextAllocLoc.Flags = 0;
Extent2 = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)(NextAllocDesc+1),
NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc);
if(!Extent2) {
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
UDFCheckSpaceAllocation(Vcb, 0, Extent2, AS_USED); // check if used
// and merge this 2 mappings into 1
Extent[i].extLength = 0;
Extent[i].extLocation = 0;
Extent = UDFMergeMappings(Extent, Extent2);
if(NextAllocLoc.Flags & EXTENT_FLAG_2K_COMPAT) {
ExtPrint(("w2k-compat\n"));
AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT;
}
MyFreePool__(Extent2);
return Extent;
}
//
#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
ASSERT(!(len & (Vcb->LBlockSize-1) ));
#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
if(len & (Vcb->LBlockSize-1)) {
w2k_compat = TRUE;
}
Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1);
locAddr.logicalBlockNum = AllocDesc[i].extPosition;
// Note: for compatibility Adaptec DirectCD we check 'len' here
// That strange implementation records bogus extLocation in terminal entries
if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) {
Extent[i].extLocation = UDFPartLbaToPhys(Vcb, &locAddr);
if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) {
UDFPrint(("bad address (2)\n"));
MyFreePool__(Extent);
return NULL;
}
} else {
Extent[i].extLocation = 0;
}
if(!len) {
// some UDF implementations set strange AllocDesc sequence length,
// but terminates it with zeros in proper place, so handle
// this case
ASSERT(i>=(lim-1));
ASSERT(!Extent[i].extLength);
Extent[i].extLocation = 0;
if(/*!SubCallCount &&*/ w2k_compat) {
ExtPrint(("w2k-compat\n"));
AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT;
}
return Extent;
}
Extent[i].extLength |= (type << 30);
}
// set terminator
Extent[i].extLength = 0;
Extent[i].extLocation = 0;
if(/*!SubCallCount &&*/ w2k_compat) {
ExtPrint(("w2k-compat\n"));
AllocLoc->Flags |= EXTENT_FLAG_2K_COMPAT;
}
return Extent;
} // end UDFShortAllocDescToMapping()
/*
This routine builds file mapping according to LongAllocDesc (LONG_AD)
array
*/
PEXTENT_MAP
UDFLongAllocDescToMapping(
IN PVCB Vcb,
IN PLONG_AD AllocDesc,
IN uint32 AllocDescLength,
IN uint32 SubCallCount,
OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero)
)
{
uint32 i, lim, l, len, type;
// uint32 BSh;
PEXTENT_MAP Extent, Extent2, AllocMap;
EXTENT_AD AllocExt;
PALLOC_EXT_DESC NextAllocDesc;
uint32 ReadBytes;
EXTENT_INFO NextAllocLoc;
ExtPrint(("UDFLongAllocDescToMapping: len=%x\n", AllocDescLength));
if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL;
// BSh = Vcb->BlockSizeBits;
l = ((lim = (AllocDescLength/sizeof(LONG_AD))) + 1 ) * sizeof(EXTENT_AD);
Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG);
if(!Extent) return NULL;
NextAllocLoc.Offset = 0;
for(i=0;i<lim;i++) {
type = AllocDesc[i].extLength >> 30;
len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK;
ExtPrint(("LnExt: type %x, loc %x (%x:%x), len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)),
AllocDesc[i].extLocation.partitionReferenceNum, AllocDesc[i].extLocation.logicalBlockNum,
len));
if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) {
// read next frag of allocation descriptors if encountered
if(len < sizeof(ALLOC_EXT_DESC)) {
MyFreePool__(Extent);
return NULL;
}
NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG);
if(!NextAllocDesc) {
MyFreePool__(Extent);
return NULL;
}
// record information about this frag
AllocExt.extLength = len;
AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) {
UDFPrint(("bad address\n"));
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
NextAllocLoc.Mapping =
AllocMap = UDFExtentToMapping(&AllocExt);
NextAllocLoc.Length = len;
if(!AllocMap) {
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap);
if(!AllocLoc->Mapping ||
// read this frag
!OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc,
0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes)))
{
MyFreePool__(AllocMap);
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
MyFreePool__(AllocMap);
// check integrity
if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) ||
(NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) {
UDFPrint(("Integrity check failed\n"));
UDFPrint(("NextAllocDesc->descTag.tagIdent = %x\n", NextAllocDesc->descTag.tagIdent));
UDFPrint(("NextAllocDesc->lengthAllocDescs = %x\n", NextAllocDesc->lengthAllocDescs));
UDFPrint(("len = %x\n", len));
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
// perform recursive call to obtain mapping
Extent2 = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)(NextAllocDesc+1),
NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc);
if(!Extent2) {
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
// and merge this 2 mappings into 1
Extent[i].extLength = 0;
Extent[i].extLocation = 0;
Extent = UDFMergeMappings(Extent, Extent2);
MyFreePool__(Extent2);
return Extent;
}
//
Extent[i].extLength = len;
#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
ASSERT(!(len & (Vcb->LBlockSize-1) ));
#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
Extent[i].extLength = (len+Vcb->LBlockSize-1) & ~(Vcb->LBlockSize-1);
// Note: for compatibility Adaptec DirectCD we check 'len' here
// That strange implementation records bogus extLocation in terminal entries
if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) {
Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) {
UDFPrint(("bad address (2)\n"));
MyFreePool__(Extent);
return NULL;
}
} else {
Extent[i].extLocation = 0;
}
if(!len) {
// some UDF implementations set strange AllocDesc sequence length,
// but terminates it with zeros in proper place, so handle
// this case
Extent[i].extLocation = 0;
return Extent;
}
Extent[i].extLength |= (type << 30);
}
// set terminator
Extent[i].extLength = 0;
Extent[i].extLocation = 0;
return Extent;
} // end UDFLongAllocDescToMapping()
/*
This routine builds file mapping according to ExtendedAllocDesc (EXT_AD)
array
*/
PEXTENT_MAP
UDFExtAllocDescToMapping(
IN PVCB Vcb,
IN PEXT_AD AllocDesc,
IN uint32 AllocDescLength,
IN uint32 SubCallCount,
OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero)
)
{
uint32 i, lim, l, len, type;
// uint32 BSh;
PEXTENT_MAP Extent, Extent2, AllocMap;
EXTENT_AD AllocExt;
PALLOC_EXT_DESC NextAllocDesc;
uint32 ReadBytes;
EXTENT_INFO NextAllocLoc;
ExtPrint(("UDFExtAllocDescToMapping: len=%x\n", AllocDescLength));
if(SubCallCount > ALLOC_DESC_MAX_RECURSE) return NULL;
// BSh = Vcb->BlockSizeBits;
l = ((lim = (AllocDescLength/sizeof(EXT_AD))) + 1 ) * sizeof(EXTENT_AD);
Extent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, l, MEM_EXTMAP_TAG);
if(!Extent) return NULL;
NextAllocLoc.Offset = 0;
for(i=0;i<lim;i++) {
type = AllocDesc[i].extLength >> 30;
len = AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK;
ExtPrint(("ExExt: type %x, loc %x, len %x\n", type, UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation)), len));
if(type == EXTENT_NEXT_EXTENT_ALLOCDESC) {
// read next frag of allocation descriptors if encountered
if(len < sizeof(ALLOC_EXT_DESC)) {
MyFreePool__(Extent);
return NULL;
}
NextAllocDesc = (PALLOC_EXT_DESC)MyAllocatePoolTag__(NonPagedPool, len, MEM_ALLOCDESC_TAG);
if(!NextAllocDesc) {
MyFreePool__(Extent);
return NULL;
}
// record information about this frag
AllocExt.extLength = len;
AllocExt.extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
if(AllocExt.extLocation == LBA_OUT_OF_EXTENT) {
UDFPrint(("bad address\n"));
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
NextAllocLoc.Mapping =
AllocMap = UDFExtentToMapping(&AllocExt);
NextAllocLoc.Length = len;
if(!AllocMap) {
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
AllocLoc->Mapping = UDFMergeMappings(AllocLoc->Mapping, AllocMap);
if(!AllocLoc->Mapping ||
// read this frag
!OS_SUCCESS(UDFReadExtent(Vcb, &NextAllocLoc,
0, len, FALSE, (int8*)NextAllocDesc, &ReadBytes)))
{
MyFreePool__(AllocMap);
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
MyFreePool__(AllocMap);
// check integrity
if((NextAllocDesc->descTag.tagIdent != TID_ALLOC_EXTENT_DESC) ||
(NextAllocDesc->lengthAllocDescs > (len - sizeof(ALLOC_EXT_DESC))) ) {
UDFPrint(("Integrity check failed\n"));
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
// perform recursive call to obtain mapping
Extent2 = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)(NextAllocDesc+1),
NextAllocDesc->lengthAllocDescs, SubCallCount+1, AllocLoc);
if(!Extent2) {
MyFreePool__(NextAllocDesc);
MyFreePool__(Extent);
return NULL;
}
// and merge this 2 mappings into 1
Extent[i].extLength = 0;
Extent[i].extLocation = 0;
Extent = UDFMergeMappings(Extent, Extent2);
MyFreePool__(Extent2);
return Extent;
}
/* if((AllocDesc[i].extLength & UDF_EXTENT_LENGTH_MASK) > // Uncomment!!!
(AllocDesc[i].recordedLength & UDF_EXTENT_LENGTH_MASK)) {
Extent[i].extLength = AllocDesc[i].recordedLength;
Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
}*/
Extent[i].extLength = len;
#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
ASSERT(!(len & (Vcb->LBlockSize-1) ));
#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
// Note: for compatibility Adaptec DirectCD we check 'len' here
// That strange implementation records bogus extLocation in terminal entries
if(type != EXTENT_NOT_RECORDED_NOT_ALLOCATED && len) {
Extent[i].extLocation = UDFPartLbaToPhys(Vcb,&(AllocDesc[i].extLocation));
if(Extent[i].extLocation == LBA_OUT_OF_EXTENT) {
UDFPrint(("bad address (2)\n"));
MyFreePool__(Extent);
return NULL;
}
} else {
Extent[i].extLocation = 0;
}
if(!len) {
// some UDF implementations set strange AllocDesc sequence length,
// but terminates it with zeros in proper place, so handle
// this case
Extent[i].extLocation = 0;
return Extent;
}
Extent[i].extLength |= (type << 30);
}
// set terminator
Extent[i].extLength = 0;
Extent[i].extLocation = 0;
return Extent;
} // end UDFExtAllocDescToMapping()
/*
This routine builds FileMapping according to given FileEntry
Return: pointer to EXTENT_MAP array
or offset inside FileEntry (negative)
when ICB_FLAG_AD_IN_ICB encountered
of NULL if an error occured
*/
PEXTENT_MAP
UDFReadMappingFromXEntry(
IN PVCB Vcb,
IN uint32 PartNum,
IN tag* XEntry,
IN OUT uint32* Offset,
OUT PEXTENT_INFO AllocLoc // .Mapping must be intialized (non-Zero)
)
{
PEXTENT_AD Extent;
uint16 AllocMode;
int8* AllocDescs;
uint32 len;
// EntityID* eID; // for compatibility with Adaptec DirectCD
Extent = NULL;
(*Offset) = 0;
if(XEntry->tagIdent == TID_FILE_ENTRY) {
// UDFPrint(("Standard FileEntry\n"));
PFILE_ENTRY FileEntry = (PFILE_ENTRY)XEntry;
ExtPrint(("Standard FileEntry\n"));
AllocDescs = (int8*)(((int8*)(FileEntry+1))+(FileEntry->lengthExtendedAttr));
len = FileEntry->lengthAllocDescs;
AllocLoc->Offset = sizeof(FILE_ENTRY) + FileEntry->lengthExtendedAttr;
// eID = &(FileEntry->impIdent);
AllocMode = FileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK;
} else if(XEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) {
// UDFPrint(("Extended FileEntry\n"));
ExtPrint(("Extended FileEntry\n"));
PEXTENDED_FILE_ENTRY ExFileEntry = (PEXTENDED_FILE_ENTRY)XEntry;
AllocDescs = (((int8*)(ExFileEntry+1))+(ExFileEntry->lengthExtendedAttr));
len = ExFileEntry->lengthAllocDescs;
AllocLoc->Offset = sizeof(EXTENDED_FILE_ENTRY) + ExFileEntry->lengthExtendedAttr;
// eID = &(FileEntry->impIdent);
AllocMode = ExFileEntry->icbTag.flags & ICB_FLAG_ALLOC_MASK;
} else {
return NULL;
}
// for compatibility with Adaptec DirectCD
// if(!(Vcb->UDF_VCB_IC_ADAPTEC_NONALLOC_COMPAT))
AllocLoc->Length=len;
AllocLoc->Flags |= EXTENT_FLAG_VERIFY; // for metadata
switch (AllocMode) {
case ICB_FLAG_AD_SHORT: {
Extent = UDFShortAllocDescToMapping(Vcb, PartNum, (PSHORT_AD)AllocDescs, len, 0, AllocLoc);
break;
}
case ICB_FLAG_AD_LONG: {
Extent = UDFLongAllocDescToMapping(Vcb, (PLONG_AD)AllocDescs, len, 0, AllocLoc);
break;
}
case ICB_FLAG_AD_EXTENDED: {
Extent = UDFExtAllocDescToMapping(Vcb, (PEXT_AD)AllocDescs, len, 0, AllocLoc);
break;
}
default : { // case ICB_FLAG_AD_IN_ICB
Extent = NULL;
*Offset = (uint32)AllocDescs - (uint32)XEntry;
AllocLoc->Offset=0;
AllocLoc->Length=0;
if(AllocLoc->Mapping) MyFreePool__(AllocLoc->Mapping);
AllocLoc->Mapping=NULL;
break;
}
}
ExtPrint(("UDFReadMappingFromXEntry: mode %x, loc %x, len %x\n", AllocMode,
AllocLoc->Mapping ? AllocLoc->Mapping[0].extLocation : -1, len));
UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
return Extent;
}// end UDFReadMappingFromXEntry()
#ifndef UDF_READ_ONLY_BUILD
/*
This routine builds data for AllocDesc sequence for specified
extent
*/
OSSTATUS
UDFBuildShortAllocDescs(
IN PVCB Vcb,
IN uint32 PartNum,
OUT int8** Buff, // data for AllocLoc
IN uint32 InitSz,
IN OUT PUDF_FILE_INFO FileInfo
)
{
uint32 i, j;
uint32 len=0;
PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping;
PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc);
PSHORT_AD Alloc;
uint32 NewLen;
OSSTATUS status;
uint32 ph_len=0; // in general, this should be uint64,
// but we need its lower part only
#ifdef UDF_ALLOW_FRAG_AD
uint32 ts, ac, len2;
uint32 LBS = Vcb->LBlockSize;
uint32 LBSh = Vcb->BlockSizeBits;
uint32 TagLen = 0;
tag* Tag = NULL;
PSHORT_AD saved_Alloc;
uint32 TagLoc, prevTagLoc;
uint32 BufOffs;
uint32 ExtOffs;
uint32 saved_NewLen;
#endif //UDF_ALLOW_FRAG_AD
ValidateFileInfo(FileInfo);
ExtPrint(("UDFBuildShortAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
// calculate length
for(len=0; (i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); len++, ph_len+=i) {
ExtPrint(("bShExt: type %x, loc %x, len %x\n",
Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK));
}
Alloc = (PSHORT_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(SHORT_AD), MEM_SHAD_TAG);
if(!Alloc) {
BrutePoint();
return STATUS_INSUFFICIENT_RESOURCES;
}
// fill contiguous AllocDesc buffer (decribing UserData)
for(i=0;i<len;i++) {
Alloc[i].extLength = Extent[i].extLength;
Alloc[i].extPosition = UDFPhysLbaToPart(Vcb, PartNum, Extent[i].extLocation);
}
if((Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) {
Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) &
(Vcb->LBlockSize-1);
ExtPrint(("bShExt: cut tail -> %x\n",
Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK));
}
Alloc[i].extLength =
Alloc[i].extPosition = 0;
j = len*sizeof(SHORT_AD); // required space
len = (InitSz & ~(sizeof(SHORT_AD)-1)); // space available in 1st block
ASSERT(len == InitSz);
// Ok. Let's init AllocLoc
if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG);
if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
BrutePoint();
MyFreePool__(Alloc);
return STATUS_INSUFFICIENT_RESOURCES;
}
// allocation descriptors are located in the same sector as FileEntry
// (at least their 1st part), just after it
FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen;
FileInfo->Dloc->AllocLoc.Length = 0;
// set terminator
FileInfo->Dloc->AllocLoc.Mapping[1].extLength =
FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0;
}
if(j <= len) {
// we needn't allocating additional blocks to store AllocDescs
AdPrint(("in-ICB AllocDescs, j=%x\n",j));
RtlCopyMemory(*Buff, (int8*)Alloc, j);
NewLen = j;
MyFreePool__(Alloc);
} else {
#ifndef UDF_ALLOW_FRAG_AD
AdPrint((" DISK_FULL\n"));
return STATUS_DISK_FULL;
#else //UDF_ALLOW_FRAG_AD
AdPrint(("multi-block AllocDescs, j=%x\n",j));
BufOffs = 0;
TagLoc = prevTagLoc = 0;
// calculate the space available for SHORT_ADs in each block
ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(SHORT_AD))) & ~(sizeof(SHORT_AD)-1);
len2 = len;
// tail size
ts = InitSz - len2;
len -= sizeof(SHORT_AD);
// calculate actual AllocSequence length (in bytes)
NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(SHORT_AD);
MyFreePool__(*Buff);
(*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_SHAD_TAG);
if(!(*Buff)) {
status = STATUS_INSUFFICIENT_RESOURCES;
UDFPrint(("UDFResizeExtent() failed (%x)\n",status));
BrutePoint();
goto sh_alloc_err;
}
if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) {
status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
if(!OS_SUCCESS(status)) {
UDFPrint(("UDFResizeExtent(2) failed (%x)\n",status));
BrutePoint();
sh_alloc_err:
MyFreePool__(Alloc);
return status;
}
}
ExtOffs = AllocExtent->Offset;
RtlZeroMemory(*Buff, NewLen);
saved_NewLen = NewLen;
NewLen = 0; // recorded length
saved_Alloc = Alloc;
// fill buffer sector by sector (adding links at the end of each one)
while(TRUE) {
// j - remained AllocDescs length (in bytes)
// len - bytes available for AllocDescs in current block
// ac - bytes available for AllocDescs in each block
// leave space for terminator or pointer to next part of sequence
if(j == len2) {
// if we have only 1 SHORT_AD that we can fit in last sector
// we shall do it instead of recording link & allocating new block
len =
TagLen = len2;
}
ASSERT(saved_NewLen >= (BufOffs + len));
RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len);
Alloc = (PSHORT_AD)((int8*)Alloc + len);
j -= len;
BufOffs += len;
if(Tag) {
// Set up Tag for AllocDesc
Tag->tagIdent = TID_ALLOC_EXTENT_DESC;
UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc);
prevTagLoc = TagLoc;
}
if(!j) {
// terminate loop
NewLen = BufOffs;
break;
}
len = ac;
if(j <= (len + sizeof(SHORT_AD)))
len = j - sizeof(SHORT_AD);
len2 = len + sizeof(SHORT_AD);
// we have more than 1 SHORT_AD that we can't fit in current block
// so we shall set up pointer to the next block
((PSHORT_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 |
(((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ;
((PSHORT_AD)((*Buff)+BufOffs))->extPosition = TagLoc =
UDFPhysLbaToPart(Vcb, PartNum,
UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping,
ExtOffs+BufOffs+sizeof(SHORT_AD)+ts,
NULL, NULL, NULL, NULL) );
// reflect additional (link) block & LBlock tail (if any)
BufOffs += ts+sizeof(SHORT_AD);
// init AllocDesc
( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2;
( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc;
Tag = (tag*)((*Buff)+BufOffs);
TagLen = len2;
ts = LBS-len2-sizeof(ALLOC_EXT_DESC);
BufOffs += sizeof(ALLOC_EXT_DESC);
}
MyFreePool__(saved_Alloc);
#endif //UDF_ALLOW_FRAG_AD
}
status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
return status;
} // end UDFBuildShortAllocDescs()
/*
This routine builds data for AllocDesc sequence for specified
extent
*/
OSSTATUS
UDFBuildLongAllocDescs(
IN PVCB Vcb,
IN uint32 PartNum,
OUT int8** Buff, // data for AllocLoc
IN uint32 InitSz,
IN OUT PUDF_FILE_INFO FileInfo
)
{
uint32 i, j;
uint32 len=0;
PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping;
PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc);
PLONG_AD Alloc;
uint32 NewLen;
OSSTATUS status;
uint32 ph_len=0; // in general, this should be uint64,
// but we need its lower part only
#ifdef UDF_ALLOW_FRAG_AD
uint32 ac, len2, ts;
uint32 TagLoc, prevTagLoc;
uint32 LBS = Vcb->LBlockSize;
uint32 LBSh = Vcb->BlockSizeBits;
uint32 BufOffs;
uint32 ExtOffs = AllocExtent->Offset;
PLONG_AD saved_Alloc;
uint32 TagLen = 0;
tag* Tag = NULL;
#endif //UDF_ALLOW_FRAG_AD
ValidateFileInfo(FileInfo);
ExtPrint(("UDFBuildLongAllocDescs: FE %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
// calculate length
//for(len=0; i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK); len++, ph_len+=i);
for(len=0; (i=(Extent[len].extLength & UDF_EXTENT_LENGTH_MASK)); len++, ph_len+=i) {
ExtPrint(("bLnExt: type %x, loc %x, len %x\n",
Extent[len].extLength >> 30, Extent[len].extLocation, Extent[len].extLength & UDF_EXTENT_LENGTH_MASK));
}
Alloc = (PLONG_AD)MyAllocatePoolTag__(NonPagedPool, (len+1)*sizeof(LONG_AD), MEM_LNGAD_TAG);
if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES;
// fill contiguous AllocDesc buffer (decribing UserData)
for(i=0;i<len;i++) {
Alloc[i].extLength = Extent[i].extLength;
Alloc[i].extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, Extent[i].extLocation);
Alloc[i].extLocation.partitionReferenceNum = (uint16)PartNum;
RtlZeroMemory(&(Alloc[i].impUse), sizeof(Alloc[i].impUse));
}
if((Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) && i) {
Alloc[i-1].extLength -= (ph_len - (ULONG)(FileInfo->Dloc->DataLoc.Length)) &
(Vcb->LBlockSize-1);
ExtPrint(("bLnExt: cut tail -> %x\n",
Alloc[i-1].extLength & UDF_EXTENT_LENGTH_MASK));
}
RtlZeroMemory(&(Alloc[i]), sizeof(LONG_AD));
j = len*sizeof(LONG_AD); // required space
len = (InitSz & ~(sizeof(LONG_AD)-1)); // space available in 1st block
ASSERT(len == InitSz);
// Ok. Let's init AllocLoc
if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool, 2 * sizeof(EXTENT_MAP), MEM_EXTMAP_TAG);
if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
MyFreePool__(Alloc);
return STATUS_INSUFFICIENT_RESOURCES;
}
// allocation descriptors are located in the same sector as FileEntry
// (at least their 1st part), just after it
FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen;
FileInfo->Dloc->AllocLoc.Length = 0;
// set terminator
FileInfo->Dloc->AllocLoc.Mapping[1].extLength =
FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0;
}
if(j <= len) {
// we needn't allocating additional blocks to store AllocDescs
RtlCopyMemory(*Buff, (int8*)Alloc, j);
NewLen = j;
MyFreePool__(Alloc);
} else {
#ifndef UDF_ALLOW_FRAG_AD
AdPrint((" DISK_FULL\n"));
return STATUS_DISK_FULL;
#else //UDF_ALLOW_FRAG_AD
BufOffs = 0;
TagLoc = prevTagLoc = 0;
// calculate the space available for LONG_ADs in each block
ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(LONG_AD))) & ~(sizeof(LONG_AD)-1);
len2 = len;
// tail size
ts = InitSz - len2;
len -= sizeof(LONG_AD);
// calculate actual AllocSequence length (in LBlocks)
NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + InitSz + sizeof(LONG_AD);
MyFreePool__(*Buff);
(*Buff) = (int8*)MyAllocatePoolTag__(NonPagedPool, NewLen, MEM_LNGAD_TAG);
if(!(*Buff)) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto lad_alloc_err;
}
if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) {
status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
if(!OS_SUCCESS(status)) {
lad_alloc_err:
MyFreePool__(Alloc);
return status;
}
}
ExtOffs = AllocExtent->Offset;
RtlZeroMemory(*Buff, NewLen);
NewLen = 0; // recorded length
saved_Alloc = Alloc;
len2 = len+sizeof(LONG_AD);
// fill buffer sector by sector (adding links at the end of each one)
while(TRUE) {
// j - remained AllocDescs length (in bytes)
// len - bytes available for in AllocDescs each block
// leave space for terminator or pointer to next part of sequence
if(j == len2) {
// if we have only 1 LONG_AD that we can fit in last sector
// we shall do it instead of recording link & allocating new block
len =
TagLen = len2;
}
RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len);
Alloc = (PLONG_AD)((int8*)Alloc + len);
j -= len;
BufOffs += len;
if(Tag) {
// Set up Tag for AllocDesc
Tag->tagIdent = TID_ALLOC_EXTENT_DESC;
UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc);
prevTagLoc = TagLoc;
}
if(!j) {
// terminate loop
NewLen = BufOffs;
break;
}
len = ac;
if(j <= (len + sizeof(LONG_AD)))
len = j - sizeof(LONG_AD);
len2 = len+sizeof(LONG_AD);
// we have more than 1 LONG_AD that we can't fit in current block
// so we shall set up pointer to the next block
((PLONG_AD)((*Buff)+BufOffs))->extLength = /*LBS*/ len2 |
(((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ;
((PLONG_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc =
UDFPhysLbaToPart(Vcb, PartNum,
UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping,
ExtOffs+BufOffs+sizeof(LONG_AD)+ts,
NULL, NULL, NULL, NULL) );
((PLONG_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum;
// reflect additional (link) block & LBlock tail (if any)
BufOffs += ts+sizeof(LONG_AD);
// init AllocDesc
( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2;
( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc;
Tag = (tag*)((*Buff)+BufOffs);
TagLen = len2;
ts = LBS-len2-sizeof(ALLOC_EXT_DESC);
BufOffs += sizeof(ALLOC_EXT_DESC);
}
MyFreePool__(saved_Alloc);
#endif //UDF_ALLOW_FRAG_AD
}
status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
return status;
} // end UDFBuildLongAllocDescs()
/*
This routine builds data for AllocDesc sequence for specified
extent
*/
/*OSSTATUS
UDFBuildExtAllocDescs(
IN PVCB Vcb,
IN uint32 PartNum,
OUT int8** Buff, // data for AllocLoc
IN uint32 InitSz,
IN OUT PUDF_FILE_INFO FileInfo
)
{
uint32 i, j;
uint32 len=0, ac, len2;
uint32 TagLoc, prevTagLoc;
uint32 LBS = Vcb->LBlockSize;
uint32 LBSh = Vcb->BlockSizeBits;
PEXTENT_MAP Extent = FileInfo->Dloc->DataLoc.Mapping;
PEXTENT_INFO AllocExtent = &(FileInfo->Dloc->AllocLoc);
PEXT_AD Alloc, saved_Alloc;
uint32 BufOffs;
uint32 ExtOffs = AllocExtent->Offset;
uint32 NewLen;
OSSTATUS status;
uint32 TagLen = 0;
tag* Tag = NULL;
ValidateFileInfo(FileInfo);
// calculate length
for(len=0; Extent[len].extLength; len++);
Alloc = (PEXT_AD)MyAllocatePool__(NonPagedPool, (len+1)*sizeof(EXT_AD));
if(!Alloc) return STATUS_INSUFFICIENT_RESOURCES;
// fill contiguous AllocDesc buffer (decribing UserData)
for(i=0;i<len;i++) {
Alloc[i].extLength =
Alloc[i].recordedLength =
Alloc[i].informationLength = Extent[i].extLength;
Alloc[i].extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, Extent[i].extLocation);
Alloc[i].extLocation.partitionReferenceNum = (uint16)PartNum;
}
RtlZeroMemory(&(Alloc[i]), sizeof(EXT_AD));
j = len*sizeof(EXT_AD); // required space
len = InitSz; // space available in 1st block
// Ok. Let's init AllocLoc
if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
FileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, 2 * sizeof(EXTENT_MAP));
if(!(FileInfo->Dloc->AllocLoc.Mapping)) {
MyFreePool__(Alloc);
return STATUS_INSUFFICIENT_RESOURCES;
}
// allocation descriptors are located in the same sector as FileEntry
// (at least their 1st part), just after it
FileInfo->Dloc->AllocLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
FileInfo->Dloc->AllocLoc.Offset = FileInfo->Dloc->FileEntryLen;
FileInfo->Dloc->AllocLoc.Length = 0;
// set terminator
FileInfo->Dloc->AllocLoc.Mapping[1].extLength =
FileInfo->Dloc->AllocLoc.Mapping[1].extLocation = 0;
}
if(j <= len) {
// we needn't allocating additional blocks to store AllocDescs
RtlCopyMemory(*Buff, (int8*)Alloc, j);
NewLen = j;
MyFreePool__(Alloc);
} else {
BufOffs = 0;
TagLoc = prevTagLoc = 0;
// calculate the space available for EXT_ADs in each block
ac = (LBS - (sizeof(ALLOC_EXT_DESC) + sizeof(EXT_AD))) & ~(sizeof(EXT_AD)-1);
// calculate actual AllocSequence length (in LBlocks)
len -= sizeof(EXT_AD);
NewLen = ( ((j - len + ac - 1) / ac) << LBSh) + len + sizeof(EXT_AD);
MyFreePool__(*Buff);
(*Buff) = (int8*)MyAllocatePool__(NonPagedPool, NewLen);
if(UDFGetExtentLength(AllocExtent->Mapping) < NewLen) {
status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
if(!OS_SUCCESS(status)) {
MyFreePool__(Alloc);
return status;
}
}
RtlZeroMemory(*Buff, NewLen);
NewLen = 0; // recorded length
saved_Alloc = Alloc;
len2 = len + sizeof(EXT_AD);
// fill buffer sector by sector (adding links at the end of each one)
while(TRUE) {
// j - remained AllocDescs length (in bytes)
// len - bytes available for in AllocDescs each block
// leave space for terminator or pointer to next part of sequence
if(j == len2) {
// if we have only 1 EXT_AD that we can fit in last sector
// we shall do it instead of recording link & allocating new block
len =
TagLen = len2;
}
RtlCopyMemory( (*Buff)+BufOffs, (int8*)Alloc, len);
Alloc = (PEXT_AD)((int8*)Alloc + len);
j -= len;
BufOffs += len;
if(Tag) {
// Set up Tag for AllocDesc
Tag->tagIdent = TID_ALLOC_EXTENT_DESC;
UDFSetUpTag(Vcb, Tag, (uint16)TagLen, TagLoc);
prevTagLoc = TagLoc;
}
if(!j) {
// terminate loop
NewLen = BufOffs;
break;
}
len = ac;
if(j <= (len + sizeof(EXT_AD)))
len = j - sizeof(EXT_AD);
len2 = len + sizeof(EXT_AD);
// we have more than 1 EXT_AD that we can't fit in current block
// so we shall set up pointer to the next block
((PEXT_AD)((*Buff)+BufOffs))->extLength =
((PEXT_AD)((*Buff)+BufOffs))->recordedLength = LBS;
((PEXT_AD)((*Buff)+BufOffs))->informationLength = len2 |
(((uint32)EXTENT_NEXT_EXTENT_ALLOCDESC) << 30) ;
((PEXT_AD)((*Buff)+BufOffs))->extLocation.logicalBlockNum = TagLoc =
UDFPhysLbaToPart(Vcb, PartNum,
UDFExtentOffsetToLba(Vcb, AllocExtent->Mapping, ExtOffs + BufOffs + 2*sizeof(EXT_AD)-1, NULL, NULL, NULL, NULL) );
((PEXT_AD)((*Buff)+BufOffs))->extLocation.partitionReferenceNum = (uint16)PartNum;
BufOffs = (BufOffs + 2*sizeof(EXT_AD) - 1) & ~(sizeof(EXT_AD)-1) ;
// init AllocDesc
( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->lengthAllocDescs = len2;
( (PALLOC_EXT_DESC) ((*Buff)+BufOffs))->previousAllocExtLocation = prevTagLoc;
Tag = (tag*)((*Buff)+BufOffs);
TagLen = len2;
BufOffs += sizeof(ALLOC_EXT_DESC);
}
MyFreePool__(saved_Alloc);
}
status = UDFResizeExtent(Vcb, PartNum, NewLen, TRUE, AllocExtent);
return status;
} // end UDFBuildExtAllocDescs()*/
void
UDFDiscardFESpace(
IN PVCB Vcb,
IN PEXTENT_MAP Mapping,
IN uint32 lim
)
{
#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
PEXTENT_MAP Mapping2;
uint32 i;
UDFPrint((" DiscardFESpace\n"));
Mapping2 = Mapping;
for(i=0;i<lim;i++, Mapping++) {
// we should not discard allocated FEs
if( (Mapping->extLength >> 30) == EXTENT_RECORDED_ALLOCATED) {
UDFPrint((" used @ %x\n", Mapping->extLocation));
Mapping->extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
Mapping->extLocation = 0;
} else {
UDFPrint((" free @ %x\n", Mapping->extLocation));
}
}
UDFMarkSpaceAsXXX(Vcb, 0, Mapping2, AS_DISCARDED);
MyFreePool__(Mapping2);
#else // UDF_FE_ALLOCATION_CHARGE
ASSERT(!Dloc->DirIndex->FECharge.Mapping);
return;
#endif // UDF_FE_ALLOCATION_CHARGE
} // end UDFDiscardFESpace()
OSSTATUS
UDFInitAllocationCache(
IN PVCB Vcb,
IN uint32 AllocClass,
OUT PUDF_ALLOCATION_CACHE_ITEM* _AllocCache,
OUT uint32* _lim,
IN BOOLEAN Init
)
{
PUDF_ALLOCATION_CACHE_ITEM AllocCache;
PUDF_ALLOCATION_CACHE_ITEM* pAllocCache;
uint32 i, lim;
uint32* plim;
switch(AllocClass) {
case UDF_PREALLOC_CLASS_FE:
UDFPrint(("AllocationCache FE:\n"));
pAllocCache = &(Vcb->FEChargeCache);
plim = &(Vcb->FEChargeCacheMaxSize);
lim = 32;
break;
case UDF_PREALLOC_CLASS_DIR:
UDFPrint(("AllocationCache DIR:\n"));
pAllocCache = &(Vcb->PreallocCache);
plim = &(Vcb->PreallocCacheMaxSize);
lim = 32;
break;
default:
return STATUS_INVALID_PARAMETER;
}
if(!(*plim)) {
if(!Init) {
return STATUS_UNSUCCESSFUL;
}
(*pAllocCache) = AllocCache =
(PUDF_ALLOCATION_CACHE_ITEM)
MyAllocatePoolTag__(NonPagedPool , sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim,
MEM_ALLOC_CACHE_TAG);
if(!AllocCache) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(AllocCache, sizeof(UDF_ALLOCATION_CACHE_ITEM)*lim);
for(i=0; i<lim; i++) {
AllocCache[i].ParentLocation = LBA_NOT_ALLOCATED;
}
(*plim) = lim;
} else {
lim = (*plim);
AllocCache = (*pAllocCache);
}
(*_lim) = lim;
(*_AllocCache) = AllocCache;
return STATUS_SUCCESS;
} // end UDFInitAllocationCache()
OSSTATUS
UDFGetCachedAllocation(
IN PVCB Vcb,
IN uint32 ParentLocation,
OUT PEXTENT_INFO Ext,
OUT uint32* Items, // optional
IN uint32 AllocClass
)
{
PUDF_ALLOCATION_CACHE_ITEM AllocCache;
uint32 i, lim;
OSSTATUS status;
UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE);
status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE);
if(!OS_SUCCESS(status)) {
UDFReleaseResource(&(Vcb->PreallocResource));
return status;
}
UDFPrint(("Get AllocationCache for %x\n", ParentLocation));
for(i=0; i<lim; i++) {
if(AllocCache[i].ParentLocation == ParentLocation) {
(*Ext) = AllocCache[i].Ext;
AdPrint((" map %x (%x)\n", Ext->Mapping, i));
if(Items) {
(*Items) = AllocCache[i].Items;
}
RtlZeroMemory(&(AllocCache[i]), sizeof(AllocCache[i]));
AllocCache[i].ParentLocation = LBA_NOT_ALLOCATED;
UDFReleaseResource(&(Vcb->PreallocResource));
return STATUS_SUCCESS;
}
}
AdPrint((" no map\n"));
UDFReleaseResource(&(Vcb->PreallocResource));
return STATUS_UNSUCCESSFUL;
} // end UDFGetCachedAllocation()
OSSTATUS
UDFStoreCachedAllocation(
IN PVCB Vcb,
IN uint32 ParentLocation,
IN PEXTENT_INFO Ext,
IN uint32 Items,
IN uint32 AllocClass
)
{
PUDF_ALLOCATION_CACHE_ITEM AllocCache;
uint32 i, lim;
OSSTATUS status;
UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE);
status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, TRUE);
if(!OS_SUCCESS(status)) {
UDFReleaseResource(&(Vcb->PreallocResource));
return status;
}
UDFPrint(("Store AllocationCache for %x, map %x\n", ParentLocation, Ext->Mapping));
for(i=0; i<lim; i++) {
if(AllocCache[i].ParentLocation == LBA_NOT_ALLOCATED) {
AdPrint((" stored in %x\n", i));
AllocCache[i].Ext = (*Ext);
AllocCache[i].Items = Items;
AllocCache[i].ParentLocation = ParentLocation;
UDFReleaseResource(&(Vcb->PreallocResource));
return STATUS_SUCCESS;
}
}
//
AdPrint((" drop map %x (%x)\n", AllocCache[lim-1].Ext.Mapping, lim-1));
switch(AllocClass) {
case UDF_PREALLOC_CLASS_FE:
UDFDiscardFESpace(Vcb, AllocCache[lim-1].Ext.Mapping, AllocCache[lim-1].Items);
break;
case UDF_PREALLOC_CLASS_DIR:
UDFMarkSpaceAsXXX(Vcb, 0, AllocCache[lim-1].Ext.Mapping, AS_DISCARDED);
break;
}
RtlMoveMemory(&(AllocCache[1]), &(AllocCache[0]), sizeof(UDF_ALLOCATION_CACHE_ITEM)*(lim-1));
AllocCache[0].Ext = (*Ext);
AllocCache[0].Items = Items;
AllocCache[0].ParentLocation = ParentLocation;
AdPrint((" stored in 0\n"));
UDFReleaseResource(&(Vcb->PreallocResource));
return STATUS_SUCCESS;
} // end UDFStoreCachedAllocation()
OSSTATUS
UDFFlushAllCachedAllocations(
IN PVCB Vcb,
IN uint32 AllocClass
)
{
PUDF_ALLOCATION_CACHE_ITEM AllocCache;
uint32 i, lim;
OSSTATUS status;
UDFPrint(("Flush AllocationCache\n"));
UDFAcquireResourceExclusive(&(Vcb->PreallocResource),TRUE);
status = UDFInitAllocationCache(Vcb, AllocClass, &AllocCache, &lim, FALSE);
if(!OS_SUCCESS(status)) {
UDFReleaseResource(&(Vcb->PreallocResource));
return status;
}
for(i=0; i<lim; i++) {
if(AllocCache[i].ParentLocation != LBA_NOT_ALLOCATED) {
switch(AllocClass) {
case UDF_PREALLOC_CLASS_FE:
UDFDiscardFESpace(Vcb, AllocCache[i].Ext.Mapping, AllocCache[i].Items);
break;
case UDF_PREALLOC_CLASS_DIR:
UDFMarkSpaceAsXXX(Vcb, 0, AllocCache[i].Ext.Mapping, AS_DISCARDED);
break;
}
}
}
MyFreePool__(AllocCache);
switch(AllocClass) {
case UDF_PREALLOC_CLASS_FE:
Vcb->FEChargeCache = NULL;
Vcb->FEChargeCacheMaxSize = 0;
break;
case UDF_PREALLOC_CLASS_DIR:
Vcb->PreallocCache = NULL;
Vcb->PreallocCacheMaxSize = 0;
break;
}
UDFReleaseResource(&(Vcb->PreallocResource));
//
return STATUS_SUCCESS;
} // end UDFFlushAllCachedAllocations()
/*
This routine allocates space for FE of the file being created
If FE-Charge is enabled it reserves an extent & allocates
space in it. It works much faster then usual way both while
allocating & accessing on disk
If FE-Charge is disabled FE may be allocated at any suitable
location
*/
OSSTATUS
UDFAllocateFESpace(
IN PVCB Vcb,
IN PUDF_FILE_INFO DirInfo,
IN uint32 PartNum,
IN PEXTENT_INFO FEExtInfo,
IN uint32 Len
)
{
#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
OSSTATUS status;
PEXTENT_INFO Ext;
EXTENT_AD Extent;
BOOLEAN retry = FALSE;
uint32 i, lim;
/*
1. #Dir1#->*File* -> Dir1's FECharge
2. #Dir1#->*Dir* -> Dir1's FECharge
3. #Dir1#->*SDir* -> Dir1's FECharge
4. Dir1->#SDir#->*Stream* -> Dir1's FEChargeSDir
5. Dir1->#File#->*SDir* -> Dir1's FEChargeSDir
6. Dir1->#Dir#->*SDir* -> (see p.2)
7. Dir1->File->#SDir#->*Stream* -> Dir1's FEChargeSDir
8. Dir1->Dir->#SDir#->*Stream* -> (see p.4)
## ~ DirInfo
** ~ Object to be created
*/
// ASSERT(!FEExtInfo->Mapping);
// check if DirInfo we are called with is a Directory
// (it can be a file with SDir)
if(!DirInfo || !DirInfo->Dloc->DirIndex ||
((lim = ((DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge)) <= 1))
#endif // UDF_FE_ALLOCATION_CHARGE
return UDFAllocFreeExtent(Vcb, Len,
UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY);
#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
Ext = &(DirInfo->Dloc->DirIndex->FECharge);
while(TRUE) {
if(!Ext->Mapping) {
ULONG p_start;
ULONG p_end;
ULONG fe_loc;
ULONG l1, l2;
p_start = UDFPartStart(Vcb, PartNum);
p_end = UDFPartEnd(Vcb, PartNum);
fe_loc = DirInfo->Dloc->FELoc.Mapping[0].extLocation;
status = UDFGetCachedAllocation(Vcb, fe_loc, Ext, NULL, UDF_PREALLOC_CLASS_FE);
if(OS_SUCCESS(status)) {
// do nothing, even do not unpack
} else
if(Vcb->LowFreeSpace) {
status = UDFAllocFreeExtent(Vcb, Len << Vcb->LBlockSizeBits,p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY);
if(OS_SUCCESS(status)) {
UDFPrint(("FE @ %x (1)\n", FEExtInfo->Mapping[0].extLocation ));
}
return status;
} else {
if(fe_loc > p_start + 512*16) {
l1 = fe_loc - 512*16;
} else {
l1 = p_start;
}
if(fe_loc + 512*16 < p_end) {
l2 = fe_loc + 512*16;
} else {
l2 = p_end;
}
status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, l1, l2, Ext, EXTENT_FLAG_VERIFY);
if(!OS_SUCCESS(status)) {
status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, (p_start+fe_loc)/2, (fe_loc+p_end)/2, Ext, EXTENT_FLAG_VERIFY);
}
if(!OS_SUCCESS(status)) {
status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY);
}
if(!OS_SUCCESS(status)) {
status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start+1024, p_end-1024, Ext, EXTENT_FLAG_VERIFY);
}
if(!OS_SUCCESS(status = UDFAllocFreeExtent(Vcb, lim << Vcb->LBlockSizeBits, p_start, p_end, Ext, EXTENT_FLAG_VERIFY) )) {
// can't pre-allocate space for multiple FEs. Try single FE
UDFPrint(("allocate single FE entry\n"));
status = UDFAllocFreeExtent(Vcb, Len,
p_start, p_end, FEExtInfo, EXTENT_FLAG_VERIFY);
if(OS_SUCCESS(status)) {
UDFPrint(("FE @ %x (2)\n", FEExtInfo->Mapping[0].extLocation ));
}
return status;
}
status = UDFUnPackMapping(Vcb, Ext);
if(!OS_SUCCESS(status)) {
MyFreePool__(Ext->Mapping);
Ext->Mapping = NULL;
return status;
}
}
}
for(i=0;i<lim;i++) {
if( (Ext->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED ) {
Ext->Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK; // EXTENT_RECORDED_ALLOCATED
Extent.extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
Extent.extLocation = Ext->Mapping[i].extLocation;
if(Vcb->BSBM_Bitmap) {
uint32 lba = Ext->Mapping[i].extLocation;
if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) {
UDFPrint(("Remove BB @ %x from FE charge\n", lba));
Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
Ext->Mapping[i].extLocation = 0;
continue;
}
}
FEExtInfo->Mapping = UDFExtentToMapping(&Extent);
if(!FEExtInfo->Mapping) {
ASSERT(!(Ext->Mapping[i].extLength >> 30));
Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
return STATUS_INSUFFICIENT_RESOURCES;
}
UDFPrint(("FE @ %x (3)\n", FEExtInfo->Mapping[0].extLocation ));
FEExtInfo->Length = Len;
FEExtInfo->Offset = 0;
FEExtInfo->Modified = TRUE;
return STATUS_SUCCESS;
}
}
if(Vcb->LowFreeSpace) {
status = UDFAllocFreeExtent(Vcb, Len,
UDFPartStart(Vcb, PartNum), UDFPartEnd(Vcb, PartNum), FEExtInfo, EXTENT_FLAG_VERIFY);
if(OS_SUCCESS(status)) {
UDFPrint(("FE @ %x (4)\n", FEExtInfo->Mapping[0].extLocation ));
}
return status;
}
if(retry)
return STATUS_INSUFFICIENT_RESOURCES;
// we can get here if there are no free slots in
// preallocated FE charge. So, we should release
// memory and try to allocate space for new FE charge.
MyFreePool__(Ext->Mapping);
Ext->Mapping = NULL;
retry = TRUE;
}
return STATUS_INSUFFICIENT_RESOURCES;
#endif // UDF_FE_ALLOCATION_CHARGE
} // end UDFAllocateFESpace()
/*
This routine frees space allocated for FE.
*/
void
UDFFreeFESpace(
IN PVCB Vcb,
IN PUDF_FILE_INFO DirInfo,
IN PEXTENT_INFO FEExtInfo
)
{
#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
PEXTENT_INFO Ext;
uint32 i, lim, j=-1;
uint32 Lba;
// check if the DirInfo we are called with is a Directory
// (it can be a file with SDir)
if(DirInfo && DirInfo->Dloc->DirIndex &&
(Ext = &(DirInfo->Dloc->DirIndex->FECharge))->Mapping) {
if(!FEExtInfo->Mapping)
return;
Lba = FEExtInfo->Mapping[0].extLocation;
lim = (DirInfo->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge;
for(i=0;i<lim;i++) {
if(Ext->Mapping[i].extLocation == Lba) {
ASSERT(!(Ext->Mapping[i].extLength >> 30));
Ext->Mapping[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
goto clean_caller;
}
if(!Ext->Mapping[i].extLocation) {
j = i;
}
}
if(j != (ULONG)-1) {
i = j;
Ext->Mapping[i].extLocation = Lba;
Ext->Mapping[i].extLength = Vcb->LBlockSize | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
goto clean_caller;
}
}
#endif // UDF_FE_ALLOCATION_CHARGE
UDFMarkSpaceAsXXX(Vcb, 0, FEExtInfo->Mapping, AS_DISCARDED); // free
clean_caller:
FEExtInfo->Mapping[0].extLocation = 0;
FEExtInfo->Mapping[0].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
return;
} // end UDFFreeFESpace()
#endif //UDF_READ_ONLY_BUILD
/*
This routine flushes FE-Charge buffer, marks unused blocks as free
in bitmap & releases memory allocated for FE-Charge management
*/
void
UDFFlushFESpace(
IN PVCB Vcb,
IN PUDF_DATALOC_INFO Dloc,
IN BOOLEAN Discard
)
{
#ifdef UDF_FE_ALLOCATION_CHARGE // UDF_FE_ALLOCATION_CHARGE
PEXTENT_MAP Mapping;
uint32 lim;
if(!(Mapping = Dloc->DirIndex->FECharge.Mapping))
return;
lim = (Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR) ? Vcb->FEChargeSDir : Vcb->FECharge;
if(!Discard) {
// cache it!
if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb,
Dloc->FELoc.Mapping[0].extLocation,
&Dloc->DirIndex->FECharge, lim, UDF_PREALLOC_CLASS_FE))) {
Dloc->DirIndex->FECharge.Mapping = NULL;
return;
}
}
Dloc->DirIndex->FECharge.Mapping = NULL;
UDFDiscardFESpace(Vcb, Mapping, lim);
#else // UDF_FE_ALLOCATION_CHARGE
ASSERT(!Dloc->DirIndex->FECharge.Mapping);
return;
#endif // UDF_FE_ALLOCATION_CHARGE
} // end UDFFlushFESpace()
#ifndef UDF_READ_ONLY_BUILD
/*
This routine rebuilds mapping on write attempts to Alloc-Not-Rec area.
Here we assume that required area lays in a single frag.
*/
OSSTATUS
UDFMarkAllocatedAsRecorded(
IN PVCB Vcb,
IN int64 Offset,
IN uint32 Length,
IN PEXTENT_INFO ExtInfo // Extent array
)
{
uint32 i, len, lba, sLen;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
PEXTENT_MAP NewExtent;
uint32 BS = Vcb->BlockSize;
uint32 LBS = Vcb->LBlockSize;
uint32 BSh = Vcb->BlockSizeBits;
BOOLEAN TryPack = TRUE;
#ifdef UDF_DBG
int64 check_size;
#endif //UDF_DBG
// I don't know what else comment can be added here.
// Just belive that it works
lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, (Offset & ~((int64)LBS-1)), NULL, NULL, NULL, &i);
if(i == (ULONG)-1) return STATUS_INVALID_PARAMETER;
#ifdef UDF_DBG
check_size = UDFGetExtentLength(ExtInfo->Mapping);
ASSERT(!(check_size & (LBS-1)));
#endif //UDF_DBG
AdPrint(("Alloc->Rec ExtInfo %x, Extent %x\n", ExtInfo, Extent));
if((Extent[i].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) return STATUS_SUCCESS;
if((Extent[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_INVALID_PARAMETER;
ASSERT((((uint32)Offset) & (LBS-1)) + Length <= (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK));
sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
if((Extent[i].extLocation == lba) && (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK ) >> BSh) == sLen)) {
// xxxxxx -> RRRRRR
Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
// Extent[i].extLength |= (EXTENT_RECORDED_ALLOCATED << 30); // = 0;
ExtInfo->Modified = TRUE;
if(i &&
((Extent[i-1].extLength >> 30) == EXTENT_RECORDED_ALLOCATED) &&
(lba == (Extent[i-1].extLocation + ((len = Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh))) &&
((len + (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK)) <= UDF_MAX_EXTENT_LENGTH) &&
(i == ((UDFGetMappingLength(Extent) / sizeof(EXTENT_MAP)) - 2)) &&
TRUE) {
// make optimization for sequentially written files
Extent[i-1].extLength += Extent[i].extLength;
Extent[i].extLocation = 0;
Extent[i].extLength = 0;
} else {
UDFPackMapping(Vcb, ExtInfo);
}
AdPrint(("Alloc->Rec (1) new %x\n", ExtInfo->Mapping));
#ifdef UDF_DBG
ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
#endif
AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
return STATUS_SUCCESS;
}
if(Extent[i].extLocation < lba) {
if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (lba - Extent[i].extLocation))
> sLen ) {
// xxxxxx -> xxRRxx
NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP)*2,
MEM_EXTMAP_TAG);
if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i].extLocation = Extent[i].extLocation;
NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh;
NewExtent[i+1].extLength = (Length+BS-1) & ~(BS-1);
NewExtent[i+1].extLocation = lba;
NewExtent[i+2].extLength = Extent[i].extLength - NewExtent[i].extLength - NewExtent[i+1].extLength;
NewExtent[i+2].extLocation = lba + ((Length+BS-1) >> BSh);
ASSERT(!(NewExtent[i].extLength >> 30));
ASSERT(!(NewExtent[i+2].extLength >> 30));
NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
NewExtent[i+2].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
TryPack = FALSE;
AdPrint(("Alloc->Rec (2) new %x\n", NewExtent));
} else {
// xxxxxx -> xxRRRR
NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP),
MEM_EXTMAP_TAG);
if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i].extLocation = Extent[i].extLocation;
NewExtent[i].extLength = (lba - Extent[i].extLocation) << BSh;
NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength;
NewExtent[i+1].extLocation = lba;
ASSERT(!(NewExtent[i].extLength >> 30));
NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
AdPrint(("Alloc->Rec (3) new %x\n", NewExtent));
}
} else {
// xxxxxx -> RRRRxx
NewExtent = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP),
MEM_EXTMAP_TAG);
if(!NewExtent) return STATUS_INSUFFICIENT_RESOURCES;
Extent[i].extLength &= UDF_EXTENT_LENGTH_MASK;
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i].extLocation = Extent[i].extLocation;
NewExtent[i].extLength = (Length+BS-1) & ~(BS-1);
NewExtent[i+1].extLength = Extent[i].extLength - NewExtent[i].extLength;
NewExtent[i+1].extLocation = Extent[i].extLocation + (NewExtent[i].extLength >> BSh);
ASSERT(!(NewExtent[i+1].extLength >> 30));
NewExtent[i+1].extLength |= (EXTENT_NOT_RECORDED_ALLOCATED << 30);
AdPrint(("Alloc->Rec (4) new %x\n", NewExtent));
}
//ASSERT(check_size == UDFGetExtentLength(Extent));
//ASSERT(!(check_size & (LBS-1)));
AdPrint(("Free Extent %x (new %x)\n", Extent, NewExtent));
MyFreePool__(Extent);
ExtInfo->Modified = TRUE;
ExtInfo->Mapping = NewExtent;
if(TryPack)
UDFPackMapping(Vcb, ExtInfo);
#ifdef UDF_DBG
ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
ASSERT(!(check_size & (LBS-1)));
#endif
AdPrint(("Alloc->Rec: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
return STATUS_SUCCESS;
} // end UDFMarkAllocatedAsRecorded()
/*
This routine rebuilds mapping on write attempts to Not-Alloc-Not-Rec area.
Here we assume that required area lays in a single frag.
*/
OSSTATUS
UDFMarkNotAllocatedAsAllocated(
IN PVCB Vcb,
IN int64 Offset,
IN uint32 Length,
IN PEXTENT_INFO ExtInfo // Extent array
)
{
uint32 i, len, /*lba,*/ d, l, BOffs, j;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
PEXTENT_MAP NewExtent;
// uint32 BS = Vcb->BlockSize;
uint32 BSh = Vcb->BlockSizeBits;
OSSTATUS status;
EXTENT_INFO TmpExtInf;
uint32 aLen, sLen;
uint32 LBS = Vcb->LBlockSize;
// I don't know what else comment can be added here.
// Just belive that it works
/*lba = */
#ifndef ALLOW_SPARSE
BrutePoint();
#endif
AdPrint(("Not->Alloc ExtInfo %x, Extent %x\n", ExtInfo, Extent));
UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i);
if(i == (ULONG)-1) return STATUS_INVALID_PARAMETER;
if((Extent[i].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) return STATUS_SUCCESS;
uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation);
BOffs = (uint32)(Offset >> BSh);
// length of existing Not-Alloc-Not-Rec frag
sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
// required allocation length increment (in bytes)
aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)));
// try to extend previous frag or allocate space _after_ it to
// avoid backward seeks, if previous frag is not Not-Rec-Not-Alloc
if(i && ((Extent[i-1].extLength >> 30) != EXTENT_NOT_RECORDED_NOT_ALLOCATED) ) {
status = UDFAllocFreeExtent(Vcb, aLen,
Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh),
min(UDFPartEnd(Vcb, PartNum), Extent[i-1].extLocation + ((Extent[i-1].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) + sLen ),
&TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
if(status == STATUS_DISK_FULL)
// if there are not enough free blocks after that frag...
goto try_alloc_anywhere;
} else {
try_alloc_anywhere:
// ... try to alloc required disk space anywhere
status = UDFAllocFreeExtent(Vcb, aLen,
UDFPartStart(Vcb, PartNum),
UDFPartEnd(Vcb, PartNum),
&TmpExtInf, ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
}
// check for successfull allocation
if(!OS_SUCCESS(status)) {
AdPrint(("Not->Alloc no free\n"));
return status;
}
// get number of frags in allocated block
d = (UDFGetMappingLength(TmpExtInf.Mapping) / sizeof(EXTENT_MAP)) - 1;
// calculate number of existing blocks before the frag to be changed
l=0;
for(j=0; j<i; j++) {
l += (uint32)((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
}
// and now just update mapping...
if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) {
// xxxxxx -> RRRRRR
// (d-1) - since we have to raplace last frag of Extent with 1 or more frags of TmpExtInf.Mapping
NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d-1)*sizeof(EXTENT_MAP) );
if(!NewExtent) {
MyFreePool__(TmpExtInf.Mapping);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
RtlCopyMemory((int8*)&(NewExtent[i+d]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
AdPrint(("Not->Alloc (1) new %x\n", NewExtent));
} else
if(l < BOffs) {
// .ExtLength, BOffs & l are already aligned...
if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) {
// xxxxxx -> xxRRxx
NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + (d+1)*sizeof(EXTENT_MAP) );
if(!NewExtent) {
MyFreePool__(TmpExtInf.Mapping);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
RtlCopyMemory((int8*)&(NewExtent[i+d+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i].extLocation = 0;
NewExtent[i].extLength = (BOffs - l) << BSh;
NewExtent[i+d+1].extLength = Extent[i].extLength - NewExtent[i].extLength - aLen;
NewExtent[i+d+1].extLocation = 0;
NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
NewExtent[i+d+1].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
AdPrint(("Not->Alloc (2) new %x\n", NewExtent));
} else {
// xxxxxx -> xxRRRR
NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) );
if(!NewExtent) {
MyFreePool__(TmpExtInf.Mapping);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+1]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i].extLocation = 0;
NewExtent[i].extLength = (BOffs - l) << BSh;
NewExtent[i].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
AdPrint(("Not->Alloc (3) new %x\n", NewExtent));
}
} else {
// xxxxxx -> RRRRxx
NewExtent = (PEXTENT_AD)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + d*sizeof(EXTENT_MAP) );
if(!NewExtent) {
MyFreePool__(TmpExtInf.Mapping);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i]), (int8*)(TmpExtInf.Mapping), d*sizeof(EXTENT_MAP) );
RtlCopyMemory((int8*)&(NewExtent[i+d+1]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i+d].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen;
NewExtent[i+d].extLocation = 0;
NewExtent[i+d].extLength |= (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
AdPrint(("Not->Alloc (4) new %x\n", NewExtent));
}
AdPrint(("Free Extent %x, TmpExtInf.Mapping, (new %x)\n", Extent, TmpExtInf.Mapping, NewExtent));
MyFreePool__(Extent);
MyFreePool__(TmpExtInf.Mapping);
ExtInfo->Modified = TRUE;
ExtInfo->Mapping = NewExtent;
AdPrint(("Not->Alloc: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
return STATUS_SUCCESS;
} // end UDFMarkNotAllocatedAsAllocated()
//#if 0
/*
This routine rebuilds mapping on write zero attempts to
Alloc-Not-Rec area.
Here we assume that required area lays in a single frag.
*/
OSSTATUS
UDFMarkAllocatedAsNotXXX(
IN PVCB Vcb,
IN int64 Offset,
IN uint32 Length,
IN PEXTENT_INFO ExtInfo, // Extent array
IN BOOLEAN Deallocate
)
{
uint32 i, len, /*lba, d,*/ l, BOffs, j;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
PEXTENT_MAP NewExtent;
// EXTENT_MAP TmpExtent;
// uint32 BS = Vcb->BlockSize;
uint32 BSh = Vcb->BlockSizeBits;
// OSSTATUS status;
EXTENT_INFO TmpExtInf;
uint32 aLen, sLen;
uint32 flags;
uint32 target_flags = Deallocate ?
EXTENT_NOT_RECORDED_NOT_ALLOCATED :
EXTENT_NOT_RECORDED_ALLOCATED;
uint32 LBS = Vcb->LBlockSize;
EXTENT_MAP DeadMapping[2];
// I don't know what else comment can be added here.
// Just belive that it works
/*lba = */
#ifndef ALLOW_SPARSE
if(Deallocate) {
BrutePoint();
}
#endif
AdPrint(("Alloc->Not ExtInfo %x, Extent %x\n", ExtInfo, Extent));
DeadMapping[0].extLocation =
UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Offset, NULL, NULL, NULL, &i);
if(i == (ULONG)-1) {
BrutePoint();
return STATUS_INVALID_PARAMETER;
}
DeadMapping[0].extLength = Extent[i].extLength;
DeadMapping[1].extLocation =
DeadMapping[1].extLength = 0;
TmpExtInf.Mapping = (PEXTENT_MAP)&DeadMapping;
TmpExtInf.Offset = 0;
TmpExtInf.Length = Extent[i].extLength & UDF_EXTENT_LENGTH_MASK;
flags = Extent[i].extLength >> 30;
if(flags == target_flags) return STATUS_SUCCESS;
// uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Extent[0].extLocation);
BOffs = (uint32)(Offset >> BSh);
// length of existing Alloc-(Not-)Rec frag (in sectors)
sLen = (( (((uint32)Offset) & (LBS-1)) + Length+LBS-1) & ~(LBS-1)) >> BSh;
// required deallocation length increment (in bytes)
aLen = (uint32)( ((Offset+Length+LBS-1) & ~(LBS-1)) - (Offset & ~(LBS-1)) );
l=0;
for(j=0; j<i; j++) {
l += (uint32)((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
}
flags <<= 30;
if( (l == BOffs) && (((Extent[j].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) == sLen) ) {
// xxxxxx -> RRRRRR
Extent[i].extLocation = 0;
Extent[i].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) | flags;
NewExtent = Extent;
AdPrint(("Alloc->Not (1) NewExtent = Extent = %x\n", NewExtent));
} else
if(l < BOffs) {
// .ExtLength, BOffs & l are already aligned...
if( (((Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh) - (BOffs-l)) > sLen ) {
// xxxxxx -> xxRRxx
NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + 2*sizeof(EXTENT_MAP) );
if(!NewExtent) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+3]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i].extLength = (BOffs - l) << BSh;
NewExtent[i].extLength |= flags;
NewExtent[i+1].extLocation = 0;
NewExtent[i+1].extLength = aLen | (target_flags << 30);
NewExtent[i+2].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) -
(NewExtent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen ;
NewExtent[i+2].extLocation = Extent[i].extLocation +
(NewExtent[i+2].extLength >> BSh);
NewExtent[i+2].extLength |= flags;
AdPrint(("Alloc->Not (2) new %x\n", NewExtent));
} else {
// xxxxxx -> xxRRRR
NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
if(!NewExtent) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i].extLength = ((BOffs - l) << BSh) | flags;
NewExtent[i+1].extLocation = 0;
NewExtent[i+1].extLength = aLen | (target_flags << 30);
AdPrint(("Alloc->Not (3) new %x\n", NewExtent));
}
} else {
// xxxxxx -> RRRRxx
NewExtent = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, UDFGetMappingLength(Extent) + sizeof(EXTENT_MAP) );
if(!NewExtent) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory((int8*)NewExtent, (int8*)Extent, i*sizeof(EXTENT_MAP));
RtlCopyMemory((int8*)&(NewExtent[i+2]), (int8*)&(Extent[i+1]), len = UDFGetMappingLength(&(Extent[i+1])) );
NewExtent[i+1].extLength = (Extent[i].extLength & UDF_EXTENT_LENGTH_MASK) - aLen;
NewExtent[i+1].extLength |= flags;
NewExtent[i].extLocation = 0;
NewExtent[i].extLength = aLen | (target_flags << 30);
AdPrint(("Alloc->Not (4) new %x\n", NewExtent));
}
if(Deallocate)
UDFMarkSpaceAsXXX(Vcb, (-1), TmpExtInf.Mapping, AS_DISCARDED); // mark as free
if(Extent) {
AdPrint(("Alloc->Not kill %x\n", Extent));
MyFreePool__(Extent);
} else {
AdPrint(("Alloc->Not keep %x\n", Extent));
}
ExtInfo->Modified = TRUE;
ExtInfo->Mapping = NewExtent;
AdPrint(("Alloc->Not: ExtInfo %x, Extent %x\n", ExtInfo, ExtInfo->Mapping));
return STATUS_SUCCESS;
} // end UDFMarkAllocatedAsNotXXX()
//#endif //0
/*
This routine resizes extent & updates associated mapping
*/
OSSTATUS
UDFResizeExtent(
IN PVCB Vcb,
IN uint32 PartNum,
IN int64 Length, // Required Length
IN BOOLEAN AlwaysInIcb, // must be TRUE for AllocDescs
OUT PEXTENT_INFO ExtInfo
)
{
uint32 i, flags, lba, lim;
int64 l;
OSSTATUS status;
EXTENT_INFO TmpExtInf;
EXTENT_MAP TmpMapping[2];
uint32 s, req_s, pe, BSh, LBS, PS;
LBS = Vcb->LBlockSize;
BSh = Vcb->BlockSizeBits;
PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
uint32 MaxGrow = (UDF_MAX_EXTENT_LENGTH & ~(LBS-1));
BOOLEAN Sequential = FALSE;
ASSERT(PartNum < 3);
ExtPrint(("Resize ExtInfo %x, %I64x -> %I64x\n", ExtInfo, ExtInfo->Length, Length));
if(ExtInfo->Flags & EXTENT_FLAG_CUT_PREALLOCATED) {
AdPrint((" cut preallocated\n"));
} else
if(ExtInfo->Length == Length) {
return STATUS_SUCCESS;
}
if((ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
MaxGrow &= ~(Vcb->WriteBlockSize-1);
Sequential = TRUE;
}
UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
if(ExtInfo->Offset) {
if(ExtInfo->Offset + Length <= LBS) {
ExtPrint(("Resize IN-ICB\n"));
ExtInfo->Length = Length;
return STATUS_SUCCESS;
}
if(!AlwaysInIcb) // simulate unused 1st sector in extent
ExtInfo->Offset = LBS; // it'll be truncated later
Length += ExtInfo->Offset; // convert to real offset in extent
}
lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length, NULL, NULL, &flags, &i);
if(ExtInfo->Length < Length) {
// increase extent
if(OS_SUCCESS(UDFGetCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
&TmpExtInf, NULL, UDF_PREALLOC_CLASS_DIR))) {
AdPrint(("Resize found cached(1)\n"));
ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
MyFreePool__(TmpExtInf.Mapping);
}
if((l = UDFGetExtentLength(ExtInfo->Mapping)) >= Length) {
// we have enough space inside extent
ExtInfo->Length = Length;
AdPrint(("Resize do nothing (1)\n"));
} else /*if(lba == LBA_OUT_OF_EXTENT)*/ {
Length -= ExtInfo->Offset;
if(/*Length && l &&*/ (l % MaxGrow) &&
(Length-1)/MaxGrow != (l-1)/MaxGrow) {
AdPrint(("Crossing MAX_FRAG boundary...\n"));
int64 l2 = ((l-1)/MaxGrow + 1)*MaxGrow;
status = UDFResizeExtent(Vcb, PartNum, l2, AlwaysInIcb, ExtInfo);
if(!OS_SUCCESS(status)) {
UDFPrint(("Sub-call to UDFResizeExtent() failed (%x)\n", status));
return status;
}
l = ExtInfo->Length;
ASSERT(l == l2);
}
while((Length - l) > MaxGrow) {
status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
if(!OS_SUCCESS(status)) {
UDFPrint(("Sub-call (2) to UDFResizeExtent() failed (%x)\n", status));
return status;
}
l = ExtInfo->Length;
}
Length += ExtInfo->Offset;
// at first, try to resize existing frag
#ifndef UDF_ALLOW_FRAG_AD
i = UDFGetMappingLength(ExtInfo->Mapping);
if(i > (LBS-sizeof(EXTENDED_FILE_ENTRY))) {
// this is very important check since we will not
// be able to _record_ too long AllocDesc because of
// some DEMO limitations in UDFBuildXXXAllocDescs()
AdPrint((" DISK_FULL\n"));
return STATUS_DISK_FULL;
}
i /= sizeof(EXTENT_MAP);
#else //UDF_ALLOW_FRAG_AD
i = UDFGetMappingLength(ExtInfo->Mapping) / sizeof(EXTENT_MAP);
#endif //UDF_ALLOW_FRAG_AD
#ifdef ALLOW_SPARSE
if(!AlwaysInIcb && !(ExtInfo->Offset) &&
(Length - l >= (Vcb->SparseThreshold << BSh))) {
// last frag will be Not-Alloc-Not-Rec...
AdPrint(("Resize sparse (2)\n"));
RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , sizeof(EXTENT_MAP)*2,
MEM_EXTMAP_TAG);
if(!TmpExtInf.Mapping) return STATUS_INSUFFICIENT_RESOURCES;
TmpExtInf.Mapping[0].extLength = (((uint32)(Length - l) + LBS-1) & ~(LBS-1)) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
TmpExtInf.Mapping[0].extLocation =// 0;
TmpExtInf.Mapping[1].extLength =
TmpExtInf.Mapping[1].extLocation = 0;
l = Length;
ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
MyFreePool__(TmpExtInf.Mapping);
} else
#endif //ALLOW_SPARSE
// allocate some sectors
if(i>1 && !(ExtInfo->Offset)) {
i-=2;
// check if Not-Alloc-Not-Rec at the end of mapping
if((uint32)Length - (uint32)l + (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) > MaxGrow) {
// do nothing, but jump directly to allocator
} else
if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
AdPrint(("Resize grow sparse (3)\n"));
ExtInfo->Mapping[i].extLength +=
(((uint32)Length-(uint32)l+LBS-1) & ~(LBS-1)) ;
l = Length;
// check if Alloc-Not-Rec at the end of mapping
} else if((ExtInfo->Mapping[i].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED) {
AdPrint(("Resize grow Not-Rec (3)\n"));
// current length of last frag
s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
// prefered location of the next frag
lba = ExtInfo->Mapping[i].extLocation + s;
pe=UDFPartEnd(Vcb,PartNum);
// maximum frag length
if(Sequential) {
lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
} else {
lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
}
// required last extent length
req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
((l + LBS - 1) & ~(LBS-1)) ) >> BSh);
if(lim > req_s) {
lim = req_s;
}
UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
/* if((ExtInfo->Flags & EXTENT_FLAG_SEQUENTIAL) &&
((Length & ~(PS-1)) > (l & ~(PS-1))) &&
TRUE) {
status = UDFResizeExtent(Vcb, PartNum, l+MaxGrow, AlwaysInIcb, ExtInfo);
}*/
// how many sectors we should add
req_s = lim - s;
ASSERT(req_s);
if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
s += UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1));
}
/* for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
s++;
}*/
if(s==lim) {
// we can just increase the last frag
AdPrint(("Resize grow last Not-Rec (4)\n"));
ExtInfo->Mapping[i].extLength = (lim << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
l = Length;
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
} else {
// we get here if simple increasing of last frag failed
// it worth truncating last frag and try to allocate
// all required data as a single frag
/* if(Sequential && s>=PS) {
s &= ~(PS-1);
AdPrint(("Resize grow last Not-Rec (4/2)\n"));
ExtInfo->Mapping[i].extLength = (s << BSh) | (EXTENT_NOT_RECORDED_ALLOCATED << 30);
l += (s << BSh);
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // mark as used
}*/
AdPrint(("Resize reloc last Not-Rec (5)\n"));
TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (i+1)*sizeof(EXTENT_MAP),
MEM_EXTMAP_TAG);
if(!TmpExtInf.Mapping) {
UDFPrint(("UDFResizeExtent: !TmpExtInf.Mapping\n"));
UDFReleaseResource(&(Vcb->BitMapResource1));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(TmpExtInf.Mapping, ExtInfo->Mapping, i*sizeof(EXTENT_MAP));
TmpExtInf.Mapping[i].extLength =
TmpExtInf.Mapping[i].extLocation = 0;
TmpExtInf.Offset = ExtInfo->Offset;
l -= (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
TmpExtInf.Length = l;
ASSERT(i || !ExtInfo->Offset);
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
MyFreePool__(ExtInfo->Mapping);
(*ExtInfo) = TmpExtInf;
}
UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
UDFReleaseResource(&(Vcb->BitMapResource1));
// check if Alloc-Rec
} else {
// current length of last frag
s = ((ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
// prefered location of the next frag
lba = ExtInfo->Mapping[i].extLocation + s;
pe=UDFPartEnd(Vcb,PartNum);
// maximum frag length
if(Sequential) {
lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(PS-1);
} else {
lim = (((uint32)UDF_MAX_EXTENT_LENGTH) >> BSh) & ~(LBS-1);
}
// required last extent length
req_s = s + (uint32)( (((Length + LBS - 1) & ~(LBS-1)) -
((l + LBS - 1) & ~(LBS-1)) ) >> BSh);
if(lim > req_s) {
lim = req_s;
}
// s=0;
// how many sectors we should add
req_s = lim - s;
if(req_s) {
uint32 d=0;
UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
//ASSERT(req_s);
if((lba < pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, lba)) {
s += (d = UDFGetBitmapLen((uint32*)(Vcb->FSBM_Bitmap), lba, min(pe, lba+req_s-1)));
}
/* for(s1=lba; (s<lim) && (s1<pe) && UDFGetFreeBit(Vcb->FSBM_Bitmap, s1); s1++) {
s++;
}*/
if(s==lim) {
AdPrint(("Resize grow last Rec (6)\n"));
// we can just increase last frag
TmpMapping[0].extLength = req_s << BSh;
TmpMapping[0].extLocation = lba;
TmpMapping[1].extLength =
TmpMapping[1].extLocation = 0;
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
} else if(d) {
AdPrint(("Resize part-grow last Rec (6)\n"));
// increase last frag, then alloc rest
TmpMapping[0].extLength = d << BSh;
TmpMapping[0].extLocation = lba;
TmpMapping[1].extLength =
TmpMapping[1].extLocation = 0;
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, &TmpMapping[0], AS_USED); // mark as used
l += (s << BSh) - (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK);
ExtInfo->Mapping[i].extLength = (ExtInfo->Mapping[i].extLength & UDF_EXTENT_FLAG_MASK) | (s << BSh);
} else {
AdPrint(("Can't grow last Rec (6)\n"));
}
UDFReleaseResource(&(Vcb->BitMapResource1));
} else {
AdPrint(("Max frag length reached (6)\n"));
}
}
}
if(l < Length) {
// we get here if simple increasing of the last frag failed
AdPrint(("Resize add new frag (7)\n"));
if(l < LBS && Length >= LBS &&
(ExtInfo->Flags & EXTENT_FLAG_ALLOC_MASK) == EXTENT_FLAG_ALLOC_SEQUENTIAL) {
AdPrint(("Resize tune for SEQUENTIAL i/o\n"));
}
status = UDFAllocFreeExtent(Vcb, Length - l,
UDFPartStart(Vcb, PartNum),
UDFPartEnd(Vcb, PartNum),
&TmpExtInf,
ExtInfo->Flags /*& EXTENT_FLAG_ALLOC_MASK*/);
if(!OS_SUCCESS(status)) {
UDFPrint(("UDFResizeExtent: UDFAllocFreeExtent() failed (%x)\n", status));
return status;
}
ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, TmpExtInf.Mapping);
MyFreePool__(TmpExtInf.Mapping);
}
UDFPackMapping(Vcb, ExtInfo);
}
} else
if(Length) {
// decrease extent
AdPrint(("Resize cut (8)\n"));
lba = UDFExtentOffsetToLba(Vcb, ExtInfo->Mapping, Length-1, NULL, &lim, &flags, &i);
i++;
ASSERT(lba != LBA_OUT_OF_EXTENT);
ASSERT(lba != LBA_NOT_ALLOCATED);
ASSERT(i);
if(ExtInfo->Mapping[i].extLength) {
UDFCheckSpaceAllocation(Vcb, 0, &(ExtInfo->Mapping[i]), AS_USED); // check if used
if(!ExtInfo->Offset && (ExtInfo->Flags & EXTENT_FLAG_PREALLOCATED)) {
AdPrint(("Resize try save cutted (8)\n"));
RtlZeroMemory(&TmpExtInf, sizeof(EXTENT_INFO));
s = UDFGetMappingLength(&(ExtInfo->Mapping[i]));
TmpExtInf.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , s, MEM_EXTMAP_TAG);
if(TmpExtInf.Mapping) {
RtlCopyMemory(TmpExtInf.Mapping, &(ExtInfo->Mapping[i]), s);
AdPrint(("Resize save cutted (8)\n"));
if(OS_SUCCESS(UDFStoreCachedAllocation(Vcb, ExtInfo->Mapping[0].extLocation,
&TmpExtInf, 0, UDF_PREALLOC_CLASS_DIR))) {
ExtInfo->Mapping[i].extLength = 0;
ExtInfo->Mapping[i].extLocation = 0;
goto tail_cached;
}
}
}
UDFMarkSpaceAsXXX(Vcb, 0, &(ExtInfo->Mapping[i]), AS_DISCARDED); // mark as free
tail_cached:;
}
if((lim-1 >= LBS) &&
(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED)) {
AdPrint(("i=%x, lba=%x, len=%x\n",i,lba,lim));
ASSERT(lim);
// BrutePoint();
EXTENT_MAP ClrMap[2];
ClrMap[0].extLength = lim & ~(LBS-1);
s = (ExtInfo->Mapping[i-1].extLength - ClrMap[0].extLength) & UDF_EXTENT_LENGTH_MASK;
ClrMap[0].extLocation = ExtInfo->Mapping[i-1].extLocation +
(s >> BSh);
ClrMap[1].extLength =
ClrMap[1].extLocation = 0;
ASSERT((ExtInfo->Mapping[i].extLocation < ClrMap[0].extLocation) ||
(ExtInfo->Mapping[i].extLocation >= (ClrMap[0].extLocation + (ClrMap[0].extLength >> BSh))));
UDFCheckSpaceAllocation(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_USED); // check if used
UDFMarkSpaceAsXXX(Vcb, 0, (PEXTENT_MAP)(&ClrMap), AS_DISCARDED); // mark as free
ExtInfo->Mapping[i-1].extLength = s | (flags << 30);
}
s = UDFGetMappingLength(ExtInfo->Mapping);
if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), (i+1)*sizeof(EXTENT_MAP))) {
// This must never happen on truncate !!!
AdPrint(("ResizeExtent: MyReallocPool__(8) failed\n"));
}
ExtInfo->Mapping[i].extLength =
ExtInfo->Mapping[i].extLocation = 0;
} else {
AdPrint(("Resize zero (9)\n"));
ASSERT(!ExtInfo->Offset);
UDFMarkSpaceAsXXX(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // mark as free
s = UDFGetMappingLength(ExtInfo->Mapping);
if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s, (int8**)&(ExtInfo->Mapping), 2*sizeof(EXTENT_MAP))) {
// This must never happen on truncate !!!
AdPrint(("ResizeExtent: MyReallocPool__(9) failed\n"));
}
ExtInfo->Mapping[0].extLength = LBS | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
ExtInfo->Mapping[0].extLocation =
ExtInfo->Mapping[1].extLength =
ExtInfo->Mapping[1].extLocation = 0;
}
if(ExtInfo->Offset) {
if(!AlwaysInIcb) {
// remove 1st entry pointing to FileEntry
s = UDFGetMappingLength(ExtInfo->Mapping);
RtlMoveMemory(&(ExtInfo->Mapping[0]), &(ExtInfo->Mapping[1]), s - sizeof(EXTENT_MAP));
if(!MyReallocPool__((int8*)(ExtInfo->Mapping), s,
(int8**)&(ExtInfo->Mapping), s - sizeof(EXTENT_MAP) )) {
// This must never happen on truncate !!!
AdPrint(("ResizeExtent: MyReallocPool__(10) failed\n"));
}
Length -= ExtInfo->Offset;
ExtInfo->Offset = 0;
} else {
Length -= ExtInfo->Offset; // back to in-icb
}
}
ExtInfo->Length = Length;
UDFCheckSpaceAllocation(Vcb, 0, ExtInfo->Mapping, AS_USED); // check if used
for(i=0; (ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK); i++) {
ExtPrint(("Resized Ext: type %x, loc %x, len %x\n",
ExtInfo->Mapping[i].extLength >> 30, ExtInfo->Mapping[i].extLocation, ExtInfo->Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK));
}
return STATUS_SUCCESS;
} // end UDFResizeExtent()
/*
This routine (re)builds AllocDescs data for all allocation modes except
in-ICB & resizes associated extent (FileInfo->Dloc->AllocLoc) for
already allocated user data extent (FileInfo->Dloc->DataLoc).
AllocMode in FileEntry pointed by FileInfo must be already initialized.
*/
OSSTATUS
UDFBuildAllocDescs(
IN PVCB Vcb,
IN uint32 PartNum,
IN OUT PUDF_FILE_INFO FileInfo,
OUT int8** AllocData
)
{
// PEXTENT_MAP InMap;
// uint32 i=0;
int8* Allocs;
uint16 AllocMode;
uint32 InitSz;
OSSTATUS status;
ValidateFileInfo(FileInfo);
AdPrint(("BuildAllocDesc\n"));
// get space available in the 1st LBlock after FE
InitSz = Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen;
Allocs = (int8*)MyAllocatePool__(NonPagedPool, InitSz);
if(!Allocs) {
*AllocData = NULL;
AdPrint(("BuildAllocDesc: cant alloc %x bytes for Allocs\n", InitSz));
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(Allocs, InitSz);
// InMap = FileInfo->Dloc->DataLoc.Mapping;
UDFCheckSpaceAllocation(Vcb, 0, InMap, AS_USED); // check if used
// TODO: move data from mapped locations here
AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
switch(AllocMode) {
case ICB_FLAG_AD_IN_ICB: {
MyFreePool__(Allocs);
ASSERT(!FileInfo->Dloc->AllocLoc.Mapping);
Allocs = NULL;
status = STATUS_SUCCESS;
break;
}
case ICB_FLAG_AD_SHORT: {
status = UDFBuildShortAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
break;
}
case ICB_FLAG_AD_LONG: {
status = UDFBuildLongAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
break;
}
/* case ICB_FLAG_AD_EXTENDED: {
status = UDFBuildExtAllocDescs(Vcb, PartNum, &Allocs, InitSz, FileInfo);
break;
}*/
default: {
MyFreePool__(Allocs);
Allocs = NULL;
status = STATUS_INVALID_PARAMETER;
}
}
*AllocData = Allocs;
UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
return status;
} // end UDFBuildAllocDescs()
/*
This routine discards file's allocation
*/
void
UDFFreeFileAllocation(
IN PVCB Vcb,
IN PUDF_FILE_INFO DirInfo,
IN PUDF_FILE_INFO FileInfo
)
{
if(FileInfo->Dloc->DataLoc.Offset) {
// in-ICB data
if(FileInfo->Dloc->DataLoc.Mapping) {
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
FileInfo->Dloc->DataLoc.Mapping[0].extLocation);
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
FileInfo->Dloc->DataLoc.Mapping[1].extLocation =
FileInfo->Dloc->DataLoc.Mapping[1].extLength = 0;
FileInfo->Dloc->DataLoc.Mapping[0].extLocation = 0;
FileInfo->Dloc->DataLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
}
if(FileInfo->Dloc->AllocLoc.Mapping) {
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
}
UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
} else {
if(FileInfo->Dloc->AllocLoc.Mapping) {
ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation ==
FileInfo->Dloc->AllocLoc.Mapping[0].extLocation);
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
FileInfo->Dloc->AllocLoc.Mapping[1].extLocation =
FileInfo->Dloc->AllocLoc.Mapping[1].extLength = 0;
FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 0;
FileInfo->Dloc->AllocLoc.Mapping[0].extLength = EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30;
}
UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
}
FileInfo->Dloc->DataLoc.Modified =
FileInfo->Dloc->AllocLoc.Modified =
FileInfo->Dloc->FELoc.Modified = FALSE;
} // end UDFFreeFileAllocation()
#endif //UDF_READ_ONLY_BUILD
/*
This routine packs physically sequential extents into single one
*/
void
__fastcall
UDFPackMapping(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo // Extent array
)
{
PEXTENT_MAP NewMap, OldMap;
uint32 i, j, l;
uint32 LastLba, LastType, OldLen;
uint32 OldSize, NewSize;
#ifdef UDF_DBG
int64 check_size;
#endif //UDF_DBG
AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
AdPrint((" Length %x\n", ExtInfo->Length));
OldMap = ExtInfo->Mapping;
LastLba = OldMap[0].extLocation;
OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
LastType = OldMap[0].extLength >> 30;
OldSize =
NewSize = UDFGetMappingLength(OldMap);
#ifdef UDF_DBG
check_size = UDFGetExtentLength(ExtInfo->Mapping);
ASSERT(!(check_size & (2048-1)));
#endif //UDF_DBG
l=OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK;
// calculate required length
for(i=1; OldMap[i].extLength; i++) {
if((LastType == (OldMap[i].extLength >> 30))
&&
((OldMap[i].extLocation == LastLba + OldLen) ||
(!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED)))
&&
(l + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) {
// we can pack two blocks in one
l += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
NewSize -= sizeof(EXTENT_MAP);
} else {
l = OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
}
LastLba = OldMap[i].extLocation;
LastType = OldMap[i].extLength >> 30;
OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
}
// no changes ?
if(OldSize <= (NewSize + PACK_MAPPING_THRESHOLD)) {
if(OldSize == NewSize)
return;
if(NewSize >= PACK_MAPPING_THRESHOLD)
return;
}
AdPrint(("Pack ExtInfo %x, Mapping %x, realloc\n", ExtInfo, ExtInfo->Mapping));
NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , NewSize,
MEM_EXTMAP_TAG);
// can't alloc ?
if(!NewMap) return;
// Ok, lets pack it...
j=0;
NewMap[0] = OldMap[0];
LastLba = OldMap[0].extLocation;
OldLen = (OldMap[0].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
LastType = OldMap[0].extLength >> 30;
for(i=1; OldMap[i].extLength; i++) {
ExtPrint(("oShExt: type %x, loc %x, len %x\n",
OldMap[i].extLength >> 30, OldMap[i].extLocation, OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK));
if((LastType == (OldMap[i].extLength >> 30))
&&
((OldMap[i].extLocation == LastLba + OldLen) ||
(!OldMap[i].extLocation && !LastLba && (LastType == EXTENT_NOT_RECORDED_NOT_ALLOCATED)))
&&
((NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK) + (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) <= UDF_MAX_EXTENT_LENGTH)) {
NewMap[j].extLength += OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK;
} else {
j++;
NewMap[j] = OldMap[i];
}
ExtPrint(("nShExt: type %x, loc %x, len %x\n",
NewMap[j].extLength >> 30, NewMap[j].extLocation, NewMap[j].extLength & UDF_EXTENT_LENGTH_MASK));
LastLba = OldMap[i].extLocation;
LastType = OldMap[i].extLength >> 30;
OldLen = (OldMap[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits;
}
// write terminator
j++;
ASSERT(NewSize == (j+1)*sizeof(EXTENT_MAP));
NewMap[j].extLength =
NewMap[j].extLocation = 0;
#ifdef UDF_DBG
ASSERT(check_size == UDFGetExtentLength(ExtInfo->Mapping));
ASSERT(check_size == UDFGetExtentLength(NewMap));
#endif
AdPrint(("Pack ExtInfo %x, NewMap %x, OldMap %x\n", ExtInfo, NewMap, OldMap));
ExtInfo->Mapping = NewMap;
MyFreePool__(OldMap);
AdPrint(("Pack ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
AdPrint((" Length %x\n", ExtInfo->Length));
} // end UDFPackMapping()
/*
This routine expands mapping to 'frag-per-LBlock' state
*/
OSSTATUS
__fastcall
UDFUnPackMapping(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo // Extent array
)
{
PEXTENT_MAP NewMapping;
PEXTENT_MAP Mapping = ExtInfo->Mapping;
uint32 LBS = Vcb->LBlockSize;
uint32 len = (uint32)(UDFGetExtentLength(Mapping) >> Vcb->LBlockSizeBits);
uint32 i,j, type, base, d;
LONG l;
NewMapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP),
MEM_EXTMAP_TAG);
if(!NewMapping) return STATUS_INSUFFICIENT_RESOURCES;
j=0;
d = LBS >> Vcb->BlockSizeBits;
for(i=0; (l = (Mapping[i].extLength & UDF_EXTENT_LENGTH_MASK)); i++) {
base = Mapping[i].extLocation;
type = Mapping[i].extLength & UDF_EXTENT_FLAG_MASK;
for(; l>=(LONG)LBS; j++) {
NewMapping[j].extLength = LBS | type;
NewMapping[j].extLocation = base;
base+=d;
l-=LBS;
}
}
// record terminator
ASSERT(NewMapping);
RtlZeroMemory(&(NewMapping[j]), sizeof(EXTENT_MAP));
MyFreePool__(Mapping);
ExtInfo->Mapping = NewMapping;
return STATUS_SUCCESS;
} // end UDFUnPackMapping()
/*
Relocate a part of extent that starts from relative (inside extent)
block number 'ExtBlock' and has length of 'BC' blocks to continuous
run which starts at block 'Lba'
*/
OSSTATUS
UDFRelocateExtent(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo,
IN uint32 ExtBlock,
IN uint32 Lba,
IN uint32 BC
)
{
return STATUS_ACCESS_DENIED;
}
/*
This routine checks if all the data required is in cache.
*/
BOOLEAN
UDFIsExtentCached(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo, // Extent array
IN int64 Offset, // offset in extent
IN uint32 Length,
IN BOOLEAN ForWrite
)
{
BOOLEAN retstat = FALSE;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
uint32 to_read, Lba, sect_offs, flags, i;
WCacheStartDirect__(&(Vcb->FastCache), Vcb, TRUE/*FALSE*//*ForWrite*/);
if(!ExtInfo || !ExtInfo->Mapping) goto EO_IsCached;
if(!Length) {
retstat = TRUE;
goto EO_IsCached;
}
// prevent reading out of data space
if(Offset > ExtInfo->Length) goto EO_IsCached;
if(Offset+Length > ExtInfo->Length) goto EO_IsCached;
Offset += ExtInfo->Offset; // used for in-ICB data
// read maximal possible part of each frag of extent
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &i);
while(((LONG)Length) > 0) {
// EOF check
if(Lba == LBA_OUT_OF_EXTENT) goto EO_IsCached;
Extent += (i + 1);
// check for reading tail
to_read = min(to_read, Length);
if(flags == EXTENT_RECORDED_ALLOCATED) {
retstat = UDFIsDataCached(Vcb, Lba, (to_read+sect_offs+Vcb->BlockSize-1)>>Vcb->BlockSizeBits);
if(!retstat) goto EO_IsCached;
} else if(ForWrite) {
goto EO_IsCached;
}
Offset += to_read;
Length -= to_read;
Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &i);
}
retstat = TRUE;
EO_IsCached:
if(!retstat) {
WCacheEODirect__(&(Vcb->FastCache), Vcb);
}
return retstat;
} // end UDFIsExtentCached()
/*
This routine reads cached data only.
*/
/*OSSTATUS
UDFReadExtentCached(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo, // Extent array
IN int64 Offset, // offset in extent
IN uint32 Length,
OUT int8* Buffer,
OUT uint32* ReadBytes
)
{
(*ReadBytes) = 0;
if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
uint32 to_read, Lba, sect_offs, flags, _ReadBytes;
OSSTATUS status;
// prevent reading out of data space
if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE;
if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset);
Offset += ExtInfo->Offset; // used for in-ICB data
// read maximal possible part of each frag of extent
while(((LONG)Length) > 0) {
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, NULL);
// EOF check
if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE;
// check for reading tail
to_read = (to_read < Length) ?
to_read : Length;
if(flags == EXTENT_RECORDED_ALLOCATED) {
status = UDFReadDataCached(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Buffer, &_ReadBytes);
(*ReadBytes) += _ReadBytes;
} else {
RtlZeroMemory(Buffer, to_read);
(*ReadBytes) += to_read;
status = STATUS_SUCCESS;
}
if(!OS_SUCCESS(status)) return status;
// prepare for reading next frag...
Buffer += to_read;
Offset += to_read;
Length -= to_read;
}
return STATUS_SUCCESS;
} // end UDFReadExtentCached()*/
/*
This routine reads data at any offset from specified extent.
*/
OSSTATUS
UDFReadExtent(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo, // Extent array
IN int64 Offset, // offset in extent
IN uint32 Length,
IN BOOLEAN Direct,
OUT int8* Buffer,
OUT uint32* ReadBytes
)
{
(*ReadBytes) = 0;
if(!ExtInfo || !ExtInfo->Mapping) return STATUS_INVALID_PARAMETER;
ASSERT((uint32)Buffer > 0x1000);
AdPrint(("Read ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
uint32 to_read, Lba, sect_offs, flags, _ReadBytes;
OSSTATUS status;
// prevent reading out of data space
if(Offset > ExtInfo->Length) return STATUS_END_OF_FILE;
if(Offset+Length > ExtInfo->Length) Length = (uint32)(ExtInfo->Length - Offset);
Offset += ExtInfo->Offset; // used for in-ICB data
// read maximal possible part of each frag of extent
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &_ReadBytes);
while(Length) {
// EOF check
if(Lba == LBA_OUT_OF_EXTENT) return STATUS_END_OF_FILE;
Extent += (_ReadBytes + 1);
// check for reading tail
to_read = min(to_read, Length);
if(flags == EXTENT_RECORDED_ALLOCATED) {
status = UDFReadData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_read, Direct, Buffer, &_ReadBytes);
(*ReadBytes) += _ReadBytes;
if(!OS_SUCCESS(status)) return status;
} else {
RtlZeroMemory(Buffer, to_read);
(*ReadBytes) += to_read;
}
// prepare for reading next frag...
Length -= to_read;
if(!Length)
break;
ASSERT(to_read);
Buffer += to_read;
// Offset += to_read;
Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &_ReadBytes);
sect_offs = 0;
}
return STATUS_SUCCESS;
} // end UDFReadExtent()
/*
This routine reads and builds mapping for
specified amount of data at any offset from specified extent.
Size of output buffer is limited by *_SubExtInfoSz
*/
OSSTATUS
UDFReadExtentLocation(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo, // Extent array
IN int64 Offset, // offset in extent to start SubExtent from
OUT PEXTENT_MAP* _SubExtInfo, // SubExtent mapping array
IN OUT uint32* _SubExtInfoSz, // IN: maximum number of fragments to get
// OUT: actually obtained fragments
OUT int64* _NextOffset // offset, caller can start from to continue
)
{
if(!ExtInfo || !ExtInfo->Mapping)
return STATUS_INVALID_PARAMETER;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
PEXTENT_MAP SubExtInfo;
uint32 to_read, Lba, sect_offs, flags, Skip_MapEntries;
int32 SubExtInfoSz = *_SubExtInfoSz;
int64 Length;
int64 NextOffset;
// OSSTATUS status = STATUS_BUFFER_OVERFLOW;
(*_SubExtInfo) = NULL;
(*_SubExtInfoSz) = 0;
NextOffset = Offset;
// prevent reading out of data space
if(Offset >= ExtInfo->Length)
return STATUS_END_OF_FILE;
Length = ExtInfo->Length - Offset;
Offset += ExtInfo->Offset; // used for in-ICB data
// read maximal possible part of each frag of extent
SubExtInfo = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , SubExtInfoSz*sizeof(EXTENT_MAP),
MEM_EXTMAP_TAG);
(*_SubExtInfo) = SubExtInfo;
if(!SubExtInfo)
return STATUS_INSUFFICIENT_RESOURCES;
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_read, &flags, &Skip_MapEntries);
while(Length && SubExtInfoSz) {
// EOF check
if(Lba == LBA_OUT_OF_EXTENT) {
BrutePoint();
return STATUS_END_OF_FILE;
}
Extent += (Skip_MapEntries + 1);
// check for reading tail
to_read = (int32)min((int64)to_read, Length);
SubExtInfo->extLength = to_read;
if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
SubExtInfo->extLocation = LBA_NOT_ALLOCATED;
} else
if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
ASSERT(!(Lba & 0x80000000));
SubExtInfo->extLocation = Lba | 0x80000000;
} else {
SubExtInfo->extLocation = Lba;
}
(*_SubExtInfoSz)++;
SubExtInfoSz--;
NextOffset += to_read;
// prepare for reading next frag...
Length -= to_read;
if(!Length) {
// status = STATUS_SUCCESS;
break;
}
ASSERT(to_read);
Lba = UDFNextExtentToLba(Vcb, Extent, &to_read, &flags, &Skip_MapEntries);
sect_offs = 0;
}
(*_NextOffset) = NextOffset;
return STATUS_SUCCESS;
} // end UDFReadExtentLocation()
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4035) // re-enable below
#endif
uint32
UDFGetZeroLength(
IN int8* Buffer,
IN uint32 Length
)
{
uint32 i;
Length /= sizeof(uint32);
for(i=0; i<Length; i++) {
if( ((uint32*)Buffer)[i] )
break;
}
return Length*sizeof(uint32);
}
#ifdef _MSC_VER
#pragma warning(pop) // re-enable warning #4035
#endif
#ifndef UDF_READ_ONLY_BUILD
/*
This routine writes data at any offset to specified extent.
*/
OSSTATUS
UDFWriteExtent(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo, // Extent array
IN int64 Offset, // offset in extent
IN uint32 Length,
IN BOOLEAN Direct, // setting this flag delays flushing of given
// data to indefinite term
IN int8* Buffer,
OUT uint32* WrittenBytes
)
{
if(!ExtInfo || !ExtInfo->Mapping)
return STATUS_INVALID_PARAMETER;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
uint32 to_write, Lba, sect_offs, flags;
OSSTATUS status;
uint32 _WrittenBytes;
BOOLEAN reread_lba;
// BOOLEAN already_prepared = FALSE;
// BOOLEAN prepare = !Buffer;
AdPrint(("Write ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
Offset += ExtInfo->Offset; // used for in-ICB data
// write maximal possible part of each frag of extent
while(((LONG)Length) > 0) {
UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
// EOF check
if(Lba == LBA_OUT_OF_EXTENT) {
return STATUS_END_OF_FILE;
}
/* if((to_write < Length) &&
!Direct && !prepare && !already_prepared) {
// rebuild mapping, allocate space, etc.
// to indicate this, set Buffer to NULL
AdPrint(("UDFWriteExtent: Prepare\n"));
BrutePoint();
_WrittenBytes = 0;
status = UDFWriteExtent(Vcb, ExtInfo, Offset, Length, *//*Direct*//*FALSE, NULL, &_WrittenBytes);
if(!OS_SUCCESS(status)) {
return status;
}
Extent = ExtInfo->Mapping;
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
already_prepared = TRUE;
}*/
if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
// here we should allocate space for this extent
if(!OS_SUCCESS(status = UDFMarkNotAllocatedAsAllocated(Vcb, Offset, to_write, ExtInfo)))
return status;
Extent = ExtInfo->Mapping;
UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
if(Lba == LBA_OUT_OF_EXTENT) {
return STATUS_END_OF_FILE;
}
// we have already re-read Lba
reread_lba = FALSE;
} else {
// we may need to re-read Lba if some changes are
// made while converting from Alloc-Not-Rec
reread_lba = TRUE;
}
// check if writing to not recorded allocated
// in this case we must pad blocks with zeros around
// modified area
//
// ...|xxxxxxxx|xxxxxxxx|xxxxxxxx|...
// . .
// . || .
// . \/ .
// . .
// ...|000ddddd|dddddddd|dd000000|...
// . .
// ^ ^
// sect_offs sect_offs+to_write
// . .
// .<-- to_write -->.
//
to_write = min(to_write, Length);
if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
if(!OS_SUCCESS(status = UDFMarkAllocatedAsRecorded(Vcb, Offset, to_write, ExtInfo)))
return status;
Extent = ExtInfo->Mapping;
UDFCheckSpaceAllocation(Vcb, 0, Extent, AS_USED); // check if used
if(reread_lba) {
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
to_write = min(to_write, Length);
}
/*
we must fill 1st block with zeros in 1 of 2 cases:
1) start offset is not aligned on LBlock boundary
OR
2) end offset is not aligned on LBlock boundary and lays in
the same LBlock
we must fill last block with zeros if both
1) end offset is not aligned on LBlock boundary
AND
2) end offset DOESN'T lay in the 1st LBlock
*/
// if(!prepare) {
// pad 1st logical block
if((sect_offs || (sect_offs + to_write < Vcb->LBlockSize) )
&&
!Vcb->CDR_Mode) {
status = UDFWriteData(Vcb, TRUE,
( ((uint64)Lba) << Vcb->BlockSizeBits),
Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes);
if(!OS_SUCCESS(status))
return status;
}
// pad last logical block
if((sect_offs + to_write > Vcb->LBlockSize) &&
(sect_offs + to_write) & (Vcb->LBlockSize - 1)) {
status = UDFWriteData(Vcb, TRUE,
(( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs + to_write) & ~((int64)(Vcb->LBlockSize)-1),
Vcb->LBlockSize, Direct, Vcb->ZBuffer, &_WrittenBytes);
}
if(!OS_SUCCESS(status))
return status;
/* } else {
status = STATUS_SUCCESS;
}*/
}
ASSERT(to_write);
// if(!prepare) {
status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, Direct, Buffer, &_WrittenBytes);
*WrittenBytes += _WrittenBytes;
if(!OS_SUCCESS(status)) return status;
/* } else {
status = STATUS_SUCCESS;
*WrittenBytes += to_write;
}*/
// prepare for writing next frag...
Buffer += to_write;
Offset += to_write;
Length -= to_write;
}
AdPrint(("Write: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
return STATUS_SUCCESS;
} // end UDFWriteExtent()
//#if 0
/*
This routine zeroes/deallocates data at any offset to specified extent.
*/
OSSTATUS
UDFZeroExtent(
IN PVCB Vcb,
IN PEXTENT_INFO ExtInfo, // Extent array
IN int64 Offset, // offset in extent
IN uint32 Length,
IN BOOLEAN Deallocate, // deallocate frag or just mark as unrecorded
IN BOOLEAN Direct, // setting this flag delays flushing of given
// data to indefinite term
OUT uint32* WrittenBytes
)
{
if(!ExtInfo || !ExtInfo->Mapping)
return STATUS_INVALID_PARAMETER;
PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array
uint32 to_write, Lba, sect_offs, flags;
OSSTATUS status;
uint32 _WrittenBytes;
uint32 LBS = Vcb->LBlockSize;
AdPrint(("Zero ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
Offset += ExtInfo->Offset; // used for in-ICB data
// fill/deallocate maximal possible part of each frag of extent
while(((LONG)Length) > 0) {
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
// EOF check
if(Lba == LBA_OUT_OF_EXTENT) {
return STATUS_END_OF_FILE;
}
// check for writing tail
to_write = min(to_write, Length);
if(flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
// here we should do nothing
*WrittenBytes += to_write;
} else
if(flags == EXTENT_NOT_RECORDED_ALLOCATED) {
// we should just deallocate this frag
if(Deallocate) {
if(!OS_SUCCESS(status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, to_write, ExtInfo)))
return status;
}
Extent = ExtInfo->Mapping;
*WrittenBytes += to_write;
} else {
// fill tail of the 1st Block with ZEROs
if(sect_offs) {
status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits) + sect_offs,
min(to_write, LBS-sect_offs),
Direct, Vcb->ZBuffer, &_WrittenBytes);
*WrittenBytes += _WrittenBytes;
if(!OS_SUCCESS(status))
return status;
Offset += _WrittenBytes;
Length -= _WrittenBytes;
to_write -= _WrittenBytes;
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED);
ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED);
ASSERT(!sect_offs);
}
// deallocate Blocks
if(to_write >= LBS) {
// use 'sect_offs' as length of extent to be deallocated
sect_offs = to_write & ~(LBS - 1);
if(Deallocate) {
status = UDFMarkAllocatedAsNotAllocated(Vcb, Offset, sect_offs, ExtInfo);
} else {
status = UDFMarkRecordedAsAllocated(Vcb, Offset, sect_offs, ExtInfo);
}
if(!OS_SUCCESS(status))
return status;
// reload extent mapping
Extent = ExtInfo->Mapping;
Offset += sect_offs;
Length -= sect_offs;
*WrittenBytes += sect_offs;
to_write -= sect_offs;
Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
ASSERT(flags != EXTENT_NOT_RECORDED_NOT_ALLOCATED);
ASSERT(flags != EXTENT_NOT_RECORDED_ALLOCATED);
ASSERT(!sect_offs);
}
// fill beginning of the last Block with ZEROs
if(to_write) {
status = UDFWriteData(Vcb, TRUE, ( ((uint64)Lba) << Vcb->BlockSizeBits), to_write, Direct, Vcb->ZBuffer, &_WrittenBytes);
*WrittenBytes += _WrittenBytes;
if(!OS_SUCCESS(status))
return status;
ASSERT(to_write == _WrittenBytes);
}
}
AdPrint(("Zero... ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
// prepare for filling next frag...
Offset += to_write;
Length -= to_write;
}
AdPrint(("Zero: ExtInfo %x, Mapping %x\n", ExtInfo, ExtInfo->Mapping));
return STATUS_SUCCESS;
} // end UDFZeroExtent()
//#endif //0
#endif //UDF_READ_ONLY_BUILD