From 7ecaba85e0b0b9f52a2afd811e398dda996424d5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 30 Jul 2013 10:59:15 +0800 Subject: [PATCH] Modules/Ext2 - Fixed bugs in read/write support --- KernelLand/Modules/Filesystems/Ext2/dir.c | 42 +++--- KernelLand/Modules/Filesystems/Ext2/ext2.c | 134 +++++++++++------- .../Modules/Filesystems/Ext2/ext2_common.h | 3 +- KernelLand/Modules/Filesystems/Ext2/read.c | 25 ++-- KernelLand/Modules/Filesystems/Ext2/write.c | 88 ++++++------ 5 files changed, 155 insertions(+), 137 deletions(-) diff --git a/KernelLand/Modules/Filesystems/Ext2/dir.c b/KernelLand/Modules/Filesystems/Ext2/dir.c index a0a5f146..f04a60cf 100644 --- a/KernelLand/Modules/Filesystems/Ext2/dir.c +++ b/KernelLand/Modules/Filesystems/Ext2/dir.c @@ -44,7 +44,7 @@ tVFS_NodeType gExt2_FileType = { */ int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) { - tExt2_Inode inode; + tExt2_Inode *inode = (void*)(Node+1); tExt2_DirEnt dirent; Uint64 Base; // Block's Base Address int block = 0; @@ -56,17 +56,16 @@ int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) ENTER("pNode iPos", Node, Pos); // Read directory's inode - Ext2_int_ReadInode(disk, Node->Inode, &inode); - size = inode.i_size; + size = inode->i_size; - LOG("inode={.i_block[0]= 0x%x, .i_size=0x%x}", inode.i_block[0], inode.i_size); + LOG("inode={.i_block[0]= 0x%x, .i_size=0x%x}", inode->i_block[0], inode->i_size); // Find Entry // Get First Block // - Do this ourselves as it is a simple operation - Base = inode.i_block[0] * disk->BlockSize; + Base = inode->i_block[0] * disk->BlockSize; // Scan directory - while(Pos -- && size > 0 && size <= inode.i_size) + while(Pos -- && size > 0 && size <= inode->i_size) { VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); ofs += dirent.rec_len; @@ -80,7 +79,7 @@ int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) entNum-1, Node->Inode); } ofs = 0; - Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block ); + Base = Ext2_int_GetBlockAddr( disk, inode->i_block, block ); if( Base == 0 ) { size = 0; break; @@ -89,7 +88,7 @@ int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) } // Check for the end of the list - if(size <= 0 || size > inode.i_size) { + if(size <= 0 || size > inode->i_size) { LEAVE('i', -ENOENT); return -ENOENT; } @@ -127,7 +126,7 @@ int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) { tExt2_Disk *disk = Node->ImplPtr; - tExt2_Inode inode; + tExt2_Inode *inode = (void*)(Node+1); tExt2_DirEnt dirent; Uint64 Base; // Block's Base Address int block = 0; @@ -137,12 +136,11 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) int filenameLen = strlen(Filename); // Read directory's inode - Ext2_int_ReadInode(disk, Node->Inode, &inode); - size = inode.i_size; + size = inode->i_size; // Get First Block // - Do this ourselves as it is a simple operation - Base = inode.i_block[0] * disk->BlockSize; + Base = inode->i_block[0] * disk->BlockSize; // Find File while(size > 0) { @@ -163,7 +161,7 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) entNum-1, Node->Inode); } ofs = 0; - Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block ); + Base = Ext2_int_GetBlockAddr( disk, inode->i_block, block ); } } @@ -231,7 +229,7 @@ int Ext2_Unlink(tVFS_Node *Node, const char *OldName) int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child) { tExt2_Disk *disk = Node->ImplPtr; - tExt2_Inode inode; + tExt2_Inode *inode = (void*)(Node+1); tExt2_DirEnt *dirent; tExt2_DirEnt newEntry; Uint64 base; // Block's Base Address @@ -246,19 +244,15 @@ int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child) void *blockData = malloc(disk->BlockSize); - // Read child inode (get's the file type) - Ext2_int_ReadInode(disk, Child->Inode, &inode); - // Create a stub entry newEntry.inode = Child->Inode; newEntry.name_len = strlen(Name); newEntry.rec_len = ((newEntry.name_len+3)&~3) + EXT2_DIRENT_SIZE; - newEntry.type = inode.i_mode >> 12; + newEntry.type = inode->i_mode >> 12; memcpy(newEntry.name, Name, newEntry.name_len); // Read directory's inode - Ext2_int_ReadInode(disk, Node->Inode, &inode); - size = inode.i_size; + size = inode->i_size; // Get a lock on the inode //Ext2_int_LockInode(disk, Node->Inode); @@ -269,7 +263,7 @@ int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child) // Get First Block // - Do this ourselves as it is a simple operation - base = inode.i_block[0] * disk->BlockSize; + base = inode->i_block[0] * disk->BlockSize; VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData ); block = 0; nEntries = 0; @@ -330,7 +324,7 @@ int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child) // BLOCK_DIR_OFS(Node->Data, block) = nEntries; block ++; ofs = 0; - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + base = Ext2_int_GetBlockAddr(disk, inode->i_block, block); VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData ); } } @@ -349,7 +343,7 @@ int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child) if( bestMatch >= 0 ) { // Read-Modify-Write - base = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock); + base = Ext2_int_GetBlockAddr(disk, inode->i_block, bestBlock); VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData ); dirent = blockData + bestOfs; // Shorten a pre-existing entry @@ -377,7 +371,7 @@ int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child) else { // Allocate block, Write Uint32 newblock = Ext2_int_AllocateBlock(disk, base / disk->BlockSize); - Ext2_int_AppendBlock(disk, &inode, newblock); + Ext2_int_AppendBlock(Node, inode, newblock); base = newblock * disk->BlockSize; Node->Size += newEntry.rec_len; Node->Flags |= VFS_FFLAG_DIRTY; diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2.c b/KernelLand/Modules/Filesystems/Ext2/ext2.c index 3a9a080e..eacf87be 100644 --- a/KernelLand/Modules/Filesystems/Ext2/ext2.c +++ b/KernelLand/Modules/Filesystems/Ext2/ext2.c @@ -21,8 +21,10 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options); void Ext2_Unmount(tVFS_Node *Node); void Ext2_CloseFile(tVFS_Node *Node); +tVFS_Node *Ext2_GetNodeFromINode(tVFS_Node *RootNode, Uint64 Inode); // - Internal Helpers int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode); +void Ext2_int_DumpInode(tExt2_Disk *Disk, Uint32 InodeID, 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_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode); @@ -37,7 +39,7 @@ tVFS_Driver gExt2_FSInfo = { .Detect = Ext2_Detect, .InitDevice = Ext2_InitDevice, .Unmount = Ext2_Unmount, - .GetNodeFromINode = NULL + .GetNodeFromINode = Ext2_GetNodeFromINode }; // === CODE === @@ -96,7 +98,6 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) int fd; int groupCount; tExt2_SuperBlock sb; - tExt2_Inode inode; ENTER("sDevice pOptions", Device, Options); @@ -169,7 +170,7 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table); // Get root Inode - Ext2_int_ReadInode(disk, 2, &inode); + Ext2_int_ReadInode(disk, 2, &disk->RootInode); // Create Root Node memset(&disk->RootNode, 0, sizeof(tVFS_Node)); @@ -181,14 +182,14 @@ tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options) disk->RootNode.Type = &gExt2_DirType; // Complete root node - disk->RootNode.UID = inode.i_uid; - disk->RootNode.GID = inode.i_gid; + disk->RootNode.UID = disk->RootInode.i_uid; + disk->RootNode.GID = disk->RootInode.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]); + LOG("inode.i_size = 0x%x", disk->RootInode.i_size); + LOG("inode.i_block[0] = 0x%x", disk->RootInode.i_block[0]); #endif LEAVE('p', &disk->RootNode); @@ -260,6 +261,11 @@ void Ext2_CloseFile(tVFS_Node *Node) return ; } +tVFS_Node *Ext2_GetNodeFromINode(tVFS_Node *RootNode, Uint64 Inode) +{ + return Ext2_int_CreateNode(RootNode->ImplPtr, Inode); +} + //================================== //= INTERNAL FUNCTIONS = //================================== @@ -304,7 +310,9 @@ int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) LEAVE('i', 0); return 0; } - + + Ext2_int_DumpInode(Disk, InodeId, Inode); + InodeId --; // Inodes are numbered starting at 1 group = InodeId / Disk->SuperBlock.s_inodes_per_group; @@ -329,112 +337,134 @@ int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode) */ 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) ) + struct { + tVFS_Node retNode; + tExt2_Inode inode; + } data; + tVFS_Node *node = &data.retNode; + tExt2_Inode *in = &data.inode; + + if( !Ext2_int_ReadInode(Disk, InodeID, &data.inode) ) return NULL; - if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) ) - return tmpNode; + if( (node = Inode_GetCache(Disk->CacheID, InodeID)) ) + return node; + node = &data.retNode; - memset(&retNode, 0, sizeof(retNode)); + memset(node, 0, sizeof(*node)); // Set identifiers - retNode.Inode = InodeID; - retNode.ImplPtr = Disk; - retNode.ImplInt = inode.i_links_count; - if( inode.i_links_count == 0 ) { + node->Inode = InodeID; + node->ImplPtr = Disk; + node->ImplInt = in->i_links_count; + if( in->i_links_count == 0 ) { Log_Notice("Ext2", "Inode %p:%x is not referenced, bug?", Disk, InodeID); } // Set file length - retNode.Size = inode.i_size; + node->Size = in->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); + node->UID = in->i_uid; + node->GID = in->i_gid; + node->NumACLs = 3; + node->ACLs = VFS_UnixToAcessACL(in->i_mode & 0777, in->i_uid, in->i_gid); // Set Function Pointers - retNode.Type = &gExt2_FileType; + node->Type = &gExt2_FileType; - switch(inode.i_mode & EXT2_S_IFMT) + switch(in->i_mode & EXT2_S_IFMT) { // Symbolic Link case EXT2_S_IFLNK: - retNode.Flags = VFS_FFLAG_SYMLINK; + node->Flags = VFS_FFLAG_SYMLINK; break; // Regular File case EXT2_S_IFREG: - retNode.Flags = 0; - retNode.Size |= (Uint64)inode.i_dir_acl << 32; + node->Flags = 0; + node->Size |= (Uint64)in->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) ); + node->Type = &gExt2_DirType; + node->Flags = VFS_FFLAG_DIRECTORY; + node->Data = calloc( sizeof(Uint16), DivUp(node->Size, Disk->BlockSize) ); break; // Unknown, Write protect it to be safe default: - retNode.Flags = VFS_FFLAG_READONLY; + node->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; + node->ATime = in->i_atime * 1000; + node->MTime = in->i_mtime * 1000; + node->CTime = in->i_ctime * 1000; // Save in node cache and return saved node - return Inode_CacheNode(Disk->CacheID, &retNode); + return Inode_CacheNodeEx(Disk->CacheID, &data.retNode, sizeof(data)); } int Ext2_int_WritebackNode(tExt2_Disk *Disk, tVFS_Node *Node) { - tExt2_Inode inode = {0}; + tExt2_Inode *inode = (void*)(Node+1); 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; + inode->i_mode = EXT2_S_IFLNK; } else if( Node->Flags & VFS_FFLAG_DIRECTORY ) { - inode.i_mode = EXT2_S_IFDIR; + 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_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_size = Node->Size & 0xFFFFFFFF; + inode->i_links_count = Node->ImplInt; - inode.i_uid = Node->UID; - inode.i_gid = Node->GID; + 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; + 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"); + inode->i_mode |= 777; - Ext2_int_WriteInode(Disk, Node->Inode, &inode); + Ext2_int_WriteInode(Disk, Node->Inode, inode); return 0; } +void Ext2_int_DumpInode(tExt2_Disk *Disk, Uint32 InodeID, tExt2_Inode *Inode) +{ + LOG("%p[Inode %i] = {", Disk, InodeID); + LOG(" .i_mode = 0%04o", Inode->i_mode); + LOG(" .i_uid:i_gid = %i:%i", Inode->i_uid, Inode->i_gid); + LOG(" .i_size = 0x%x", Inode->i_size); + LOG(" .i_block[0:3] = {0x%x,0x%x,0x%x,0x%x}", + Inode->i_block[0], Inode->i_block[1], Inode->i_block[2], Inode->i_block[3]); + LOG(" .i_block[4:7] = {0x%x,0x%x,0x%x,0x%x}", + Inode->i_block[4], Inode->i_block[5], Inode->i_block[6], Inode->i_block[7]); + LOG(" .i_block[8:11] = {0x%x,0x%x,0x%x,0x%x}", + Inode->i_block[8], Inode->i_block[6], Inode->i_block[10], Inode->i_block[11]); + LOG(" .i_block[12:14] = {0x%x,0x%x,0x%x}", + Inode->i_block[12], Inode->i_block[13], Inode->i_block[14]); + LOG("}"); +} + /** * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum) * \brief Get the address of a block from an inode's list diff --git a/KernelLand/Modules/Filesystems/Ext2/ext2_common.h b/KernelLand/Modules/Filesystems/Ext2/ext2_common.h index 04fcae41..d4cdec91 100644 --- a/KernelLand/Modules/Filesystems/Ext2/ext2_common.h +++ b/KernelLand/Modules/Filesystems/Ext2/ext2_common.h @@ -15,6 +15,7 @@ typedef struct { int FD; tInodeCache *CacheID; tVFS_Node RootNode; + tExt2_Inode RootInode; tExt2_SuperBlock SuperBlock; Uint BlockSize; @@ -49,6 +50,6 @@ extern size_t Ext2_Read(tVFS_Node *node, off_t offset, size_t length, void *buff extern size_t Ext2_Write(tVFS_Node *node, off_t offset, size_t length, const void *buffer, Uint Flags); extern Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 LastBlock); extern void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block); -extern int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block); +extern int Ext2_int_AppendBlock(tVFS_Node *Node, tExt2_Inode *Inode, Uint32 Block); #endif diff --git a/KernelLand/Modules/Filesystems/Ext2/read.c b/KernelLand/Modules/Filesystems/Ext2/read.c index c77f06f3..76ee9939 100644 --- a/KernelLand/Modules/Filesystems/Ext2/read.c +++ b/KernelLand/Modules/Filesystems/Ext2/read.c @@ -7,7 +7,7 @@ * \brief Second Extended Filesystem Driver * \todo Implement file full write support */ -#define DEBUG 1 +#define DEBUG 0 #define VERBOSE 0 #include "ext2_common.h" @@ -18,29 +18,26 @@ size_t Ext2_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) { tExt2_Disk *disk = Node->ImplPtr; - tExt2_Inode inode; + tExt2_Inode *inode = (void*)(Node+1); Uint64 base; Uint block; Uint64 remLen; - ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); - - // Get Inode - Ext2_int_ReadInode(disk, Node->Inode, &inode); + ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer); // Sanity Checks - if(Offset >= inode.i_size) { + if(Offset >= inode->i_size) { LEAVE('i', 0); return 0; } - if(Offset + Length > inode.i_size) - Length = inode.i_size - Offset; + 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); + 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); + Log_Warning("EXT2", "NULL Block Detected in INode 0x%llx (Block %i)", Node->Inode, block); LEAVE('i', 0); return 0; } @@ -64,7 +61,7 @@ size_t Ext2_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uin // Read middle blocks while(remLen > disk->BlockSize) { - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + base = Ext2_int_GetBlockAddr(disk, inode->i_block, block); if(base == 0) { Log_Warning("EXT2", "NULL Block Detected in INode 0x%llx", Node->Inode); LEAVE('i', 0); @@ -77,7 +74,7 @@ size_t Ext2_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uin } // Read last block - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + base = Ext2_int_GetBlockAddr(disk, inode->i_block, block); VFS_ReadAt( disk->FD, base, remLen, Buffer); LEAVE('X', Length); diff --git a/KernelLand/Modules/Filesystems/Ext2/write.c b/KernelLand/Modules/Filesystems/Ext2/write.c index 022bc96a..78cf36c0 100644 --- a/KernelLand/Modules/Filesystems/Ext2/write.c +++ b/KernelLand/Modules/Filesystems/Ext2/write.c @@ -7,14 +7,13 @@ * \brief Second Extended Filesystem Driver * \todo Implement file full write support */ -#define DEBUG 1 +#define DEBUG 0 #define VERBOSE 0 #include "ext2_common.h" // === PROTOYPES === Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock); void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block); - int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block); // === CODE === /** @@ -23,7 +22,7 @@ void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block); size_t Ext2_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags) { tExt2_Disk *disk = Node->ImplPtr; - tExt2_Inode inode; + tExt2_Inode *inode = (void*)(Node+1); Uint64 base; Uint64 retLen; Uint block; @@ -33,13 +32,12 @@ size_t Ext2_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buff //Debug_HexDump("Ext2_Write", Buffer, Length); // TODO: Handle (Flags & VFS_IOFLAG_NOBLOCK) - - Ext2_int_ReadInode(disk, Node->Inode, &inode); // 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-1) & ~(disk->BlockSize-1); + allocSize = (inode->i_size + disk->BlockSize-1) & ~(disk->BlockSize-1); + LOG("allocSize = %llx, Offset=%llx", allocSize, Offset); // Are we writing to inside the allocated space? if( Offset > allocSize ) return 0; @@ -56,7 +54,7 @@ size_t Ext2_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buff // Within the allocated space block = Offset / disk->BlockSize; Offset %= disk->BlockSize; - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + base = Ext2_int_GetBlockAddr(disk, inode->i_block, block); // Write only block (if only one) if(Offset + retLen <= disk->BlockSize) { @@ -74,7 +72,7 @@ size_t Ext2_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buff // Write middle blocks while(retLen > disk->BlockSize) { - base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + base = Ext2_int_GetBlockAddr(disk, inode->i_block, block); VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer); Buffer += disk->BlockSize; retLen -= disk->BlockSize; @@ -82,25 +80,24 @@ size_t Ext2_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buff } // Write last block - base = Ext2_int_GetBlockAddr(disk, inode.i_block, 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 } else - base = Ext2_int_GetBlockAddr(disk, inode.i_block, allocSize/disk->BlockSize-1); + base = Ext2_int_GetBlockAddr(disk, inode->i_block, allocSize/disk->BlockSize-1); addBlocks: - Log_Notice("EXT2", "File extending is untested"); - // Allocate blocks and copy data to them retLen = Length - (allocSize-Offset); - while( retLen > disk->BlockSize ) + while( retLen > 0 ) { + size_t blk_len = (retLen < disk->BlockSize ? retLen : disk->BlockSize); // Allocate a block block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); if(!block) return Length - retLen; // Add it to this inode - if( Ext2_int_AppendBlock(disk, &inode, block) ) { + if( Ext2_int_AppendBlock(Node, inode, block) ) { Log_Warning("Ext2", "Appending %x to inode %p:%X failed", block, disk, Node->Inode); Ext2_int_DeallocateBlock(disk, block); @@ -108,34 +105,24 @@ addBlocks: } // Copy data to the node base = block * disk->BlockSize; - VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer); + VFS_WriteAt(disk->FD, base, blk_len, Buffer); // Update pointer and size remaining - inode.i_size += disk->BlockSize; - Buffer += disk->BlockSize; - retLen -= disk->BlockSize; - } - // Last block :D - block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize); - if(!block) goto ret; - if( Ext2_int_AppendBlock(disk, &inode, block) ) { - Log_Warning("Ext2", "Appending %x to inode %p:%X failed", - block, disk, Node->Inode); - Ext2_int_DeallocateBlock(disk, block); - goto ret; + Buffer += blk_len; + retLen -= blk_len; } - base = block * disk->BlockSize; - VFS_WriteAt(disk->FD, base, retLen, Buffer); - - // TODO: When should the size update be committed? - inode.i_size += retLen; - Node->Size += retLen; - Node->Flags |= VFS_FFLAG_DIRTY; - - retLen = 0; -ret: // Makes sure the changes to the inode are committed - Ext2_int_WriteInode(disk, Node->Inode, &inode); - return Length - retLen; + +ret: + retLen = Length - retLen; + if( retLen ) + { + // TODO: When should the size update be committed? + inode->i_size += retLen; + Node->Size += retLen; + Node->Flags |= VFS_FFLAG_DIRTY; + //Ext2_int_WriteInode(disk, Node->Inode, inode); + } + return retLen; } /** @@ -159,9 +146,10 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) // First: Check the next block after `PrevBlock` int iblock = (PrevBlock + 1) % Disk->SuperBlock.s_blocks_per_group; + //LOG("iblock = %i, Disk=%p, blockgroup=%i", iblock, Disk, blockgroup); if( iblock != 0 && Disk->Groups[blockgroup].bg_free_blocks_count > 0 ) { - LOG("Checking %i:%i", blockgroup, iblock); + //LOG("Checking %i:%i", blockgroup, iblock); bg = &Disk->Groups[blockgroup]; @@ -174,7 +162,7 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) Uint64 vol_ofs = Disk->BlockSize*bg->bg_block_bitmap+ofs; VFS_ReadAt(Disk->FD, vol_ofs, sector_size, buf); - LOG("buf@%llx[%i] = %02x (& %02x)", vol_ofs, byte, buf[byte], bit); + //LOG("buf@%llx[%i] = %02x (& %02x)", vol_ofs, byte, buf[byte], bit); if( (buf[byte] & bit) == 0 ) { @@ -208,7 +196,7 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) Disk); return 0; } - LOG("BG%i has free blocks", blockgroup); + //LOG("BG%i has free blocks", blockgroup); // Search the bitmap for a free block bg = &Disk->Groups[blockgroup]; @@ -224,7 +212,7 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) ; if( byte < sector_size ) { - LOG("buf@%llx[%i] = %02x", vol_ofs, byte, buf[byte]); + //LOG("buf@%llx[%i] = %02x", vol_ofs, byte, buf[byte]); for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++) ; ASSERT(bit != 8); @@ -239,7 +227,7 @@ Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock) #endif Uint32 ret = blockgroup * Disk->SuperBlock.s_blocks_per_group + byte * 8 + bit; - Log_Debug("Ext2", "Ext2_int_AllocateBlock - Allocated 0x%x", ret); + LOG("Allocated 0x%x", ret); return ret; } } while(ofs < Disk->SuperBlock.s_blocks_per_group / 8); @@ -260,14 +248,17 @@ void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block) /** * \brief Append a block to an inode */ -int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) +int Ext2_int_AppendBlock(tVFS_Node *Node, tExt2_Inode *Inode, Uint32 Block) { + tExt2_Disk *Disk = Node->ImplPtr; int nBlocks; int dwPerBlock = Disk->BlockSize / 4; Uint32 *blocks; Uint32 id1, id2; nBlocks = (Inode->i_size + Disk->BlockSize - 1) / Disk->BlockSize; + + LOG("Append 0x%x to inode [%i]", Block, nBlocks); // Direct Blocks if( nBlocks < 12 ) { @@ -282,6 +273,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) // Single Indirect if( nBlocks < dwPerBlock) { + LOG("Indirect 1 %i", nBlocks); // Allocate/Get Indirect block if( nBlocks == 0 ) { Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); @@ -298,14 +290,16 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) blocks[nBlocks] = Block; VFS_WriteAt(Disk->FD, Inode->i_block[12]*Disk->BlockSize, Disk->BlockSize, blocks); + Node->Flags |= VFS_FFLAG_DIRTY; free(blocks); return 0; } - nBlocks += dwPerBlock; + nBlocks -= dwPerBlock; // Double Indirect if( nBlocks < dwPerBlock*dwPerBlock ) { + LOG("Indirect 2 %i/%i", nBlocks/dwPerBlock, nBlocks%dwPerBlock); // Allocate/Get Indirect block if( nBlocks == 0 ) { Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]); @@ -315,6 +309,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) return 1; } memset(blocks, 0, Disk->BlockSize); + Node->Flags |= VFS_FFLAG_DIRTY; } else VFS_ReadAt(Disk->FD, Inode->i_block[13]*Disk->BlockSize, Disk->BlockSize, blocks); @@ -357,6 +352,7 @@ int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block) return 1; } memset(blocks, 0, Disk->BlockSize); + Node->Flags |= VFS_FFLAG_DIRTY; } else VFS_ReadAt(Disk->FD, Inode->i_block[14]*Disk->BlockSize, Disk->BlockSize, blocks); -- 2.20.1