Various Changes
[tpg/acess2.git] / Kernel / vfs / fs / ext2.c
1 /*\r
2  * Acess OS\r
3  * Ext2 Driver Version 1\r
4  */\r
5 /**\r
6  * \file fs/ext2.c\r
7  * \brief Second Extended Filesystem Driver\r
8  * \todo Implement file read support\r
9  */\r
10 #define DEBUG   1\r
11 #include <common.h>\r
12 #include <vfs.h>\r
13 #include <modules.h>\r
14 #include "fs_ext2.h"\r
15 \r
16 // === STRUCTURES ===\r
17 typedef struct {\r
18          int    FD;\r
19          int    CacheID;\r
20         tVFS_Node       RootNode;\r
21         \r
22         tExt2_SuperBlock        SuperBlock;\r
23          int    BlockSize;\r
24          \r
25          int    GroupCount;\r
26         tExt2_Group             Groups[];\r
27 } tExt2_Disk;\r
28 \r
29 // === PROTOTYPES ===\r
30  int    Ext2_Install(char **Arguments);\r
31 // Interface Functions\r
32 tVFS_Node       *Ext2_InitDevice(char *Device, char **Options);\r
33 void            Ext2_Unmount(tVFS_Node *Node);\r
34 Uint64          Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
35 Uint64          Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
36 void            Ext2_CloseFile(tVFS_Node *Node);\r
37 char            *Ext2_ReadDir(tVFS_Node *Node, int Pos);\r
38 tVFS_Node       *Ext2_FindDir(tVFS_Node *Node, char *FileName);\r
39  int            Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);\r
40 // Internal Helpers\r
41  int            Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
42 tVFS_Node       *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name);\r
43  int            Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode);\r
44 Uint64          Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
45 \r
46 // === SEMI-GLOBALS ===\r
47 MODULE_DEFINE(0, 0x5B /*v0.90*/, EXT2, Ext2_Install, NULL);\r
48 tExt2_Disk      gExt2_disks[6];\r
49  int    giExt2_count = 0;\r
50 tVFS_Driver     gExt2_FSInfo = {\r
51         "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
52         };\r
53 \r
54 // === CODE ===\r
55 \r
56 /**\r
57  * \fn int Ext2_Install(char **Arguments)\r
58  * \brief Install the Ext2 Filesystem Driver\r
59  */\r
60 int Ext2_Install(char **Arguments)\r
61 {\r
62         VFS_AddDriver( &gExt2_FSInfo );\r
63         return 1;\r
64 }\r
65 \r
66 /**\r
67  \fn tVFS_Node *Ext2_initDevice(char *Device, char **Options)\r
68  \brief Initializes a device to be read by by the driver\r
69  \param Device  String - Device to read from\r
70  \param Options NULL Terminated array of option strings\r
71  \return Root Node\r
72 */\r
73 tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
74 {\r
75         tExt2_Disk      *disk;\r
76          int    fd;\r
77          int    groupCount;\r
78         tExt2_SuperBlock        sb;\r
79         tExt2_Inode     inode;\r
80         \r
81         // Open Disk\r
82         fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);            //Open Device\r
83         if(fd == -1) {\r
84                 Warning("[EXT2] Unable to open '%s'\n", Device);\r
85                 return NULL;\r
86         }\r
87         \r
88         // Read Superblock at offset 1024\r
89         VFS_ReadAt(fd, 1024, 1024, &sb);        // Read Superblock\r
90         \r
91         // Sanity Check Magic value\r
92         if(sb.s_magic != 0xEF53) {\r
93                 Warning("[EXT2 ] Volume '%s' is not an EXT2 volume\n", Device);\r
94                 VFS_Close(fd);\r
95                 return NULL;\r
96         }\r
97         \r
98         // Get Group count\r
99         groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
100         //LogF(" Ext2_initDevice: groupCount = %i\n", groupCount);\r
101         \r
102         // Allocate Disk Information\r
103         disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
104         disk->FD = fd;\r
105         memcpy(&disk->SuperBlock, &sb, 1024);\r
106         disk->GroupCount = groupCount;\r
107         \r
108         // Get an inode cache handle\r
109         disk->CacheID = Inode_GetHandle();\r
110         \r
111         // Get Block Size\r
112         //LogF(" Ext2_initDevice: s_log_block_size = 0x%x\n", sb.s_log_block_size);\r
113         disk->BlockSize = 1024 << sb.s_log_block_size;\r
114         \r
115         // Read Group Information\r
116         VFS_ReadAt(disk->FD,\r
117                 sb.s_first_data_block * disk->BlockSize + 1024,\r
118                 sizeof(tExt2_Group)*groupCount,\r
119                 disk->Groups);\r
120         \r
121         #if 0\r
122         Log(" Ext2_initDevice: Block Group 0\n");\r
123         Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[0].bg_block_bitmap);\r
124         Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[0].bg_inode_bitmap);\r
125         Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[0].bg_inode_table);\r
126         Log(" Ext2_initDevice: Block Group 1\n");\r
127         Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[1].bg_block_bitmap);\r
128         Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[1].bg_inode_bitmap);\r
129         Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[1].bg_inode_table);\r
130         #endif\r
131         \r
132         // Get root Inode\r
133         Ext2_int_ReadInode(disk, 2, &inode);\r
134         \r
135         // Create Root Node\r
136         memset(&disk->RootNode, 0, sizeof(tVFS_Node));\r
137         disk->RootNode.Inode = 2;       // Root inode ID\r
138         disk->RootNode.ImplPtr = disk;  // Save disk pointer\r
139         disk->RootNode.Size = -1;       // Fill in later (on readdir)\r
140         disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;\r
141         \r
142         disk->RootNode.ReadDir = Ext2_ReadDir;\r
143         disk->RootNode.FindDir = Ext2_FindDir;\r
144         //disk->RootNode.Relink = Ext2_Relink;\r
145         \r
146         // Complete root node\r
147         disk->RootNode.UID = inode.i_uid;\r
148         disk->RootNode.GID = inode.i_gid;\r
149         disk->RootNode.NumACLs = 1;\r
150         disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;\r
151         \r
152         #if 0\r
153         Log(" Ext2_InitDevice: inode.i_size = 0x%x\n", inode.i_size);\r
154         Log(" Ext2_InitDevice: inode.i_block[0] = 0x%x\n", inode.i_block[0]);\r
155         #endif\r
156         \r
157         return &disk->RootNode;\r
158 }\r
159 \r
160 /**\r
161  * \fn void Ext2_Unmount(tVFS_Node *Node)\r
162  * \brief Close a mounted device\r
163  */\r
164 void Ext2_Unmount(tVFS_Node *Node)\r
165 {\r
166         tExt2_Disk      *disk = Node->ImplPtr;\r
167         \r
168         VFS_Close( disk->FD );\r
169         Inode_ClearCache( disk->CacheID );\r
170         memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
171         free(disk);\r
172 }\r
173 \r
174 /**\r
175  * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
176  * \brief Read from a file\r
177  */\r
178 Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
179 {\r
180         tExt2_Disk      *disk = Node->ImplPtr;\r
181         tExt2_Inode     inode;\r
182         Uint64  base;\r
183         Uint    block;\r
184         Uint64  remLen;\r
185         \r
186         // Get Inode\r
187         Ext2_int_GetInode(Node, &inode);\r
188         \r
189         block = Offset / disk->BlockSize;\r
190         Offset = Offset / disk->BlockSize;\r
191         base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
192         \r
193         // Read only block\r
194         if(Length <= disk->BlockSize - Offset)\r
195         {\r
196                 VFS_ReadAt( disk->FD, base+Offset, Length, Buffer);\r
197                 return Length;\r
198         }\r
199         \r
200         // Read first block\r
201         remLen = Length;\r
202         VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer);\r
203         remLen -= disk->BlockSize - Offset;\r
204         Buffer += disk->BlockSize - Offset;\r
205         block ++;\r
206         \r
207         // Read middle blocks\r
208         while(remLen > disk->BlockSize)\r
209         {\r
210                 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
211                 VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer);\r
212                 Buffer += disk->BlockSize;\r
213                 remLen -= disk->BlockSize;\r
214                 block ++;\r
215         }\r
216         \r
217         // Read last block\r
218         base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
219         VFS_ReadAt( disk->FD, base, remLen, Buffer);\r
220         \r
221         return Length;\r
222 }\r
223 \r
224 /**\r
225  * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
226  * \brief Write to a file\r
227  */\r
228 Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
229 {\r
230         tExt2_Disk      *disk = Node->ImplPtr;\r
231         tExt2_Inode     inode;\r
232         Uint64  base;\r
233         Uint64  retLen;\r
234         Uint    block;\r
235         Uint64  allocSize;\r
236          int    bNewBlocks = 0;\r
237         \r
238         Ext2_int_GetInode(Node, &inode);\r
239         \r
240         // Round size up to block size\r
241         // block size is a power of two, so this will work\r
242         allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1);\r
243         if( Offset < allocSize )\r
244         {\r
245                 if(Offset + Length > allocSize) {\r
246                         bNewBlocks = 1;\r
247                         retLen = allocSize - Offset;\r
248                 } else\r
249                         retLen = Length;\r
250                 // Within the allocated space\r
251                 block = Offset / disk->BlockSize;\r
252                 Offset %= disk->BlockSize;\r
253                 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
254                 \r
255                 // Write only block (if only one)\r
256                 if(Offset + retLen <= disk->BlockSize) {\r
257                         VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);\r
258                         if(bNewBlocks)  return Length;\r
259                         goto addBlocks; // Ugh! A goto, but it seems unavoidable\r
260                 }\r
261                 \r
262                 // Write First Block\r
263                 VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);\r
264                 Buffer += disk->BlockSize-Offset;\r
265                 retLen -= disk->BlockSize-Offset;\r
266                 block ++;\r
267                 \r
268                 // Write middle blocks\r
269                 while(retLen > disk->BlockSize)\r
270                 {\r
271                         base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
272                         VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);\r
273                         Buffer += disk->BlockSize;\r
274                         retLen -= disk->BlockSize;\r
275                         block ++;\r
276                 }\r
277                 \r
278                 // Write last block\r
279                 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);\r
280                 VFS_WriteAt(disk->FD, base, retLen, Buffer);\r
281                 if(bNewBlocks)  return Length;  // Writing in only allocated space\r
282         }\r
283         \r
284 addBlocks:\r
285         ///\todo Implement block allocation\r
286         Warning("[EXT2] File extending is not yet supported");\r
287         \r
288         return 0;\r
289 }\r
290 \r
291 /**\r
292  * \fn void Ext2_CloseFile(vfs_node *Node)\r
293  * \brief Close a file (Remove it from the cache)\r
294  */\r
295 void Ext2_CloseFile(tVFS_Node *Node)\r
296 {\r
297         tExt2_Disk      *disk = Node->ImplPtr;\r
298         Inode_UncacheNode(disk->CacheID, Node->Inode);\r
299         return ;\r
300 }\r
301 \r
302 /**\r
303  \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos)\r
304  \brief Reads a directory entry\r
305 */\r
306 char *Ext2_ReadDir(tVFS_Node *Node, int Pos)\r
307 {\r
308         tExt2_Inode     inode;\r
309         char    namebuf[EXT2_NAME_LEN+1];\r
310         tExt2_DirEnt    dirent;\r
311         Uint64  Base;   // Block's Base Address\r
312          int    block = 0, ofs = 0;\r
313          int    entNum = 0;\r
314         tExt2_Disk      *disk = Node->ImplPtr;\r
315         Uint    size;\r
316         \r
317         ENTER("pNode iPos", Node, Pos);\r
318         \r
319         // Read directory's inode\r
320         Ext2_int_GetInode(Node, &inode);\r
321         size = inode.i_size;\r
322         \r
323         LOG("inode.i_block[0] = 0x%x\n", inode.i_block[0]);\r
324         \r
325         // Find Entry\r
326         // Get First Block\r
327         // - Do this ourselves as it is a simple operation\r
328         Base = inode.i_block[0] * disk->BlockSize;\r
329         while(Pos -- && size > 0)\r
330         {\r
331                 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);\r
332                 ofs += dirent.rec_len;\r
333                 size -= dirent.rec_len;\r
334                 entNum ++;\r
335                 \r
336                 if(ofs >= disk->BlockSize) {\r
337                         block ++;\r
338                         if( ofs > disk->BlockSize ) {\r
339                                 Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring\n",\r
340                                         entNum-1, Node->Inode);\r
341                         }\r
342                         ofs = 0;\r
343                         Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );\r
344                 }\r
345         }\r
346         \r
347         if(size <= 0)   return NULL;\r
348         \r
349         // Read Entry\r
350         VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );\r
351         //LOG(" Ext2_ReadDir: dirent.inode = %i\n", dirent.inode);\r
352         //LOG(" Ext2_ReadDir: dirent.rec_len = %i\n", dirent.rec_len);\r
353         //LOG(" Ext2_ReadDir: dirent.name_len = %i\n", dirent.name_len);\r
354         VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );\r
355         namebuf[ dirent.name_len ] = '\0';      // Cap off string\r
356         \r
357         \r
358         // Ignore . and .. (these are done in the VFS)\r
359         if( (namebuf[0] == '.' && namebuf[1] == '\0')\r
360         ||  (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) {\r
361                 LEAVE('p', VFS_SKIP);\r
362                 return VFS_SKIP;        // Skip\r
363         }\r
364         \r
365         LEAVE('s', namebuf);\r
366         // Create new node\r
367         return strdup(namebuf);\r
368 }\r
369 \r
370 /**\r
371  \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename)\r
372  \brief Gets information about a file\r
373  \param node    vfs node - Parent Node\r
374  \param filename        String - Name of file\r
375  \return VFS Node of file\r
376 */\r
377 tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)\r
378 {\r
379         tExt2_Disk      *disk = Node->ImplPtr;\r
380         tExt2_Inode     inode;\r
381         char    namebuf[EXT2_NAME_LEN+1];\r
382         tExt2_DirEnt    dirent;\r
383         Uint64  Base;   // Block's Base Address\r
384          int    block = 0, ofs = 0;\r
385          int    entNum = 0;\r
386         Uint    size;\r
387         \r
388         // Read directory's inode\r
389         Ext2_int_GetInode(Node, &inode);\r
390         size = inode.i_size;\r
391         \r
392         // Get First Block\r
393         // - Do this ourselves as it is a simple operation\r
394         Base = inode.i_block[0] * disk->BlockSize;\r
395         // Find File\r
396         while(size > 0)\r
397         {\r
398                 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);\r
399                 VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );\r
400                 namebuf[ dirent.name_len ] = '\0';      // Cap off string\r
401                 // If it matches, create a node and return it\r
402                 if(strcmp(namebuf, Filename) == 0)\r
403                         return Ext2_int_CreateNode( disk, dirent.inode, namebuf );\r
404                 // Increment pointers\r
405                 ofs += dirent.rec_len;\r
406                 size -= dirent.rec_len;\r
407                 entNum ++;\r
408                 \r
409                 // Check for end of block\r
410                 if(ofs >= disk->BlockSize) {\r
411                         block ++;\r
412                         if( ofs > disk->BlockSize ) {\r
413                                 Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring\n",\r
414                                         entNum-1, Node->Inode);\r
415                         }\r
416                         ofs = 0;\r
417                         Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );\r
418                 }\r
419         }\r
420         \r
421         return NULL;\r
422 }\r
423 \r
424 /**\r
425  * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)\r
426  * \brief Create a new node\r
427  */\r
428 int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)\r
429 {\r
430         return 0;\r
431 }\r
432 \r
433 //==================================\r
434 //=       INTERNAL FUNCTIONS       =\r
435 //==================================\r
436 \r
437 \r
438 /**\r
439  \internal\r
440  \fn int Ext2_int_GetInode(vfs_node *Node, tExt2_Inode *Inode)\r
441  \brief Gets the inode descriptor for a node\r
442  \param node    node to get the Inode of\r
443  \param inode   Destination\r
444 */\r
445 int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)\r
446 {\r
447         return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode);\r
448 }\r
449 \r
450 /**\r
451  * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)\r
452  * \brief Create a new VFS Node\r
453  */\r
454 tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)\r
455 {\r
456         tExt2_Inode     inode;\r
457         tVFS_Node       retNode;\r
458         tVFS_Node       *tmpNode;\r
459         \r
460         if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )\r
461                 return NULL;\r
462         \r
463         if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )\r
464                 return tmpNode;\r
465         \r
466         \r
467         // Set identifiers\r
468         retNode.Inode = InodeID;\r
469         retNode.ImplPtr = Disk;\r
470         \r
471         // Set file length\r
472         retNode.Size = inode.i_size;\r
473         \r
474         // Set Access Permissions\r
475         retNode.UID = inode.i_uid;\r
476         retNode.GID = inode.i_gid;\r
477         retNode.NumACLs = 3;\r
478         retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);\r
479         \r
480         //  Set Function Pointers\r
481         retNode.Read = Ext2_Read;\r
482         retNode.Write = Ext2_Write;\r
483         retNode.Close = Ext2_CloseFile;\r
484         \r
485         switch(inode.i_mode & EXT2_S_IFMT)\r
486         {\r
487         // Symbolic Link\r
488         case EXT2_S_IFLNK:\r
489                 retNode.Flags = VFS_FFLAG_SYMLINK;\r
490                 break;\r
491         // Regular File\r
492         case EXT2_S_IFREG:\r
493                 retNode.Flags = 0;\r
494                 break;\r
495         // Directory\r
496         case EXT2_S_IFDIR:\r
497                 retNode.ReadDir = Ext2_ReadDir;\r
498                 retNode.FindDir = Ext2_FindDir;\r
499                 retNode.MkNod = Ext2_MkNod;\r
500                 //retNode.Relink = Ext2_Relink;\r
501                 retNode.Flags = VFS_FFLAG_DIRECTORY;\r
502                 break;\r
503         // Unknown, Write protect and hide it to be safe \r
504         default:\r
505                 retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;\r
506                 break;\r
507         }\r
508         \r
509         // Check if the file should be hidden\r
510         //if(Name[0] == '.')    retNode.Flags |= VFS_FFLAG_HIDDEN;\r
511         \r
512         // Set Timestamps\r
513         retNode.ATime = now();\r
514         retNode.MTime = inode.i_mtime * 1000;\r
515         retNode.CTime = inode.i_ctime * 1000;\r
516         \r
517         // Save in node cache and return saved node\r
518         return Inode_CacheNode(Disk->CacheID, &retNode);\r
519 }\r
520 \r
521 /**\r
522  * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
523  * \brief Read an inode into memory\r
524  */\r
525 int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
526 {\r
527          int    group, subId;\r
528         \r
529         //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)\n", Disk, InodeId, Inode);\r
530         \r
531         if(InodeId == 0)        return 0;\r
532         \r
533         InodeId --;     // Inodes are numbered starting at 1\r
534         \r
535         group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
536         subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
537         \r
538         //LogF(" Ext2_int_ReadInode: group=%i, subId = %i\n", group, subId);\r
539         \r
540         // Read Inode\r
541         VFS_ReadAt(Disk->FD,\r
542                 Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
543                 sizeof(tExt2_Inode),\r
544                 Inode);\r
545         return 1;\r
546 }\r
547 \r
548 /**\r
549  * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
550  * \brief Get the address of a block from an inode's list\r
551  * \param Disk  Disk information structure\r
552  * \param Blocks        Pointer to an inode's block list\r
553  * \param BlockNum      Block index in list\r
554  */\r
555 Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
556 {\r
557         Uint32  *iBlocks;\r
558         // Direct Blocks\r
559         if(BlockNum < 12)\r
560                 return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
561         \r
562         // Single Indirect Blocks\r
563         iBlocks = malloc( Disk->BlockSize );\r
564         VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
565         \r
566         BlockNum -= 12;\r
567         if(BlockNum < 256) {\r
568                 BlockNum = iBlocks[BlockNum];\r
569                 free(iBlocks);\r
570                 return (Uint64)BlockNum * Disk->BlockSize;\r
571         }\r
572         \r
573         // Double Indirect Blocks\r
574         if(BlockNum < 256*256)\r
575         {\r
576                 VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
577                 VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
578                 BlockNum = iBlocks[BlockNum%256];\r
579                 free(iBlocks);\r
580                 return (Uint64)BlockNum * Disk->BlockSize;\r
581         }\r
582         // Triple Indirect Blocks\r
583         VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
584         VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(256*256)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
585         VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/256)%256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
586         BlockNum = iBlocks[BlockNum%256];\r
587         free(iBlocks);\r
588         return (Uint64)BlockNum * Disk->BlockSize;\r
589 }\r

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