Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188/* * COPYRIGHT: See COPYRIGHT.TXT * PROJECT: Ext2 File System Driver for WinNT/2K/XP * FILE: indirect.c * PROGRAMMER: Matt Wu <mattwu@163.com> * HOMEPAGE: http://www.ext2fsd.com * UPDATE HISTORY: */
/* INCLUDES *****************************************************************/
#include "ext2fs.h"
/* GLOBALS *****************************************************************/
extern PEXT2_GLOBAL Ext2Global;
/* DEFINITIONS *************************************************************/
#ifdef ALLOC_PRAGMA#endif
NTSTATUSExt2ExpandLast( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN PULONG * Data, IN PULONG Hint, IN PULONG Block, IN OUT PULONG Number){ PULONG pData = NULL; ULONG i; NTSTATUS Status = STATUS_SUCCESS;
if (Layer > 0 || IsMcbDirectory(Mcb)) {
/* allocate buffer for new block */ pData = (ULONG *) Ext2AllocatePool( PagedPool, BLOCK_SIZE, EXT2_DATA_MAGIC ); if (!pData) { DEBUG(DL_ERR, ( "Ex2ExpandBlock: failed to allocate memory for Data.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } RtlZeroMemory(pData, BLOCK_SIZE); INC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); }
/* allocate block from disk */ Status = Ext2NewBlock( IrpContext, Vcb, (Mcb->Inode.i_ino - 1) / BLOCKS_PER_GROUP, *Hint, Block, Number );
if (!NT_SUCCESS(Status)) { goto errorout; }
/* increase inode i_blocks */ Mcb->Inode.i_blocks += (*Number << (BLOCK_BITS - 9));
if (Layer == 0) {
if (IsMcbDirectory(Mcb)) { /* for directory we need initialize it's entry structure */ PEXT2_DIR_ENTRY2 pEntry; pEntry = (PEXT2_DIR_ENTRY2) pData; pEntry->rec_len = (USHORT)(BLOCK_SIZE); ASSERT(*Number == 1); Ext2SaveBlock(IrpContext, Vcb, *Block, (PVOID)pData); }
/* add new Extent into Mcb */ if (!Ext2AddBlockExtent(Vcb, Mcb, Base, (*Block), *Number)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); }
} else {
/* zero the content of all meta blocks */ for (i = 0; i < *Number; i++) { Ext2SaveBlock(IrpContext, Vcb, *Block + i, (PVOID)pData); /* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1); } } }
errorout:
if (NT_SUCCESS(Status)) { *Hint = *Block + *Number; if (Data) { *Data = pData; ASSERT(*Number == 1); } else { if (pData) { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } } } else { if (pData) { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } if (*Block) { Ext2FreeBlock(IrpContext, Vcb, *Block, *Number); Mcb->Inode.i_blocks -= (*Number << (BLOCK_BITS - 9)); *Block = 0; } }
return Status;}
NTSTATUSExt2GetBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN ULONG Start, IN ULONG SizeArray, IN PULONG BlockArray, IN BOOLEAN bAlloc, IN OUT PULONG Hint, OUT PULONG Block, OUT PULONG Number){ NTSTATUS Status = STATUS_SUCCESS; PBCB Bcb = NULL; PULONG pData = NULL; ULONG Slot = 0, i = 0; ULONG Unit = 1;
LARGE_INTEGER Offset;
if (Layer == 0) {
*Number = 1; if (BlockArray[0] == 0 && bAlloc) {
/* now allocate new block */ Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &BlockArray[0], Number );
if (!NT_SUCCESS(Status)) { goto errorout; } } else { /* check the block is valid or not */ if (BlockArray[0] >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; } }
*Block = BlockArray[0]; for (i=1; i < SizeArray; i++) { if (BlockArray[i] == BlockArray[i-1] + 1) { *Number = *Number + 1; } else { break; } } *Hint = BlockArray[*Number - 1];
} else if (Layer <= 3) {
/* check the block is valid or not */ if (BlockArray[0] == 0 || BlockArray[0] >= TOTAL_BLOCKS) { DbgBreak(); Status = STATUS_DISK_CORRUPT_ERROR; goto errorout; }
/* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[0], 1); }
/* map memory in cache for the index block */ Offset.QuadPart = ((LONGLONG)BlockArray[0]) << BLOCK_BITS; if ( !CcPinRead( Vcb->Volume, (PLARGE_INTEGER) (&Offset), BLOCK_SIZE, PIN_WAIT, &Bcb,#ifdef __REACTOS__ (void **)&pData )) {#else &pData )) {#endif
DEBUG(DL_ERR, ( "Ext2GetBlock: Failed to PinLock block: %xh ...\n", BlockArray[0] )); Status = STATUS_CANT_WAIT; goto errorout; }
if (Layer > 1) { Unit = Vcb->max_blocks_per_layer[Layer - 1]; } else { Unit = 1; }
Slot = Start / Unit; Start = Start % Unit;
if (pData[Slot] == 0) {
if (bAlloc) {
/* we need allocate new block and zero all data in case it's an in-direct block. Index stores the new block no. */ ULONG Count = 1; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &pData[Slot], &Count );
if (!NT_SUCCESS(Status)) { goto errorout; }
/* refresh hint block */ *Hint = pData[Slot];
/* set dirty bit to notify system to flush */ CcSetDirtyPinnedData(Bcb, NULL ); SetFlag(Vcb->Volume->Flags, FO_FILE_MODIFIED); if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE)) { DbgBreak(); Ext2Sleep(100); if (!Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)BLOCK_SIZE)) { Status = STATUS_INSUFFICIENT_RESOURCES; goto errorout; } }
/* save inode information here */ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
} else {
*Number = 1;
if (Layer == 1) { for (i = Slot + 1; i < BLOCK_SIZE/4; i++) { if (pData[i] == 0) { *Number = *Number + 1; } else { break; } } } else if (Layer == 2) { *Number = BLOCK_SIZE/4 - Start; } else { *Number = BLOCK_SIZE/4; }
goto errorout; } }
/* transfer to next recursion call */ Status = Ext2GetBlock( IrpContext, Vcb, Mcb, Base, Layer - 1, Start, BLOCK_SIZE/4 - Slot, &pData[Slot], bAlloc, Hint, Block, Number );
if (!NT_SUCCESS(Status)) { goto errorout; } }
errorout:
/* free the memory of pData */ if (Bcb) { CcUnpinData(Bcb); }
if (!NT_SUCCESS(Status)) { *Block = 0; }
return Status;}
NTSTATUSExt2ExpandBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Layer, IN ULONG Start, IN ULONG SizeArray, IN PULONG BlockArray, IN PULONG Hint, IN PULONG Extra){ ULONG i = 0; ULONG j; ULONG Slot; ULONG Block = 0; LARGE_INTEGER Offset;
PBCB Bcb = NULL; PULONG pData = NULL; ULONG Skip = 0;
ULONG Number; ULONG Wanted;
NTSTATUS Status = STATUS_SUCCESS;
if (Layer == 1) {
/* * try to make all leaf block continuous to avoid fragments */
Number = min(SizeArray, ((*Extra + (Start & (BLOCK_SIZE/4 - 1))) * 4 / BLOCK_SIZE)); Wanted = 0; DEBUG(DL_BLK, ("Ext2ExpandBlock: SizeArray=%xh Extra=%xh Start=%xh %xh\n", SizeArray, *Extra, Start, Number ));
for (i=0; i < Number; i++) { if (BlockArray[i] == 0) { Wanted += 1; } }
i = 0; while (Wanted > 0) {
Number = Wanted; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, Hint, &Block, &Number ); if (!NT_SUCCESS(Status)) { goto errorout; }
ASSERT(Number > 0); Wanted -= Number; while (Number) { if (BlockArray[i] == 0) { BlockArray[i] = Block++; Number--; } i++; } }
} else if (Layer == 0) {
/* * bulk allocation for inode data blocks */
i = 0;
while (*Extra && i < SizeArray) {
Wanted = 0; Number = 1;
for (j = i; j < SizeArray && j < i + *Extra; j++) {
if (BlockArray[j] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[j] = 0; }
if (BlockArray[j] == 0) { Wanted += 1; } else { break; } }
if (Wanted == 0) {
/* add block extent into Mcb */ ASSERT(BlockArray[i] != 0); if (!Ext2AddBlockExtent(Vcb, Mcb, Base + i, BlockArray[i], 1)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); }
} else {
Number = Wanted; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base + i, 0, NULL, Hint, &Block, &Number ); if (!NT_SUCCESS(Status)) { goto errorout; }
ASSERT(Number > 0); for (j = 0; j < Number; j++) { BlockArray[i + j] = Block++; } }
*Extra -= Number; i += Number; }
goto errorout; }
/* * only for meta blocks allocation */
for (i = 0; *Extra && i < SizeArray; i++) {
if (Layer <= 3) {
if (BlockArray[i] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[i] = 0; }
if (BlockArray[i] == 0) { Number = 1; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, &pData, Hint, &BlockArray[i], &Number ); if (!NT_SUCCESS(Status)) { goto errorout; }
} else {
Offset.QuadPart = (((LONGLONG)BlockArray[i]) << BLOCK_BITS); if (!CcPinRead( Vcb->Volume, &Offset, BLOCK_SIZE, PIN_WAIT, &Bcb,#ifdef __REACTOS__ (void **)&pData )) {#else &pData )) {#endif
DEBUG(DL_ERR, ( "Ext2ExpandInode: failed to PinLock offset :%I64xh...\n", Offset.QuadPart)); Status = STATUS_CANT_WAIT; DbgBreak(); goto errorout; }
/* add block to meta extents */ if (!Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1)) { DbgBreak(); Ext2Sleep(500); Ext2AddMcbMetaExts(Vcb, Mcb, BlockArray[i], 1); } }
Skip = Vcb->max_blocks_per_layer[Layer] * i;
if (i == 0) { if (Layer > 1) { Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; Skip += Slot * Vcb->max_blocks_per_layer[Layer - 1]; } else { Slot = Start; Start = 0; Skip += Slot; } } else { Start = 0; Slot = 0; }
Status = Ext2ExpandBlock( IrpContext, Vcb, Mcb, Base + Skip, Layer - 1, Start, BLOCK_SIZE/4 - Slot, &pData[Slot], Hint, Extra );
if (Bcb) { CcSetDirtyPinnedData(Bcb, NULL); if (!Ext2AddBlockExtent(Vcb, NULL, BlockArray[i], BlockArray[i], 1)) { DbgBreak(); Ext2Sleep(500); if (!Ext2AddBlockExtent(Vcb, NULL, BlockArray[i], BlockArray[i], 1)) { } } } else { Ext2SaveBlock(IrpContext, Vcb, BlockArray[i], (PVOID)pData); }
if (pData) { if (Bcb) { CcUnpinData(Bcb); Bcb = NULL; } else { Ext2FreePool(pData, EXT2_DATA_MAGIC); DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE); } pData = NULL; }
if (!NT_SUCCESS(Status)) { DbgBreak(); break; } } }
errorout:
return Status;}
BOOLEANExt2IsBlockEmpty(PULONG BlockArray, ULONG SizeArray){ ULONG i = 0; for (i=0; i < SizeArray; i++) { if (BlockArray[i]) { break; } } return (i == SizeArray);}
NTSTATUSExt2TruncateBlock( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Base, IN ULONG Start, IN ULONG Layer, IN ULONG SizeArray, IN PULONG BlockArray, IN PULONG Extra){ NTSTATUS Status = STATUS_SUCCESS; ULONG i = 0; ULONG Slot = 0; ULONG Skip = 0;
LONGLONG Offset; PBCB Bcb = NULL; PULONG pData = NULL;
ASSERT(Mcb != NULL);
for (i = 0; i < SizeArray; i++) {
if (Layer == 0) {
ULONG Number = 1;
while (Extra && SizeArray > i + 1 && Number < *Extra) {
if (BlockArray[SizeArray - i - 1] == BlockArray[SizeArray - i - 2] + 1) {
BlockArray[SizeArray - i - 1] = 0; Number++; SizeArray--;
} else { break; } }
if (BlockArray[SizeArray - i - 1]) {
Status = Ext2FreeBlock(IrpContext, Vcb, BlockArray[SizeArray - i - 1], Number); if (NT_SUCCESS(Status)) { ASSERT(Mcb->Inode.i_blocks >= (Number << (BLOCK_BITS - 9))); if (Mcb->Inode.i_blocks < (Number << (BLOCK_BITS - 9))) { Mcb->Inode.i_blocks = 0; DbgBreak(); } else { Mcb->Inode.i_blocks -= (Number << (BLOCK_BITS - 9)); } BlockArray[SizeArray - i - 1] = 0; } }
if (Extra) {
/* dec blocks count */ ASSERT(*Extra >= Number); *Extra = *Extra - Number;
/* remove block mapping frm Mcb Extents */ if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + SizeArray - 1 - i, Number)) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } }
} else {
ASSERT(Layer <= 3);
if (BlockArray[SizeArray - i - 1] >= TOTAL_BLOCKS) { DbgBreak(); BlockArray[SizeArray - i - 1] = 0; }
if (i == 0) { if (Layer > 1) { Slot = Start / Vcb->max_blocks_per_layer[Layer - 1]; Start = Start % Vcb->max_blocks_per_layer[Layer - 1]; } else { Slot = Start; Start = (BLOCK_SIZE / 4) - 1; } } else { Slot = Start = (BLOCK_SIZE / 4) - 1; }
Skip = (SizeArray - i - 1) * Vcb->max_blocks_per_layer[Layer];
if (BlockArray[SizeArray - i - 1]) {
Offset = (LONGLONG) (BlockArray[SizeArray - i - 1]); Offset = Offset << BLOCK_BITS;
if (!CcPinRead( Vcb->Volume, (PLARGE_INTEGER) (&Offset), BLOCK_SIZE, PIN_WAIT, &Bcb,#ifdef __REACTOS__ (void **)&pData )) {#else &pData )) {#endif
DEBUG(DL_ERR, ( "Ext2TruncateBlock: PinLock failed on block %xh ...\n", BlockArray[SizeArray - i - 1])); Status = STATUS_CANT_WAIT; DbgBreak(); goto errorout; }
Status = Ext2TruncateBlock( IrpContext, Vcb, Mcb, Base + Skip, Start, Layer - 1, Slot + 1, &pData[0], Extra );
if (!NT_SUCCESS(Status)) { break; }
CcSetDirtyPinnedData(Bcb, NULL); Ext2AddVcbExtent(Vcb, Offset, (LONGLONG)BLOCK_SIZE);
if (*Extra || Ext2IsBlockEmpty(pData, BLOCK_SIZE/4)) {
Ext2TruncateBlock( IrpContext, Vcb, Mcb, Base + Skip, /* base */ 0, /* start */ 0, /* layer */ 1, &BlockArray[SizeArray - i - 1], NULL );
if (!Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1)) { DbgBreak(); Ext2Sleep(500); Ext2RemoveMcbMetaExts(Vcb, Mcb, BlockArray[SizeArray - i - 1], 1); } }
if (pData) { CcUnpinData(Bcb); Bcb = NULL; pData = NULL; }
} else {
if (Layer > 1) { if (*Extra > Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1) { *Extra -= (Slot * Vcb->max_blocks_per_layer[Layer - 1] + Start + 1); } else { *Extra = 0; } } else { if (*Extra > Slot + 1) { *Extra -= (Slot + 1); } else { *Extra = 0; } }
if (!Ext2RemoveBlockExtent(Vcb, Mcb, Base + Skip, (Start + 1))) { DbgBreak(); ClearFlag(Mcb->Flags, MCB_ZONE_INITED); Ext2ClearAllExtents(&Mcb->Extents); } } }
if (Extra && *Extra == 0) { break; } }
errorout:
if (pData) { CcUnpinData(Bcb); }
return Status;}
NTSTATUSExt2MapIndirect( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Index, IN BOOLEAN bAlloc, OUT PULONG pBlock, OUT PULONG Number){ ULONG Layer; ULONG Slot;
ULONG Base = Index;
NTSTATUS Status = STATUS_SUCCESS;
*pBlock = 0; *Number = 0;
for (Layer = 0; Layer < EXT2_BLOCK_TYPES; Layer++) {
if (Index < Vcb->max_blocks_per_layer[Layer]) {
ULONG dwRet = 0, dwBlk = 0, dwHint = 0, dwArray = 0;
Slot = (Layer==0) ? (Index):(Layer + EXT2_NDIR_BLOCKS - 1); dwBlk = Mcb->Inode.i_block[Slot];
if (dwBlk == 0) {
if (!bAlloc) {
*Number = 1; goto errorout;
} else {
if (Slot) { dwHint = Mcb->Inode.i_block[Slot - 1]; }
/* allocate and zero block if necessary */ *Number = 1; Status = Ext2ExpandLast( IrpContext, Vcb, Mcb, Base, Layer, NULL, &dwHint, &dwBlk, Number );
if (!NT_SUCCESS(Status)) { goto errorout; }
/* save the it into inode*/ Mcb->Inode.i_block[Slot] = dwBlk;
/* save the inode */ if (!Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode)) { DbgBreak(); Status = STATUS_UNSUCCESSFUL; goto errorout; } } }
if (Layer == 0) dwArray = Vcb->max_blocks_per_layer[Layer] - Index; else dwArray = 1;
/* querying block number of the index-th file block */ Status = Ext2GetBlock( IrpContext, Vcb, Mcb, Base, Layer, Index, dwArray,#ifdef __REACTOS__ (PULONG)&Mcb->Inode.i_block[Slot],#else &Mcb->Inode.i_block[Slot],#endif bAlloc, &dwHint, &dwRet, Number );
if (NT_SUCCESS(Status)) { *pBlock = dwRet; }
break; }
Index -= Vcb->max_blocks_per_layer[Layer]; }
errorout:
return Status;}
NTSTATUSExt2ExpandIndirect( PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, PEXT2_MCB Mcb, ULONG Start, ULONG End, PLARGE_INTEGER Size){ NTSTATUS Status = STATUS_SUCCESS;
ULONG Layer = 0; ULONG Extra = 0; ULONG Hint = 0; ULONG Slot = 0; ULONG Base = 0;
Extra = End - Start;
/* exceeds the biggest file size (indirect) */ if (End > Vcb->max_data_blocks) { return STATUS_INVALID_PARAMETER; }
for (Layer = 0; Layer < EXT2_BLOCK_TYPES && Extra; Layer++) {
if (Start >= Vcb->max_blocks_per_layer[Layer]) {
Base += Vcb->max_blocks_per_layer[Layer]; Start -= Vcb->max_blocks_per_layer[Layer];
} else {
/* get the slot in i_block array */ if (Layer == 0) { Base = Slot = Start; } else { Slot = Layer + EXT2_NDIR_BLOCKS - 1; }
/* set block hint to avoid fragments */ if (Hint == 0) { if (Mcb->Inode.i_block[Slot] != 0) { Hint = Mcb->Inode.i_block[Slot]; } else if (Slot > 1) { Hint = Mcb->Inode.i_block[Slot-1]; } }
/* now expand this slot */ Status = Ext2ExpandBlock( IrpContext, Vcb, Mcb, Base, Layer, Start, (Layer == 0) ? (Vcb->max_blocks_per_layer[Layer] - Start) : 1,#ifdef __REACTOS__ (PULONG)&Mcb->Inode.i_block[Slot],#else &Mcb->Inode.i_block[Slot],#endif &Hint, &Extra ); if (!NT_SUCCESS(Status)) { break; }
Start = 0; if (Layer == 0) { Base = 0; } Base += Vcb->max_blocks_per_layer[Layer]; } }
Size->QuadPart = ((LONGLONG)(End - Extra)) << BLOCK_BITS;
/* save inode whatever it succeeds to expand or not */ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
return Status;}
NTSTATUSExt2TruncateIndirectFast( PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, PEXT2_MCB Mcb ){ LONGLONG Vba; LONGLONG Lba; LONGLONG Length; NTSTATUS Status = STATUS_SUCCESS; int i;
/* try to load all indirect blocks if mcb zone is not initialized */ if (!IsZoneInited(Mcb)) { Status = Ext2InitializeZone(IrpContext, Vcb, Mcb); if (!NT_SUCCESS(Status)) { DbgBreak(); ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED); goto errorout; } }
ASSERT (IsZoneInited(Mcb));
/* delete all data blocks here */ if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents) != 0) { for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->Extents, i, &Vba, &Lba, &Length); i++) { /* ignore the non-existing runs */ if (-1 == Lba || Vba == 0 || Length <= 0) continue; /* now do data block free */ Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); } }
/* delete all meta blocks here */ if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts) != 0) { for (i = 0; FsRtlGetNextLargeMcbEntry(&Mcb->MetaExts, i, &Vba, &Lba, &Length); i++) { /* ignore the non-existing runs */ if (-1 == Lba || Vba == 0 || Length <= 0) continue; /* now do meta block free */ Ext2FreeBlock(IrpContext, Vcb, (ULONG)(Lba - 1), (ULONG)Length); } }
/* clear data and meta extents */ Ext2ClearAllExtents(&Mcb->Extents); Ext2ClearAllExtents(&Mcb->MetaExts); ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
/* clear inode blocks & sizes */ Mcb->Inode.i_blocks = 0; Mcb->Inode.i_size = 0; memset(&Mcb->Inode.i_block[0], 0, sizeof(__u32) * 15);
/* the caller will do inode save */
errorout:
return Status;}
NTSTATUSExt2TruncateIndirect( PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, PEXT2_MCB Mcb, PLARGE_INTEGER Size){ NTSTATUS Status = STATUS_SUCCESS;
ULONG Layer = 0;
ULONG Extra = 0; ULONG Wanted = 0; ULONG End; ULONG Base;
ULONG SizeArray = 0; PULONG BlockArray = NULL;
/* translate file size to block */ End = Base = Vcb->max_data_blocks; Wanted = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
/* do fast deletion here */ if (Wanted == 0) { Status = Ext2TruncateIndirectFast(IrpContext, Vcb, Mcb); if (NT_SUCCESS(Status)) goto errorout; }
/* calculate blocks to be freed */ Extra = End - Wanted;
for (Layer = EXT2_BLOCK_TYPES; Layer > 0 && Extra; Layer--) {
if (Vcb->max_blocks_per_layer[Layer - 1] == 0) { continue; }
Base -= Vcb->max_blocks_per_layer[Layer - 1];
if (Layer - 1 == 0) {#ifdef __REACTOS__ BlockArray = (PULONG)&Mcb->Inode.i_block[0];#else BlockArray = &Mcb->Inode.i_block[0];#endif SizeArray = End; ASSERT(End == EXT2_NDIR_BLOCKS && Base == 0); } else {#ifdef __REACTOS__ BlockArray = (PULONG)&Mcb->Inode.i_block[EXT2_NDIR_BLOCKS - 1 + Layer - 1];#else BlockArray = &Mcb->Inode.i_block[EXT2_NDIR_BLOCKS - 1 + Layer - 1];#endif SizeArray = 1; }
Status = Ext2TruncateBlock( IrpContext, Vcb, Mcb, Base, End - Base - 1, Layer - 1, SizeArray, BlockArray, &Extra ); if (!NT_SUCCESS(Status)) { break; }
End = Base; }
errorout:
if (!NT_SUCCESS(Status)) { Size->QuadPart += ((ULONGLONG)Extra << BLOCK_BITS); }
/* save inode */ if (Mcb->Inode.i_size > (loff_t)(Size->QuadPart)) Mcb->Inode.i_size = (loff_t)(Size->QuadPart); Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
return Status;}