* \brief Second Extended Filesystem Driver\r
* \todo Implement file read support\r
*/\r
+#define DEBUG 1\r
#include <common.h>\r
#include <vfs.h>\r
+#include <modules.h>\r
#include "fs_ext2.h"\r
\r
+#define EXT2_UPDATE_WRITEBACK 1\r
+\r
// === STRUCTURES ===\r
typedef struct {\r
int FD;\r
int CacheID;\r
- vfs_node RootNode;\r
+ tVFS_Node RootNode;\r
\r
tExt2_SuperBlock SuperBlock;\r
int BlockSize;\r
} tExt2_Disk;\r
\r
// === PROTOTYPES ===\r
-//Interface Functions\r
+ int Ext2_Install(char **Arguments);\r
+// Interface Functions\r
tVFS_Node *Ext2_InitDevice(char *Device, char **Options);\r
-void Ext2_UnMount(tVFS_Node *Node);\r
+void Ext2_Unmount(tVFS_Node *Node);\r
Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
+void Ext2_CloseFile(tVFS_Node *Node);\r
char *Ext2_ReadDir(tVFS_Node *Node, int Pos);\r
tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName);\r
-tVFS_Node *Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);\r
- int Ext2_int_GetInode(vfs_node *Node, tExt2_Inode *Inode);\r
-tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name, Uint64 VfsInode);\r
+ int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);\r
+// Internal Helpers\r
+ int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name);\r
int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode);\r
Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
+Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
+Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);\r
+void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
\r
// === SEMI-GLOBALS ===\r
+MODULE_DEFINE(0, 0x5B /*v0.90*/, EXT2, Ext2_Install, NULL);\r
tExt2_Disk gExt2_disks[6];\r
int giExt2_count = 0;\r
-tVFS_Driver gExt2_FSInfo = {NULL,\r
- "ext2", 0, Ext2_InitDevice, Ext2_UnMount, NULL\r
+tVFS_Driver gExt2_FSInfo = {\r
+ "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
};\r
\r
// === CODE ===\r
\r
/**\r
- * \fn void Ext2_Install()\r
+ * \fn int Ext2_Install(char **Arguments)\r
* \brief Install the Ext2 Filesystem Driver\r
*/\r
-void Ext2_Install()\r
+int Ext2_Install(char **Arguments)\r
{\r
VFS_AddDriver( &gExt2_FSInfo );\r
+ return 1;\r
}\r
\r
/**\r
tExt2_SuperBlock sb;\r
tExt2_Inode inode;\r
\r
+ ENTER("sDevice pOptions", Device, Options);\r
+ \r
// Open Disk\r
fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device\r
if(fd == -1) {\r
- Warning"[EXT2] Unable to open '%s'\n", Device);\r
+ Warning("[EXT2 ] Unable to open '%s'\n", Device);\r
+ LEAVE('n');\r
return NULL;\r
}\r
\r
\r
// Sanity Check Magic value\r
if(sb.s_magic != 0xEF53) {\r
- WarningEx("EXT2", "Volume '%s' is not an EXT2 volume\n", Device);\r
+ Warning("[EXT2 ] Volume '%s' is not an EXT2 volume\n", Device);\r
VFS_Close(fd);\r
+ LEAVE('n');\r
return NULL;\r
}\r
\r
// Get Group count\r
groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
- //LogF(" Ext2_initDevice: groupCount = %i\n", groupCount);\r
+ LOG("groupCount = %i", groupCount);\r
\r
// Allocate Disk Information\r
disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
- disk->fd = fd;\r
+ if(!disk) {\r
+ Warning("[EXT2 ] Unable to allocate disk structure\n");\r
+ VFS_Close(fd);\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
+ disk->FD = fd;\r
memcpy(&disk->SuperBlock, &sb, 1024);\r
disk->GroupCount = groupCount;\r
\r
disk->CacheID = Inode_GetHandle();\r
\r
// Get Block Size\r
- //LogF(" Ext2_initDevice: s_log_block_size = 0x%x\n", sb.s_log_block_size);\r
+ LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
disk->BlockSize = 1024 << sb.s_log_block_size;\r
\r
// Read Group Information\r
- VFS_ReadAt(disk->fd,\r
+ VFS_ReadAt(\r
+ disk->FD,\r
sb.s_first_data_block * disk->BlockSize + 1024,\r
sizeof(tExt2_Group)*groupCount,\r
- disk->Groups);\r
- \r
- #if 0\r
- Log(" Ext2_initDevice: Block Group 0\n");\r
- Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[0].bg_block_bitmap);\r
- Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[0].bg_inode_bitmap);\r
- Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[0].bg_inode_table);\r
- Log(" Ext2_initDevice: Block Group 1\n");\r
- Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[1].bg_block_bitmap);\r
- Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[1].bg_inode_bitmap);\r
- Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[1].bg_inode_table);\r
+ disk->Groups\r
+ );\r
+ \r
+ #if DEBUG\r
+ LOG("Block Group 0");\r
+ LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
+ LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
+ LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);\r
+ LOG("Block Group 1");\r
+ LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
+ LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
+ LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
#endif\r
\r
// Get root Inode\r
Ext2_int_ReadInode(disk, 2, &inode);\r
\r
// Create Root Node\r
- memset(&disk->RootNode, 0, sizeof(vfs_node));\r
+ memset(&disk->RootNode, 0, sizeof(tVFS_Node));\r
disk->RootNode.Inode = 2; // Root inode ID\r
disk->RootNode.ImplPtr = disk; // Save disk pointer\r
disk->RootNode.Size = -1; // Fill in later (on readdir)\r
disk->RootNode.NumACLs = 1;\r
disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;\r
\r
- #if 0\r
- Log(" Ext2_InitDevice: inode.i_size = 0x%x\n", inode.i_size);\r
- Log(" Ext2_InitDevice: inode.i_block[0] = 0x%x\n", inode.i_block[0]);\r
+ #if DEBUG\r
+ LOG("inode.i_size = 0x%x", inode.i_size);\r
+ LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
#endif\r
\r
+ LEAVE('p', &disk->RootNode);\r
return &disk->RootNode;\r
}\r
\r
{\r
tExt2_Disk *disk = Node->ImplPtr;\r
\r
- VFS_Close( disk->fd );\r
+ VFS_Close( disk->FD );\r
Inode_ClearCache( disk->CacheID );\r
memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
free(disk);\r
Uint block;\r
Uint64 remLen;\r
\r
+ ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);\r
+ \r
// Get Inode\r
Ext2_int_GetInode(Node, &inode);\r
\r
+ // Sanity Checks\r
+ if(Offset >= inode.i_size) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ if(Offset + Length > inode.i_size)\r
+ Length = inode.i_size - Offset;\r
+ \r
block = Offset / disk->BlockSize;\r
Offset = Offset / disk->BlockSize;\r
base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
+ if(base == 0) {\r
+ Warning("[EXT2 ] NULL Block Detected in INode 0x%llx\n", Node->Inode);\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
\r
// Read only block\r
if(Length <= disk->BlockSize - Offset)\r
{\r
- VFS_ReadAt( disk->fd, base+Offset, Length, Buffer);\r
+ VFS_ReadAt( disk->FD, base+Offset, Length, Buffer);\r
+ LEAVE('X', Length);\r
return Length;\r
}\r
\r
// Read first block\r
remLen = Length;\r
- VFS_ReadAt( disk->fd, base + Offset, disk->BlockSize - Offset, Buffer);\r
+ VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer);\r
remLen -= disk->BlockSize - Offset;\r
Buffer += disk->BlockSize - Offset;\r
block ++;\r
while(remLen > disk->BlockSize)\r
{\r
base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
- VFS_ReadAt( disk->fd, base, disk->BlockSize, Buffer);\r
+ if(base == 0) {\r
+ Warning("[EXT2 ] NULL Block Detected in INode 0x%llx\n", Node->Inode);\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer);\r
Buffer += disk->BlockSize;\r
remLen -= disk->BlockSize;\r
block ++;\r
\r
// Read last block\r
base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
- VFS_ReadAt( disk->fd, base, remLen, Buffer);\r
+ VFS_ReadAt( disk->FD, base, remLen, Buffer);\r
\r
+ LEAVE('X', Length);\r
return Length;\r
}\r
\r
Uint64 allocSize;\r
int bNewBlocks = 0;\r
\r
+ Debug_HexDump("Ext2_Write", Buffer, Length);\r
+ \r
Ext2_int_GetInode(Node, &inode);\r
\r
- // Round size up to block size\r
- // block size is a power of two, so this will work\r
+ // Get the ammount of space already allocated\r
+ // - Round size up to block size\r
+ // - block size is a power of two, so this will work\r
allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1);\r
+ \r
+ // Are we writing to inside the allocated space?\r
if( Offset < allocSize )\r
{\r
+ // Will we go out of it?\r
if(Offset + Length > allocSize) {\r
bNewBlocks = 1;\r
retLen = allocSize - Offset;\r
} else\r
retLen = Length;\r
+ \r
// Within the allocated space\r
block = Offset / disk->BlockSize;\r
Offset %= disk->BlockSize;\r
\r
// Write only block (if only one)\r
if(Offset + retLen <= disk->BlockSize) {\r
- VFS_WriteAt(disk->fd, base+Offset, retLen, Buffer);\r
- if(bNewBlocks) return Length;\r
+ VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);\r
+ if(!bNewBlocks) return Length;\r
goto addBlocks; // Ugh! A goto, but it seems unavoidable\r
}\r
\r
// Write First Block\r
- VFS_WriteAt(disk->fd, base+Offset, disk->BlockSize-Offset, Buffer);\r
+ VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);\r
Buffer += disk->BlockSize-Offset;\r
retLen -= disk->BlockSize-Offset;\r
block ++;\r
while(retLen > disk->BlockSize)\r
{\r
base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
- VFS_WriteAt(disk->fd, base, disk->BlockSize, Buffer);\r
+ VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);\r
Buffer += disk->BlockSize;\r
retLen -= disk->BlockSize;\r
block ++;\r
\r
// Write last block\r
base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
- VFS_WriteAt(disk->fd, base, retLen, Buffer);\r
- if(bNewBlocks) return Length; // Writing in only allocated space\r
+ VFS_WriteAt(disk->FD, base, retLen, Buffer);\r
+ if(!bNewBlocks) return Length; // Writing in only allocated space\r
}\r
\r
addBlocks:\r
///\todo Implement block allocation\r
- WarningEx("EXT2", "File extending is not yet supported");\r
+ Warning("[EXT2] File extending is not yet supported");\r
\r
return 0;\r
}\r
\r
/**\r
- * \fn int Ext2_CloseFile(vfs_node *Node)\r
+ * \fn void Ext2_CloseFile(vfs_node *Node)\r
* \brief Close a file (Remove it from the cache)\r
*/\r
-int Ext2_CloseFile(tVFS_Node *Node)\r
+void Ext2_CloseFile(tVFS_Node *Node)\r
{\r
tExt2_Disk *disk = Node->ImplPtr;\r
- inode_uncacheNode(disk->CacheID, Node->impl);\r
- return 1;\r
+ Inode_UncacheNode(disk->CacheID, Node->Inode);\r
+ return ;\r
}\r
\r
/**\r
int block = 0, ofs = 0;\r
int entNum = 0;\r
tExt2_Disk *disk = Node->ImplPtr;\r
- Uint64 vfsInode = 0;\r
- tVFS_Node *retNode;\r
Uint size;\r
\r
ENTER("pNode iPos", Node, Pos);\r
Base = inode.i_block[0] * disk->BlockSize;\r
while(Pos -- && size > 0)\r
{\r
- VFS_ReadAt( disk->fd, Base+ofs, sizeof(tExt2_DirEnt), &dirent);\r
+ VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);\r
ofs += dirent.rec_len;\r
size -= dirent.rec_len;\r
entNum ++;\r
if(ofs >= disk->BlockSize) {\r
block ++;\r
if( ofs > disk->BlockSize ) {\r
- Warning("[EXT2] Directory Entry %i of inode %i ('%s') extends over a block boundary, ignoring\n",\r
- entNum-1, Node->impl, Node->name);\r
+ Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring\n",\r
+ entNum-1, Node->Inode);\r
}\r
ofs = 0;\r
Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );\r
if(size <= 0) return NULL;\r
\r
// Read Entry\r
- VFS_ReadAt( disk->fd, Base+ofs, sizeof(tExt2_DirEnt), &dirent );\r
- //LOG(" Ext2_ReadDir: dirent.inode = %i\n", dirent.inode);\r
- //LOG(" Ext2_ReadDir: dirent.rec_len = %i\n", dirent.rec_len);\r
- //LOG(" Ext2_ReadDir: dirent.name_len = %i\n", dirent.name_len);\r
- VFS_ReadAt( disk->fd, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );\r
+ VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );\r
+ //LOG("dirent.inode = %i\n", dirent.inode);\r
+ //LOG("dirent.rec_len = %i\n", dirent.rec_len);\r
+ //LOG("dirent.name_len = %i\n", dirent.name_len);\r
+ VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );\r
namebuf[ dirent.name_len ] = '\0'; // Cap off string\r
\r
\r
// Ignore . and .. (these are done in the VFS)\r
if( (namebuf[0] == '.' && namebuf[1] == '\0')\r
- || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0'))\r
+ || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) {\r
LEAVE('p', VFS_SKIP);\r
return VFS_SKIP; // Skip\r
}\r
// Find File\r
while(size > 0)\r
{\r
- VFS_ReadAt( disk->fd, Base+ofs, sizeof(tExt2_DirEnt), &dirent);\r
- VFS_ReadAt( disk->fd, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );\r
+ VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);\r
+ VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );\r
namebuf[ dirent.name_len ] = '\0'; // Cap off string\r
// If it matches, create a node and return it\r
if(strcmp(namebuf, Filename) == 0)\r
if(ofs >= disk->BlockSize) {\r
block ++;\r
if( ofs > disk->BlockSize ) {\r
- Warnin("[EXT2 ] Directory Entry %i of inode %i ('%s') extends over a block boundary, ignoring\n",\r
- entNum-1, Node->impl, Node->name);\r
+ Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring\n",\r
+ entNum-1, Node->Inode);\r
}\r
ofs = 0;\r
Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );\r
}\r
\r
/**\r
- * \fn tVFS_Node *Ext2_MkNod(tVFS_Node *Parent, char *Name, int Flags)\r
+ * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)\r
* \brief Create a new node\r
*/\r
-tVFS_Node *Ext2_MkNod(tVFS_Node *Parent, char *Name, int Flags)\r
+int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)\r
{\r
return 0;\r
}\r
\r
\r
/**\r
- \internal\r
\fn int Ext2_int_GetInode(vfs_node *Node, tExt2_Inode *Inode)\r
\brief Gets the inode descriptor for a node\r
\param node node to get the Inode of\r
if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )\r
return NULL;\r
\r
- if( (tmpNode = inode_getCache(Disk->CacheID, InodeID)) )\r
+ if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )\r
return tmpNode;\r
\r
\r
break;\r
// Regular File\r
case EXT2_S_IFREG:\r
- retNode.flags = 0;\r
+ retNode.Flags = 0;\r
+ retNode.Size |= (Uint64)inode.i_dir_acl << 32;\r
break;\r
// Directory\r
case EXT2_S_IFDIR:\r
- retNode.ReadRir = Ext2_ReadDir;\r
+ retNode.ReadDir = Ext2_ReadDir;\r
retNode.FindDir = Ext2_FindDir;\r
retNode.MkNod = Ext2_MkNod;\r
//retNode.Relink = Ext2_Relink;\r
break;\r
// Unknown, Write protect and hide it to be safe \r
default:\r
- retNode.flags = VFS_FFLAG_READONLY|VFS_FFLAG_HIDDEN;\r
+ retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;\r
break;\r
}\r
\r
// Check if the file should be hidden\r
- if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN;\r
+ //if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN;\r
\r
// Set Timestamps\r
retNode.ATime = now();\r
\r
//LogF(" Ext2_int_ReadInode: group=%i, subId = %i\n", group, subId);\r
\r
- //Seek to Block - Absolute\r
- vfs_seek(Disk->fd, Disk->Groups[group].bg_inode_table * Disk->BlockSize, SEEK_SET);\r
- //Seeek to inode - Relative\r
- vfs_seek(Disk->fd, sizeof(tExt2_Inode)*subId, SEEK_CUR);\r
- vfs_read(Disk->fd, sizeof(tExt2_Inode), Inode);\r
+ // Read Inode\r
+ VFS_ReadAt(Disk->FD,\r
+ Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
+ sizeof(tExt2_Inode),\r
+ Inode);\r
return 1;\r
}\r
\r
\r
// Single Indirect Blocks\r
iBlocks = malloc( Disk->BlockSize );\r
- VFS_ReadAt(Disk->fd, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
+ VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
\r
BlockNum -= 12;\r
if(BlockNum < 256) {\r
// Double Indirect Blocks\r
if(BlockNum < 256*256)\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
+ 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
free(iBlocks);\r
return (Uint64)BlockNum * Disk->BlockSize;\r
}\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
+ 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
free(iBlocks);\r
return (Uint64)BlockNum * Disk->BlockSize;\r
}\r
+\r
+/**\r
+ * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
+ * \brief Allocate an inode (from the current group preferably)\r
+ * \param Disk EXT2 Disk Information Structure\r
+ * \param Parent Inode ID of the parent (used to locate the child nearby)\r
+ */\r
+Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
+{\r
+// Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)\r
+ * \brief Allocate a block from the best possible location\r
+ * \param Disk EXT2 Disk Information Structure\r
+ * \param PrevBlock Previous block ID in the file\r
+ */\r
+Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)\r
+{\r
+ int bpg = Disk->SuperBlock.s_blocks_per_group;\r
+ Uint blockgroup = PrevBlock / bpg;\r
+ Uint bitmap[Disk->BlockSize/sizeof(Uint)];\r
+ Uint bitsperblock = 8*Disk->BlockSize;\r
+ int i, j = 0;\r
+ Uint block;\r
+ \r
+ // Are there any free blocks?\r
+ if(Disk->SuperBlock.s_free_blocks_count == 0) return 0;\r
+ \r
+ if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)\r
+ {\r
+ // Search block group's bitmap\r
+ for(i = 0; i < bpg; i++)\r
+ {\r
+ // Get the block in the bitmap block\r
+ j = i & (bitsperblock-1);\r
+ \r
+ // Read in if needed\r
+ if(j == 0) {\r
+ VFS_ReadAt(\r
+ Disk->FD,\r
+ (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,\r
+ Disk->BlockSize,\r
+ bitmap\r
+ );\r
+ }\r
+ \r
+ // Fast Check\r
+ if( bitmap[j/32] == -1 ) {\r
+ j = (j + 31) & ~31;\r
+ continue;\r
+ }\r
+ \r
+ // Is the bit set?\r
+ if( bitmap[j/32] & (1 << (j%32)) )\r
+ continue;\r
+ \r
+ // Ooh! We found one\r
+ break;\r
+ }\r
+ if( i < bpg ) {\r
+ Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");\r
+ goto checkAll; // Search the entire filesystem for a free block\r
+ // Goto needed for neatness\r
+ }\r
+ \r
+ // Mark as used\r
+ bitmap[j/32] |= (1 << (j%32));\r
+ VFS_WriteAt(\r
+ Disk->FD,\r
+ (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,\r
+ Disk->BlockSize,\r
+ bitmap\r
+ );\r
+ block = i;\r
+ Disk->Groups[blockgroup].bg_free_blocks_count --;\r
+ }\r
+ else\r
+ {\r
+ checkAll:\r
+ Warning("[EXT2 ] TODO - Implement using blocks outside the current block group");\r
+ return 0;\r
+ }\r
+ \r
+ // Reduce global count\r
+ Disk->SuperBlock.s_free_blocks_count --;\r
+ #if EXT2_UPDATE_WRITEBACK\r
+ Ext2_int_UpdateSuperblock(Disk);\r
+ #endif\r
+ \r
+ return block;\r
+}\r
+\r
+/**\r
+ * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
+ */\r
+void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
+{\r
+ VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);\r
+}\r