Working on cleaning up the FAT driver, but atm it's more messy than ever.
authorJohn Hodge <[email protected]>
Sun, 28 Mar 2010 11:47:35 +0000 (19:47 +0800)
committerJohn Hodge <[email protected]>
Sun, 28 Mar 2010 11:47:35 +0000 (19:47 +0800)
<UNTESTED COMMIT>

Kernel/Makefile.BuildNum
Kernel/include/vfs.h
Kernel/vfs/nodecache.c
Modules/Filesystems/FAT/fat.c

index dbceacb..200094b 100644 (file)
@@ -1 +1 @@
-BUILD_NUM = 1601
+BUILD_NUM = 1602
index 5d39a98..b75710f 100644 (file)
@@ -324,7 +324,7 @@ extern tVFS_Node    *Inode_GetCache(int Handle, Uint64 Inode);
  */
 extern tVFS_Node       *Inode_CacheNode(int Handle, tVFS_Node *Node);
 /**
- * \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
+ * \fn int Inode_UncacheNode(int Handle, Uint64 Inode)
  * \brief Dereferences (and removes if needed) a node from the cache
  * \param Handle       A handle returned by Inode_GetHandle()
  * \param Inode        Value of the Inode field of the ::tVFS_Node you want to remove
index 0124e62..a898d5d 100644 (file)
@@ -121,9 +121,9 @@ void Inode_UncacheNode(int Handle, Uint64 Inode)
        tCachedInode    *ent, *prev;
        
        cache = Inode_int_GetFSCache(Handle);
-       if(!cache)      return;
+       if(!cache)      return ;
        
-       if(Inode > cache->MaxCached)    return;
+       if(Inode > cache->MaxCached)    return ;
        
        // Search Cache
        ent = cache->FirstNode;
@@ -147,8 +147,10 @@ void Inode_UncacheNode(int Handle, Uint64 Inode)
                                
                        free(ent);
                }
-               return;
+               return ;
        }
+       
+       return ;
 }
 
 /**
index bfd4a6a..92aa431 100644 (file)
@@ -9,14 +9,16 @@
 #define DEBUG  0\r
 #define VERBOSE        1\r
 \r
+#define CACHE_FAT      1       //!< Caches the FAT in memory\r
+#define USE_LFN                1       //!< Enables the use of Long File Names\r
+\r
 #include <acess.h>\r
 #include <modules.h>\r
 #include <vfs.h>\r
 #include "fs_fat.h"\r
 \r
-#define CACHE_FAT      1       //!< Caches the FAT in memory\r
-#define USE_LFN                1       //!< Enables the use of Long File Names\r
-\r
+#define FAT_FLAG_DIRTY 0x10000\r
+#define FAT_FLAG_DELETE        0x20000\r
 \r
 // === TYPES ===\r
 #if USE_LFN\r
@@ -226,7 +228,7 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options)
        node->Size = bs->files_in_root;\r
        node->Inode = diskInfo->rootOffset;     // 0:31 - Cluster, 32:63 - Parent Directory Cluster\r
        node->ImplPtr = diskInfo;       // Disk info pointer\r
-       node->ImplInt = 0;      // 0:15 - Directory Index, 16: Dirty Flag\r
+       node->ImplInt = 0;      // 0:15 - Directory Index, 16: Dirty Flag, 17: Deletion Flag\r
        \r
        node->ReferenceCount = 1;\r
        \r
@@ -268,6 +270,69 @@ void FAT_Unmount(tVFS_Node *Node)
        return;\r
 }\r
 \r
+/**\r
+ * \brief Converts an offset in a file into a disk address\r
+ * \param Node File (or directory) node\r
+ * \param Offset       Offset in the file\r
+ * \param Addr Return Address\r
+ * \param Cluster      Set to the current cluster (or the last one if \a Offset\r
+ *                  is past EOC) - Not touched if the node is the root\r
+ *                  directory.\r
+ * \return Zero on success, non-zero on error\r
+ */\r
+int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster)\r
+{\r
+       Uint32  cluster;\r
+       Uint64  addr;\r
+        int    skip;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       \r
+       ENTER("pNode XOffset", Node, Offset);\r
+       \r
+       cluster = Node->Inode & 0xFFFFFFFF;     // Cluster ID\r
+       \r
+       // Do Cluster Skip\r
+       // - Pre FAT32 had a reserved area for the root.\r
+       if( disk->type == FAT32 || cluster != disk->rootOffset )\r
+       {\r
+               skip = Offset / disk->BytesPerCluster;\r
+               // Skip previous clusters\r
+               for(; skip-- ; )\r
+               {\r
+                       if(Cluster)     *Cluster = cluster;\r
+                       cluster = FAT_int_GetFatValue(disk, cluster);\r
+                       // Check for end of cluster chain\r
+                       if(cluster == -1) {     LEAVE('i', 1);  return 1;}\r
+               }\r
+               if(Cluster)     *Cluster = cluster;\r
+       }\r
+       \r
+       // Bounds Checking (Used to spot corruption)\r
+       if(cluster > disk->ClusterCount + 2)\r
+       {\r
+               Log_Warning("FAT", "Cluster ID is over cluster count (0x%x>0x%x)",\r
+                       cluster, disk->ClusterCount+2);\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       \r
+       // Compute Offsets\r
+       // - Pre FAT32 cluster base (in sectors)\r
+       if( cluster == disk->rootOffset && disk->type != FAT32 ) {\r
+               addr = disk->bootsect.resvSectCount * disk->bootsect.bps;\r
+               addr += cluster * disk->BytesPerCluster;\r
+       }\r
+       else {\r
+               addr = disk->firstDataSect;\r
+               addr += (cluster - 2) * disk->BytesPerCluster;\r
+       }\r
+       addr += Offset % disk->BytesPerCluster;\r
+       \r
+       *Addr = addr;\r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+\r
 /*\r
  * ====================\r
  *   FAT Manipulation\r
@@ -352,7 +417,9 @@ append:
        Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
        return 0;\r
        \r
-       if(Disk->type == FAT12) {\r
+       switch(Disk->type)\r
+       {\r
+       case FAT12:\r
                VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
                if( Previous & 1 ) {\r
                        val &= 0xFFF000;\r
@@ -364,7 +431,7 @@ append:
                }\r
                VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
                \r
-               VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
+               VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
                if( Cluster & 1 ) {\r
                        val &= 0xFFF000;\r
                        val |= eoc;\r
@@ -373,18 +440,71 @@ append:
                        val &= 0x000FFF;\r
                        val |= eoc<<12;\r
                }\r
-               VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
-       } else if(Disk->type == FAT16) {\r
+               VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
+               break;\r
+       case FAT16:\r
                VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
-               VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &eoc);\r
-       } else {\r
+               VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);\r
+               break;\r
+       case FAT32:\r
                VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
-               VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &eoc);\r
+               VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);\r
+               break;\r
        }\r
        return ret;\r
        #endif\r
 }\r
 \r
+/**\r
+ * \brief Free's a cluster\r
+ * \return The original contents of the cluster\r
+ */\r
+Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)\r
+{\r
+       Uint32  ret;\r
+       #if CACHE_FAT\r
+       LOCK(Disk->lFAT);\r
+       \r
+       ret = Disk->FATCache[Cluster];\r
+       Disk->FATCache[Cluster] = 0;\r
+       \r
+       RELEASE(Disk->lFAT);\r
+       #else\r
+       Uint32  val;\r
+       LOCK(Disk->lFAT);\r
+       switch(Disk->type)\r
+       {\r
+       case FAT12:\r
+               VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
+               if( Cluster & 1 ) {\r
+                       ret = val & 0xFFF0000;\r
+                       val &= 0xFFF;\r
+               }\r
+               else {\r
+                       ret = val & 0xFFF;\r
+                       val &= 0xFFF000;\r
+               }\r
+               VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
+               break;\r
+       case FAT16:\r
+               VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
+               val = 0;\r
+               VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
+               break;\r
+       case FAT32:\r
+               VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
+               val = 0;\r
+               VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
+               break;\r
+       }\r
+       RELEASE(Disk->lFAT);\r
+       #endif\r
+       if(Disk->type == FAT12 && ret == EOC_FAT12)     ret = -1;\r
+       if(Disk->type == FAT16 && ret == EOC_FAT16)     ret = -1;\r
+       if(Disk->type == FAT32 && ret == EOC_FAT32)     ret = -1;\r
+       return ret;\r
+}\r
+\r
 /*\r
  * ====================\r
  *      Cluster IO\r
@@ -770,10 +890,75 @@ tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFi
        return ret;\r
 }\r
 \r
+/* ====================\r
+ *     Directory IO\r
+ * ====================\r
+ */\r
+\r
+/**\r
+ * \brief Reads a sector from the disk\r
+ */\r
+int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)\r
+{\r
+       Uint64  addr;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       \r
+       ENTER("pNode iSector pEntry", Node, Sector, Buffer)\r
+       \r
+       if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))\r
+       {\r
+               LEAVE('i', 1);\r
+               return 1;\r
+       }\r
+       \r
+       // Read Sector\r
+       VFS_ReadAt(disk->fileHandle, addr, 512, Buffer);        // Read Dir Data\r
+       \r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+\r
+/**\r
+ * \brief Writes an entry to the disk\r
+ * \todo Support expanding a directory\r
+ * \return Zero on success, non-zero on error\r
+ */\r
+int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)\r
+{\r
+       Uint64  addr = 0;\r
+        int    tmp;\r
+       Uint32  cluster = 0;\r
+       tFAT_VolInfo    *disk = Node->ImplPtr;\r
+       \r
+       ENTER("pNode iID pEntry", Node, ID, Entry);\r
+       \r
+       tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
+       if( tmp )\r
+       {\r
+               //TODO: Allocate a cluster\r
+               cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);\r
+               if(cluster == -1) {\r
+                       Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);\r
+                       LEAVE('i', 1);\r
+                       return 1;\r
+               }\r
+               FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
+       }\r
+       \r
+\r
+       LOG("addr = 0x%llx", addr);\r
+       \r
+       // Read Sector\r
+       VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);      // Read Dir Data\r
+       \r
+       LEAVE('i', 0);\r
+       return 0;\r
+}\r
+\r
 #if USE_LFN\r
 /**\r
- \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
- \brief Return pointer to LFN cache entry\r
\fn char *FAT_int_GetLFN(tVFS_Node *node)\r
\brief Return pointer to LFN cache entry\r
  */\r
 char *FAT_int_GetLFN(tVFS_Node *node)\r
 {\r
@@ -797,9 +982,9 @@ char *FAT_int_GetLFN(tVFS_Node *node)
 }\r
 \r
 /**\r
- \fn void FAT_int_DelLFN(tVFS_Node *node)\r
- \brief Delete a LFN cache entry\r
-*/\r
\fn void FAT_int_DelLFN(tVFS_Node *node)\r
\brief Delete a LFN cache entry\r
+ */\r
 void FAT_int_DelLFN(tVFS_Node *node)\r
 {\r
        t_lfncache      *tmp;\r
@@ -827,22 +1012,15 @@ void FAT_int_DelLFN(tVFS_Node *node)
 }\r
 #endif\r
 \r
