⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 generic.c

📁 可以在不启动LINUX的情况下直接访问EXT2和EXT3格式的磁盘
💻 C
📖 第 1 页 / 共 5 页
字号:
                    goto errorout;
                }
            }

            Skip = Vcb->NumBlocks[Layer] * i;

            if (i == 0) {
                if (Layer > 1) {
                    Slot  = Start / Vcb->NumBlocks[Layer - 1];
                    Start = Start % Vcb->NumBlocks[Layer - 1];
                    Skip += Slot * Vcb->NumBlocks[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)) {
                        Status = STATUS_INSUFFICIENT_RESOURCES;
                        goto errorout;
                    }
                }
            } else {
                Ext2SaveBlock(IrpContext, Vcb, BlockArray[i], (PVOID)pData);
            }

            if (pData) {
                if (Bcb) {
                    CcUnpinData(Bcb);
                    Bcb = NULL;
                } else {
                    ExFreePoolWithTag(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;

    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)) {
#if EXT2_DEBUG
                    if (i == 0 || i == SizeArray - 1 || *Extra == Number) {
                        DEBUG(DL_BLK, ("Ext2TruncateBlock: Vbn: %xh Lbn: %xh Num: %xh\n",
                            Base + SizeArray - 1 - i, BlockArray[SizeArray - i - 1], Number));
                    }
#endif
                    ASSERT(Mcb->Inode->i_blocks >= Number * (BLOCK_SIZE >> 9));
                    if (Mcb->Inode->i_blocks < Number * (BLOCK_SIZE >> 9)) {
                        Mcb->Inode->i_blocks = 0;
                        DbgBreak();
                    } else {
                        Mcb->Inode->i_blocks -= Number * (BLOCK_SIZE >> 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_INIT);
                    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->NumBlocks[Layer - 1];
                    Start = Start % Vcb->NumBlocks[Layer - 1];
                } else {
                    Slot  = Start;
                    Start = (BLOCK_SIZE / 4) - 1;
                }
            } else {
                Slot = Start = (BLOCK_SIZE / 4) - 1;
            }

            Skip = (SizeArray - i - 1) * Vcb->NumBlocks[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,
                                Ext2CanIWait(),
                                &Bcb,
                                &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)) {

                    Status = Ext2TruncateBlock(
                                IrpContext,
                                Vcb,
                                Mcb,
                                Base + Skip,    /* base */
                                0,              /* start */
                                0,              /* layer */
                                1,
                                &BlockArray[SizeArray - i - 1],
                                NULL
                                );
                }

                if (pData) {
                    CcUnpinData(Bcb);
                    Bcb = NULL;
                    pData = NULL;
                }

            } else {

                if (Layer > 1) {
                    if (*Extra > Slot * Vcb->NumBlocks[Layer - 1] + Start + 1) {
                        *Extra -= (Slot * Vcb->NumBlocks[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_INIT);
                    Ext2ClearAllExtents(&Mcb->Extents);
                }
            }
        }

        if (Extra && *Extra == 0) {
            break;
        }
    }

errorout:

    if (pData) {
        CcUnpinData(Bcb);
    }

    return Status;
}

NTSTATUS
Ext2NewInode(
    IN PEXT2_IRP_CONTEXT    IrpContext,
    IN PEXT2_VCB            Vcb,
    IN ULONG                GroupHint,
    IN ULONG                Type,
    OUT PULONG              Inode
    )
{
    RTL_BITMAP      InodeBitmap;
    PVOID           BitmapCache;
    PBCB            BitmapBcb;

    ULONG           Group, i, j;
    ULONG           Average, Length;
    LARGE_INTEGER   Offset;
    
    ULONG           dwInode;

    NTSTATUS        Status = STATUS_DISK_FULL;

    *Inode = dwInode = 0XFFFFFFFF;

    ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);

