//==================================\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
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
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
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
// === 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 ===
/**
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 )
}
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;
}
/**
block = i;
Disk->Groups[blockgroup].bg_free_blocks_count --;
#if EXT2_UPDATE_WRITEBACK
- //Ext2_int_UpdateBlockGroup(blockgroup);
+ //Ext2_int_UpdateBlockGroup(Disk, blockgroup);
#endif
}
else
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;
+}