reactos/drivers/filesystems/udfs/udf_info/alloc.cpp
2021-06-11 15:33:08 +03:00

1457 lines
37 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:
alloc.cpp
Abstract:
This file contains filesystem-specific routines
responsible for disk space management
*/
#include "udf.h"
#define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO_ALLOC
static const int8 bit_count_tab[] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
/*
This routine converts physical address to logical in specified partition
*/
uint32
UDFPhysLbaToPart(
IN PVCB Vcb,
IN uint32 PartNum,
IN uint32 Addr
)
{
PUDFPartMap pm = Vcb->Partitions;
#if defined (_X86_) && defined (_MSC_VER) && !defined(__clang__)
uint32 retval;
__asm {
push ebx
push ecx
push edx
mov ebx,Vcb
mov edx,[ebx]Vcb.PartitionMaps
mov ebx,pm
mov ecx,PartNum
xor eax,eax
loop_pl2p:
cmp ecx,edx
jae short EO_pl2p
cmp [ebx]pm.PartitionNum,cx
jne short cont_pl2p
mov eax,Addr
sub eax,[ebx]pm.PartitionRoot
mov ecx,Vcb
mov ecx,[ecx]Vcb.LB2B_Bits
shr eax,cl
jmp short EO_pl2p
cont_pl2p:
add ebx,size UDFPartMap
inc ecx
jmp short loop_pl2p
EO_pl2p:
mov retval,eax
pop edx
pop ecx
pop ebx
}
#ifdef UDF_DBG
{
// validate return value
lb_addr locAddr;
locAddr.logicalBlockNum = retval;
locAddr.partitionReferenceNum = (uint16)PartNum;
UDFPartLbaToPhys(Vcb, &locAddr);
}
#endif // UDF_DBG
return retval;
#else // NO X86 optimization , use generic C/C++
uint32 i;
// walk through partition maps to find suitable one...
for(i=PartNum; i<Vcb->PartitionMaps; i++, pm++) {
if(pm->PartitionNum == PartNum)
// wow! return relative address
return (Addr - pm->PartitionRoot) >> Vcb->LB2B_Bits;
}
return 0;
#endif // _X86_
} // end UDFPhysLbaToPart()
/*
This routine returns physycal Lba for partition-relative addr
*/
uint32
__fastcall
UDFPartLbaToPhys(
IN PVCB Vcb,
IN lb_addr* Addr
)
{
uint32 i, a;
if(Addr->partitionReferenceNum >= Vcb->PartitionMaps) {
AdPrint(("UDFPartLbaToPhys: part %x, lbn %x (err)\n",
Addr->partitionReferenceNum, Addr->logicalBlockNum));
if(Vcb->PartitionMaps &&
(Vcb->CompatFlags & UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS)) {
AdPrint(("UDFPartLbaToPhys: try to recover: part %x -> %x\n",
Addr->partitionReferenceNum, Vcb->PartitionMaps-1));
Addr->partitionReferenceNum = (USHORT)(Vcb->PartitionMaps-1);
} else {
return LBA_OUT_OF_EXTENT;
}
}
// walk through partition maps & transform relative address
// to physical
for(i=Addr->partitionReferenceNum; i<Vcb->PartitionMaps; i++) {
if(Vcb->Partitions[i].PartitionNum == Addr->partitionReferenceNum) {
a = Vcb->Partitions[i].PartitionRoot +
(Addr->logicalBlockNum << Vcb->LB2B_Bits);
if(a > Vcb->LastPossibleLBA) {
AdPrint(("UDFPartLbaToPhys: root %x, lbn %x, lba %x (err1)\n",
Vcb->Partitions[i].PartitionRoot, Addr->logicalBlockNum, a));
BrutePoint();
return LBA_OUT_OF_EXTENT;
}
return a;
}
}
a = Vcb->Partitions[i-1].PartitionRoot +
(Addr->logicalBlockNum << Vcb->LB2B_Bits);
if(a > Vcb->LastPossibleLBA) {
AdPrint(("UDFPartLbaToPhys: i %x, root %x, lbn %x, lba %x (err2)\n",
i, Vcb->Partitions[i-1].PartitionRoot, Addr->logicalBlockNum, a));
BrutePoint();
return LBA_OUT_OF_EXTENT;
}
return a;
} // end UDFPartLbaToPhys()
/*
This routine returns physycal Lba for partition-relative addr
No partition bounds check is performed.
This routine only checks if requested partition exists.
It is introduced for 'Adaptec DirectCD' compatibility,
because it uses negative values as extent terminator (against standard)
*/
/*uint32
__fastcall
UDFPartLbaToPhysCompat(
IN PVCB Vcb,
IN lb_addr* Addr
)
{
uint32 i, a;
if(Addr->partitionReferenceNum >= Vcb->PartitionMaps) return LBA_NOT_ALLOCATED;
// walk through partition maps & transform relative address
// to physical
for(i=Addr->partitionReferenceNum; i<Vcb->PartitionMaps; i++) {
if(Vcb->Partitions[i].PartitionNum == Addr->partitionReferenceNum) {
a = Vcb->Partitions[i].PartitionRoot +
(Addr->logicalBlockNum << Vcb->LB2B_Bits);
if(a > Vcb->LastPossibleLBA) {
BrutePoint();
}
return a;
}
}
a = Vcb->Partitions[i-1].PartitionRoot +
(Addr->logicalBlockNum << Vcb->LB2B_Bits);
if(a > Vcb->LastPossibleLBA) {
BrutePoint();
}
return a;
} // end UDFPartLbaToPhysCompat()*/
/*
This routine looks for the partition containing given physical sector
*/
uint32
__fastcall
UDFGetPartNumByPhysLba(
IN PVCB Vcb,
IN uint32 Lba
)
{
uint32 i=Vcb->PartitionMaps-1, root;
PUDFPartMap pm = &(Vcb->Partitions[i]);
// walk through the partition maps to find suitable one
for(;i!=0xffffffff;i--,pm--) {
if( ((root = pm->PartitionRoot) <= Lba) &&
((root + pm->PartitionLen) > Lba) ) return (uint16)pm->PartitionNum;
}
return LBA_OUT_OF_EXTENT; // Lba doesn't belong to any partition
} // end UDFGetPartNumByPhysLba()
/*
Very simple routine. It walks through the Partition Maps & returns
the 1st Lba of the 1st suitable one
*/
uint32
__fastcall
UDFPartStart(
PVCB Vcb,
uint32 PartNum
)
{
uint32 i;
if(PartNum == (uint32)-1) return 0;
if(PartNum == (uint32)-2) return Vcb->Partitions[0].PartitionRoot;
for(i=PartNum; i<Vcb->PartitionMaps; i++) {
if(Vcb->Partitions[i].PartitionNum == PartNum) return Vcb->Partitions[i].PartitionRoot;
}
return 0;
} // end UDFPartStart(
/*
This routine does almost the same as previous.
The only difference is changing First Lba to Last one...
*/
uint32
__fastcall
UDFPartEnd(
PVCB Vcb,
uint32 PartNum
)
{
uint32 i;
if(PartNum == (uint32)-1) return Vcb->LastLBA;
if(PartNum == (uint32)-2) PartNum = Vcb->PartitionMaps-1;
for(i=PartNum; i<Vcb->PartitionMaps; i++) {
if(Vcb->Partitions[i].PartitionNum == PartNum)
return (Vcb->Partitions[i].PartitionRoot +
Vcb->Partitions[i].PartitionLen);
}
return (Vcb->Partitions[i-1].PartitionRoot +
Vcb->Partitions[i-1].PartitionLen);
} // end UDFPartEnd()
/*
Very simple routine. It walks through the Partition Maps & returns
the 1st Lba of the 1st suitable one
*/
uint32
__fastcall
UDFPartLen(
PVCB Vcb,
uint32 PartNum
)
{
if(PartNum == (uint32)-2) return UDFPartEnd(Vcb, -2) - UDFPartStart(Vcb, -2);
/*#ifdef _X86_
uint32 ret_val;
__asm {
mov ebx,Vcb
mov eax,PartNum
cmp eax,-1
jne short NOT_last_gpl
mov eax,[ebx]Vcb.LastLBA
jmp short EO_gpl
NOT_last_gpl:
mov esi,eax
xor eax,eax
mov ecx,[ebx]Vcb.PartitionMaps
jecxz EO_gpl
mov eax,esi
mov edx,size UDFTrackMap
mul edx
add ebx,eax
mov eax,esi
gpl_loop:
cmp [ebx]Vcb.PartitionMaps.PartitionNum,ax
je short EO_gpl_1
add ebx,size UDFTrackMap
inc eax
cmp eax,ecx
jb short gpl_loop
sub ebx,size UDFTrackMap
EO_gpl_1:
mov eax,[ebx]Vcb.PartitionMaps.PartitionLen
add eax,[ebx]Vcb.PartitionMaps.PartitionRoot
EO_gpl:
mov ret_val,eax
}
return ret_val;
#else // NO X86 optimization , use generic C/C++*/
uint32 i;
if(PartNum == (uint32)-1) return Vcb->LastLBA;
for(i=PartNum; i<Vcb->PartitionMaps; i++) {
if(Vcb->Partitions[i].PartitionNum == PartNum)
return Vcb->Partitions[i].PartitionLen;
}
return (Vcb->Partitions[i-1].PartitionRoot +
Vcb->Partitions[i-1].PartitionLen);
/*#endif // _X86_*/
} // end UDFPartLen()
/*
This routine returns length of bit-chain starting from Offs bit in
array Bitmap. Bitmap scan is limited with Lim.
*/
#if defined (_X86_) && defined (_MSC_VER)
__declspec (naked)
SIZE_T
__stdcall
UDFGetBitmapLen(
uint32* Bitmap,
SIZE_T Offs,
SIZE_T Lim // NOT included
)
{
_asm {
push ebp
mov ebp, esp
push ebx
push ecx
push edx
push esi
push edi
xor edx,edx // init bit-counter
mov ebx,[ebp+0x08] // set base pointer in EBX (Bitmap)
mov esi,[ebp+0x0c] // set Offs in ESI
mov edi,[ebp+0x10] // set Lim in EDI
// check if Lim <= Offs
cmp esi,edi
// jb start_count
// ja exit_count
// inc edx
// jmp exit_count
jae exit_count
//start_count:
// set 1st bit number in CL
mov ecx,esi
and cl,0x1f
// make ESI uint32-index
shr esi,5
// save last bit number in CH
mov eax,edi
and al,0x1f
mov ch,al
// make EDI uint32-index of the last uint32
shr edi,5
mov eax,[ebx+esi*4]
shr eax,cl
test eax,1
jz Loop_0
/* COUNT 1-BITS SECTION */
Loop_1:
cmp esi,edi
ja exit_count // must never happen
jb non_last_1
Loop_last_1:
cmp cl,ch
jae exit_count
// do we met 0 ?
test eax,1
jz exit_count
shr eax,1
inc edx
inc cl
jmp Loop_last_1
non_last_1:
or cl,cl
jnz std_count_1
cmp eax,-1
je quick_count_1
std_count_1:
cmp cl,0x1f
ja next_uint32_1
// do we met 0 ?
test eax,1
jz exit_count
shr eax,1
inc edx
inc cl
jmp std_count_1
quick_count_1:
add edx,0x20
next_uint32_1:
inc esi
mov eax,[ebx+esi*4]
xor cl,cl
jmp Loop_1
/* COUNT 0-BITS SECTION */
Loop_0:
cmp esi,edi
ja exit_count // must never happen
jb non_last_0
Loop_last_0:
cmp cl,ch
jae exit_count
// do we met 1 ?
test eax,1
jnz exit_count
shr eax,1
inc edx
inc cl
jmp Loop_last_0
non_last_0:
or cl,cl
jnz std_count_0
or eax,eax
jz quick_count_0
std_count_0:
cmp cl,0x1f
ja next_uint32_0
// do we met 1 ?
test eax,1
jnz exit_count
shr eax,1
inc edx
inc cl
jmp std_count_0
quick_count_0:
add edx,0x20
next_uint32_0:
inc esi
mov eax,[ebx+esi*4]
xor cl,cl
jmp Loop_0
exit_count:
mov eax,edx
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp
ret 0x0c
}
#else // NO X86 optimization , use generic C/C++
SIZE_T
__stdcall
UDFGetBitmapLen(
uint32* Bitmap,
SIZE_T Offs,
SIZE_T Lim // NOT included
)
{
ASSERT(Offs <= Lim);
if(Offs >= Lim) {
return 0;//(Offs == Lim);
}
BOOLEAN bit = UDFGetBit(Bitmap, Offs);
SIZE_T i=Offs>>5;
SIZE_T len=0;
uint8 j=(uint8)(Offs&31);
uint8 lLim=(uint8)(Lim&31);
Lim = Lim>>5;
ASSERT((bit == 0) || (bit == 1));
uint32 a;
a = Bitmap[i] >> j;
while(i<=Lim) {
while( j < ((i<Lim) ? 32 : lLim) ) {
if( ((BOOLEAN)(a&1)) != bit)
return len;
len++;
a>>=1;
j++;
}
j=0;
While_3:
i++;
a = Bitmap[i];
if(i<Lim) {
if((bit && (a==0xffffffff)) ||
(!bit && !a)) {
len+=32;
goto While_3;
}
}
}
return len;
#endif // _X86_
} // end UDFGetBitmapLen()
#ifndef UDF_READ_ONLY_BUILD
/*
This routine scans disc free space Bitmap for minimal suitable extent.
It returns maximal available extent if no long enough extents found.
*/
SIZE_T
UDFFindMinSuitableExtent(
IN PVCB Vcb,
IN uint32 Length, // in blocks
IN uint32 SearchStart,
IN uint32 SearchLim, // NOT included
OUT uint32* MaxExtLen,
IN uint8 AllocFlags
)
{
SIZE_T i, len;
uint32* cur;
SIZE_T best_lba=0;
SIZE_T best_len=0;
SIZE_T max_lba=0;
SIZE_T max_len=0;
BOOLEAN align = FALSE;
SIZE_T PS = Vcb->WriteBlockSize >> Vcb->BlockSizeBits;
UDF_CHECK_BITMAP_RESOURCE(Vcb);
// we'll try to allocate packet-aligned block at first
if(!(Length & (PS-1)) && !Vcb->CDR_Mode && (Length >= PS*2))
align = TRUE;
if(AllocFlags & EXTENT_FLAG_ALLOC_SEQUENTIAL)
align = TRUE;
if(Length > (uint32)(UDF_MAX_EXTENT_LENGTH >> Vcb->BlockSizeBits))
Length = (UDF_MAX_EXTENT_LENGTH >> Vcb->BlockSizeBits);
// align Length according to _Logical_ block size & convert it to BCount
i = (1<<Vcb->LB2B_Bits)-1;
Length = (Length+i) & ~i;
cur = (uint32*)(Vcb->FSBM_Bitmap);
retry_no_align:
i=SearchStart;
// scan Bitmap
while(i<SearchLim) {
ASSERT(i <= SearchLim);
if(align) {
i = (i+PS-1) & ~(PS-1);
ASSERT(i <= SearchLim);
if(i >= SearchLim)
break;
}
len = UDFGetBitmapLen(cur, i, SearchLim);
if(UDFGetFreeBit(cur, i)) { // is the extent found free or used ?
// wow! it is free!
if(len >= Length) {
// minimize extent length
if(!best_len || (best_len > len)) {
best_lba = i;
best_len = len;
}
if(len == Length)
break;
} else {
// remember max extent
if(max_len < len) {
max_lba = i;
max_len = len;
}
}
// if this is CD-R mode, we should not think about fragmentation
// due to CD-R nature file will be fragmented in any case
if(Vcb->CDR_Mode) break;
}
i += len;
}
// if we can't find suitable Packet-size aligned block,
// retry without any alignment requirements
if(!best_len && align) {
align = FALSE;
goto retry_no_align;
}
if(best_len) {
// minimal suitable block
(*MaxExtLen) = best_len;
return best_lba;
}
// maximal available
(*MaxExtLen) = max_len;
return max_lba;
} // end UDFFindMinSuitableExtent()
#endif //UDF_READ_ONLY_BUILD
#ifdef UDF_CHECK_DISK_ALLOCATION
/*
This routine checks space described by Mapping as Used/Freed (optionaly)
*/
void
UDFCheckSpaceAllocation_(
IN PVCB Vcb,
IN PEXTENT_MAP Map,
IN uint32 asXXX
#ifdef UDF_TRACK_ONDISK_ALLOCATION
,IN uint32 FE_lba,
IN uint32 BugCheckId,
IN uint32 Line
#endif //UDF_TRACK_ONDISK_ALLOCATION
)
{
uint32 i=0;
uint32 lba, j, len, BS, BSh;
BOOLEAN asUsed = (asXXX == AS_USED);
if(!Map) return;
BS = Vcb->BlockSize;
BSh = Vcb->BlockSizeBits;
UDFAcquireResourceShared(&(Vcb->BitMapResource1),TRUE);
// walk through all frags in data area specified
#ifdef UDF_TRACK_ONDISK_ALLOCATION
AdPrint(("ChkAlloc:Map:%x:File:%x:Line:%d\n",
Map,
BugCheckId,
Line
));
#endif //UDF_TRACK_ONDISK_ALLOCATION
while(Map[i].extLength & UDF_EXTENT_LENGTH_MASK) {
#ifdef UDF_TRACK_ONDISK_ALLOCATION
AdPrint(("ChkAlloc:%x:%s:%x:@:%x:(%x):File:%x:Line:%d\n",
FE_lba,
asUsed ? "U" : "F",
(Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh,
Map[i].extLocation,
(Map[i].extLength >> 30),
BugCheckId,
Line
));
#endif //UDF_TRACK_ONDISK_ALLOCATION
if(asUsed) {
UDFCheckUsedBitOwner(Vcb, (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh, FE_lba);
} else {
UDFCheckFreeBitOwner(Vcb, (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
}
if((Map[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
// skip unallocated frags
// ASSERT(!(Map[i].extLength & UDF_EXTENT_LENGTH_MASK));
ASSERT(!Map[i].extLocation);
i++;
continue;
} else {
// ASSERT(!(Map[i].extLength & UDF_EXTENT_LENGTH_MASK));
ASSERT(Map[i].extLocation);
}
#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
ASSERT(!(Map[i].extLength & (BS-1)));
#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
len = ((Map[i].extLength & UDF_EXTENT_LENGTH_MASK)+BS-1) >> BSh;
lba = Map[i].extLocation;
if((lba+len) > Vcb->LastPossibleLBA) {
// skip blocks beyond media boundary
if(lba > Vcb->LastPossibleLBA) {
ASSERT(FALSE);
i++;
continue;
}
len = Vcb->LastPossibleLBA - lba;
}
// mark frag as XXX (see asUsed parameter)
if(asUsed) {
ASSERT(len);
for(j=0;j<len;j++) {
if(lba+j > Vcb->LastPossibleLBA) {
BrutePoint();
AdPrint(("USED Mapping covers block(s) beyond media @%x\n",lba+j));
break;
}
if(!UDFGetUsedBit(Vcb->FSBM_Bitmap, lba+j)) {
BrutePoint();
AdPrint(("USED Mapping covers FREE block(s) @%x\n",lba+j));
break;
}
}
} else {
ASSERT(len);
for(j=0;j<len;j++) {
if(lba+j > Vcb->LastPossibleLBA) {
BrutePoint();
AdPrint(("USED Mapping covers block(s) beyond media @%x\n",lba+j));
break;
}
if(!UDFGetFreeBit(Vcb->FSBM_Bitmap, lba+j)) {
BrutePoint();
AdPrint(("FREE Mapping covers USED block(s) @%x\n",lba+j));
break;
}
}
}
i++;
}
UDFReleaseResource(&(Vcb->BitMapResource1));
} // end UDFCheckSpaceAllocation_()
#endif //UDF_CHECK_DISK_ALLOCATION
void
UDFMarkBadSpaceAsUsed(
IN PVCB Vcb,
IN lba_t lba,
IN ULONG len
)
{
uint32 j;
#define BIT_C (sizeof(Vcb->BSBM_Bitmap[0])*8)
len = (lba+len+BIT_C-1)/BIT_C;
if(Vcb->BSBM_Bitmap) {
for(j=lba/BIT_C; j<len; j++) {
Vcb->FSBM_Bitmap[j] &= ~Vcb->BSBM_Bitmap[j];
}
}
#undef BIT_C
} // UDFMarkBadSpaceAsUsed()
/*
This routine marks space described by Mapping as Used/Freed (optionaly)
*/
void
UDFMarkSpaceAsXXXNoProtect_(
IN PVCB Vcb,
IN PEXTENT_MAP Map,
IN uint32 asXXX
#ifdef UDF_TRACK_ONDISK_ALLOCATION
,IN uint32 FE_lba,
IN uint32 BugCheckId,
IN uint32 Line
#endif //UDF_TRACK_ONDISK_ALLOCATION
)
{
uint32 i=0;
uint32 lba, j, len, BS, BSh;
uint32 root;
BOOLEAN asUsed = (asXXX == AS_USED || (asXXX & AS_BAD));
#ifdef UDF_TRACK_ONDISK_ALLOCATION
BOOLEAN bit_before, bit_after;
#endif //UDF_TRACK_ONDISK_ALLOCATION
UDF_CHECK_BITMAP_RESOURCE(Vcb);
if(!Map) return;
BS = Vcb->BlockSize;
BSh = Vcb->BlockSizeBits;
Vcb->BitmapModified = TRUE;
UDFSetModified(Vcb);
// walk through all frags in data area specified
while(Map[i].extLength & UDF_EXTENT_LENGTH_MASK) {
if((Map[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) {
// skip unallocated frags
i++;
continue;
}
ASSERT(Map[i].extLocation);
#ifdef UDF_TRACK_ONDISK_ALLOCATION
AdPrint(("Alloc:%x:%s:%x:@:%x:File:%x:Line:%d\n",
FE_lba,
asUsed ? ((asXXX & AS_BAD) ? "B" : "U") : "F",
(Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> Vcb->BlockSizeBits,
Map[i].extLocation,
BugCheckId,
Line
));
#endif //UDF_TRACK_ONDISK_ALLOCATION
#ifdef UDF_DBG
#ifdef UDF_CHECK_EXTENT_SIZE_ALIGNMENT
ASSERT(!(Map[i].extLength & (BS-1)));
#endif //UDF_CHECK_EXTENT_SIZE_ALIGNMENT
// len = ((Map[i].extLength & UDF_EXTENT_LENGTH_MASK)+BS-1) >> BSh;
#else // UDF_DBG
// len = (Map[i].extLength & UDF_EXTENT_LENGTH_MASK) >> BSh;
#endif // UDF_DBG
len = ((Map[i].extLength & UDF_EXTENT_LENGTH_MASK)+BS-1) >> BSh;
lba = Map[i].extLocation;
if((lba+len) > Vcb->LastPossibleLBA) {
// skip blocks beyond media boundary
if(lba > Vcb->LastPossibleLBA) {
ASSERT(FALSE);
i++;
continue;
}
len = Vcb->LastPossibleLBA - lba;
}
#ifdef UDF_TRACK_ONDISK_ALLOCATION
if(lba)
bit_before = UDFGetBit(Vcb->FSBM_Bitmap, lba-1);
bit_after = UDFGetBit(Vcb->FSBM_Bitmap, lba+len);
#endif //UDF_TRACK_ONDISK_ALLOCATION
// mark frag as XXX (see asUsed parameter)
if(asUsed) {
/* for(j=0;j<len;j++) {
UDFSetUsedBit(Vcb->FSBM_Bitmap, lba+j);
}*/
ASSERT(len);
UDFSetUsedBits(Vcb->FSBM_Bitmap, lba, len);
#ifdef UDF_TRACK_ONDISK_ALLOCATION
for(j=0;j<len;j++) {
ASSERT(UDFGetUsedBit(Vcb->FSBM_Bitmap, lba+j));
}
#endif //UDF_TRACK_ONDISK_ALLOCATION
if(Vcb->Vat) {
// mark logical blocks in VAT as used
for(j=0;j<len;j++) {
root = UDFPartStart(Vcb, UDFGetPartNumByPhysLba(Vcb, lba));
if((Vcb->Vat[lba-root+j] == UDF_VAT_FREE_ENTRY) &&
(lba > Vcb->LastLBA)) {
Vcb->Vat[lba-root+j] = 0x7fffffff;
}
}
}
} else {
/* for(j=0;j<len;j++) {
UDFSetFreeBit(Vcb->FSBM_Bitmap, lba+j);
}*/
ASSERT(len);
UDFSetFreeBits(Vcb->FSBM_Bitmap, lba, len);
#ifdef UDF_TRACK_ONDISK_ALLOCATION
for(j=0;j<len;j++) {
ASSERT(UDFGetFreeBit(Vcb->FSBM_Bitmap, lba+j));
}
#endif //UDF_TRACK_ONDISK_ALLOCATION
if(asXXX & AS_BAD) {
UDFSetBits(Vcb->BSBM_Bitmap, lba, len);
}
UDFMarkBadSpaceAsUsed(Vcb, lba, len);
if(asXXX & AS_DISCARDED) {
UDFUnmapRange(Vcb, lba, len);
WCacheDiscardBlocks__(&(Vcb->FastCache), Vcb, lba, len);
UDFSetZeroBits(Vcb->ZSBM_Bitmap, lba, len);
}
if(Vcb->Vat) {
// mark logical blocks in VAT as free
// this operation can decrease resulting VAT size
for(j=0;j<len;j++) {
root = UDFPartStart(Vcb, UDFGetPartNumByPhysLba(Vcb, lba));
Vcb->Vat[lba-root+j] = UDF_VAT_FREE_ENTRY;
}
}
// mark discarded extent as Not-Alloc-Not-Rec to
// prevent writes there
Map[i].extLength = (len << BSh) | (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30);
Map[i].extLocation = 0;
}
#ifdef UDF_TRACK_ONDISK_ALLOCATION
if(lba)
ASSERT(bit_before == UDFGetBit(Vcb->FSBM_Bitmap, lba-1));
ASSERT(bit_after == UDFGetBit(Vcb->FSBM_Bitmap, lba+len));
#endif //UDF_TRACK_ONDISK_ALLOCATION
i++;
}
} // end UDFMarkSpaceAsXXXNoProtect_()
/*
This routine marks space described by Mapping as Used/Freed (optionaly)
It protects data with sync Resource
*/
void
UDFMarkSpaceAsXXX_(
IN PVCB Vcb,
IN PEXTENT_MAP Map,
IN uint32 asXXX
#ifdef UDF_TRACK_ONDISK_ALLOCATION
,IN uint32 FE_lba,
IN uint32 BugCheckId,
IN uint32 Line
#endif //UDF_TRACK_ONDISK_ALLOCATION
)
{
if(!Map) return;
if(!Map[0].extLength) {
#ifdef UDF_DBG
ASSERT(!Map[0].extLocation);
#endif // UDF_DBG
return;
}
UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
#ifdef UDF_TRACK_ONDISK_ALLOCATION
UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX, FE_lba, BugCheckId, Line);
#else //UDF_TRACK_ONDISK_ALLOCATION
UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX);
#endif //UDF_TRACK_ONDISK_ALLOCATION
UDFReleaseResource(&(Vcb->BitMapResource1));
} // end UDFMarkSpaceAsXXX_()
#ifndef UDF_READ_ONLY_BUILD
/*
This routine builds mapping for Length bytes in FreeSpace
It should be used when IN_ICB method is unavailable.
*/
OSSTATUS
UDFAllocFreeExtent_(
IN PVCB Vcb,
IN int64 Length,
IN uint32 SearchStart,
IN uint32 SearchLim, // NOT included
OUT PEXTENT_INFO ExtInfo,
IN uint8 AllocFlags
#ifdef UDF_TRACK_ALLOC_FREE_EXTENT
,IN uint32 src,
IN uint32 line
#endif //UDF_TRACK_ALLOC_FREE_EXTENT
)
{
EXTENT_AD Ext;
PEXTENT_MAP Map = NULL;
uint32 len, LBS, BSh, blen;
LBS = Vcb->LBlockSize;
BSh = Vcb->BlockSizeBits;
blen = (uint32)(((Length+LBS-1) & ~((int64)LBS-1)) >> BSh);
ExtInfo->Mapping = NULL;
ExtInfo->Offset = 0;
ASSERT(blen <= (uint32)(UDF_MAX_EXTENT_LENGTH >> BSh));
UDFAcquireResourceExclusive(&(Vcb->BitMapResource1),TRUE);
if(blen > (SearchLim - SearchStart)) {
goto no_free_space_err;
}
// walk through the free space bitmap & find a single extent or a set of
// frags giving in sum the Length specified
while(blen) {
Ext.extLocation = UDFFindMinSuitableExtent(Vcb, blen, SearchStart,
SearchLim, &len, AllocFlags);
// ASSERT(len <= (uint32)(UDF_MAX_EXTENT_LENGTH >> BSh));
if(len >= blen) {
// complete search
Ext.extLength = blen<<BSh;
blen = 0;
} else if(len) {
// we need still some frags to complete request &
// probably we have the opportunity to do it
Ext.extLength = len<<BSh;
blen -= len;
} else {
no_free_space_err:
// no more free space. abort
if(ExtInfo->Mapping) {
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // free
MyFreePool__(ExtInfo->Mapping);
ExtInfo->Mapping = NULL;
}
UDFReleaseResource(&(Vcb->BitMapResource1));
ExtInfo->Length = 0;//UDFGetExtentLength(ExtInfo->Mapping);
AdPrint((" DISK_FULL\n"));
return STATUS_DISK_FULL;
}
// append the frag found to mapping
ASSERT(!(Ext.extLength >> 30));
ASSERT(Ext.extLocation);
// mark newly allocated blocks as zero-filled
UDFSetZeroBits(Vcb->ZSBM_Bitmap, Ext.extLocation, (Ext.extLength & UDF_EXTENT_LENGTH_MASK) >> BSh);
if(AllocFlags & EXTENT_FLAG_VERIFY) {
if(!UDFCheckArea(Vcb, Ext.extLocation, Ext.extLength >> BSh)) {
AdPrint(("newly allocated extent contains BB\n"));
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, ExtInfo->Mapping, AS_DISCARDED); // free
UDFMarkBadSpaceAsUsed(Vcb, Ext.extLocation, Ext.extLength >> BSh); // bad -> bad+used
// roll back
blen += Ext.extLength>>BSh;
continue;
}
}
Ext.extLength |= EXTENT_NOT_RECORDED_ALLOCATED << 30;
if(!(ExtInfo->Mapping)) {
// create new
#ifdef UDF_TRACK_ALLOC_FREE_EXTENT
ExtInfo->Mapping = UDFExtentToMapping_(&Ext, src, line);
#else // UDF_TRACK_ALLOC_FREE_EXTENT
ExtInfo->Mapping = UDFExtentToMapping(&Ext);
#endif // UDF_TRACK_ALLOC_FREE_EXTENT
if(!ExtInfo->Mapping) {
BrutePoint();
UDFReleaseResource(&(Vcb->BitMapResource1));
ExtInfo->Length = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, ExtInfo->Mapping, AS_USED); // used
} else {
// update existing
Map = UDFExtentToMapping(&Ext);
if(!Map) {
BrutePoint();
UDFReleaseResource(&(Vcb->BitMapResource1));
ExtInfo->Length = UDFGetExtentLength(ExtInfo->Mapping);
return STATUS_INSUFFICIENT_RESOURCES;
}
UDFMarkSpaceAsXXXNoProtect(Vcb, 0, Map, AS_USED); // used
ExtInfo->Mapping = UDFMergeMappings(ExtInfo->Mapping, Map);
MyFreePool__(Map);
}
if(!ExtInfo->Mapping) {
BrutePoint();
UDFReleaseResource(&(Vcb->BitMapResource1));
ExtInfo->Length = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
}
UDFReleaseResource(&(Vcb->BitMapResource1));
ExtInfo->Length = Length;
return STATUS_SUCCESS;
} // end UDFAllocFreeExtent_()
#endif //UDF_READ_ONLY_BUILD
/*
Returns block-count
*/
uint32
__fastcall
UDFGetPartFreeSpace(
IN PVCB Vcb,
IN uint32 partNum
)
{
uint32 lim/*, len=1*/;
uint32 s=0;
uint32 j;
PUCHAR cur = (PUCHAR)(Vcb->FSBM_Bitmap);
lim = (UDFPartEnd(Vcb,partNum)+7)/8;
for(j=(UDFPartStart(Vcb,partNum)+7)/8; j<lim/* && len*/; j++) {
s+=bit_count_tab[cur[j]];
}
return s;
} // end UDFGetPartFreeSpace()
int64
__fastcall
UDFGetFreeSpace(
IN PVCB Vcb
)
{
int64 s=0;
uint32 i;
// uint32* cur = (uint32*)(Vcb->FSBM_Bitmap);
if(!Vcb->CDR_Mode &&
!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) {
for(i=0;i<Vcb->PartitionMaps;i++) {
/* lim = UDFPartEnd(Vcb,i);
for(j=UDFPartStart(Vcb,i); j<lim && len; ) {
len = UDFGetBitmapLen(cur, j, lim);
if(UDFGetFreeBit(cur, j)) // is the extent found free or used ?
s+=len;
j+=len;
}*/
s += UDFGetPartFreeSpace(Vcb, i);
}
} else {
ASSERT(Vcb->LastPossibleLBA >= max(Vcb->NWA, Vcb->LastLBA));
s = Vcb->LastPossibleLBA - max(Vcb->NWA, Vcb->LastLBA);
//if(s & ((int64)1 << 64)) s=0;
}
return s >> Vcb->LB2B_Bits;
} // end UDFGetFreeSpace()
/*
Returns block-count
*/
int64
__fastcall
UDFGetTotalSpace(
IN PVCB Vcb
)
{
int64 s=0;
uint32 i;
if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
s= Vcb->LastPossibleLBA;
} else if(!Vcb->CDR_Mode) {
for(i=0;i<Vcb->PartitionMaps;i++) {
s+=Vcb->Partitions[i].PartitionLen;
}
} else {
if(s & ((int64)1 << 63)) s=0; /* FIXME ReactOS this shift value was 64, which is undefiened behavior. */
s= Vcb->LastPossibleLBA - Vcb->Partitions[0].PartitionRoot;
}
return s >> Vcb->LB2B_Bits;
} // end UDFGetTotalSpace()
/*
Callback for WCache
returns Allocated and Zero-filled flags for given block
any data in 'unallocated' blocks may be changed during flush process
*/
uint32
UDFIsBlockAllocated(
IN void* _Vcb,
IN uint32 Lba
)
{
ULONG ret_val = 0;
uint32* bm;
// return TRUE;
if(!(((PVCB)_Vcb)->VCBFlags & UDF_VCB_ASSUME_ALL_USED)) {
// check used
if((bm = (uint32*)(((PVCB)_Vcb)->FSBM_Bitmap)))
ret_val = (UDFGetUsedBit(bm, Lba) ? WCACHE_BLOCK_USED : 0);
// check zero-filled
if((bm = (uint32*)(((PVCB)_Vcb)->ZSBM_Bitmap)))
ret_val |= (UDFGetZeroBit(bm, Lba) ? WCACHE_BLOCK_ZERO : 0);
} else {
ret_val = WCACHE_BLOCK_USED;
}
// check bad block
// WCache works with LOGICAL addresses, not PHYSICAL, BB check must be performed UNDER cache
/*
if(bm = (uint32*)(((PVCB)_Vcb)->BSBM_Bitmap)) {
ret_val |= (UDFGetBadBit(bm, Lba) ? WCACHE_BLOCK_BAD : 0);
if(ret_val & WCACHE_BLOCK_BAD) {
UDFPrint(("Marked BB @ %#x\n", Lba));
}
}
*/
return ret_val;
} // end UDFIsBlockAllocated()
#ifdef _X86_
#ifdef _MSC_VER
#pragma warning(disable:4035) // re-enable below
#endif
#ifdef _MSC_VER
__declspec (naked)
#endif
BOOLEAN
__fastcall
UDFGetBit__(
IN uint32* arr, // ECX
IN uint32 bit // EDX
)
{
// CheckAddr(arr);
// ASSERT(bit < 300000);
#ifdef _MSC_VER
__asm {
push ebx
push ecx
// mov eax,bit
mov eax,edx
shr eax,3
and al,0fch
add eax,ecx // eax+arr
mov eax,[eax]
mov cl,dl
ror eax,cl
and eax,1
pop ecx
pop ebx
ret
}
#else
/* FIXME ReactOS */
return ((BOOLEAN)(((((uint32*)(arr))[(bit)>>5]) >> ((bit)&31)) &1));
#endif
} // end UDFGetBit__()
#ifdef _MSC_VER
__declspec (naked)
#endif
void
__fastcall
UDFSetBit__(
IN uint32* arr, // ECX
IN uint32 bit // EDX
)
{
// CheckAddr(arr);
// ASSERT(bit < 300000);
#ifdef _MSC_VER
__asm {
push eax
push ebx
push ecx
// mov eax,bit
mov eax,edx
shr eax,3
and al,0fch
add eax,ecx // eax+arr
mov ebx,1
mov cl,dl
rol ebx,cl
or [eax],ebx
pop ecx
pop ebx
pop eax
ret
}
#else
/* FIXME ReactOS */
(((uint32*)(arr))[(bit)>>5]) |= (((uint32)1) << ((bit)&31));
#endif
} // end UDFSetBit__()
void
UDFSetBits__(
IN uint32* arr,
IN uint32 bit,
IN uint32 bc
)
{
#if defined(_MSC_VER) && !defined(__clang__)
__asm {
push eax
push ebx
push ecx
push edx
push esi
mov edx,bc
or edx,edx
jz short EO_sb_loop
mov ecx,bit
mov esi,arr
mov ebx,1
rol ebx,cl
mov eax,ecx
shr eax,3
and al,0fch
test cl, 0x1f
jnz short sb_loop_cont
sb_loop_2:
cmp edx,0x20
jb short sb_loop_cont
mov [dword ptr esi+eax],0xffffffff
sub edx,0x20
jz short EO_sb_loop
add eax,4
add ecx,0x20
jmp short sb_loop_2
sb_loop_cont:
or [esi+eax],ebx
rol ebx,1
inc ecx
dec edx
jz short EO_sb_loop
test cl, 0x1f
jnz short sb_loop_cont
add eax,4
jmp short sb_loop_2
EO_sb_loop:
pop esi
pop edx
pop ecx
pop ebx
pop eax
}
#else
/* FIXME ReactOS */
uint32 j;
for(j=0;j<bc;j++) {
UDFSetBit(arr, bit+j);
}
#endif
} // end UDFSetBits__()
#ifdef _MSC_VER
__declspec (naked)
#endif
void
__fastcall
UDFClrBit__(
IN uint32* arr, // ECX
IN uint32 bit // EDX
)
{
// CheckAddr(arr);
// ASSERT(bit < 300000);
#ifdef _MSC_VER
__asm {
push eax
push ebx
push ecx
// mov eax,bit
mov eax,edx
shr eax,3
and al,0fch
add eax,ecx // eax+arr
mov ebx,0fffffffeh
mov cl,dl
rol ebx,cl
and [eax],ebx
pop ecx
pop ebx
pop eax
ret
}
#else
/* FIXME ReactOS */
(((uint32*)(arr))[(bit)>>5]) &= (~(((uint32)1) << ((bit)&31)));
#endif
} // end UDFClrBit__()
void
UDFClrBits__(
IN uint32* arr,
IN uint32 bit,
IN uint32 bc
)
{
#if defined(_MSC_VER) && !defined(__clang__)
__asm {
push eax
push ebx
push ecx
push edx
push esi
mov edx,bc
or edx,edx
jz short EO_cp_loop
mov ecx,bit
mov esi,arr
mov ebx,0xfffffffe
rol ebx,cl
mov eax,ecx
shr eax,3
and al,0fch
test cl, 0x1f
jnz short cp_loop_cont
cp_loop_2:
cmp edx,0x20
jb short cp_loop_cont
mov [dword ptr esi+eax],0x00000000
sub edx,0x20
jz short EO_cp_loop
add eax,4
add ecx,0x20
jmp short cp_loop_2
cp_loop_cont:
and [esi+eax],ebx
rol ebx,1
inc ecx
dec edx
jz short EO_cp_loop
test cl, 0x1f
jnz short cp_loop_cont
add eax,4
jmp short cp_loop_2
EO_cp_loop:
pop esi
pop edx
pop ecx
pop ebx
pop eax
}
#else
/* FIXME ReactOS */
uint32 j;
for(j=0;j<bc;j++) {
UDFClrBit(arr, bit+j);
}
#endif
} // end UDFClrBits__()
#ifdef _MSC_VER
#pragma warning(default:4035)
#endif
#endif // _X86_