#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
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
}\r
\r
/**\r
- \fn tVFS_Node *Ext2_initDevice(char *Device, char **Options)\r
+ \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
\brief Initializes a device to be read by by the driver\r
\param Device String - Device to read from\r
\param Options NULL Terminated array of option strings\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'", Device);\r
LEAVE('n');\r
return NULL;\r
}\r
\r
// Sanity Check Magic value\r
if(sb.s_magic != 0xEF53) {\r
- Warning("[EXT2 ] Volume '%s' is not an EXT2 volume\n", Device);\r
+ Warning("[EXT2 ] Volume '%s' is not an EXT2 volume", Device);\r
VFS_Close(fd);\r
LEAVE('n');\r
return NULL;\r
// Allocate Disk Information\r
disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
if(!disk) {\r
- Warning("[EXT2 ] Unable to allocate disk structure\n");\r
+ Warning("[EXT2 ] Unable to allocate disk structure");\r
VFS_Close(fd);\r
LEAVE('n');\r
return NULL;\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
+ Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);\r
LEAVE('i', 0);\r
return 0;\r
}\r
{\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
+ Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);\r
LEAVE('i', 0);\r
return 0;\r
}\r
}\r
\r
/**\r
- * \fn void Ext2_CloseFile(vfs_node *Node)\r
+ * \fn void Ext2_CloseFile(tVFS_Node *Node)\r
* \brief Close a file (Remove it from the cache)\r
*/\r
void Ext2_CloseFile(tVFS_Node *Node)\r
Ext2_int_GetInode(Node, &inode);\r
size = inode.i_size;\r
\r
- LOG("inode.i_block[0] = 0x%x\n", inode.i_block[0]);\r
+ LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
\r
// Find Entry\r
// Get First Block\r
if(ofs >= disk->BlockSize) {\r
block ++;\r
if( ofs > disk->BlockSize ) {\r
- Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring\n",\r
+ Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring",\r
entNum-1, Node->Inode);\r
}\r
ofs = 0;\r
}\r
}\r
\r
- if(size <= 0) return NULL;\r
+ // Check for the end of the list\r
+ if(size <= 0) {\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
\r
// Read Entry\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
+ //LOG("dirent.inode = %i", dirent.inode);\r
+ //LOG("dirent.rec_len = %i", dirent.rec_len);\r
+ //LOG("dirent.name_len = %i", 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
if(ofs >= disk->BlockSize) {\r
block ++;\r
if( ofs > disk->BlockSize ) {\r
- Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring\n",\r
+ Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring",\r
entNum-1, Node->Inode);\r
}\r
ofs = 0;\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
- \param inode Destination\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
// Regular File\r
case EXT2_S_IFREG:\r
retNode.Flags = 0;\r
+ retNode.Size |= (Uint64)inode.i_dir_acl << 32;\r
break;\r
// Directory\r
case EXT2_S_IFDIR:\r
{\r
int group, subId;\r
\r
- //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)\n", Disk, InodeId, Inode);\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
\r
group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
\r
- //LogF(" Ext2_int_ReadInode: group=%i, subId = %i\n", group, subId);\r
+ //LOG("group=%i, subId = %i", group, subId);\r
\r
// Read Inode\r
VFS_ReadAt(Disk->FD,\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