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

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