Various changes, most of them involving the FAT and Ext2 Drivers, adding write support
[tpg/acess2.git] / Modules / Filesystems / Ext2 / dir.c
diff --git a/Modules/Filesystems/Ext2/dir.c b/Modules/Filesystems/Ext2/dir.c
new file mode 100644 (file)
index 0000000..0ab3ed3
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Acess OS
+ * Ext2 Driver Version 1
+ */
+/**
+ * \file dir.c
+ * \brief Second Extended Filesystem Driver
+ * \todo Implement file full write support
+ */
+#define DEBUG  1
+#define VERBOSE        0
+#include "ext2_common.h"
+
+
+// === 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);
+
+// === CODE ===
+/**
+ \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+ \brief Reads a directory entry
+*/
+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    entNum = 0;
+       tExt2_Disk      *disk = Node->ImplPtr;
+       Uint    size;
+       
+       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;
+       
+       LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
+       
+       // Find Entry
+       // Get First Block
+       // - Do this ourselves as it is a simple operation
+       Base = inode.i_block[0] * disk->BlockSize;
+       while(Pos -- && size > 0)
+       {
+               VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+               ofs += dirent.rec_len;
+               size -= dirent.rec_len;
+               entNum ++;
+               
+               if(ofs >= disk->BlockSize) {
+                       block ++;
+                       if( ofs > disk->BlockSize ) {
+                               Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring",
+                                       entNum-1, Node->Inode);
+                       }
+                       ofs = 0;
+                       Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+               }
+       }
+       
+       // Check for the end of the list
+       if(size <= 0) {
+               LEAVE('n');
+               return NULL;
+       }
+       
+       // 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);
+       VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
+       namebuf[ 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')) {
+               LEAVE('p', VFS_SKIP);
+               return VFS_SKIP;        // Skip
+       }
+       
+       LEAVE('s', namebuf);
+       // Create new node
+       return strdup(namebuf);
+}
+
+/**
+ \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)
+{
+       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    entNum = 0;
+       Uint    size;
+       
+       // Read directory's inode
+       Ext2_int_ReadInode(disk, Node->Inode, &inode);
+       size = inode.i_size;
+       
+       // Get First Block
+       // - Do this ourselves as it is a simple operation
+       Base = inode.i_block[0] * disk->BlockSize;
+       // Find File
+       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
+               // If it matches, create a node and return it
+               if(strcmp(namebuf, Filename) == 0)
+                       return Ext2_int_CreateNode( disk, dirent.inode, namebuf );
+               // Increment pointers
+               ofs += dirent.rec_len;
+               size -= dirent.rec_len;
+               entNum ++;
+               
+               // Check for end of block
+               if(ofs >= disk->BlockSize) {
+                       block ++;
+                       if( ofs > disk->BlockSize ) {
+                               Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring",
+                                       entNum-1, Node->Inode);
+                       }
+                       ofs = 0;
+                       Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+               }
+       }
+       
+       return NULL;
+}
+
+/**
+ * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
+ * \brief Create a new node
+ */
+int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
+{
+       return 0;
+}
+
+// ---- INTERNAL FUNCTIONS ----
+/**
+ * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
+ * \brief Create a new VFS Node
+ */
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
+{
+       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;
+       
+       // 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.Read = Ext2_Read;
+       retNode.Write = Ext2_Write;
+       retNode.Close = Ext2_CloseFile;
+       
+       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.ReadDir = Ext2_ReadDir;
+               retNode.FindDir = Ext2_FindDir;
+               retNode.MkNod = Ext2_MkNod;
+               //retNode.Relink = Ext2_Relink;
+               retNode.Flags = VFS_FFLAG_DIRECTORY;
+               break;
+       // Unknown, Write protect and hide it to be safe 
+       default:
+               retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;
+               break;
+       }
+       
+       // Check if the file should be hidden
+       //if(Name[0] == '.')    retNode.Flags |= VFS_FFLAG_HIDDEN;
+       
+       // Set Timestamps
+       retNode.ATime = now();
+       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);
+}

UCC git Repository :: git.ucc.asn.au