X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FFilesystems%2FExt2%2Fext2.c;h=4d13f1ed795e57da1148c362bc04cbdbf3fcd8c5;hb=04a050f42807686dc119838c82372409246d55bb;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..4d13f1ed 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,9 +132,7 @@ 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); @@ -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; + + 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