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

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