Altered & Renamed LookupString, Added DrvUtil_SetIdent
[tpg/acess2.git] / Modules / FS_Ext2 / 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 full write support\r
9  */\r
10 #define DEBUG   1\r
11 #define VERBOSE 0\r
12 #include "ext2_common.h"\r
13 #include <modules.h>\r
14 \r
15 // === PROTOTYPES ===\r
16  int    Ext2_Install(char **Arguments);\r
17 // Interface Functions\r
18 tVFS_Node       *Ext2_InitDevice(char *Device, char **Options);\r
19 void            Ext2_Unmount(tVFS_Node *Node);\r
20 void            Ext2_CloseFile(tVFS_Node *Node);\r
21 // Internal Helpers\r
22  int            Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
23 Uint64          Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
24 Uint32          Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
25 void            Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
26 \r
27 // === SEMI-GLOBALS ===\r
28 MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL);\r
29 tExt2_Disk      gExt2_disks[6];\r
30  int    giExt2_count = 0;\r
31 tVFS_Driver     gExt2_FSInfo = {\r
32         "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
33         };\r
34 \r
35 // === CODE ===\r
36 \r
37 /**\r
38  * \fn int Ext2_Install(char **Arguments)\r
39  * \brief Install the Ext2 Filesystem Driver\r
40  */\r
41 int Ext2_Install(char **Arguments)\r
42 {\r
43         VFS_AddDriver( &gExt2_FSInfo );\r
44         return 1;\r
45 }\r
46 \r
47 /**\r
48  \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
49  \brief Initializes a device to be read by by the driver\r
50  \param Device  String - Device to read from\r
51  \param Options NULL Terminated array of option strings\r
52  \return Root Node\r
53 */\r
54 tVFS_Node *Ext2_InitDevice(char *Device, char **Options)\r
55 {\r
56         tExt2_Disk      *disk;\r
57          int    fd;\r
58          int    groupCount;\r
59         tExt2_SuperBlock        sb;\r
60         tExt2_Inode     inode;\r
61         \r
62         ENTER("sDevice pOptions", Device, Options);\r
63         \r
64         // Open Disk\r
65         fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);            //Open Device\r
66         if(fd == -1) {\r
67                 Warning("[EXT2 ] Unable to open '%s'", Device);\r
68                 LEAVE('n');\r
69                 return NULL;\r
70         }\r
71         \r
72         // Read Superblock at offset 1024\r
73         VFS_ReadAt(fd, 1024, 1024, &sb);        // Read Superblock\r
74         \r
75         // Sanity Check Magic value\r
76         if(sb.s_magic != 0xEF53) {\r
77                 Warning("[EXT2 ] Volume '%s' is not an EXT2 volume", Device);\r
78                 VFS_Close(fd);\r
79                 LEAVE('n');\r
80                 return NULL;\r
81         }\r
82         \r
83         // Get Group count\r
84         groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
85         LOG("groupCount = %i", groupCount);\r
86         \r
87         // Allocate Disk Information\r
88         disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
89         if(!disk) {\r
90                 Warning("[EXT2 ] Unable to allocate disk structure");\r
91                 VFS_Close(fd);\r
92                 LEAVE('n');\r
93                 return NULL;\r
94         }\r
95         disk->FD = fd;\r
96         memcpy(&disk->SuperBlock, &sb, 1024);\r
97         disk->GroupCount = groupCount;\r
98         \r
99         // Get an inode cache handle\r
100         disk->CacheID = Inode_GetHandle();\r
101         \r
102         // Get Block Size\r
103         LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
104         disk->BlockSize = 1024 << sb.s_log_block_size;\r
105         \r
106         // Read Group Information\r
107         VFS_ReadAt(\r
108                 disk->FD,\r
109                 sb.s_first_data_block * disk->BlockSize + 1024,\r
110                 sizeof(tExt2_Group)*groupCount,\r
111                 disk->Groups\r
112                 );\r
113         \r
114         #if VERBOSE\r
115         LOG("Block Group 0");\r
116         LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
117         LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
118         LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);\r
119         LOG("Block Group 1");\r
120         LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
121         LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
122         LOG(".bg_inode_table = 0x%x", 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(tVFS_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 DEBUG\r
146         LOG("inode.i_size = 0x%x", inode.i_size);\r
147         LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);\r
148         #endif\r
149         \r
150         LEAVE('p', &disk->RootNode);\r
151         return &disk->RootNode;\r
152 }\r
153 \r
154 /**\r
155  * \fn void Ext2_Unmount(tVFS_Node *Node)\r
156  * \brief Close a mounted device\r
157  */\r
158 void Ext2_Unmount(tVFS_Node *Node)\r
159 {\r
160         tExt2_Disk      *disk = Node->ImplPtr;\r
161         \r
162         VFS_Close( disk->FD );\r
163         Inode_ClearCache( disk->CacheID );\r
164         memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));\r
165         free(disk);\r
166 }\r
167 \r
168 /**\r
169  * \fn void Ext2_CloseFile(tVFS_Node *Node)\r
170  * \brief Close a file (Remove it from the cache)\r
171  */\r
172 void Ext2_CloseFile(tVFS_Node *Node)\r
173 {\r
174         tExt2_Disk      *disk = Node->ImplPtr;\r
175         Inode_UncacheNode(disk->CacheID, Node->Inode);\r
176         return ;\r
177 }\r
178 \r
179 //==================================\r
180 //=       INTERNAL FUNCTIONS       =\r
181 //==================================\r
182 \r
183 \r
184 /**\r
185  * \fn int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)\r
186  * \brief Gets the inode descriptor for a node\r
187  * \param Node  node to get the Inode of\r
188  * \param Inode Destination\r
189  */\r
190 int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)\r
191 {\r
192         return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode);\r
193 }\r
194 \r
195 /**\r
196  * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
197  * \brief Read an inode into memory\r
198  */\r
199 int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)\r
200 {\r
201          int    group, subId;\r
202         \r
203         //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)", Disk, InodeId, Inode);\r
204         //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);\r
205         \r
206         if(InodeId == 0)        return 0;\r
207         \r
208         InodeId --;     // Inodes are numbered starting at 1\r
209         \r
210         group = InodeId / Disk->SuperBlock.s_inodes_per_group;\r
211         subId = InodeId % Disk->SuperBlock.s_inodes_per_group;\r
212         \r
213         //LOG("group=%i, subId = %i", group, subId);\r
214         \r
215         // Read Inode\r
216         VFS_ReadAt(Disk->FD,\r
217                 Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,\r
218                 sizeof(tExt2_Inode),\r
219                 Inode);\r
220         return 1;\r
221 }\r
222 \r
223 /**\r
224  * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
225  * \brief Get the address of a block from an inode's list\r
226  * \param Disk  Disk information structure\r
227  * \param Blocks        Pointer to an inode's block list\r
228  * \param BlockNum      Block index in list\r
229  */\r
230 Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
231 {\r
232         Uint32  *iBlocks;\r
233         // Direct Blocks\r
234         if(BlockNum < 12)\r
235                 return (Uint64)Blocks[BlockNum] * Disk->BlockSize;\r
236         \r
237         // Single Indirect Blocks\r
238         iBlocks = malloc( Disk->BlockSize );\r
239         VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
240         \r
241         BlockNum -= 12;\r
242         if(BlockNum < 256) {\r
243                 BlockNum = iBlocks[BlockNum];\r
244                 free(iBlocks);\r
245                 return (Uint64)BlockNum * Disk->BlockSize;\r
246         }\r
247         \r
248         // Double Indirect Blocks\r
249         if(BlockNum < 256*256)\r
250         {\r
251                 VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
252                 VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
253                 BlockNum = iBlocks[BlockNum%256];\r
254                 free(iBlocks);\r
255                 return (Uint64)BlockNum * Disk->BlockSize;\r
256         }\r
257         // Triple Indirect Blocks\r
258         VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
259         VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(256*256)]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
260         VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/256)%256]*Disk->BlockSize, Disk->BlockSize, iBlocks);\r
261         BlockNum = iBlocks[BlockNum%256];\r
262         free(iBlocks);\r
263         return (Uint64)BlockNum * Disk->BlockSize;\r
264 }\r
265 \r
266 /**\r
267  * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
268  * \brief Allocate an inode (from the current group preferably)\r
269  * \param Disk  EXT2 Disk Information Structure\r
270  * \param Parent        Inode ID of the parent (used to locate the child nearby)\r
271  */\r
272 Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
273 {\r
274 //      Uint    block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
275         return 0;\r
276 }\r
277 \r
278 /**\r
279  * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
280  * \brief Updates the superblock\r
281  */\r
282 void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
283 {\r
284          int    bpg = Disk->SuperBlock.s_blocks_per_group;\r
285          int    ngrp = Disk->SuperBlock.s_blocks_count / bpg;\r
286          int    i;\r
287          \r
288         // Update Primary\r
289         VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);\r
290         \r
291         // Secondaries\r
292         // at Block Group 1, 3^n, 5^n, 7^n\r
293         \r
294         // 1\r
295         if(ngrp <= 1)   return;\r
296         VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
297         \r
298         // Powers of 3\r
299         for( i = 3; i < ngrp; i *= 3 )\r
300                 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
301         \r
302         // Powers of 5\r
303         for( i = 5; i < ngrp; i *= 5 )\r
304                 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
305         \r
306         // Powers of 7\r
307         for( i = 7; i < ngrp; i *= 7 )\r
308                 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);\r
309 }\r

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