-/* ====================\r
- *     Directory IO\r
- * ====================\r
- */\r
 /**\r
- \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
\param Node   Node structure of directory\r
\param ID     Directory position\r
-**/\r
\fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
* \param Node Node structure of directory\r
* \param ID   Directory position\r
+ */\r
 char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
 {\r
        fat_filetable   fileinfo[16];   //Sizeof=32, 16 per sector\r
         int    a=0;\r
-       tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       Uint32  cluster, offset;\r
-        int    preSkip;\r
        char    *ret;\r
        #if USE_LFN\r
        char    *lfn = NULL;\r
@@ -850,58 +1028,20 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID)
        \r
        ENTER("pNode iID", Node, ID);\r
        \r
-       // Get Byte Offset and skip\r
-       offset = ID * sizeof(fat_filetable);\r
-       preSkip = offset / (512 * disk->bootsect.spc);\r
-       LOG("disk->bootsect.spc = %i", disk->bootsect.spc);\r
-       LOG("Node->size = %i", Node->Size);\r
-       cluster = Node->Inode & 0xFFFFFFFF;     // Cluster ID\r
-       \r
-       // Do Cluster Skip\r
-       // - Pre FAT32 had a reserved area for the root.\r
-       if( disk->type == FAT32 || cluster != disk->rootOffset )\r
-       {\r
-               //Skip previous clusters\r
-               for(a=preSkip;a--;)     {\r
-                       cluster = FAT_int_GetFatValue(disk, cluster);\r
-                       // Check for end of cluster chain\r
-                       if(cluster == -1) {     LEAVE('n');     return NULL;}\r
-               }\r
-       }\r
-       \r
-       // Bounds Checking (Used to spot heap overflows)\r
-       if(cluster > disk->ClusterCount + 2)\r
+       if(FAT_int_ReadDirSector(Node, ID, fileinfo))\r
        {\r
-               Log_Warning("FAT", "Cluster ID is over cluster count (0x%x>0x%x)",\r
-                       cluster, disk->ClusterCount+2);\r
                LEAVE('n');\r
                return NULL;\r
        }\r
        \r
