Implemented Dependency resolving for compile-time modules and Updated the README
[tpg/acess2.git] / Kernel / vfs / fs / ext2.c
index 06189f8..0b60e54 100644 (file)
@@ -5,14 +5,17 @@
 /**\r
  * \file fs/ext2.c\r
  * \brief Second Extended Filesystem Driver\r
- * \todo Implement file read support\r
+ * \todo Implement file full write support\r
  */\r
 #define DEBUG  1\r
+#define VERBOSE        0\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
@@ -42,6 +45,9 @@ tVFS_Node     *Ext2_FindDir(tVFS_Node *Node, char *FileName);
 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
@@ -64,7 +70,7 @@ int Ext2_Install(char **Arguments)
 }\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
@@ -78,10 +84,13 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
        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'", Device);\r
+               LEAVE('n');\r
                return NULL;\r
        }\r
        \r
@@ -90,17 +99,24 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
        \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
        }\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
+       if(!disk) {\r
+               Warning("[EXT2 ] Unable to allocate disk structure");\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
@@ -109,24 +125,26 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
        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 VERBOSE\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
@@ -149,11 +167,12 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
        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
@@ -183,17 +202,33 @@ Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
        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", 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
+               LEAVE('X', Length);\r
                return Length;\r
        }\r
        \r
@@ -208,6 +243,11 @@ Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
        while(remLen > disk->BlockSize)\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", 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
@@ -218,6 +258,7 @@ Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
        base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
        VFS_ReadAt( disk->FD, base, remLen, Buffer);\r
        \r
+       LEAVE('X', Length);\r
        return Length;\r
 }\r
 \r
@@ -235,18 +276,25 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
        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
@@ -255,7 +303,7 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
                // 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
+                       if(!bNewBlocks) return Length;\r
                        goto addBlocks; // Ugh! A goto, but it seems unavoidable\r
                }\r
                \r
@@ -278,7 +326,7 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
                // 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
+               if(!bNewBlocks) return Length;  // Writing in only allocated space\r
        }\r
        \r
 addBlocks:\r
@@ -289,7 +337,7 @@ addBlocks:
 }\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
@@ -320,7 +368,7 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
        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
@@ -336,7 +384,7 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
                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
@@ -344,13 +392,17 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
                }\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(" 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
+       //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
@@ -410,7 +462,7 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)
                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
@@ -436,12 +488,11 @@ int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
 \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
@@ -491,6 +542,7 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
        // 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
@@ -526,7 +578,8 @@ int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
 {\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
@@ -535,7 +588,7 @@ int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
        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
@@ -587,3 +640,105 @@ Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
        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

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