Kernel - Slight reworks to timer code
[tpg/acess2.git] / Modules / Filesystems / Ext2 / dir.c
index 1832ff9..5eb476f 100644 (file)
 #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);
+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);
+
+// === GLOBALS ===
+tVFS_NodeType  gExt2_DirType = {
+       .TypeName = "ext2-dir",
+       .ReadDir = Ext2_ReadDir,
+       .FindDir = Ext2_FindDir,
+       .MkNod = Ext2_MkNod,
+       .Relink = Ext2_Relink,
+       .Link = Ext2_Link,
+       .Close = Ext2_CloseFile
+       };
+tVFS_NodeType  gExt2_FileType = {
+       .TypeName = "ext2-file",
+       .Read = Ext2_Read,
+       .Write = Ext2_Write,
+       .Close = Ext2_CloseFile
+       };
 
 // === CODE ===
 /**
@@ -27,10 +49,10 @@ tVFS_Node   *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name);
 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;
@@ -38,7 +60,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;
        
@@ -78,20 +99,19 @@ 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);
 }
 
 /**
@@ -100,16 +120,17 @@ 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, char *Filename)
+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);
@@ -122,11 +143,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;
@@ -148,15 +168,51 @@ 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_AllocateNode(Parent, Flags);
+       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;
 }
 
 /**
@@ -166,17 +222,119 @@ int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
  * \param Name New name for the node
  * \return Boolean Failure - See ::tVFS_Node.Link for info
  */
-int Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, char *Name)
-{
+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;
@@ -195,6 +353,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;
@@ -203,9 +362,7 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
        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;
+       retNode.Type = &gExt2_FileType;
        
        switch(inode.i_mode & EXT2_S_IFMT)
        {
@@ -220,21 +377,16 @@ tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
                break;
        // Directory
        case EXT2_S_IFDIR:
-               retNode.ReadDir = Ext2_ReadDir;
-               retNode.FindDir = Ext2_FindDir;
-               retNode.MkNod = Ext2_MkNod;
-               //retNode.Relink = Ext2_Relink;
+               retNode.Type = &gExt2_DirType;
                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;

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