-       LOG("cluster=0x%x, ID=%i", cluster, ID);\r
-       \r
-       // Compute Offsets\r
-       // - Pre FAT32 cluster base (in sectors)\r
-       if( cluster == disk->rootOffset && disk->type != FAT32 )\r
-               offset = disk->bootsect.resvSectCount + cluster*disk->bootsect.spc;\r
-       else\r
-       {       // FAT32 cluster base (in sectors)\r
-               offset = disk->firstDataSect;\r
-               offset += (cluster - 2) * disk->bootsect.spc;\r
-       }\r
-       // Sector in cluster\r
-       if(disk->bootsect.spc != 1)\r
-               offset += (ID / 16) % disk->bootsect.spc;\r
        // Offset in sector\r
        a = ID % 16;\r
 \r
-       LOG("offset=%i, a=%i", offset, a);\r
-       \r
-       // Read Sector\r
-       VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo);        // Read Dir Data\r
+       LOG("a = %i", a);\r
        \r
        LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]);\r
-       //Check if this is the last entry\r
+       \r
+       // Check if this is the last entry\r
        if( fileinfo[a].name[0] == '\0' ) {\r
                Node->Size = ID;\r
                LOG("End of list");\r
@@ -964,11 +1104,9 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID)
                fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
        \r
        #if USE_LFN\r
