Added file extending to Ext2 Driver, also cleaned up the FS_Ext2 source
authorJohn Hodge <[email protected]>
Tue, 16 Mar 2010 02:20:34 +0000 (10:20 +0800)
committerJohn Hodge <[email protected]>
Tue, 16 Mar 2010 02:20:34 +0000 (10:20 +0800)
- 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
Modules/Filesystems/FS_Ext2/ext2.c
Modules/Filesystems/FS_Ext2/ext2_common.h
Modules/Filesystems/FS_Ext2/read.c
Modules/Filesystems/FS_Ext2/write.c

index 5fe8933..0ab3ed3 100644 (file)
@@ -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
index 68fd939..c2c2df9 100644 (file)
@@ -179,28 +179,14 @@ void Ext2_CloseFile(tVFS_Node *Node)
 //==================================\r
 //=       INTERNAL FUNCTIONS       =\r
 //==================================\r
-\r
-\r
-/**\r
- * \fn int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)\r
- * \brief Gets the inode descriptor for a node\r
- * \param Node node to get the Inode of\r
- * \param Inode        Destination\r
- */\r
-int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)\r
-{\r
-       return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode);\r
-}\r
-\r
 /**\r
  * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
  * \brief Read an inode into memory\r
  */\r
-int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
+int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
 {\r
         int    group, subId;\r
        \r
-       //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)", Disk, InodeId, Inode);\r
        //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
        \r
        if(InodeId == 0)        return 0;\r
@@ -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,\r
                sizeof(tExt2_Inode),\r
                Inode);\r
+       \r
+       //LEAVE('i', 1);\r
+       return 1;\r
+}\r
+\r
+/**\r
+ * \brief Write a modified inode out to disk\r
+ */\r
+int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
+{\r
+        int    group, subId;\r
+       ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
+       \r
+       if(InodeId == 0)        return 0;\r
+       \r
+       InodeId --;     // Inodes are numbered starting at 1\r
+       \r
+       group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
+       subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
+       \r
+       LOG("group=%i, subId = %i", group, subId);\r
+       \r
+       // Write Inode\r
+       VFS_WriteAt(Disk->FD,\r
+               Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
+               sizeof(tExt2_Inode),\r
+               Inode);\r
+       \r
+       LEAVE('i', 1);\r
        return 1;\r
 }\r
 \r
@@ -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)\r
 {\r
        Uint32  *iBlocks;\r
+        int    dwPerBlock = Disk->BlockSize / 4;\r
+       \r
        // Direct Blocks\r
        if(BlockNum < 12)\r
                return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
@@ -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);\r
        \r
        BlockNum -= 12;\r
-       if(BlockNum < 256) {\r
+       if(BlockNum < dwPerBlock)\r
+       {\r
                BlockNum = iBlocks[BlockNum];\r
                free(iBlocks);\r
                return (Uint64)BlockNum * Disk->BlockSize;\r
        }\r
        \r
+       BlockNum -= dwPerBlock;\r
        // Double Indirect Blocks\r
-       if(BlockNum < 256*256)\r
+       if(BlockNum < dwPerBlock*dwPerBlock)\r
        {\r
                VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-               VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-               BlockNum = iBlocks[BlockNum%256];\r
+               VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+               BlockNum = iBlocks[BlockNum%dwPerBlock];\r
                free(iBlocks);\r
                return (Uint64)BlockNum * Disk->BlockSize;\r
        }\r
+       \r
+       BlockNum -= dwPerBlock*dwPerBlock;\r
        // Triple Indirect Blocks\r
        VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(256*256)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/256)%256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
-       BlockNum = iBlocks[BlockNum%256];\r
+       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+       VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+       BlockNum = iBlocks[BlockNum%dwPerBlock];\r
        free(iBlocks);\r
        return (Uint64)BlockNum * Disk->BlockSize;\r
 }\r
index 2e2baba..877b71d 100644 (file)
@@ -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);
 
index cb6649a..81f5ee6 100644 (file)
@@ -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) {
index f3fdc6b..950f6d5 100644 (file)
@@ -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;
+}

UCC git Repository :: git.ucc.asn.au