X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=sidebyside;f=Modules%2FFilesystems%2FExt2%2Fext2.c;fp=Modules%2FFilesystems%2FExt2%2Fext2.c;h=c2c2df9cd7ee579b4afa59cd51bdf876d07ac506;hb=923a9dc473851ec2bb1c94021bbf139724e7e8a5;hp=0000000000000000000000000000000000000000;hpb=f4646f2b6d64e42d1eec1d97877ae23eac6863f6;p=tpg%2Facess2.git diff --git a/Modules/Filesystems/Ext2/ext2.c b/Modules/Filesystems/Ext2/ext2.c new file mode 100644 index 00000000..c2c2df9c --- /dev/null +++ b/Modules/Filesystems/Ext2/ext2.c @@ -0,0 +1,330 @@ +/* + * Acess OS + * Ext2 Driver Version 1 + */ +/** + * \file fs/ext2.c + * \brief Second Extended Filesystem Driver + * \todo Implement file full write support + */ +#define DEBUG 1 +#define VERBOSE 0 +#include "ext2_common.h" +#include + +// === PROTOTYPES === + int Ext2_Install(char **Arguments); +// Interface Functions +tVFS_Node *Ext2_InitDevice(char *Device, char **Options); +void Ext2_Unmount(tVFS_Node *Node); +void Ext2_CloseFile(tVFS_Node *Node); +// Internal Helpers + int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode); +Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum); +Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent); +void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk); + +// === SEMI-GLOBALS === +MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL); +tExt2_Disk gExt2_disks[6]; + int giExt2_count = 0; +tVFS_Driver gExt2_FSInfo = { + "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL + }; + +// === CODE === + +/** + * \fn int Ext2_Install(char **Arguments) + * \brief Install the Ext2 Filesystem Driver + */ +int Ext2_Install(char **Arguments) +{ + VFS_AddDriver( &gExt2_FSInfo ); + return MODULE_ERR_OK; +} + +/** + \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options) + \brief Initializes a device to be read by by the driver + \param Device String - Device to read from + \param Options NULL Terminated array of option strings + \return Root Node +*/ +tVFS_Node *Ext2_InitDevice(char *Device, char **Options) +{ + tExt2_Disk *disk; + int fd; + int groupCount; + tExt2_SuperBlock sb; + tExt2_Inode inode; + + ENTER("sDevice pOptions", Device, Options); + + // Open Disk + fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device + if(fd == -1) { + Warning("[EXT2 ] Unable to open '%s'", Device); + LEAVE('n'); + return NULL; + } + + // Read Superblock at offset 1024 + VFS_ReadAt(fd, 1024, 1024, &sb); // Read Superblock + + // Sanity Check Magic value + if(sb.s_magic != 0xEF53) { + Warning("[EXT2 ] Volume '%s' is not an EXT2 volume", Device); + VFS_Close(fd); + LEAVE('n'); + return NULL; + } + + // Get Group count + groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group); + LOG("groupCount = %i", groupCount); + + // Allocate Disk Information + disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount); + if(!disk) { + Warning("[EXT2 ] Unable to allocate disk structure"); + VFS_Close(fd); + LEAVE('n'); + return NULL; + } + disk->FD = fd; + memcpy(&disk->SuperBlock, &sb, 1024); + disk->GroupCount = groupCount; + + // Get an inode cache handle + disk->CacheID = Inode_GetHandle(); + + // Get Block Size + LOG("s_log_block_size = 0x%x", sb.s_log_block_size); + disk->BlockSize = 1024 << sb.s_log_block_size; + + // Read Group Information + VFS_ReadAt( + disk->FD, + sb.s_first_data_block * disk->BlockSize + 1024, + sizeof(tExt2_Group)*groupCount, + disk->Groups + ); + + #if VERBOSE + LOG("Block Group 0"); + LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap); + LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap); + LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table); + LOG("Block Group 1"); + LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap); + LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap); + LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table); + #endif + + // Get root Inode + Ext2_int_ReadInode(disk, 2, &inode); + + // Create Root Node + memset(&disk->RootNode, 0, sizeof(tVFS_Node)); + disk->RootNode.Inode = 2; // Root inode ID + disk->RootNode.ImplPtr = disk; // Save disk pointer + disk->RootNode.Size = -1; // Fill in later (on readdir) + disk->RootNode.Flags = VFS_FFLAG_DIRECTORY; + + disk->RootNode.ReadDir = Ext2_ReadDir; + disk->RootNode.FindDir = Ext2_FindDir; + //disk->RootNode.Relink = Ext2_Relink; + + // Complete root node + disk->RootNode.UID = inode.i_uid; + disk->RootNode.GID = inode.i_gid; + disk->RootNode.NumACLs = 1; + disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW; + + #if DEBUG + LOG("inode.i_size = 0x%x", inode.i_size); + LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); + #endif + + LEAVE('p', &disk->RootNode); + return &disk->RootNode; +} + +/** + * \fn void Ext2_Unmount(tVFS_Node *Node) + * \brief Close a mounted device + */ +void Ext2_Unmount(tVFS_Node *Node) +{ + tExt2_Disk *disk = Node->ImplPtr; + + VFS_Close( disk->FD ); + Inode_ClearCache( disk->CacheID ); + memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group)); + free(disk); +} + +/** + * \fn void Ext2_CloseFile(tVFS_Node *Node) + * \brief Close a file (Remove it from the cache) + */ +void Ext2_CloseFile(tVFS_Node *Node) +{ + tExt2_Disk *disk = Node->ImplPtr; + Inode_UncacheNode(disk->CacheID, Node->Inode); + return ; +} + +//================================== +//= INTERNAL FUNCTIONS = +//================================== +/** + * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) + * \brief Read an inode into memory + */ +int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) +{ + int group, subId; + + //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); + + if(InodeId == 0) return 0; + + InodeId --; // Inodes are numbered starting at 1 + + group = InodeId / Disk->SuperBlock.s_inodes_per_group; + subId = InodeId % Disk->SuperBlock.s_inodes_per_group; + + //LOG("group=%i, subId = %i", group, subId); + + // Read Inode + VFS_ReadAt(Disk->FD, + Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, + sizeof(tExt2_Inode), + Inode); + + //LEAVE('i', 1); + return 1; +} + +/** + * \brief Write a modified inode out to disk + */ +int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) +{ + int group, subId; + ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); + + if(InodeId == 0) return 0; + + InodeId --; // Inodes are numbered starting at 1 + + group = InodeId / Disk->SuperBlock.s_inodes_per_group; + subId = InodeId % Disk->SuperBlock.s_inodes_per_group; + + LOG("group=%i, subId = %i", group, subId); + + // Write Inode + VFS_WriteAt(Disk->FD, + Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId, + sizeof(tExt2_Inode), + Inode); + + LEAVE('i', 1); + return 1; +} + +/** + * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) + * \brief Get the address of a block from an inode's list + * \param Disk Disk information structure + * \param Blocks Pointer to an inode's block list + * \param BlockNum Block index in list + */ +Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) +{ + Uint32 *iBlocks; + int dwPerBlock = Disk->BlockSize / 4; + + // Direct Blocks + if(BlockNum < 12) + return (Uint64)Blocks[BlockNum] * Disk->BlockSize; + + // Single Indirect Blocks + iBlocks = malloc( Disk->BlockSize ); + VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks); + + BlockNum -= 12; + if(BlockNum < dwPerBlock) + { + BlockNum = iBlocks[BlockNum]; + free(iBlocks); + return (Uint64)BlockNum * Disk->BlockSize; + } + + BlockNum -= dwPerBlock; + // Double Indirect Blocks + if(BlockNum < dwPerBlock*dwPerBlock) + { + VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks); + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); + BlockNum = iBlocks[BlockNum%dwPerBlock]; + free(iBlocks); + return (Uint64)BlockNum * Disk->BlockSize; + } + + BlockNum -= dwPerBlock*dwPerBlock; + // Triple Indirect Blocks + VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks); + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(dwPerBlock*dwPerBlock)]*Disk->BlockSize, Disk->BlockSize, iBlocks); + VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/dwPerBlock)%dwPerBlock]*Disk->BlockSize, Disk->BlockSize, iBlocks); + BlockNum = iBlocks[BlockNum%dwPerBlock]; + free(iBlocks); + return (Uint64)BlockNum * Disk->BlockSize; +} + +/** + * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent) + * \brief Allocate an inode (from the current group preferably) + * \param Disk EXT2 Disk Information Structure + * \param Parent Inode ID of the parent (used to locate the child nearby) + */ +Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent) +{ +// Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group; + return 0; +} + +/** + * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) + * \brief Updates the superblock + */ +void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) +{ + int bpg = Disk->SuperBlock.s_blocks_per_group; + int ngrp = Disk->SuperBlock.s_blocks_count / bpg; + int i; + + // Update Primary + VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock); + + // Secondaries + // at Block Group 1, 3^n, 5^n, 7^n + + // 1 + if(ngrp <= 1) return; + VFS_WriteAt(Disk->FD, 1*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); + + // Powers of 3 + for( i = 3; i < ngrp; i *= 3 ) + VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); + + // Powers of 5 + for( i = 5; i < ngrp; i *= 5 ) + VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); + + // Powers of 7 + for( i = 7; i < ngrp; i *= 7 ) + VFS_WriteAt(Disk->FD, i*bpg*Disk->BlockSize, 1024, &Disk->SuperBlock); +}