Modules/Ext2 - Bugfixing to write support
[tpg/acess2.git] / KernelLand / Modules / Filesystems / Ext2 / ext2.c
1 /*\r
2  * Acess2 Ext2 Driver\r
3  * - By John Hodge (thePowersGang)\r
4  *\r
5  * ext2.c\r
6  * - Driver core\r
7  */\r
8 #define DEBUG   0\r
9 #define VERSION VER2(0,90)\r
10 #include "ext2_common.h"\r
11 #include <modules.h>\r
12 \r
13 #define MIN_BLOCKS_PER_GROUP    2\r
14 #define MAX_BLOCK_LOG_SIZE      10      // 1024 << 10 = 1MiB\r
15 \r
16 // === PROTOTYPES ===\r
17  int    Ext2_Install(char **Arguments);\r
18  int    Ext2_Cleanup(void);\r
19 // - Interface Functions\r
20  int    Ext2_Detect(int FD);\r
21 tVFS_Node       *Ext2_InitDevice(const char *Device, const char **Options);\r
22 void    Ext2_Unmount(tVFS_Node *Node);\r
23 void    Ext2_CloseFile(tVFS_Node *Node);\r
24 // - Internal Helpers\r
25  int    Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
26 Uint64  Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
27 Uint32  Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
28 void    Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode);\r
29 void    Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
30 \r
31 // === SEMI-GLOBALS ===\r
32 MODULE_DEFINE(0, VERSION, FS_Ext2, Ext2_Install, Ext2_Cleanup);\r
33 tExt2_Disk      gExt2_disks[6];\r
34  int    giExt2_count = 0;\r
35 tVFS_Driver     gExt2_FSInfo = {\r
36         .Name = "ext2",\r
37         .Detect = Ext2_Detect,\r
38         .InitDevice = Ext2_InitDevice,\r
39         .Unmount = Ext2_Unmount,\r
40         .GetNodeFromINode = NULL\r
41         };\r
42 \r
43 // === CODE ===\r
44 /**\r
45  * \fn int Ext2_Install(char **Arguments)\r
46  * \brief Install the Ext2 Filesystem Driver\r
47  */\r
48 int Ext2_Install(char **Arguments)\r
49 {\r
50         VFS_AddDriver( &gExt2_FSInfo );\r
51         return MODULE_ERR_OK;\r
52 }\r
53 \r
54 /**\r
55  * \brief Clean up driver state before unload\r
56  */\r
57 int Ext2_Cleanup(void)\r
58 {\r
59         return 0;\r
60 }\r
61 \r
62 /**\r
63  * Detect if a volume is Ext2 formatted\r
64  */\r
65 int Ext2_Detect(int FD)\r
66 {\r
67         tExt2_SuperBlock        sb;\r
68         size_t  len;\r
69         \r
70         len = VFS_ReadAt(FD, 1024, 1024, &sb);\r
71 \r
72         if( len != 1024 ) {\r
73                 Log_Debug("Ext2", "_Detect: Read failed? (0x%x != 1024)", len);\r
74                 return 0;\r
75         }\r
76         \r
77         switch(sb.s_magic)\r
78         {\r
79         case 0xEF53:\r
80                 return 2;\r
81         default:\r
82                 Log_Debug("Ext2", "_Detect: s_magic = 0x%x", sb.s_magic);\r
83                 return 0;\r
84         }\r
85 }\r
86 \r
87 /**\r
88  \brief Initializes a device to be read by by the driver\r
89  \param Device  String - Device to read from\r
90  \param Options NULL Terminated array of option strings\r
91  \return Root Node\r
92 */\r
93 tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)\r
94 {\r
95         tExt2_Disk      *disk = NULL;\r
96          int    fd;\r
97          int    groupCount;\r
98         tExt2_SuperBlock        sb;\r
99         tExt2_Inode     inode;\r
100         \r
101         ENTER("sDevice pOptions", Device, Options);\r
102         \r
103         // Open Disk\r
104         fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);            //Open Device\r
105         if(fd == -1) {\r
106                 Log_Warning("EXT2", "Unable to open '%s'", Device);\r
107                 LEAVE('n');\r
108                 return NULL;\r
109         }\r
110         \r
111         // Read Superblock at offset 1024\r
112         VFS_ReadAt(fd, 1024, 1024, &sb);        // Read Superblock\r
113         \r
114         // Sanity Check Magic value\r
115         if(sb.s_magic != 0xEF53) {\r
116                 Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume (0x%x != 0xEF53)",\r
117                         Device, sb.s_magic);\r
118                 goto _error;\r
119         }\r
120 \r
121         if( sb.s_blocks_per_group < MIN_BLOCKS_PER_GROUP ) {\r
122                 Log_Warning("Ext2", "Blocks per group is too small (%i < %i)",\r
123                         sb.s_blocks_per_group, MIN_BLOCKS_PER_GROUP);\r
124                 goto _error;\r
125         }       \r
126 \r
127         // Get Group count\r
128         groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
129         LOG("groupCount = %i", groupCount);\r
130         \r
131         // Allocate Disk Information\r
132         disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
133         if(!disk) {\r
134                 Log_Warning("EXT2", "Unable to allocate disk structure");\r
135                 goto _error;\r
136         }\r
137         disk->FD = fd;\r
138         memcpy(&disk->SuperBlock, &sb, 1024);\r
139         disk->GroupCount = groupCount;\r
140         \r
141         // Get an inode cache handle\r
142         disk->CacheID = Inode_GetHandle(NULL);\r
143         \r
144         // Get Block Size\r
145         if( sb.s_log_block_size > MAX_BLOCK_LOG_SIZE ) {\r
146                 Log_Warning("Ext2", "Block size (log2) too large (%i > %i)",\r
147                         sb.s_log_block_size, MAX_BLOCK_LOG_SIZE);\r
148                 goto _error;\r
149         }\r
150         disk->BlockSize = 1024 << sb.s_log_block_size;\r
151         LOG("Disk->BlockSie = 0x%x (1024 << %i)", disk->BlockSize, sb.s_log_block_size);\r
152         \r
153         // Read Group Information\r
154         LOG("sb,s_first_data_block = %x", sb.s_first_data_block);\r
155         VFS_ReadAt(\r
156                 disk->FD,\r
157                 sb.s_first_data_block * disk->BlockSize + 1024,\r
158                 sizeof(tExt2_Group)*groupCount,\r
159                 disk->Groups\r
160                 );\r
161         \r
162         LOG("Block Group 0");\r
163         LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
164         LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
165         LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);\r
166         LOG("Block Group 1");\r
167         LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
168         LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
169         LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
170         \r
171         // Get root Inode\r
172         Ext2_int_ReadInode(disk, 2, &inode);\r
173         \r
174         // Create Root Node\r
175         memset(&disk->RootNode, 0, sizeof(tVFS_Node));\r
176         disk->RootNode.Inode = 2;       // Root inode ID\r
177         disk->RootNode.ImplPtr = disk;  // Save disk pointer\r
178         disk->RootNode.Size = -1;       // Fill in later (on readdir)\r
179         disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
180 \r
181         disk->RootNode.Type = &gExt2_DirType;\r
182         \r
183         // Complete root node\r
184         disk->RootNode.UID = inode.i_uid;\r
185         disk->RootNode.GID = inode.i_gid;\r
186         disk->RootNode.NumACLs = 1;\r
187         disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;\r
188         \r
189         #if DEBUG\r
190         LOG("inode.i_size = 0x%x", inode.i_size);\r
191         LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
192         #endif\r
193         \r
194         LEAVE('p', &disk->RootNode);\r
195         return &disk->RootNode;\r
196 _error:\r
197         if( disk )\r
198                 free(disk);\r
199         VFS_Close(fd);\r
200         LEAVE('n');\r
201         return NULL;\r
202 }\r
203 \r
204 /**\r
205  * \fn void Ext2_Unmount(tVFS_Node *Node)\r
206  * \brief Close a mounted device\r
207  */\r
208 void Ext2_Unmount(tVFS_Node *Node)\r
209 {\r
210         tExt2_Disk      *disk = Node->ImplPtr;\r
211         \r
212         VFS_Close( disk->FD );\r
213         Inode_ClearCache( disk->CacheID );\r
214         memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
215         free(disk);\r
216 }\r
217 \r
218 /**\r
219  * \fn void Ext2_CloseFile(tVFS_Node *Node)\r
220  * \brief Close a file (Remove it from the cache)\r
221  */\r
222 void Ext2_CloseFile(tVFS_Node *Node)\r
223 {\r
224         tExt2_Disk      *disk = Node->ImplPtr;\r
225         ENTER("pNode", Node);\r
226 \r
227         if( Mutex_Acquire(&Node->Lock) != 0 )\r
228         {\r
229                 LEAVE('-');\r
230                 return ;\r
231         }\r
232 \r
233         if( Node->Flags & VFS_FFLAG_DIRTY )\r
234         {\r
235                 // Commit changes\r
236                 Ext2_int_WritebackNode(disk, Node);\r
237                 Node->Flags &= ~VFS_FFLAG_DIRTY;\r
238         }\r
239 \r
240         int was_not_referenced = (Node->ImplInt == 0);\r
241         tVFS_ACL        *acls = Node->ACLs;\r
242         if( Inode_UncacheNode(disk->CacheID, Node->Inode) == 1 )\r
243         {\r
244                 if( was_not_referenced )\r
245                 {\r
246                         LOG("Removng inode");\r
247                         // Remove inode\r
248                         Log_Warning("Ext2", "TODO: Remove inode when not referenced (%x)", (Uint32)Node->Inode);\r
249                 }\r
250                 if( acls != &gVFS_ACL_EveryoneRW ) {\r
251                         free(acls);\r
252                 }\r
253                 LOG("Node cleaned");\r
254         }\r
255         else {\r
256                 LOG("Still referenced, releasing lock");\r
257                 Mutex_Release(&Node->Lock);\r
258         }\r
259         LEAVE('-');\r
260         return ;\r
261 }\r
262 \r
263 //==================================\r
264 //=       INTERNAL FUNCTIONS       =\r
265 //==================================\r
266 /**\r
267  * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
268  * \brief Read an inode into memory\r
269  */\r
270 int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
271 {\r
272          int    group, subId;\r
273         \r
274         ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
275         \r
276         if(InodeId == 0)        return 0;\r
277         \r
278         InodeId --;     // Inodes are numbered starting at 1\r
279         \r
280         group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
281         subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
282         \r
283         LOG("group=%i, subId = %i", group, subId);\r
284         \r
285         // Read Inode\r
286         VFS_ReadAt(Disk->FD,\r
287                 Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
288                 sizeof(tExt2_Inode),\r
289                 Inode);\r
290         \r
291         LEAVE('i', 1);\r
292         return 1;\r
293 }\r
294 \r
295 /**\r
296  * \brief Write a modified inode out to disk\r
297  */\r
298 int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode)\r
299 {\r
300          int    group, subId;\r
301         ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
302         \r
303         if(InodeId == 0) {\r
304                 LEAVE('i', 0);\r
305                 return 0;\r
306         }\r
307         \r
308         InodeId --;     // Inodes are numbered starting at 1\r
309         \r
310         group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
311         subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
312         \r
313         LOG("group=%i, subId = %i", group, subId);\r
314         \r
315         // Write Inode\r
316         VFS_WriteAt(Disk->FD,\r
317                 Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
318                 sizeof(tExt2_Inode),\r
319                 Inode\r
320                 );\r
321         \r
322         LEAVE('i', 1);\r
323         return 1;\r
324 }\r
325 \r
326 /**\r
327  * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)\r
328  * \brief Create a new VFS Node\r
329  */\r
330 tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)\r
331 {\r
332         tExt2_Inode     inode;\r
333         tVFS_Node       retNode;\r
334         tVFS_Node       *tmpNode;\r
335         \r
336         if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )\r
337                 return NULL;\r
338         \r
339         if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )\r
340                 return tmpNode;\r
341 \r
342         memset(&retNode, 0, sizeof(retNode));   \r
343         \r
344         // Set identifiers\r
345         retNode.Inode = InodeID;\r
346         retNode.ImplPtr = Disk;\r
347         retNode.ImplInt = inode.i_links_count;\r
348         if( inode.i_links_count == 0 ) {\r
349                 Log_Notice("Ext2", "Inode %p:%x is not referenced, bug?", Disk, InodeID);\r
350         }\r
351         \r
352         // Set file length\r
353         retNode.Size = inode.i_size;\r
354         \r
355         // Set Access Permissions\r
356         retNode.UID = inode.i_uid;\r
357         retNode.GID = inode.i_gid;\r
358         retNode.NumACLs = 3;\r
359         retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);\r
360         \r
361         //  Set Function Pointers\r
362         retNode.Type = &gExt2_FileType;\r
363         \r
364         switch(inode.i_mode & EXT2_S_IFMT)\r
365         {\r
366         // Symbolic Link\r
367         case EXT2_S_IFLNK:\r
368                 retNode.Flags = VFS_FFLAG_SYMLINK;\r
369                 break;\r
370         // Regular File\r
371         case EXT2_S_IFREG:\r
372                 retNode.Flags = 0;\r
373                 retNode.Size |= (Uint64)inode.i_dir_acl << 32;\r
374                 break;\r
375         // Directory\r
376         case EXT2_S_IFDIR:\r
377                 retNode.Type = &gExt2_DirType;\r
378                 retNode.Flags = VFS_FFLAG_DIRECTORY;\r
379                 retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );\r
380                 break;\r
381         // Unknown, Write protect it to be safe \r
382         default:\r
383                 retNode.Flags = VFS_FFLAG_READONLY;\r
384                 break;\r
385         }\r
386         \r
387         // Set Timestamps\r
388         retNode.ATime = inode.i_atime * 1000;\r
389         retNode.MTime = inode.i_mtime * 1000;\r
390         retNode.CTime = inode.i_ctime * 1000;\r
391         \r
392         // Save in node cache and return saved node\r
393         return Inode_CacheNode(Disk->CacheID, &retNode);\r
394 }\r
395 \r
396 int Ext2_int_WritebackNode(tExt2_Disk *Disk, tVFS_Node *Node)\r
397 {\r
398         tExt2_Inode     inode = {0};\r
399 \r
400         if( Disk != Node->ImplPtr ) {\r
401                 Log_Error("Ext2", "Ext2_int_WritebackNode - Disk != Node->ImplPtr");\r
402                 return -1;\r
403         }\r
404         \r
405         if( Node->Flags & VFS_FFLAG_SYMLINK ) {\r
406                 inode.i_mode = EXT2_S_IFLNK;\r
407         }\r
408         else if( Node->Flags & VFS_FFLAG_DIRECTORY ) {\r
409                 inode.i_mode = EXT2_S_IFDIR;\r
410         }\r
411         else if( Node->Flags & VFS_FFLAG_READONLY ) {\r
412                 Log_Notice("Ext2", "Not writing back readonly inode %p:%x", Disk, Node->Inode);\r
413                 return 1;\r
414         }\r
415         else {\r
416                 inode.i_mode = EXT2_S_IFREG;\r
417                 inode.i_dir_acl = Node->Size >> 32;\r
418         }\r
419 \r
420         inode.i_size = Node->Size & 0xFFFFFFFF;\r
421         inode.i_links_count = Node->ImplInt;\r
422 \r
423         inode.i_uid = Node->UID;\r
424         inode.i_gid = Node->GID;\r
425 \r
426         inode.i_atime = Node->ATime / 1000;\r
427         inode.i_mtime = Node->MTime / 1000;\r
428         inode.i_ctime = Node->CTime / 1000;\r
429 \r
430         // TODO: Compact ACLs into unix mode\r
431         Log_Warning("Ext2", "TODO: Support converting Acess ACLs into unix modes");\r
432 \r
433         Ext2_int_WriteInode(Disk, Node->Inode, &inode);\r
434 \r
435         return 0;\r
436 }\r
437 \r
438 /**\r
439  * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
440  * \brief Get the address of a block from an inode's list\r
441  * \param Disk  Disk information structure\r
442  * \param Blocks        Pointer to an inode's block list\r
443  * \param BlockNum      Block index in list\r
444  */\r
445 Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
446 {\r
447         Uint32  *iBlocks;\r
448          int    dwPerBlock = Disk->BlockSize / 4;\r
449         \r
450         // Direct Blocks\r
451         if(BlockNum < 12)\r
452                 return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
453         \r
454         // Single Indirect Blocks\r
455         iBlocks = malloc( Disk->BlockSize );\r
456         VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
457         \r
458         BlockNum -= 12;\r
459         if(BlockNum < dwPerBlock)\r
460         {\r
461                 BlockNum = iBlocks[BlockNum];\r
462                 free(iBlocks);\r
463                 return (Uint64)BlockNum * Disk->BlockSize;\r
464         }\r
465         \r
466         BlockNum -= dwPerBlock;\r
467         // Double Indirect Blocks\r
468         if(BlockNum < dwPerBlock*dwPerBlock)\r
469         {\r
470                 VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
471                 VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
472                 BlockNum = iBlocks[BlockNum%dwPerBlock];\r
473                 free(iBlocks);\r
474                 return (Uint64)BlockNum * Disk->BlockSize;\r
475         }\r
476         \r
477         BlockNum -= dwPerBlock*dwPerBlock;\r
478         // Triple Indirect Blocks\r
479         VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
480         VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
481         VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
482         BlockNum = iBlocks[BlockNum%dwPerBlock];\r
483         free(iBlocks);\r
484         return (Uint64)BlockNum * Disk->BlockSize;\r
485 }\r
486 \r
487 /**\r
488  * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
489  * \brief Allocate an inode (from the current group preferably)\r
490  * \param Disk  EXT2 Disk Information Structure\r
491  * \param Parent        Inode ID of the parent (used to locate the child nearby)\r
492  */\r
493 Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
494 {\r
495         Uint    start_group = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
496         Uint    group = start_group;\r
497 \r
498         if( Disk->SuperBlock.s_free_inodes_count == 0 ) \r
499         {\r
500                 Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p", Disk);\r
501                 return 0;\r
502         }\r
503 \r
504         while( group < Disk->GroupCount && Disk->Groups[group].bg_free_inodes_count == 0 )\r
505                 group ++;\r
506         if( group == Disk->GroupCount )\r
507         {\r
508                 group = 0;\r
509                 while( group < start_group && Disk->Groups[group].bg_free_inodes_count == 0 )\r
510                         group ++;\r
511         }\r
512         \r
513         if( Disk->Groups[group].bg_free_inodes_count == 0 )\r
514         {\r
515                 Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p, but superblock says some free", Disk);\r
516                 return 0;\r
517         }\r
518 \r
519         // Load bitmap for group\r
520         //  (s_inodes_per_group / 8) bytes worth\r
521         // - Allocate a buffer the size of a sector/block\r
522         // - Read in part of the bitmap\r
523         // - Search for a free inode\r
524         tExt2_Group     *bg = &Disk->Groups[group];\r
525          int    ofs = 0;\r
526         do {\r
527                 const int sector_size = 512;\r
528                 Uint8 buf[sector_size];\r
529                 VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
530 \r
531                 int byte, bit;\r
532                 for( byte = 0; byte < sector_size && buf[byte] == 0xFF; byte ++ )\r
533                         ;\r
534                 if( byte < sector_size )\r
535                 {\r
536                         for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++)\r
537                                 ;\r
538                         ASSERT(bit != 8);\r
539                         buf[byte] |= 1 << bit;\r
540                         VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
541 \r
542                         bg->bg_free_inodes_count --;\r
543                         Disk->SuperBlock.s_free_inodes_count --;\r
544 \r
545                         Uint32  ret = group * Disk->SuperBlock.s_inodes_per_group + byte * 8 + bit + 1;\r
546                         Log_Debug("Ext2", "Ext2_int_AllocateInode - Allocated 0x%x", ret);\r
547                         return ret;\r
548                 }\r
549 \r
550                 ofs += sector_size;\r
551         } while(ofs < Disk->SuperBlock.s_inodes_per_group / 8);\r
552 \r
553         Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes in group %p:%i but header reported free",\r
554                 Disk, group);\r
555 \r
556         return 0;\r
557 }\r
558 \r
559 /**\r
560  * \brief Reduce the reference count on an inode\r
561  */\r
562 void Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode)\r
563 {\r
564         Log_Warning("Ext2", "TODO: Impliment Ext2_int_DereferenceInode");\r
565 }\r
566 \r
567 /**\r
568  * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
569  * \brief Updates the superblock\r
570  */\r
571 void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
572 {\r
573          int    bpg = Disk->SuperBlock.s_blocks_per_group;\r
574          int    ngrp = Disk->SuperBlock.s_blocks_count / bpg;\r
575          int    i;\r
576          \r
577         // Update Primary\r
578         VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);\r
579         \r
580         // - Update block groups while we're at it\r
581         VFS_WriteAt(\r
582                 Disk->FD,\r
583                 Disk->SuperBlock.s_first_data_block * Disk->BlockSize + 1024,\r
584                 sizeof(tExt2_Group)*Disk->GroupCount,\r
585                 Disk->Groups\r
586                 );\r
587         \r
588         // Secondaries\r
589         // at Block Group 1, 3^n, 5^n, 7^n\r
590         \r
591         // 1\r
592         if(ngrp <= 1)   return;\r
593         VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
594         \r
595         #define INT_MAX (((long long int)1<<(sizeof(int)*8))-1)\r
596         \r
597         // Powers of 3\r
598         for( i = 3; i < ngrp && i < INT_MAX/3; i *= 3 )\r
599                 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
600         \r
601         // Powers of 5\r
602         for( i = 5; i < ngrp && i < INT_MAX/5; i *= 5 )\r
603                 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
604         \r
605         // Powers of 7\r
606         for( i = 7; i < ngrp && i < INT_MAX/7; i *= 7 )\r
607                 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
608 }\r

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