More work on the FAT driver, more messy, but more complete
[tpg/acess2.git] / Modules / Filesystems / FAT / fat.c
index d063c87..9a3c79e 100644 (file)
@@ -2,6 +2,10 @@
  * Acess 2\r
  * FAT12/16/32 Driver Version (Incl LFN)\r
  */\r
+/**\r
+ * \todo Implement changing of the parent directory when a file is written to\r
+ * \todo Implement file creation / deletion\r
+ */\r
 #define DEBUG  0\r
 #define VERBOSE        1\r
 \r
@@ -13,6 +17,8 @@
 #include <vfs.h>\r
 #include "fs_fat.h"\r
 \r
+#define FAT_FLAG_DIRTY 0x10000\r
+#define FAT_FLAG_DELETE        0x20000\r
 \r
 // === TYPES ===\r
 #if USE_LFN\r
@@ -83,14 +89,14 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options)
        //Open device and read boot sector\r
        diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);\r
        if(diskInfo->fileHandle == -1) {\r
-               Warning("FAT_InitDisk - Unable to open device '%s'", Device);\r
+               Log_Notice("FAT", "Unable to open device '%s'", Device);\r
                return NULL;\r
        }\r
        \r
        VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
        \r
        if(bs->bps == 0 || bs->spc == 0) {\r
-               Warning("FAT_InitDisk - Error in FAT Boot Sector\n");\r
+               Log_Notice("FAT", "Error in FAT Boot Sector\n");\r
                return NULL;\r
        }\r
        \r
@@ -136,7 +142,7 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options)
                        sSize = "GiB";\r
                        iSize >>= 20;\r
                }\r
-               Log("[FAT ] '%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
+               Log_Notice("FAT", "'%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
        }\r
        #endif\r
        \r
@@ -165,7 +171,7 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options)
        Uint32  Ofs;\r
        diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
        if(diskInfo->FATCache == NULL) {\r
-               Warning("FAT_InitDisk - Heap Exhausted\n");\r
+               Log_Warning("FAT", "Heap Exhausted\n");\r
                return NULL;\r
        }\r
        Ofs = bs->resvSectCount*512;\r
@@ -222,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
@@ -264,8 +270,73 @@ 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
- * === FILE IO ===\r
+ * ====================\r
+ *   FAT Manipulation\r
+ * ====================\r
  */\r
 /**\r
  * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
@@ -343,10 +414,12 @@ append:
        #else\r
        Uint32  val;\r
        //Uint8 buf[512];\r
-       Warning("[FAT  ] TODO: Implement cluster allocation with non cached FAT");\r
+       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
@@ -358,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
@@ -367,18 +440,76 @@ 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
+ * ====================\r
+ */\r
 /**\r
  * \brief Read a cluster\r
  */\r
@@ -412,6 +543,10 @@ void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)
        LEAVE('-');\r
 }\r
 \r
+/* ====================\r
+ *       File IO\r
+ * ====================\r
+ */\r
 /**\r
  * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
  * \brief Reads data from a specified file\r
@@ -457,13 +592,22 @@ Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer)
                return length;\r
        }\r
        \r
+       #if 0\r
+       if( FAT_int_GetAddress(Node, offset, &addr) )\r
+       {\r
+               Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
+               LEAVE('i', 0);\r
+               return 0;\r
+       }\r
+       #endif\r
+       \r
        preSkip = offset / bpc;\r
        \r
        //Skip previous clusters\r
        for(i=preSkip;i--;)     {\r
                cluster = FAT_int_GetFatValue(disk, cluster);\r
                if(cluster == -1) {\r
-                       Warning("FAT_Read - Offset is past end of cluster chain mark");\r
+                       Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
                        LEAVE('i', 0);\r
                        return 0;\r
                }\r
@@ -547,7 +691,7 @@ Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
        {\r
                cluster = FAT_int_GetFatValue( disk, cluster );\r
                if(cluster == -1) {\r
-                       Warning("[FAT  ] EOC Unexpectedly Reached");\r
+                       Log_Warning("FAT", "EOC Unexpectedly Reached");\r
                        return 0;\r
                }\r
                Offset -= disk->BytesPerCluster;\r
@@ -629,6 +773,10 @@ Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
        return Length;\r
 }\r
 \r
+/* ====================\r
+ *  File Names & Nodes\r
+ * ====================\r
+ */\r
 /**\r
  * \fn void FAT_int_ProperFilename(char *dest, char *src)\r
  * \brief Converts a FAT directory entry name into a proper filename\r
@@ -751,10 +899,80 @@ 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
+// I should probably more tightly associate the LFN cache with the node\r
+// somehow, maybe by adding a field to tVFS_Node before locking it\r
+// Maybe .Cache or something like that (something that is free'd by the\r
+// Inode_UncacheNode function)\r
+       \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
@@ -778,9 +996,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
@@ -809,17 +1027,14 @@ void FAT_int_DelLFN(tVFS_Node *node)
 #endif\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
@@ -827,58 +1042,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
-               Warning("FAT_ReadDir - 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
@@ -941,11 +1118,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
@@ -963,14 +1138,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
@@ -981,29 +1154,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] == '\0')     break;  // Free and last\r
+               if(fileinfo[i&0xF].name[0] == '\xE5')   continue;       //Free\r
                \r
                \r
                #if USE_LFN\r
@@ -1063,17 +1226,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
@@ -1095,7 +1247,36 @@ int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)
  */\r
 int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
 {\r
-       return 0;\r
+       tVFS_Node       *child;\r
+       fat_filetable   ft = {0};\r
+        int    ret;\r
+       \r
+       child = FAT_FindDir(Node, OldName);\r
+       if(!child)      return ENOTFOUND;\r
+       \r
+       // Delete?\r
+       if( NewName == NULL )\r
+       {\r
+               child->ImplInt |= FAT_FLAG_DELETE;      // Mark for deletion on close\r
+               \r
+               // Delete from the directory\r
+               ft.name[0] = '\xE9';\r
+               FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft);\r
+               \r
+               // Return success\r
+               ret = EOK;\r
+       }\r
+       // Rename\r
+       else\r
+       {\r
+               Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')",\r
+                       Node, OldName, NewName);\r
+               ret = ENOTIMPL;\r
+       }\r
+       \r
+       // Close child\r
+       child->Close( child );\r
+       return ret;\r
 }\r
 \r
 /**\r
@@ -1107,13 +1288,40 @@ void FAT_CloseFile(tVFS_Node *Node)
        tFAT_VolInfo    *disk = Node->ImplPtr;\r
        if(Node == NULL)        return ;\r
        \r
+       // Update the node if it's dirty (don't bother if it's marked for\r
+       // deletion)\r
+       if( Node->ImplInt & FAT_FLAG_DIRTY && !(Node->ImplInt & FAT_FLAG_DELETE) )\r
+       {\r
+               tFAT_VolInfo    buf[16];\r
+               tFAT_VolInfo    *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ];\r
+               \r
+               FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf);\r
+               ft->size = Node->Size;\r
+               // TODO: update adate, mtime, mdate\r
+               FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft);\r
+               \r
+               Node->ImplInt &= ~FAT_FLAG_DIRTY;\r
+       }\r
+       \r
+       // TODO: Make this more thread safe somehow, probably by moving the\r
+       // Inode_UncacheNode higher up and saving the cluster value somewhere\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