-       //node = FAT_int_CreateNode(Node, &fileinfo[a], lfn);\r
        ret = FAT_int_CreateName(Node, &fileinfo[a], lfn);\r
        lfn[0] = '\0';\r
        #else\r
-       //node = FAT_int_CreateNode(Node, &fileinfo[a], NULL);\r
        ret = FAT_int_CreateName(Node, &fileinfo[a], NULL);\r
        #endif\r
        \r
@@ -986,14 +1124,12 @@ tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name)
        char    tmpName[11];\r
        #if USE_LFN\r
        fat_longfilename        *lfnInfo;\r
-       char    *lfn = NULL;\r
+       char    lfn[256];\r
         int    lfnPos=255, lfnId = -1;\r
        #endif\r
         int    i=0;\r
        tVFS_Node       *tmpNode;\r
-       Uint64  diskOffset;\r
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
-       Uint32  dirCluster;\r
        Uint32  cluster;\r
        \r
        ENTER("pNode sname", Node, name);\r
@@ -1004,29 +1140,19 @@ tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name)
                return NULL;\r
        }\r
        \r
-       #if USE_LFN\r
-       lfn = FAT_int_GetLFN(Node);\r
-       #endif\r
-       \r
-       dirCluster = Node->Inode & 0xFFFFFFFF;\r
-       // Seek to Directory\r
-       if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
-               diskOffset = (disk->bootsect.resvSectCount+dirCluster*disk->bootsect.spc) << 9;\r
-       else\r
-               diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc) << 9;\r
-       \r
        for(;;i++)\r
        {\r
-               // Load sector\r
                if((i & 0xF) == 0) {\r
-                       //Log("FAT_FindDir: diskOffset = 0x%x", diskOffset);\r
-                       VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo);\r
-                       diskOffset += 512;\r
+                       if(FAT_int_ReadDirSector(Node, i, fileinfo))\r
+                       {\r
+                               LEAVE('n');\r
+                               return NULL;\r
+                       }\r
                }\r
                \r
                //Check if the files are free\r
                if(fileinfo[i&0xF].name[0] == '\0')     break;          //Free and last\r
