X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FFilesystems%2FExt2%2Fdir.c;h=2f2b72f67267070779a2f5ad0bb3f64fb29bbc69;hb=015f48988e0ff398409d71dfc692005ab439490a;hp=5eb476f4b1f3b88ecc867f85ca1a2c6107b39831;hpb=48743e39650eb1ef988380e9d95f27fd40d3a9ce;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/Filesystems/Ext2/dir.c b/KernelLand/Modules/Filesystems/Ext2/dir.c index 5eb476f4..2f2b72f6 100644 --- a/KernelLand/Modules/Filesystems/Ext2/dir.c +++ b/KernelLand/Modules/Filesystems/Ext2/dir.c @@ -1,27 +1,23 @@ /* - * Acess OS - * Ext2 Driver Version 1 + * Acess2 Ext2 Driver + * - By John Hodge (thePowersGang) + * + * dir.c + * - Directory Handling */ -/** - * \file dir.c - * \brief Second Extended Filesystem Driver - * \todo Implement file full write support - */ -#define DEBUG 1 +#define DEBUG 0 #define VERBOSE 0 #include "ext2_common.h" // === MACROS === -#define BLOCK_DIR_OFS(_data, _block) ((Uint16*)(_data)[(_block)]) +#define BLOCK_DIR_OFS(_data, _block) (((Uint16*)(_data))[(_block)]) // === PROTOTYPES === -char *Ext2_ReadDir(tVFS_Node *Node, int Pos); -tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *FileName); - int Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags); - int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName); - int Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name); -// --- Helpers --- -tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId); + int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]); +tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *FileName, Uint Flags); +tVFS_Node *Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags); + int Ext2_Unlink(tVFS_Node *Node, const char *OldName); + int Ext2_Link(tVFS_Node *Parent, const char *Name, tVFS_Node *Node); // === GLOBALS === tVFS_NodeType gExt2_DirType = { @@ -29,7 +25,7 @@ tVFS_NodeType gExt2_DirType = { .ReadDir = Ext2_ReadDir, .FindDir = Ext2_FindDir, .MkNod = Ext2_MkNod, - .Relink = Ext2_Relink, + .Unlink = Ext2_Unlink, .Link = Ext2_Link, .Close = Ext2_CloseFile }; @@ -46,7 +42,7 @@ tVFS_NodeType gExt2_FileType = { * \param Node Directory node * \param Pos Position of desired element */ -char *Ext2_ReadDir(tVFS_Node *Node, int Pos) +int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]) { tExt2_Inode inode; tExt2_DirEnt dirent; @@ -63,14 +59,14 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) Ext2_int_ReadInode(disk, Node->Inode, &inode); size = inode.i_size; - LOG("inode.i_block[0] = 0x%x", inode.i_block[0]); + 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; // Scan directory - while(Pos -- && size > 0) + while(Pos -- && size > 0 && size <= inode.i_size) { VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); ofs += dirent.rec_len; @@ -85,33 +81,41 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) } ofs = 0; Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block ); + if( Base == 0 ) { + size = 0; + break; + } } } // Check for the end of the list - if(size <= 0) { - LEAVE('n'); - return NULL; + if(size <= 0 || size > inode.i_size) { + LEAVE('i', -ENOENT); + return -ENOENT; } // Read Entry VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent ); - //LOG("dirent.inode = %i", dirent.inode); - //LOG("dirent.rec_len = %i", dirent.rec_len); - //LOG("dirent.name_len = %i", dirent.name_len); + LOG("dirent={.rec_len=%i,.inode=0x%x,.name_len=%i}", + dirent.rec_len, dirent.inode, dirent.name_len); dirent.name[ dirent.name_len ] = '\0'; // Cap off string + if( dirent.name_len == 0 ) { + LEAVE('i', 1); + return 1; + } // Ignore . and .. (these are done in the VFS) if( (dirent.name[0] == '.' && dirent.name[1] == '\0') || (dirent.name[0] == '.' && dirent.name[1] == '.' && dirent.name[2]=='\0')) { - LEAVE('p', VFS_SKIP); - return VFS_SKIP; // Skip + LEAVE('i', 1); + return 1; // Skip } - LEAVE('s', dirent.name); - // Create new node - return strdup(dirent.name); + LOG("Name '%s'", dirent.name); + strncpy(Dest, dirent.name, FILENAME_MAX); + LEAVE('i', 0); + return 0; } /** @@ -120,7 +124,7 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) * \param Filename Name of wanted file * \return VFS Node of file */ -tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename) +tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename, Uint Flags) { tExt2_Disk *disk = Node->ImplPtr; tExt2_Inode inode; @@ -143,9 +147,8 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename) while(size > 0) { VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); - dirent.name[ dirent.name_len ] = '\0'; // Cap off string // If it matches, create a node and return it - if(dirent.name_len == filenameLen && strcmp(dirent.name, Filename) == 0) + if(dirent.name_len == filenameLen && strncmp(dirent.name, Filename, filenameLen) == 0) return Ext2_int_CreateNode( disk, dirent.inode ); // Increment pointers ofs += dirent.rec_len; @@ -171,36 +174,38 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename) * \fn int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags) * \brief Create a new node */ -int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags) +tVFS_Node *Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags) { - #if 0 - tVFS_Node *child; - Uint64 inodeNum; - tExt2_Inode inode; - inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode); - - memset(&inode, 0, sizeof(tExt2_Inode)); + ENTER("pParent sName xFlags", Parent, Name, Flags); - // File type - inode.i_mode = 0664; - if( Flags & VFS_FFLAG_READONLY ) - inode.i_mode &= ~0222; - if( Flags & VFS_FFLAG_SYMLINK ) - inode.i_mode |= EXT2_S_IFLNK; - else if( Flags & VFS_FFLAG_DIRECTORY ) - inode.i_mode |= EXT2_S_IFDIR | 0111; - - inode.i_uid = Threads_GetUID(); - inode.i_gid = Threads_GetGID(); - inode.i_ctime = - inode.i_mtime = - inode.i_atime = now() / 1000; - - child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum); - return Ext2_Link(Parent, child, Name); - #else - return 1; - #endif + Uint64 inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode); + if( inodeNum == 0 ) { + LOG("Inode allocation failed"); + LEAVE_RET('n', NULL); + } + tVFS_Node *child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum); + if( !child ) { + Ext2_int_DereferenceInode(Parent->ImplPtr, inodeNum); + Log_Warning("Ext2", "Ext2_MkNod - Node creation failed"); + LEAVE_RET('n', NULL); + } + + child->Flags = Flags & (VFS_FFLAG_DIRECTORY|VFS_FFLAG_SYMLINK|VFS_FFLAG_READONLY); + child->UID = Threads_GetUID(); + child->GID = Threads_GetGID(); + child->CTime = + child->MTime = + child->ATime = + now(); + child->ImplInt = 0; // ImplInt is the link count + // TODO: Set up ACLs + + int rv = Ext2_Link(Parent, Name, child); + if( rv ) { + Ext2_CloseFile(child); + return NULL; + } + LEAVE_RET('p', child); } /** @@ -208,33 +213,37 @@ int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags) * \param Node This (directory) node * \param OldName Old name of file * \param NewName New name for file - * \return Boolean Failure - See ::tVFS_Node.Relink for info + * \return Boolean Failure - See ::tVFS_Node.Unlink for info */ -int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName) +int Ext2_Unlink(tVFS_Node *Node, const char *OldName) { + Log_Warning("Ext2", "TODO: Impliment Ext2_Unlink"); return 1; } /** * \brief Links an existing node to a new name * \param Parent Parent (directory) node - * \param Node Node to link * \param Name New name for the node + * \param Node Node to link * \return Boolean Failure - See ::tVFS_Node.Link for info */ -int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name) +int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child) { - #if 0 tExt2_Disk *disk = Node->ImplPtr; tExt2_Inode inode; - tExt2_DirEnt dirent; + tExt2_DirEnt *dirent; tExt2_DirEnt newEntry; - Uint64 Base; // Block's Base Address + Uint64 base; // Block's Base Address int block = 0, ofs = 0; Uint size; void *blockData; - int bestMatch = -1, bestSize, bestBlock, bestOfs; + int bestMatch = -1; + int bestSize=0, bestBlock=0, bestOfs=0, bestNeedsSplit=0; int nEntries; + + ENTER("pNode sName pChild", + Node, Name, Child); blockData = malloc(disk->BlockSize); @@ -244,7 +253,7 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name) // Create a stub entry newEntry.inode = Child->Inode; newEntry.name_len = strlen(Name); - newEntry.rec_len = (newEntry.name_len+3+8)&~3; + newEntry.rec_len = ((newEntry.name_len+3)&~3) + EXT2_DIRENT_SIZE; newEntry.type = inode.i_mode >> 12; memcpy(newEntry.name, Name, newEntry.name_len); @@ -253,13 +262,18 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name) size = inode.i_size; // Get a lock on the inode - Ext2_int_LockInode(disk, Node->Inode); - + //Ext2_int_LockInode(disk, Node->Inode); + Mutex_Acquire(&Node->Lock); + +// if( !Node->Data ) { +// } + // Get First Block // - Do this ourselves as it is a simple operation base = inode.i_block[0] * disk->BlockSize; VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData ); block = 0; + nEntries = 0; // Find File while(size > 0) { @@ -270,10 +284,12 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name) "Directory entry %i of inode 0x%x extends over a block boundary", nEntries, (Uint)Node->Inode); } - else { - + else + { + LOG("Entry %i: %x %i bytes", nEntries, dirent->type, dirent->rec_len); // Free entry - if(dirent->type == 0) { + if(dirent->type == 0) + { if( dirent->rec_len >= newEntry.rec_len && (bestMatch == -1 || bestSize > dirent->rec_len) ) { @@ -281,23 +297,40 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name) bestSize = dirent->rec_len; bestBlock = block; bestOfs = ofs; + bestNeedsSplit = 0; } } // Non free - check name to avoid duplicates - else { + else + { + LOG(" name='%.*s'", dirent->name_len, dirent->name); if(strncmp(Name, dirent->name, dirent->name_len) == 0) { - Ext2_int_UnlockInode(disk, Node->Inode); + //Ext2_int_UnlockInode(disk, Node->Inode); + Mutex_Release(&Node->Lock); + LEAVE('i', 1); return 1; // ERR_??? } + + int spare_space = dirent->rec_len - (dirent->name_len + EXT2_DIRENT_SIZE); + if( spare_space > newEntry.rec_len + && (bestMatch == -1 || bestSize > spare_space) ) + { + bestMatch = nEntries; + bestSize = spare_space; + bestBlock = block; + bestOfs = ofs; + bestNeedsSplit = 1; + } } } // Increment the pointer nEntries ++; ofs += dirent->rec_len; - if( ofs >= disk->BlockSize ) { + size -= dirent->rec_len; + if( size > 0 && ofs >= disk->BlockSize ) { // Read the next block if needed - BLOCK_DIR_OFS(Node->Data, block) = nEntries; + // BLOCK_DIR_OFS(Node->Data, block) = nEntries; block ++; ofs = 0; base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); @@ -305,93 +338,63 @@ int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name) } } + LOG("bestMatch = %i", bestMatch); + // If EOF was reached with no space, check if we can fit one on the end + if( bestMatch < 0 && ofs + newEntry.rec_len < disk->BlockSize ) { + Node->Size += newEntry.rec_len; + Node->Flags |= VFS_FFLAG_DIRTY; + bestBlock = block; + bestOfs = ofs; + bestSize = newEntry.rec_len; + bestNeedsSplit = 0; + } // Check if a free slot was found - if( bestMatch >= 0 ) { + if( bestMatch >= 0 ) + { // Read-Modify-Write - bestBlock = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock); - if( block > 0 ) - bestMatch = BLOCK_DIR_OFS(Node->Data, bestBlock); + base = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock); VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData ); dirent = blockData + bestOfs; - memcpy(dirent, newEntry, newEntry.rec_len); + // Shorten a pre-existing entry + if(bestNeedsSplit) + { + dirent->rec_len = EXT2_DIRENT_SIZE + dirent->name_len; + bestOfs += dirent->rec_len; + //bestSize -= dirent->rec_len; // (not needed, bestSize is the spare space after) + dirent = blockData + bestOfs; + } + // Insert new file entry + memcpy(dirent, &newEntry, newEntry.rec_len); + // Create a new blank entry + if( bestSize != newEntry.rec_len ) + { + bestOfs += newEntry.rec_len; + dirent = blockData + bestOfs; + + dirent->rec_len = bestSize - newEntry.rec_len; + dirent->type = 0; + } + // Save changes VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData ); } else { // Allocate block, Write - block = Ext2_int_AllocateBlock(Disk, block); - Log_Warning("EXT2", ""); + Uint32 newblock = Ext2_int_AllocateBlock(disk, base / disk->BlockSize); + Ext2_int_AppendBlock(disk, &inode, newblock); + base = newblock * disk->BlockSize; + Node->Size += newEntry.rec_len; + Node->Flags |= VFS_FFLAG_DIRTY; + memcpy(blockData, &newEntry, newEntry.rec_len); + memset(blockData + newEntry.rec_len, 0, disk->BlockSize - newEntry.rec_len); + VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData ); } - Ext2_int_UnlockInode(disk, Node->Inode); + Child->ImplInt ++; + Child->Flags |= VFS_FFLAG_DIRTY; + + //Ext2_int_UnlockInode(disk, Node->Inode); + Mutex_Release(&Node->Lock); + LEAVE('i', 0); return 0; - #else - return 1; - #endif } -// ---- INTERNAL FUNCTIONS ---- -/** - * \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; - - - // Set identifiers - retNode.Inode = InodeID; - retNode.ImplPtr = Disk; - - // Set file length - retNode.Size = inode.i_size; - retNode.Data = NULL; - - // 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); -}