2015-10-12 10:19:10 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2ExpandLast(
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2GetBlock(
|
|
|
|
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,
|
|
|
|
(void **)&pData )) {
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2ExpandBlock(
|
|
|
|
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,
|
|
|
|
(void **)&pData )) {
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
Ext2IsBlockEmpty(PULONG BlockArray, ULONG SizeArray)
|
|
|
|
{
|
|
|
|
ULONG i = 0;
|
|
|
|
for (i=0; i < SizeArray; i++) {
|
|
|
|
if (BlockArray[i]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (i == SizeArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2TruncateBlock(
|
|
|
|
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,
|
|
|
|
(void **)&pData )) {
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2MapIndirect(
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-11 12:29:21 +00:00
|
|
|
if (Layer == 0)
|
2015-10-12 10:19:10 +00:00
|
|
|
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,
|
|
|
|
(PULONG)&Mcb->Inode.i_block[Slot],
|
|
|
|
bAlloc,
|
|
|
|
&dwHint,
|
|
|
|
&dwRet,
|
|
|
|
Number
|
|
|
|
);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
*pBlock = dwRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Index -= Vcb->max_blocks_per_layer[Layer];
|
|
|
|
}
|
|
|
|
|
|
|
|
errorout:
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2ExpandIndirect(
|
|
|
|
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,
|
|
|
|
(PULONG)&Mcb->Inode.i_block[Slot],
|
|
|
|
&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;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2TruncateIndirectFast(
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
Ext2TruncateIndirect(
|
|
|
|
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) {
|
|
|
|
BlockArray = (PULONG)&Mcb->Inode.i_block[0];
|
|
|
|
SizeArray = End;
|
|
|
|
ASSERT(End == EXT2_NDIR_BLOCKS && Base == 0);
|
|
|
|
} else {
|
|
|
|
BlockArray = (PULONG)&Mcb->Inode.i_block[EXT2_NDIR_BLOCKS - 1 + Layer - 1];
|
|
|
|
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;
|
|
|
|
}
|