3 * Ext2 Driver Version 1
\r
7 * \brief Second Extended Filesystem Driver
\r
8 * \todo Implement file full write support
\r
12 #include "ext2_common.h"
\r
13 #include <modules.h>
\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
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
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
38 * \fn int Ext2_Install(char **Arguments)
\r
39 * \brief Install the Ext2 Filesystem Driver
\r
41 int Ext2_Install(char **Arguments)
\r
43 VFS_AddDriver( &gExt2_FSInfo );
\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
54 tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
\r
59 tExt2_SuperBlock sb;
\r
62 ENTER("sDevice pOptions", Device, Options);
\r
65 fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device
\r
67 Warning("[EXT2 ] Unable to open '%s'", Device);
\r
72 // Read Superblock at offset 1024
\r
73 VFS_ReadAt(fd, 1024, 1024, &sb); // Read Superblock
\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
84 groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);
\r
85 LOG("groupCount = %i", groupCount);
\r
87 // Allocate Disk Information
\r
88 disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);
\r
90 Warning("[EXT2 ] Unable to allocate disk structure");
\r
96 memcpy(&disk->SuperBlock, &sb, 1024);
\r
97 disk->GroupCount = groupCount;
\r
99 // Get an inode cache handle
\r
100 disk->CacheID = Inode_GetHandle();
\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
106 // Read Group Information
\r
109 sb.s_first_data_block * disk->BlockSize + 1024,
\r
110 sizeof(tExt2_Group)*groupCount,
\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
126 Ext2_int_ReadInode(disk, 2, &inode);
\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
135 disk->RootNode.ReadDir = Ext2_ReadDir;
\r
136 disk->RootNode.FindDir = Ext2_FindDir;
\r
137 //disk->RootNode.Relink = Ext2_Relink;
\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
146 LOG("inode.i_size = 0x%x", inode.i_size);
\r
147 LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
\r
150 LEAVE('p', &disk->RootNode);
\r
151 return &disk->RootNode;
\r
155 * \fn void Ext2_Unmount(tVFS_Node *Node)
\r
156 * \brief Close a mounted device
\r
158 void Ext2_Unmount(tVFS_Node *Node)
\r
160 tExt2_Disk *disk = Node->ImplPtr;
\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
169 * \fn void Ext2_CloseFile(tVFS_Node *Node)
\r
170 * \brief Close a file (Remove it from the cache)
\r
172 void Ext2_CloseFile(tVFS_Node *Node)
\r
174 tExt2_Disk *disk = Node->ImplPtr;
\r
175 Inode_UncacheNode(disk->CacheID, Node->Inode);
\r
179 //==================================
\r
180 //= INTERNAL FUNCTIONS =
\r
181 //==================================
\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
190 int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)
\r
192 return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode);
\r
196 * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
\r
197 * \brief Read an inode into memory
\r
199 int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
\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
206 if(InodeId == 0) return 0;
\r
208 InodeId --; // Inodes are numbered starting at 1
\r
210 group = InodeId / Disk->SuperBlock.s_inodes_per_group;
\r
211 subId = InodeId % Disk->SuperBlock.s_inodes_per_group;
\r
213 //LOG("group=%i, subId = %i", group, subId);
\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
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
230 Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
\r
235 return (Uint64)Blocks[BlockNum] * Disk->BlockSize;
\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
242 if(BlockNum < 256) {
\r
243 BlockNum = iBlocks[BlockNum];
\r
245 return (Uint64)BlockNum * Disk->BlockSize;
\r
248 // Double Indirect Blocks
\r
249 if(BlockNum < 256*256)
\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
255 return (Uint64)BlockNum * Disk->BlockSize;
\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
263 return (Uint64)BlockNum * Disk->BlockSize;
\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
272 Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)
\r
274 // Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;
\r
279 * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)
\r
280 * \brief Updates the superblock
\r
282 void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)
\r
284 int bpg = Disk->SuperBlock.s_blocks_per_group;
\r
285 int ngrp = Disk->SuperBlock.s_blocks_count / bpg;
\r
289 VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);
\r
292 // at Block Group 1, 3^n, 5^n, 7^n
\r
295 if(ngrp <= 1) return;
\r
296 VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);
\r
299 for( i = 3; i < ngrp; i *= 3 )
\r
300 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);
\r
303 for( i = 5; i < ngrp; i *= 5 )
\r
304 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);
\r
307 for( i = 7; i < ngrp; i *= 7 )
\r
308 VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock);
\r