X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FFilesystems%2FExt2%2Fext2.c;h=3a9a080ebf1bece04d8c2b7cccdcf0b421dfe180;hb=cbe0bf8833612d7581e96a55681fc576202d2969;hp=5015e14b17957c883e517b825e7cef1d3ad56c11;hpb=36c9094d0e26188c3dbf1b974e813797b76e7687;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2.c b/KernelLand/Modules/Filesystems/Ext2/ext2.c index 5015e14b..3a9a080e 100644 --- a/KernelLand/Modules/Filesystems/Ext2/ext2.c +++ b/KernelLand/Modules/Filesystems/Ext2/ext2.c @@ -13,9 +13,6 @@ #define MIN_BLOCKS_PER_GROUP 2 #define MAX_BLOCK_LOG_SIZE 10 // 1024 << 10 = 1MiB -// === IMPORTS === -extern tVFS_NodeType gExt2_DirType; - // === PROTOTYPES === int Ext2_Install(char **Arguments); int Ext2_Cleanup(void); @@ -95,7 +92,7 @@ int Ext2_Detect(int FD) */ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) { - tExt2_Disk *disk; + tExt2_Disk *disk = NULL; int fd; int groupCount; tExt2_SuperBlock sb; @@ -118,9 +115,7 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) if(sb.s_magic != 0xEF53) { Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume (0x%x != 0xEF53)", Device, sb.s_magic); - VFS_Close(fd); - LEAVE('n'); - return NULL; + goto _error; } if( sb.s_blocks_per_group < MIN_BLOCKS_PER_GROUP ) { @@ -137,16 +132,14 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount); if(!disk) { Log_Warning("EXT2", "Unable to allocate disk structure"); - VFS_Close(fd); - LEAVE('n'); - return NULL; + goto _error; } disk->FD = fd; memcpy(&disk->SuperBlock, &sb, 1024); disk->GroupCount = groupCount; // Get an inode cache handle - disk->CacheID = Inode_GetHandle(); + disk->CacheID = Inode_GetHandle(NULL); // Get Block Size if( sb.s_log_block_size > MAX_BLOCK_LOG_SIZE ) { @@ -201,7 +194,8 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) LEAVE('p', &disk->RootNode); return &disk->RootNode; _error: - free(disk); + if( disk ) + free(disk); VFS_Close(fd); LEAVE('n'); return NULL; @@ -239,7 +233,8 @@ void Ext2_CloseFile(tVFS_Node *Node) if( Node->Flags & VFS_FFLAG_DIRTY ) { // Commit changes - Log_Warning("Ext2", "TODO: Commit node changes"); + Ext2_int_WritebackNode(disk, Node); + Node->Flags &= ~VFS_FFLAG_DIRTY; } int was_not_referenced = (Node->ImplInt == 0); @@ -250,7 +245,7 @@ void Ext2_CloseFile(tVFS_Node *Node) { LOG("Removng inode"); // Remove inode - Log_Warning("Ext2", "TODO: Remove inode when not referenced"); + Log_Warning("Ext2", "TODO: Remove inode when not referenced (%x)", (Uint32)Node->Inode); } if( acls != &gVFS_ACL_EveryoneRW ) { free(acls); @@ -328,6 +323,118 @@ int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) return 1; } +/** + * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID) + * \brief Create a new VFS Node + */ +tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID) +{ + tExt2_Inode inode; + tVFS_Node retNode; + tVFS_Node *tmpNode; + + if( !Ext2_int_ReadInode(Disk, InodeID, &inode) ) + return NULL; + + if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) ) + return tmpNode; + + memset(&retNode, 0, sizeof(retNode)); + + // Set identifiers + retNode.Inode = InodeID; + retNode.ImplPtr = Disk; + retNode.ImplInt = inode.i_links_count; + if( inode.i_links_count == 0 ) { + Log_Notice("Ext2", "Inode %p:%x is not referenced, bug?", Disk, InodeID); + } + + // Set file length + retNode.Size = inode.i_size; + + // Set Access Permissions + retNode.UID = inode.i_uid; + retNode.GID = inode.i_gid; + retNode.NumACLs = 3; + retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid); + + // Set Function Pointers + retNode.Type = &gExt2_FileType; + + switch(inode.i_mode & EXT2_S_IFMT) + { + // Symbolic Link + case EXT2_S_IFLNK: + retNode.Flags = VFS_FFLAG_SYMLINK; + break; + // Regular File + case EXT2_S_IFREG: + retNode.Flags = 0; + retNode.Size |= (Uint64)inode.i_dir_acl << 32; + break; + // Directory + case EXT2_S_IFDIR: + retNode.Type = &gExt2_DirType; + retNode.Flags = VFS_FFLAG_DIRECTORY; + retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) ); + break; + // Unknown, Write protect it to be safe + default: + retNode.Flags = VFS_FFLAG_READONLY; + break; + } + + // Set Timestamps + retNode.ATime = inode.i_atime * 1000; + retNode.MTime = inode.i_mtime * 1000; + retNode.CTime = inode.i_ctime * 1000; + + // Save in node cache and return saved node + return Inode_CacheNode(Disk->CacheID, &retNode); +} + +int Ext2_int_WritebackNode(tExt2_Disk *Disk, tVFS_Node *Node) +{ + tExt2_Inode inode = {0}; + + if( Disk != Node->ImplPtr ) { + Log_Error("Ext2", "Ext2_int_WritebackNode - Disk != Node->ImplPtr"); + return -1; + } + + if( Node->Flags & VFS_FFLAG_SYMLINK ) { + inode.i_mode = EXT2_S_IFLNK; + } + else if( Node->Flags & VFS_FFLAG_DIRECTORY ) { + inode.i_mode = EXT2_S_IFDIR; + } + else if( Node->Flags & VFS_FFLAG_READONLY ) { + Log_Notice("Ext2", "Not writing back readonly inode %p:%x", Disk, Node->Inode); + return 1; + } + else { + inode.i_mode = EXT2_S_IFREG; + inode.i_dir_acl = Node->Size >> 32; + } + + inode.i_size = Node->Size & 0xFFFFFFFF; + inode.i_links_count = Node->ImplInt; + + inode.i_uid = Node->UID; + inode.i_gid = Node->GID; + + inode.i_atime = Node->ATime / 1000; + inode.i_mtime = Node->MTime / 1000; + inode.i_ctime = Node->CTime / 1000; + + // TODO: Compact ACLs into unix mode + Log_Warning("Ext2", "TODO: Support converting Acess ACLs into unix modes"); + + Ext2_int_WriteInode(Disk, Node->Inode, &inode); + + return 0; +} + /** * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) * \brief Get the address of a block from an inode's list @@ -422,7 +529,7 @@ Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent) VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf); int byte, bit; - for( byte = 0; byte < sector_size && buf[byte] != 0xFF; byte ++ ) + for( byte = 0; byte < sector_size && buf[byte] == 0xFF; byte ++ ) ; if( byte < sector_size ) { @@ -470,6 +577,14 @@ void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk) // Update Primary VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock); + // - Update block groups while we're at it + VFS_WriteAt( + Disk->FD, + Disk->SuperBlock.s_first_data_block * Disk->BlockSize + 1024, + sizeof(tExt2_Group)*Disk->GroupCount, + Disk->Groups + ); + // Secondaries // at Block Group 1, 3^n, 5^n, 7^n