-               if(fileinfo[i&0xF].name[0] == '\xE5')   goto loadCluster;       //Free\r
+               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       //Free\r
                \r
                \r
                #if USE_LFN\r
@@ -1086,17 +1212,6 @@ tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name)
                #if USE_LFN\r
                }\r
                #endif\r
-               \r
-       loadCluster:\r
-               //Load Next cluster?\r
-               if( ((i+1) >> 4) % disk->bootsect.spc == 0 && ((i+1) & 0xF) == 0)\r
-               {\r
-                       if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
-                               continue;\r
-                       dirCluster = FAT_int_GetFatValue(disk, dirCluster);\r
-                       if(dirCluster == -1)    break;\r
-                       diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512;\r
-               }\r
        }\r
        \r
        LEAVE('n');\r
@@ -1118,6 +1233,27 @@ int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)
  */\r
 int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
 {\r
+       tVFS_Node       *child;\r
+       fat_filetable   ft = {0};\r
+       Uint32  cluster;\r
+        int    ofs;\r
+       \r
+       child = FAT_FindDir(Node, OldName);\r
+       if(!child)      return 0;\r
+       \r
+       // Delete?\r
+       if( NewName == NULL )\r
+       {\r
+               child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close\r
+               cluster = Node->Inode & 0xFFFFFFFF;\r
+               ofs = child->ImplInt & 0xFFFF;\r
+               ft.name[0] = '\xE9';\r
+       }\r
+       // Rename\r
+       else\r
+       {\r
+       }\r
+       \r
        return 0;\r
 }\r
 \r
@@ -1130,13 +1266,33 @@ void FAT_CloseFile(tVFS_Node *Node)
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        if(Node == NULL)        return ;\r
        \r
+       if( Node->ImplInt & FAT_FLAG_DIRTY ) {\r
+               #if 0\r
+               // Write back\r
+               FAT_int_UpdateDirEntry(\r
+                       Node->Inode >> 32, Node->ImplInt & 0xFFFF,\r
+                       Node\r
+                       );\r
+               #endif\r
+       }\r
+       \r
+       if( Node->ReferenceCount == 1 )\r
+       {\r
+               // Delete LFN Cache\r
+               #if USE_LFN\r
+               if(     Node->Flags & VFS_FFLAG_DIRECTORY)\r
+                       FAT_int_DelLFN(Node);\r
+               #endif\r
+               \r
+               // Delete File\r
+               if( Node->ImplInt & FAT_FLAG_DELETE ) {\r
+                       // Since the node is marked, we only need to remove it's data\r
+                       Uint32  cluster = Node->Inode & 0xFFFFFFFF;\r
+                       while( cluster != -1 )\r
+                               cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster);\r
+               }\r
+       }\r
+       \r
        Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
-       #if USE_LFN\r
-       // If node has been uncached and is a directory, delete the LFN cache\r
-       if(     !Inode_GetCache(disk->inodeHandle, Node->Inode) && Node->Flags & VFS_FFLAG_DIRECTORY)\r
-               FAT_int_DelLFN(Node);\r
-       else    // Get Cache references the node, so dereference it\r
-               Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
-       #endif\r
        return ;\r
 }\r

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