From f4646f2b6d64e42d1eec1d97877ae23eac6863f6 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 16 Mar 2010 10:20:34 +0800 Subject: [PATCH] Added file extending to Ext2 Driver, also cleaned up the FS_Ext2 source - Fixed an off-by-one error when calculating allocated blocks - Fixed using a fixed 256 blocks per indirect block (now depends on the block size) --- Modules/Filesystems/FS_Ext2/dir.c | 5 +- Modules/Filesystems/FS_Ext2/ext2.c | 65 ++++--- Modules/Filesystems/FS_Ext2/ext2_common.h | 4 +- Modules/Filesystems/FS_Ext2/read.c | 3 +- Modules/Filesystems/FS_Ext2/write.c | 201 +++++++++++++++++++++- 5 files changed, 244 insertions(+), 34 deletions(-) diff --git a/Modules/Filesystems/FS_Ext2/dir.c b/Modules/Filesystems/FS_Ext2/dir.c index 5fe89336..0ab3ed39 100644 --- a/Modules/Filesystems/FS_Ext2/dir.c +++ b/Modules/Filesystems/FS_Ext2/dir.c @@ -37,7 +37,8 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) ENTER("pNode iPos", Node, Pos); // Read directory's inode - Ext2_int_GetInode(Node, &inode); + //Ext2_int_GetInode(Node, &inode); + Ext2_int_ReadInode(disk, Node->Inode, &inode); size = inode.i_size; LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); @@ -110,7 +111,7 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename) Uint size; // Read directory's inode - Ext2_int_GetInode(Node, &inode); + Ext2_int_ReadInode(disk, Node->Inode, &inode); size = inode.i_size; // Get First Block diff --git a/Modules/Filesystems/FS_Ext2/ext2.c b/Modules/Filesystems/FS_Ext2/ext2.c index 68fd939a..c2c2df9c 100644 --- a/Modules/Filesystems/FS_Ext2/ext2.c +++ b/Modules/Filesystems/FS_Ext2/ext2.c @@ -179,28 +179,14 @@ void Ext2_CloseFile(tVFS_Node *Node) //================================== //= INTERNAL FUNCTIONS = //================================== - - -/** - * \fn int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode) - * \brief Gets the inode descriptor for a node - * \param Node node to get the Inode of - * \param Inode Destination - */ -int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode) -{ - return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode); -} - /** * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) * \brief Read an inode into memory */ -int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) +int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) { int group, subId; - //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)", Disk, InodeId, Inode); //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); if(InodeId == 0) return 0; @@ -217,6 +203,35 @@ int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, sizeof(tExt2_Inode), Inode); + + //LEAVE('i', 1); + return 1; +} + +/** + * \brief Write a modified inode out to disk + */ +int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) +{ + int group, subId; + ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); + + if(InodeId == 0) return 0; + + InodeId --; // Inodes are numbered starting at 1 + + group = InodeId / Disk->SuperBlock.s_inodes_per_group; + subId = InodeId % Disk->SuperBlock.s_inodes_per_group; + + LOG("group=%i, subId = %i", group, subId); + + // Write Inode + VFS_WriteAt(Disk->FD, + Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, + sizeof(tExt2_Inode), + Inode); + + LEAVE('i', 1); return 1; } @@ -230,6 +245,8 @@ int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) { Uint32 *iBlocks; + int dwPerBlock = Disk->BlockSize / 4; + // Direct Blocks if(BlockNum < 12) return (Uint64)Blocks[BlockNum] * Disk->BlockSize; @@ -239,26 +256,30 @@ Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks); BlockNum -= 12; - if(BlockNum < 256) { + if(BlockNum < dwPerBlock) + { BlockNum = iBlocks[BlockNum]; free(iBlocks); return (Uint64)BlockNum * Disk->BlockSize; } + BlockNum -= dwPerBlock; // Double Indirect Blocks - if(BlockNum < 256*256) + if(BlockNum < dwPerBlock*dwPerBlock) { VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks); - VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/256]*Disk->BlockSize, Disk->BlockSize, iBlocks); - BlockNum = iBlocks[BlockNum%256]; + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); + BlockNum = iBlocks[BlockNum%dwPerBlock]; free(iBlocks); return (Uint64)BlockNum * Disk->BlockSize; } + + BlockNum -= dwPerBlock*dwPerBlock; // Triple Indirect Blocks VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks); - VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(256*256)]*Disk->BlockSize, Disk->BlockSize, iBlocks); - VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/256)%256]*Disk->BlockSize, Disk->BlockSize, iBlocks); - BlockNum = iBlocks[BlockNum%256]; + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks); + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); + BlockNum = iBlocks[BlockNum%dwPerBlock]; free(iBlocks); return (Uint64)BlockNum * Disk->BlockSize; } diff --git a/Modules/Filesystems/FS_Ext2/ext2_common.h b/Modules/Filesystems/FS_Ext2/ext2_common.h index 2e2babae..877b71d3 100644 --- a/Modules/Filesystems/FS_Ext2/ext2_common.h +++ b/Modules/Filesystems/FS_Ext2/ext2_common.h @@ -30,16 +30,16 @@ typedef struct { // === FUNCTIONS === // --- Common --- extern void Ext2_CloseFile(tVFS_Node *Node); -extern int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode); extern Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum); extern void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk); +extern int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode); +extern int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode); // --- Dir --- extern char *Ext2_ReadDir(tVFS_Node *Node, int Pos); extern tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName); extern int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags); // --- Read --- extern Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); -extern int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode); // --- Write --- extern Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); diff --git a/Modules/Filesystems/FS_Ext2/read.c b/Modules/Filesystems/FS_Ext2/read.c index cb6649a6..81f5ee64 100644 --- a/Modules/Filesystems/FS_Ext2/read.c +++ b/Modules/Filesystems/FS_Ext2/read.c @@ -13,7 +13,6 @@ // === PROTOTYPES === Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); - int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode); // === CODE === /** @@ -31,7 +30,7 @@ Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); // Get Inode - Ext2_int_GetInode(Node, &inode); + Ext2_int_ReadInode(disk, Node->Inode, &inode); // Sanity Checks if(Offset >= inode.i_size) { diff --git a/Modules/Filesystems/FS_Ext2/write.c b/Modules/Filesystems/FS_Ext2/write.c index f3fdc6b3..950f6d59 100644 --- a/Modules/Filesystems/FS_Ext2/write.c +++ b/Modules/Filesystems/FS_Ext2/write.c @@ -14,6 +14,8 @@ // === PROTOYPES === Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer); Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock); +void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block); + int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block); // === CODE === /** @@ -32,12 +34,12 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Debug_HexDump("Ext2_Write", Buffer, Length); - Ext2_int_GetInode(Node, &inode); + Ext2_int_ReadInode(disk, Node->Inode, &inode); // Get the ammount of space already allocated // - Round size up to block size // - block size is a power of two, so this will work - allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1); + allocSize = (inode.i_size + disk->BlockSize-1) & ~(disk->BlockSize-1); // Are we writing to inside the allocated space? if( Offset < allocSize ) @@ -84,10 +86,43 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) } addBlocks: - ///\todo Implement block allocation - Warning("[EXT2] File extending is not yet supported"); + Warning("[EXT2 ] File extending is untested"); - return 0; + // Allocate blocks and copy data to them + retLen = Length - allocSize; + while( retLen > disk->BlockSize ) + { + // Allocate a block + block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); + if(!block) return Length - retLen; + // Add it to this inode + if( !Ext2_int_AppendBlock(disk, &inode, block) ) { + Ext2_int_DeallocateBlock(disk, block); + goto ret; + } + // Copy data to the node + base = block * disk->BlockSize; + VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer); + // Update pointer and size remaining + inode.i_size += disk->BlockSize; + Buffer += disk->BlockSize; + retLen -= disk->BlockSize; + } + // Last block :D + block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); + if(!block) goto ret; + if( !Ext2_int_AppendBlock(disk, &inode, block) ) { + Ext2_int_DeallocateBlock(disk, block); + goto ret; + } + base = block * disk->BlockSize; + VFS_WriteAt(disk->FD, base, retLen, Buffer); + inode.i_size += retLen; + retLen = 0; + +ret: // Makes sure the changes to the inode are committed + Ext2_int_WriteInode(disk, Node->Inode, &inode); + return Length - retLen; } /** @@ -156,7 +191,7 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) block = i; Disk->Groups[blockgroup].bg_free_blocks_count --; #if EXT2_UPDATE_WRITEBACK - //Ext2_int_UpdateBlockGroup(blockgroup); + //Ext2_int_UpdateBlockGroup(Disk, blockgroup); #endif } else @@ -174,3 +209,157 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) return block; } + +/** + * \brief Deallocates a block + */ +void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block) +{ +} + +/** + * \brief Append a block to an inode + */ +int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) +{ + int nBlocks; + int dwPerBlock = Disk->BlockSize / 4; + Uint32 *blocks; + Uint32 id1, id2; + + nBlocks = (Inode->i_size + Disk->BlockSize - 1) / Disk->BlockSize; + + // Direct Blocks + if( nBlocks < 12 ) { + Inode->i_block[nBlocks] = Block; + return 0; + } + + blocks = malloc( Disk->BlockSize ); + if(!blocks) return 1; + + nBlocks -= 12; + // Single Indirect + if( nBlocks < dwPerBlock) + { + // Allocate/Get Indirect block + if( nBlocks == 0 ) { + Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !Inode->i_block[12] ) { + free(blocks); + return 1; + } + memset(blocks, 0, Disk->BlockSize); + } + else + VFS_ReadAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks); + + blocks[nBlocks] = Block; + + VFS_WriteAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks); + free(blocks); + return 0; + } + + nBlocks += dwPerBlock; + // Double Indirect + if( nBlocks < dwPerBlock*dwPerBlock ) + { + // Allocate/Get Indirect block + if( nBlocks == 0 ) { + Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !Inode->i_block[13] ) { + free(blocks); + return 1; + } + memset(blocks, 0, Disk->BlockSize); + } + else + VFS_ReadAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks); + + // Allocate / Get Indirect lvl2 Block + if( nBlocks % dwPerBlock == 0 ) { + id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !id1 ) { + free(blocks); + return 1; + } + blocks[nBlocks/dwPerBlock] = id1; + // Write back indirect 1 block + VFS_WriteAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks); + memset(blocks, 0, Disk->BlockSize); + } + else { + id1 = blocks[nBlocks / dwPerBlock]; + VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + } + + blocks[nBlocks % dwPerBlock] = Block; + + VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + free(blocks); + return 0; + } + + nBlocks -= dwPerBlock*dwPerBlock; + // Triple Indirect + if( nBlocks < dwPerBlock*dwPerBlock*dwPerBlock ) + { + // Allocate/Get Indirect block + if( nBlocks == 0 ) { + Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !Inode->i_block[14] ) { + free(blocks); + return 1; + } + memset(blocks, 0, Disk->BlockSize); + } + else + VFS_ReadAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks); + + // Allocate / Get Indirect lvl2 Block + if( (nBlocks/dwPerBlock) % dwPerBlock == 0 && nBlocks % dwPerBlock == 0 ) + { + id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); + if( !id1 ) { + free(blocks); + return 1; + } + blocks[nBlocks/dwPerBlock] = id1; + // Write back indirect 1 block + VFS_WriteAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks); + memset(blocks, 0, Disk->BlockSize); + } + else { + id1 = blocks[nBlocks / (dwPerBlock*dwPerBlock)]; + VFS_ReadAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + } + + // Allocate / Get Indirect Level 3 Block + if( nBlocks % dwPerBlock == 0 ) { + id2 = Ext2_int_AllocateBlock(Disk, id1); + if( !id2 ) { + free(blocks); + return 1; + } + blocks[(nBlocks/dwPerBlock)%dwPerBlock] = id2; + // Write back indirect 1 block + VFS_WriteAt(Disk->FD, id1*Disk->BlockSize, Disk->BlockSize, blocks); + memset(blocks, 0, Disk->BlockSize); + } + else { + id2 = blocks[(nBlocks/dwPerBlock)%dwPerBlock]; + VFS_ReadAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks); + } + + blocks[nBlocks % dwPerBlock] = Block; + + VFS_WriteAt(Disk->FD, id2*Disk->BlockSize, Disk->BlockSize, blocks); + free(blocks); + return 0; + } + + Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used"); + free(blocks); + return 1; +} -- 2.20.1