X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FFilesystems%2FExt2%2Fdir.c;h=c7d8dd899cceb78602bc32bc592043fb3ca870ef;hb=4f1a9b430a3fa57bbe52a6a2fe546f6fe93c389d;hp=86092b0fca11c6f361badd5884dcc054586c646f;hpb=351dd3b194833c923bad0292e9019320fb2a41fa;p=tpg%2Facess2.git diff --git a/Modules/Filesystems/Ext2/dir.c b/Modules/Filesystems/Ext2/dir.c index 86092b0f..c7d8dd89 100644 --- a/Modules/Filesystems/Ext2/dir.c +++ b/Modules/Filesystems/Ext2/dir.c @@ -11,25 +11,31 @@ #define VERBOSE 0 #include "ext2_common.h" +// === MACROS === +#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, char *FileName); - int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags); -tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name); +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); // === CODE === /** - \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos) - \brief Reads a directory entry -*/ + * \brief Reads a directory entry + * \param Node Directory node + * \param Pos Position of desired element + */ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) { tExt2_Inode inode; - char namebuf[EXT2_NAME_LEN+1]; tExt2_DirEnt dirent; Uint64 Base; // Block's Base Address - int block = 0, ofs = 0; + int block = 0; + Uint ofs = 0; int entNum = 0; tExt2_Disk *disk = Node->ImplPtr; Uint size; @@ -37,7 +43,6 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) ENTER("pNode iPos", Node, Pos); // Read directory's inode - //Ext2_int_GetInode(Node, &inode); Ext2_int_ReadInode(disk, Node->Inode, &inode); size = inode.i_size; @@ -47,6 +52,7 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) // 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) { VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); @@ -76,39 +82,38 @@ char *Ext2_ReadDir(tVFS_Node *Node, int Pos) //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 + dirent.name[ dirent.name_len ] = '\0'; // Cap off string // Ignore . and .. (these are done in the VFS) - if( (namebuf[0] == '.' && namebuf[1] == '\0') - || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) { + 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('s', namebuf); + LEAVE('s', dirent.name); // Create new node - return strdup(namebuf); + return strdup(dirent.name); } /** - \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename) - \brief Gets information about a file - \param node vfs node - Parent Node - \param filename String - Name of file - \return VFS Node of file -*/ -tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename) + * \brief Gets information about a file + * \param Node Parent Node + * \param Filename Name of wanted file + * \return VFS Node of file + */ +tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *Filename) { tExt2_Disk *disk = Node->ImplPtr; tExt2_Inode inode; - char namebuf[EXT2_NAME_LEN+1]; tExt2_DirEnt dirent; Uint64 Base; // Block's Base Address - int block = 0, ofs = 0; + int block = 0; + Uint ofs = 0; int entNum = 0; Uint size; + int filenameLen = strlen(Filename); // Read directory's inode Ext2_int_ReadInode(disk, Node->Inode, &inode); @@ -121,11 +126,10 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename) while(size > 0) { VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent); - VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf ); - namebuf[ dirent.name_len ] = '\0'; // Cap off string + dirent.name[ dirent.name_len ] = '\0'; // Cap off string // If it matches, create a node and return it - if(strcmp(namebuf, Filename) == 0) - return Ext2_int_CreateNode( disk, dirent.inode, namebuf ); + if(dirent.name_len == filenameLen && strcmp(dirent.name, Filename) == 0) + return Ext2_int_CreateNode( disk, dirent.inode ); // Increment pointers ofs += dirent.rec_len; size -= dirent.rec_len; @@ -147,20 +151,173 @@ tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename) } /** - * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags) + * \fn int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags) * \brief Create a new node */ -int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags) +int 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)); + + // 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 +} + +/** + * \brief Rename a file + * \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 + */ +int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName) { + 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 + * \return Boolean Failure - See ::tVFS_Node.Link for info + */ +int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name) +{ + #if 0 + tExt2_Disk *disk = Node->ImplPtr; + tExt2_Inode inode; + tExt2_DirEnt dirent; + tExt2_DirEnt newEntry; + Uint64 Base; // Block's Base Address + int block = 0, ofs = 0; + Uint size; + void *blockData; + int bestMatch = -1, bestSize, bestBlock, bestOfs; + int nEntries; + + 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+8)&~3; + 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; + + // Get a lock on the inode + Ext2_int_LockInode(disk, Node->Inode); + + // 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; + // Find File + while(size > 0) + { + dirent = blockData + ofs; + // Sanity Check the entry + if(ofs + dirent->rec_len > disk->BlockSize) { + Log_Warning("EXT2", + "Directory entry %i of inode 0x%x extends over a block boundary", + nEntries, (Uint)Node->Inode); + } + else { + + // Free entry + if(dirent->type == 0) { + if( dirent->rec_len >= newEntry.rec_len + && (bestMatch == -1 || bestSize > dirent->rec_len) ) + { + bestMatch = nEntries; + bestSize = dirent->rec_len; + bestBlock = block; + bestOfs = ofs; + } + } + // Non free - check name to avoid duplicates + else { + if(strncmp(Name, dirent->name, dirent->name_len) == 0) { + Ext2_int_UnlockInode(disk, Node->Inode); + return 1; // ERR_??? + } + } + } + + // Increment the pointer + nEntries ++; + ofs += dirent->rec_len; + if( ofs >= disk->BlockSize ) { + // Read the next block if needed + BLOCK_DIR_OFS(Node->Data, block) = nEntries; + block ++; + ofs = 0; + base = Ext2_int_GetBlockAddr(disk, inode.i_block, block); + VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData ); + } + } + + // Check if a free slot was found + 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); + VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData ); + dirent = blockData + bestOfs; + memcpy(dirent, newEntry, newEntry.rec_len); + VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData ); + } + else { + // Allocate block, Write + block = Ext2_int_AllocateBlock(Disk, block); + Log_Warning("EXT2", ""); + } + + Ext2_int_UnlockInode(disk, Node->Inode); return 0; + #else + return 1; + #endif } // ---- INTERNAL FUNCTIONS ---- /** - * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) + * \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, char *Name) +tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID) { tExt2_Inode inode; tVFS_Node retNode; @@ -179,6 +336,7 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) // Set file length retNode.Size = inode.i_size; + retNode.Data = NULL; // Set Access Permissions retNode.UID = inode.i_uid; @@ -207,18 +365,17 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name) retNode.ReadDir = Ext2_ReadDir; retNode.FindDir = Ext2_FindDir; retNode.MkNod = Ext2_MkNod; - //retNode.Relink = Ext2_Relink; + retNode.Relink = Ext2_Relink; + retNode.Link = Ext2_Link; retNode.Flags = VFS_FFLAG_DIRECTORY; + retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) ); break; - // Unknown, Write protect and hide it to be safe + // Unknown, Write protect it to be safe default: - retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN; + retNode.Flags = VFS_FFLAG_READONLY; break; } - // Check if the file should be hidden - //if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN; - // Set Timestamps retNode.ATime = inode.i_atime * 1000; retNode.MTime = inode.i_mtime * 1000;