X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fvfs%2Ffs%2Fext2.c;h=0b60e5427930921cc559588ee7e433d0d88d6844;hb=3c777e58e6baba6760f43b8fdde4daf62081048b;hp=06189f88e43ead9ce66cd80da49eb02d8b9f65a5;hpb=466eda7c917791866a29c253c6c22197faf41bf7;p=tpg%2Facess2.git diff --git a/Kernel/vfs/fs/ext2.c b/Kernel/vfs/fs/ext2.c index 06189f88..0b60e542 100644 --- a/Kernel/vfs/fs/ext2.c +++ b/Kernel/vfs/fs/ext2.c @@ -5,14 +5,17 @@ /** * \file fs/ext2.c * \brief Second Extended Filesystem Driver - * \todo Implement file read support + * \todo Implement file full write support */ #define DEBUG 1 +#define VERBOSE 0 #include #include #include #include "fs_ext2.h" +#define EXT2_UPDATE_WRITEBACK 1 + // === STRUCTURES === typedef struct { int FD; @@ -42,6 +45,9 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName); tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name); int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode); Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum); +Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent); +Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock); +void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk); // === SEMI-GLOBALS === MODULE_DEFINE(0, 0x5B /*v0.90*/, EXT2, Ext2_Install, NULL); @@ -64,7 +70,7 @@ int Ext2_Install(char **Arguments) } /** - \fn tVFS_Node *Ext2_initDevice(char *Device, char **Options) + \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 @@ -78,10 +84,13 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options) 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'\n", Device); + Warning("[EXT2 ] Unable to open '%s'", Device); + LEAVE('n'); return NULL; } @@ -90,17 +99,24 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options) // Sanity Check Magic value if(sb.s_magic != 0xEF53) { - Warning("[EXT2 ] Volume '%s' is not an EXT2 volume\n", Device); + 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); - //LogF(" Ext2_initDevice: groupCount = %i\n", groupCount); + 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; @@ -109,24 +125,26 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options) disk->CacheID = Inode_GetHandle(); // Get Block Size - //LogF(" Ext2_initDevice: s_log_block_size = 0x%x\n", sb.s_log_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, + VFS_ReadAt( + disk->FD, sb.s_first_data_block * disk->BlockSize + 1024, sizeof(tExt2_Group)*groupCount, - disk->Groups); - - #if 0 - Log(" Ext2_initDevice: Block Group 0\n"); - Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[0].bg_block_bitmap); - Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[0].bg_inode_bitmap); - Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[0].bg_inode_table); - Log(" Ext2_initDevice: Block Group 1\n"); - Log(" Ext2_initDevice: .bg_block_bitmap = 0x%x\n", disk->Groups[1].bg_block_bitmap); - Log(" Ext2_initDevice: .bg_inode_bitmap = 0x%x\n", disk->Groups[1].bg_inode_bitmap); - Log(" Ext2_initDevice: .bg_inode_table = 0x%x\n", disk->Groups[1].bg_inode_table); + 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 @@ -149,11 +167,12 @@ tVFS_Node *Ext2_InitDevice(char *Device, char **Options) disk->RootNode.NumACLs = 1; disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW; - #if 0 - Log(" Ext2_InitDevice: inode.i_size = 0x%x\n", inode.i_size); - Log(" Ext2_InitDevice: inode.i_block[0] = 0x%x\n", inode.i_block[0]); + #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; } @@ -183,17 +202,33 @@ Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Uint block; Uint64 remLen; + ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + // Get Inode Ext2_int_GetInode(Node, &inode); + // Sanity Checks + if(Offset >= inode.i_size) { + LEAVE('i', 0); + return 0; + } + if(Offset + Length > inode.i_size) + Length = inode.i_size - Offset; + block = Offset / disk->BlockSize; Offset = Offset / disk->BlockSize; base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + if(base == 0) { + Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode); + LEAVE('i', 0); + return 0; + } // Read only block if(Length <= disk->BlockSize - Offset) { VFS_ReadAt( disk->FD, base+Offset, Length, Buffer); + LEAVE('X', Length); return Length; } @@ -208,6 +243,11 @@ Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) while(remLen > disk->BlockSize) { base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + if(base == 0) { + Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode); + LEAVE('i', 0); + return 0; + } VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer); Buffer += disk->BlockSize; remLen -= disk->BlockSize; @@ -218,6 +258,7 @@ Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); VFS_ReadAt( disk->FD, base, remLen, Buffer); + LEAVE('X', Length); return Length; } @@ -235,18 +276,25 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) Uint64 allocSize; int bNewBlocks = 0; + Debug_HexDump("Ext2_Write", Buffer, Length); + Ext2_int_GetInode(Node, &inode); - // Round size up to block size - // block size is a power of two, so this will work + // Get the ammount of space already allocated + // - Round size up to block size + // - block size is a power of two, so this will work allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1); + + // Are we writing to inside the allocated space? if( Offset < allocSize ) { + // Will we go out of it? if(Offset + Length > allocSize) { bNewBlocks = 1; retLen = allocSize - Offset; } else retLen = Length; + // Within the allocated space block = Offset / disk->BlockSize; Offset %= disk->BlockSize; @@ -255,7 +303,7 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) // Write only block (if only one) if(Offset + retLen <= disk->BlockSize) { VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer); - if(bNewBlocks) return Length; + if(!bNewBlocks) return Length; goto addBlocks; // Ugh! A goto, but it seems unavoidable } @@ -278,7 +326,7 @@ Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) // Write last block base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); VFS_WriteAt(disk->FD, base, retLen, Buffer); - if(bNewBlocks) return Length; // Writing in only allocated space + if(!bNewBlocks) return Length; // Writing in only allocated space } addBlocks: @@ -289,7 +337,7 @@ addBlocks: } /** - * \fn void Ext2_CloseFile(vfs_node *Node) + * \fn void Ext2_CloseFile(tVFS_Node *Node) * \brief Close a file (Remove it from the cache) */ void Ext2_CloseFile(tVFS_Node *Node) @@ -320,7 +368,7 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) Ext2_int_GetInode(Node, &inode); size = inode.i_size; - LOG("inode.i_block[0] = 0x%x\n", inode.i_block[0]); + LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); // Find Entry // Get First Block @@ -336,7 +384,7 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) if(ofs >= disk->BlockSize) { block ++; if( ofs > disk->BlockSize ) { - Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring\n", + Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring", entNum-1, Node->Inode); } ofs = 0; @@ -344,13 +392,17 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) } } - if(size <= 0) return NULL; + // Check for the end of the list + if(size <= 0) { + LEAVE('n'); + return NULL; + } // Read Entry VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent ); - //LOG(" Ext2_ReadDir: dirent.inode = %i\n", dirent.inode); - //LOG(" Ext2_ReadDir: dirent.rec_len = %i\n", dirent.rec_len); - //LOG(" Ext2_ReadDir: dirent.name_len = %i\n", dirent.name_len); + //LOG("dirent.inode = %i", dirent.inode); + //LOG("dirent.rec_len = %i", dirent.rec_len); + //LOG("dirent.name_len = %i", dirent.name_len); VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf ); namebuf[ dirent.name_len ] = '\0'; // Cap off string @@ -410,7 +462,7 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename) if(ofs >= disk->BlockSize) { block ++; if( ofs > disk->BlockSize ) { - Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring\n", + Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring", entNum-1, Node->Inode); } ofs = 0; @@ -436,12 +488,11 @@ int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags) /** - \internal - \fn int Ext2_int_GetInode(vfs_node *Node, tExt2_Inode *Inode) - \brief Gets the inode descriptor for a node - \param node node to get the Inode of - \param inode Destination -*/ + * \fn int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode) + * \brief Gets the inode descriptor for a node + * \param Node node to get the Inode of + * \param Inode Destination + */ int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode) { return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode); @@ -491,6 +542,7 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) // Regular File case EXT2_S_IFREG: retNode.Flags = 0; + retNode.Size |= (Uint64)inode.i_dir_acl << 32; break; // Directory case EXT2_S_IFDIR: @@ -526,7 +578,8 @@ int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) { int group, subId; - //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)\n", Disk, InodeId, Inode); + //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)", Disk, InodeId, Inode); + //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode); if(InodeId == 0) return 0; @@ -535,7 +588,7 @@ int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode) group = InodeId / Disk->SuperBlock.s_inodes_per_group; subId = InodeId % Disk->SuperBlock.s_inodes_per_group; - //LogF(" Ext2_int_ReadInode: group=%i, subId = %i\n", group, subId); + //LOG("group=%i, subId = %i", group, subId); // Read Inode VFS_ReadAt(Disk->FD, @@ -587,3 +640,105 @@ Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) 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 Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) + * \brief Allocate a block from the best possible location + * \param Disk EXT2 Disk Information Structure + * \param PrevBlock Previous block ID in the file + */ +Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) +{ + int bpg = Disk->SuperBlock.s_blocks_per_group; + Uint blockgroup = PrevBlock / bpg; + Uint bitmap[Disk->BlockSize/sizeof(Uint)]; + Uint bitsperblock = 8*Disk->BlockSize; + int i, j = 0; + Uint block; + + // Are there any free blocks? + if(Disk->SuperBlock.s_free_blocks_count == 0) return 0; + + if(Disk->Groups[blockgroup].bg_free_blocks_count > 0) + { + // Search block group's bitmap + for(i = 0; i < bpg; i++) + { + // Get the block in the bitmap block + j = i & (bitsperblock-1); + + // Read in if needed + if(j == 0) { + VFS_ReadAt( + Disk->FD, + (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock, + Disk->BlockSize, + bitmap + ); + } + + // Fast Check + if( bitmap[j/32] == -1 ) { + j = (j + 31) & ~31; + continue; + } + + // Is the bit set? + if( bitmap[j/32] & (1 << (j%32)) ) + continue; + + // Ooh! We found one + break; + } + if( i < bpg ) { + Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist"); + goto checkAll; // Search the entire filesystem for a free block + // Goto needed for neatness + } + + // Mark as used + bitmap[j/32] |= (1 << (j%32)); + VFS_WriteAt( + Disk->FD, + (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock, + Disk->BlockSize, + bitmap + ); + block = i; + Disk->Groups[blockgroup].bg_free_blocks_count --; + } + else + { + checkAll: + Warning("[EXT2 ] TODO - Implement using blocks outside the current block group"); + return 0; + } + + // Reduce global count + Disk->SuperBlock.s_free_blocks_count --; + #if EXT2_UPDATE_WRITEBACK + Ext2_int_UpdateSuperblock(Disk); + #endif + + return block; +} + +/** + * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) + */ +void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) +{ + VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock); +}