repeat:

    Group = i = 0;
    
    if (Type == EXT2_FT_DIR) {

        Average = Vcb->SuperBlock->s_free_inodes_count / Vcb->NumOfGroups;

        for (j = 0; j < Vcb->NumOfGroups; j++) {

            i = (j + GroupHint) % (Vcb->NumOfGroups);

            if ((Vcb->GroupDesc[i].bg_used_dirs_count << 8) < 
                 Vcb->GroupDesc[i].bg_free_inodes_count ) {
                Group = i + 1;
                break;
            }
        }

        if (!Group) {

            /* get the group with the biggest vacancy */
            for (j = 0; j < Vcb->NumOfGroups; j++) {
                if (!Group) {
                    if (Vcb->GroupDesc[j].bg_free_inodes_count > 0) {
                        Group = j + 1;
                    }
                } else {
                    if ( Vcb->GroupDesc[j].bg_free_blocks_count >
                         Vcb->GroupDesc[Group - 1].bg_free_blocks_count ) {
                        Group = j + 1;
                    }
                }
            }
        }

    } else {

        /*
         * Try to place the inode in its parent directory (GroupHint)
         */

        if (Vcb->GroupDesc[GroupHint].bg_free_inodes_count) {

            Group = GroupHint + 1;

        } else {

            i = GroupHint;

            /*
             * Use a quadratic hash to find a group with a free inode
             */

            for (j = 1; j < Vcb->NumOfGroups; j <<= 1) {

                i = (i + j) % Vcb->NumOfGroups;

                if (Vcb->GroupDesc[i].bg_free_inodes_count) {
                    Group = i + 1;
                    break;
                }
            }
        }

        if (!Group) {
            /*
             * That failed: try linear search for a free inode
             */
            i = GroupHint;
            for (j = 2; j < Vcb->NumOfGroups; j++) {
                i = (i + 1) % Vcb->NumOfGroups;
                if (Vcb->GroupDesc[i].bg_free_inodes_count) {
                    Group = i + 1;
                    break;
                }
            }
        }
    }

    if (Group == 0) {
        goto errorout;
    }

    Group -= 1;

    /* finally we got the group */
    if (Group >= Vcb->NumOfGroups) {
        DbgBreak();
        goto errorout;
    }

    /* check the block is valid or not */
    if (Vcb->GroupDesc[Group].bg_inode_bitmap >= TOTAL_BLOCKS) {
        DbgBreak();
        Status = STATUS_DISK_CORRUPT_ERROR;
        goto errorout;
    }

    /*  this group is used up, we should go here */
    if (Vcb->GroupDesc[Group].bg_inode_bitmap == 0) {
        DbgBreak();
        goto errorout;
    }

    Offset.QuadPart = (LONGLONG) Vcb->GroupDesc[Group].bg_inode_bitmap;
    Offset.QuadPart = Offset.QuadPart << BLOCK_BITS ;

    if (Vcb->NumOfGroups == 1) {
        Length = INODES_COUNT;
    } else {
        if (Group + 1 == Vcb->NumOfGroups) {
            Length = INODES_COUNT % INODES_PER_GROUP;
            if (!Length) {
                /* INODES_COUNT is integer multiple of INODES_PER_GROUP */
                Length = INODES_PER_GROUP;
            }
        } else  {
            Length = INODES_PER_GROUP;
        }
    }
        
    if (!CcPinRead( Vcb->Volume,
                    &Offset,
                    Vcb->BlockSize,
                    Ext2CanIWait(),
                    &BitmapBcb,
                    &BitmapCache ) ) {

        DEBUG(DL_ERR, ( "Ext2NewInode: Failed to PinLock inode bitmap block %xh ...\n",
                         Vcb->GroupDesc[Group].bg_inode_bitmap ));
        Status = STATUS_CANT_WAIT;
        DbgBreak();
        goto errorout;
    }

    RtlInitializeBitMap(&InodeBitmap, BitmapCache, Length);
    dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);

    if (dwInode == 0xFFFFFFFF || dwInode >= Length) {

        CcUnpinData(BitmapBcb);
        BitmapBcb = NULL;
        BitmapCache = NULL;
        RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
        if (Vcb->GroupDesc[Group].bg_free_inodes_count > 0) {
            Vcb->GroupDesc[Group].bg_free_inodes_count = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -