Merge branch 'master' of git://localhost/acess2
[tpg/acess2.git] / KernelLand / Modules / Filesystems / Ext2 / ext2.c
index 5c9f97a..adf9163 100644 (file)
@@ -10,6 +10,9 @@
 #include "ext2_common.h"\r
 #include <modules.h>\r
 \r
+#define MIN_BLOCKS_PER_GROUP   2\r
+#define MAX_BLOCK_LOG_SIZE     10      // 1024 << 10 = 1MiB\r
+\r
 // === IMPORTS ===\r
 extern tVFS_NodeType   gExt2_DirType;\r
 \r
@@ -92,7 +95,7 @@ int Ext2_Detect(int FD)
 */\r
 tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)\r
 {\r
-       tExt2_Disk      *disk;\r
+       tExt2_Disk      *disk = NULL;\r
         int    fd;\r
         int    groupCount;\r
        tExt2_SuperBlock        sb;\r
@@ -115,11 +118,15 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        if(sb.s_magic != 0xEF53) {\r
                Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume (0x%x != 0xEF53)",\r
                        Device, sb.s_magic);\r
-               VFS_Close(fd);\r
-               LEAVE('n');\r
-               return NULL;\r
+               goto _error;\r
        }\r
-       \r
+\r
+       if( sb.s_blocks_per_group < MIN_BLOCKS_PER_GROUP ) {\r
+               Log_Warning("Ext2", "Blocks per group is too small (%i < %i)",\r
+                       sb.s_blocks_per_group, MIN_BLOCKS_PER_GROUP);\r
+               goto _error;\r
+       }       \r
+\r
        // Get Group count\r
        groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
        LOG("groupCount = %i", groupCount);\r
@@ -128,9 +135,7 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
        if(!disk) {\r
                Log_Warning("EXT2", "Unable to allocate disk structure");\r
-               VFS_Close(fd);\r
-               LEAVE('n');\r
-               return NULL;\r
+               goto _error;\r
        }\r
        disk->FD = fd;\r
        memcpy(&disk->SuperBlock, &sb, 1024);\r
@@ -140,6 +145,11 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        disk->CacheID = Inode_GetHandle();\r
        \r
        // Get Block Size\r
+       if( sb.s_log_block_size > MAX_BLOCK_LOG_SIZE ) {\r
+               Log_Warning("Ext2", "Block size (log2) too large (%i > %i)",\r
+                       sb.s_log_block_size, MAX_BLOCK_LOG_SIZE);\r
+               goto _error;\r
+       }\r
        disk->BlockSize = 1024 << sb.s_log_block_size;\r
        LOG("Disk->BlockSie = 0x%x (1024 << %i)", disk->BlockSize, sb.s_log_block_size);\r
        \r
@@ -186,6 +196,12 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)
        \r
        LEAVE('p', &disk->RootNode);\r
        return &disk->RootNode;\r
+_error:\r
+       if( disk )\r
+               free(disk);\r
+       VFS_Close(fd);\r
+       LEAVE('n');\r
+       return NULL;\r
 }\r
 \r
 /**\r
@@ -209,29 +225,40 @@ void Ext2_Unmount(tVFS_Node *Node)
 void Ext2_CloseFile(tVFS_Node *Node)\r
 {\r
        tExt2_Disk      *disk = Node->ImplPtr;\r
+       ENTER("pNode", Node);\r
 \r
        if( Mutex_Acquire(&Node->Lock) != 0 )\r
        {\r
+               LEAVE('-');\r
                return ;\r
        }\r
 \r
        if( Node->Flags & VFS_FFLAG_DIRTY )\r
        {\r
                // Commit changes\r
+               Log_Warning("Ext2", "TODO: Commit node changes");\r
        }\r
 \r
        int was_not_referenced = (Node->ImplInt == 0);\r
        tVFS_ACL        *acls = Node->ACLs;\r
-       if( Inode_UncacheNode(disk->CacheID, Node->Inode) )\r
+       if( Inode_UncacheNode(disk->CacheID, Node->Inode) == 1 )\r
        {\r
                if( was_not_referenced )\r
                {\r
+                       LOG("Removng inode");\r
                        // Remove inode\r
+                       Log_Warning("Ext2", "TODO: Remove inode when not referenced");\r
                }\r
                if( acls != &gVFS_ACL_EveryoneRW ) {\r
                        free(acls);\r
                }\r
+               LOG("Node cleaned");\r
+       }\r
+       else {\r
+               LOG("Still referenced, releasing lock");\r
+               Mutex_Release(&Node->Lock);\r
        }\r
+       LEAVE('-');\r
        return ;\r
 }\r
 \r
@@ -355,8 +382,67 @@ Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
  */\r
 Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
 {\r
-//     Uint    block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
-       Log_Warning("EXT2", "Ext2_int_AllocateInode is unimplemented");\r
+       Uint    start_group = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
+       Uint    group = start_group;\r
+\r
+       if( Disk->SuperBlock.s_free_inodes_count == 0 ) \r
+       {\r
+               Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p", Disk);\r
+               return 0;\r
+       }\r
+\r
+       while( group < Disk->GroupCount && Disk->Groups[group].bg_free_inodes_count == 0 )\r
+               group ++;\r
+       if( group == Disk->GroupCount )\r
+       {\r
+               group = 0;\r
+               while( group < start_group && Disk->Groups[group].bg_free_inodes_count == 0 )\r
+                       group ++;\r
+       }\r
+       \r
+       if( Disk->Groups[group].bg_free_inodes_count == 0 )\r
+       {\r
+               Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p, but superblock says some free", Disk);\r
+               return 0;\r
+       }\r
+\r
+       // Load bitmap for group\r
+       //  (s_inodes_per_group / 8) bytes worth\r
+       // - Allocate a buffer the size of a sector/block\r
+       // - Read in part of the bitmap\r
+       // - Search for a free inode\r
+       tExt2_Group     *bg = &Disk->Groups[group];\r
+        int    ofs = 0;\r
+       do {\r
+               const int sector_size = 512;\r
+               Uint8 buf[sector_size];\r
+               VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
+\r
+               int byte, bit;\r
+               for( byte = 0; byte < sector_size && buf[byte] != 0xFF; byte ++ )\r
+                       ;\r
+               if( byte < sector_size )\r
+               {\r
+                       for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++)\r
+                               ;\r
+                       ASSERT(bit != 8);\r
+                       buf[byte] |= 1 << bit;\r
+                       VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
+\r
+                       bg->bg_free_inodes_count --;\r
+                       Disk->SuperBlock.s_free_inodes_count --;\r
+\r
+                       Uint32  ret = group * Disk->SuperBlock.s_inodes_per_group + byte * 8 + bit + 1;\r
+                       Log_Debug("Ext2", "Ext2_int_AllocateInode - Allocated 0x%x", ret);\r
+                       return ret;\r
+               }\r
+\r
+               ofs += sector_size;\r
+       } while(ofs < Disk->SuperBlock.s_inodes_per_group / 8);\r
+\r
+       Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes in group %p:%i but header reported free",\r
+               Disk, group);\r
+\r
        return 0;\r
 }\r
 \r
@@ -365,7 +451,7 @@ Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)
  */\r
 void Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode)\r
 {\r
-       \r
+       Log_Warning("Ext2", "TODO: Impliment Ext2_int_DereferenceInode");\r
 }\r
 \r
 /**\r

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