Cleanups in FAT driver
[tpg/acess2.git] / Modules / Filesystems / FAT / fat.c
1 /*\r
2  * Acess 2\r
3  * FAT12/16/32 Driver Version (Incl LFN)\r
4  */\r
5 /**\r
6  * \todo Implement changing of the parent directory when a file is written to\r
7  * \todo Implement file creation / deletion\r
8  */\r
9 #define DEBUG   0\r
10 #define VERBOSE 1\r
11 \r
12 #include <acess.h>\r
13 #include <modules.h>\r
14 #include <vfs.h>\r
15 #include "fs_fat.h"\r
16 \r
17 #define CACHE_FAT       1       //!< Caches the FAT in memory\r
18 #define USE_LFN         1       //!< Enables the use of Long File Names\r
19 \r
20 \r
21 // === TYPES ===\r
22 #if USE_LFN\r
23 typedef struct s_lfncache\r
24 {\r
25         Uint    Inode;\r
26         tFAT_VolInfo    *Disk;\r
27          int    id;\r
28         char    Name[256];\r
29         struct s_lfncache       *Next;\r
30 }       t_lfncache;\r
31 #endif\r
32 \r
33 // === PROTOTYPES ===\r
34  int    FAT_Install(char **Arguments);\r
35 tVFS_Node       *FAT_InitDevice(char *device, char **options);\r
36 void    FAT_Unmount(tVFS_Node *Node);\r
37 \r
38 Uint32  FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);\r
39 Uint32  FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);\r
40 \r
41 void    FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);\r
42 void    FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer);\r
43 \r
44 Uint64  FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
45 Uint64  FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
46 char    *FAT_ReadDir(tVFS_Node *Node, int ID);\r
47 tVFS_Node       *FAT_FindDir(tVFS_Node *Node, char *Name);\r
48  int    FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags);\r
49  int    FAT_Relink(tVFS_Node *node, char *OldName, char *NewName);\r
50 void    FAT_CloseFile(tVFS_Node *node);\r
51 \r
52 // === SEMI-GLOBALS ===\r
53 MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);\r
54 tFAT_VolInfo    gFAT_Disks[8];\r
55  int    giFAT_PartCount = 0;\r
56 #if USE_LFN\r
57 t_lfncache      *fat_lfncache;\r
58 #endif\r
59 tVFS_Driver     gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, NULL};\r
60 \r
61 // === CODE ===\r
62 /**\r
63  * \fn int FAT_Install(char **Arguments)\r
64  * \brief \r
65  */\r
66 int FAT_Install(char **Arguments)\r
67 {\r
68         VFS_AddDriver( &gFAT_FSInfo );\r
69         return MODULE_ERR_OK;\r
70 }\r
71 \r
72 /**\r
73  * \fn tVFS_Node *FAT_InitDevice(char *Device, char **Options)\r
74  * \brief Reads the boot sector of a disk and prepares the structures for it\r
75  */\r
76 tVFS_Node *FAT_InitDevice(char *Device, char **Options)\r
77 {\r
78         fat_bootsect *bs;\r
79          int    i;\r
80         Uint32  FATSz, RootDirSectors, TotSec;\r
81         tVFS_Node       *node = NULL;\r
82         tFAT_VolInfo    *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
83         \r
84         // Temporary Pointer\r
85         bs = &diskInfo->bootsect;\r
86         \r
87         //Open device and read boot sector\r
88         diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);\r
89         if(diskInfo->fileHandle == -1) {\r
90                 Log_Notice("FAT", "Unable to open device '%s'", Device);\r
91                 return NULL;\r
92         }\r
93         \r
94         VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
95         \r
96         if(bs->bps == 0 || bs->spc == 0) {\r
97                 Log_Notice("FAT", "Error in FAT Boot Sector\n");\r
98                 return NULL;\r
99         }\r
100         \r
101         // FAT Type Determining\r
102         // - From Microsoft FAT Specifcation\r
103         RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps;\r
104         \r
105         if(bs->fatSz16 != 0)            FATSz = bs->fatSz16;\r
106         else                                    FATSz = bs->spec.fat32.fatSz32;\r
107         \r
108         if(bs->totalSect16 != 0)                TotSec = bs->totalSect16;\r
109         else                                            TotSec = bs->totalSect32;\r
110         \r
111         diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
112         \r
113         if(diskInfo->ClusterCount < 4085)\r
114                 diskInfo->type = FAT12;\r
115         else if(diskInfo->ClusterCount < 65525)\r
116                 diskInfo->type = FAT16;\r
117         else\r
118                 diskInfo->type = FAT32;\r
119         \r
120         #if VERBOSE\r
121         {\r
122                 char    *sFatType, *sSize;\r
123                 Uint    iSize = diskInfo->ClusterCount * bs->spc * bs->bps / 1024;\r
124                 \r
125                 switch(diskInfo->type)\r
126                 {\r
127                 case FAT12:     sFatType = "FAT12";     break;\r
128                 case FAT16:     sFatType = "FAT16";     break;\r
129                 case FAT32:     sFatType = "FAT32";     break;\r
130                 default:        sFatType = "UNKNOWN";   break;\r
131                 }\r
132                 if(iSize <= 2*1024) {\r
133                         sSize = "KiB";\r
134                 }\r
135                 else if(iSize <= 2*1024*1024) {\r
136                         sSize = "MiB";\r
137                         iSize >>= 10;\r
138                 }\r
139                 else {\r
140                         sSize = "GiB";\r
141                         iSize >>= 20;\r
142                 }\r
143                 Log_Notice("FAT", "'%s' %s, %i %s", Device, sFatType, iSize, sSize);\r
144         }\r
145         #endif\r
146         \r
147         // Get Name\r
148         if(diskInfo->type == FAT32) {\r
149                 for(i=0;i<11;i++)\r
150                         diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]);\r
151         }\r
152         else {\r
153                 for(i=0;i<11;i++)\r
154                         diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]);\r
155         }\r
156         diskInfo->name[11] = '\0';\r
157         \r
158         // Compute Root directory offset\r
159         if(diskInfo->type == FAT32)\r
160                 diskInfo->rootOffset = bs->spec.fat32.rootClust;\r
161         else\r
162                 diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc;\r
163         \r
164         diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors;\r
165         \r
166         //Allow for Caching the FAT\r
167         #if CACHE_FAT\r
168         {\r
169         Uint32  Ofs;\r
170         diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
171         if(diskInfo->FATCache == NULL) {\r
172                 Log_Warning("FAT", "Heap Exhausted\n");\r
173                 return NULL;\r
174         }\r
175         Ofs = bs->resvSectCount*512;\r
176         if(diskInfo->type == FAT12)\r
177         {\r
178                 Uint32  val;\r
179                  int    j;\r
180                 char    buf[1536];\r
181                 for(i = 0; i < diskInfo->ClusterCount/2; i++) {\r
182                         j = i & 511;    //%512\r
183                         if( j == 0 ) {\r
184                                 VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf);\r
185                                 Ofs += 3*512;\r
186                         }\r
187                         val = *((int*)(buf+j*3));\r
188                         diskInfo->FATCache[i*2] = val & 0xFFF;\r
189                         diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF;\r
190                 }\r
191         }\r
192         else if(diskInfo->type == FAT16)\r
193         {\r
194                 Uint16  buf[256];\r
195                 for(i=0;i<diskInfo->ClusterCount;i++) {\r
196                         if( (i & 255) == 0 ) {\r
197                                 VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
198                                 Ofs += 512;\r
199                         }\r
200                         diskInfo->FATCache[i] = buf[i&255];\r
201                 }\r
202         }\r
203         else if(diskInfo->type == FAT32)\r
204         {\r
205                 Uint32  buf[128];\r
206                 for(i=0;i<diskInfo->ClusterCount;i++) {\r
207                         if( (i & 127) == 0 ) {\r
208                                 VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
209                                 Ofs += 512;\r
210                         }\r
211                         diskInfo->FATCache[i] = buf[i&127];\r
212                 }\r
213         }\r
214         LOG("FAT Fully Cached");\r
215         }\r
216         #endif /*CACHE_FAT*/\r
217         \r
218         diskInfo->BytesPerCluster = bs->spc * bs->bps;\r
219         \r
220         // Initalise inode cache for filesystem\r
221         diskInfo->inodeHandle = Inode_GetHandle();\r
222         LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
223         \r
224         // == VFS Interface\r
225         node = &diskInfo->rootNode;\r
226         node->Size = bs->files_in_root;\r
227         node->Inode = diskInfo->rootOffset;     // 0:31 - Cluster, 32:63 - Parent Directory Cluster\r
228         node->ImplPtr = diskInfo;       // Disk info pointer\r
229         node->ImplInt = 0;      // 0:15 - Directory Index, 16: Dirty Flag\r
230         \r
231         node->ReferenceCount = 1;\r
232         \r
233         node->UID = 0;  node->GID = 0;\r
234         node->NumACLs = 1;\r
235         node->ACLs = &gVFS_ACL_EveryoneRWX;\r
236         node->Flags = VFS_FFLAG_DIRECTORY;\r
237         node->CTime = node->MTime = node->ATime = now();\r
238         \r
239         node->Read = node->Write = NULL;\r
240         node->ReadDir = FAT_ReadDir;\r
241         node->FindDir = FAT_FindDir;\r
242         node->Relink = FAT_Relink;\r
243         node->MkNod = FAT_Mknod;\r
244         //node->Close = FAT_Unmount;\r
245         \r
246         giFAT_PartCount ++;\r
247         return node;\r
248 }\r
249 \r
250 /**\r
251  * \brief Closes a mount and marks it as free\r
252  * \param Node  Mount Root\r
253  * \r
254  * \todo Remove FAT Cache\r
255  * \todo Clear LFN Cache\r
256  * \todo Check that all files are closed and flushed\r
257  */\r
258 void FAT_Unmount(tVFS_Node *Node)\r
259 {\r
260         tFAT_VolInfo    *disk = Node->ImplPtr;\r
261         \r
262         // Close Disk Handle\r
263         VFS_Close( disk->fileHandle );\r
264         // Clear Node Cache\r
265         Inode_ClearCache(disk->inodeHandle);\r
266         // Mark as unused\r
267         disk->fileHandle = -2;\r
268         return;\r
269 }\r
270 \r
271 /*\r
272  * ====================\r
273  *   FAT Manipulation\r
274  * ====================\r
275  */\r
276 /**\r
277  * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
278  * \brief Fetches a value from the FAT\r
279  */\r
280 Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
281 {\r
282         Uint32  val = 0;\r
283         #if !CACHE_FAT\r
284         Uint32  ofs = Disk->bootsect.resvSectCount*512;\r
285         #endif\r
286         ENTER("pDisk xCluster", Disk, cluster);\r
287         LOCK( &Disk->lFAT );\r
288         #if CACHE_FAT\r
289         val = Disk->FATCache[cluster];\r
290         if(Disk->type == FAT12 && val == EOC_FAT12)     val = -1;\r
291         if(Disk->type == FAT16 && val == EOC_FAT16)     val = -1;\r
292         if(Disk->type == FAT32 && val == EOC_FAT32)     val = -1;\r
293         #else\r
294         if(Disk->type == FAT12) {\r
295                 VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val);\r
296                 val = (cluster&1 ? val&0xFFF : val>>12);\r
297                 if(val == EOC_FAT12)    val = -1;\r
298         } else if(Disk->type == FAT16) {\r
299                 VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
300                 if(val == EOC_FAT16)    val = -1;\r
301         } else {\r
302                 VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
303                 if(val == EOC_FAT32)    val = -1;\r
304         }\r
305         #endif /*CACHE_FAT*/\r
306         RELEASE( &Disk->lFAT );\r
307         LEAVE('x', val);\r
308         return val;\r
309 }\r
310 \r
311 /**\r
312  * \brief Allocate a new cluster\r
313  */\r
314 Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)\r
315 {\r
316         Uint32  ret = Previous;\r
317         #if CACHE_FAT\r
318         Uint32  eoc;\r
319         \r
320         LOCK(Disk->lFAT);\r
321         for(ret = Previous; ret < Disk->ClusterCount; ret++)\r
322         {\r
323                 if(Disk->FATCache[ret] == 0)\r
324                         goto append;\r
325         }\r
326         for(ret = 0; ret < Previous; ret++)\r
327         {\r
328                 if(Disk->FATCache[ret] == 0)\r
329                         goto append;\r
330         }\r
331         \r
332         RELEASE(Disk->lFAT);\r
333         return 0;\r
334         \r
335 append:\r
336         switch(Disk->type)\r
337         {\r
338         case FAT12:     eoc = EOC_FAT12;        break;\r
339         case FAT16:     eoc = EOC_FAT16;        break;\r
340         case FAT32:     eoc = EOC_FAT32;        break;\r
341         default:        return 0;\r
342         }\r
343         \r
344         Disk->FATCache[ret] = eoc;\r
345         Disk->FATCache[Previous] = ret;\r
346         \r
347         RELEASE(Disk->lFAT);\r
348         return ret;\r
349         #else\r
350         Uint32  val;\r
351         //Uint8 buf[512];\r
352         Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
353         return 0;\r
354         \r
355         if(Disk->type == FAT12) {\r
356                 VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
357                 if( Previous & 1 ) {\r
358                         val &= 0xFFF000;\r
359                         val |= ret;\r
360                 }\r
361                 else {\r
362                         val &= 0xFFF;\r
363                         val |= ret<<12;\r
364                 }\r
365                 VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
366                 \r
367                 VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
368                 if( Cluster & 1 ) {\r
369                         val &= 0xFFF000;\r
370                         val |= eoc;\r
371                 }\r
372                 else {\r
373                         val &= 0x000FFF;\r
374                         val |= eoc<<12;\r
375                 }\r
376                 VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
377         } else if(Disk->type == FAT16) {\r
378                 VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
379                 VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &eoc);\r
380         } else {\r
381                 VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
382                 VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &eoc);\r
383         }\r
384         return ret;\r
385         #endif\r
386 }\r
387 \r
388 /*\r
389  * ====================\r
390  *      Cluster IO\r
391  * ====================\r
392  */\r
393 /**\r
394  * \brief Read a cluster\r
395  */\r
396 void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)\r
397 {\r
398         ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);\r
399         //Log("Cluster = %i (0x%x)", Cluster, Cluster);\r
400         VFS_ReadAt(\r
401                 Disk->fileHandle,\r
402                 (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
403                         * Disk->bootsect.bps,\r
404                 Length,\r
405                 Buffer\r
406                 );\r
407         LEAVE('-');\r
408 }\r
409 \r
410 /**\r
411  * \brief Write a cluster to disk\r
412  */\r
413 void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)\r
414 {\r
415         ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);\r
416         VFS_ReadAt(\r
417                 Disk->fileHandle,\r
418                 (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
419                         * Disk->bootsect.bps,\r
420                 Disk->BytesPerCluster,\r
421                 Buffer\r
422                 );\r
423         LEAVE('-');\r
424 }\r
425 \r
426 /* ====================\r
427  *       File IO\r
428  * ====================\r
429  */\r
430 /**\r
431  * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)\r
432  * \brief Reads data from a specified file\r
433  */\r
434 Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer)\r
435 {\r
436          int    preSkip, count;\r
437          int    i, cluster, pos;\r
438          int    bpc;\r
439         void    *tmpBuf;\r
440         tFAT_VolInfo    *disk = Node->ImplPtr;\r
441         \r
442         ENTER("pNode Xoffset Xlength pbuffer", Node, offset, length, buffer);\r
443         \r
444         // Calculate and Allocate Bytes Per Cluster\r
445         bpc = disk->BytesPerCluster;\r
446         tmpBuf = (void*) malloc(bpc);\r
447         if( !tmpBuf )   return 0;\r
448         \r
449         // Cluster is stored in Inode Field\r
450         cluster = Node->Inode & 0xFFFFFFFF;\r
451         \r
452         // Sanity Check offset\r
453         if(offset > Node->Size) {\r
454                 //LOG("Reading past EOF (%i > %i)", offset, node->Size);\r
455                 LEAVE('i', 0);\r
456                 return 0;\r
457         }\r
458         // Clamp Size\r
459         if(offset + length > Node->Size) {\r
460                 //LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli",\r
461                 //      offset, length, node->Size, node->Size - offset);\r
462                 length = Node->Size - offset;\r
463         }\r
464         \r
465         // Single Cluster including offset\r
466         if(length + offset < bpc)\r
467         {\r
468                 FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
469                 memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length );\r
470                 free(tmpBuf);\r
471                 LEAVE('i', 1);\r
472                 return length;\r
473         }\r
474         \r
475         preSkip = offset / bpc;\r
476         \r
477         //Skip previous clusters\r
478         for(i=preSkip;i--;)     {\r
479                 cluster = FAT_int_GetFatValue(disk, cluster);\r
480                 if(cluster == -1) {\r
481                         Warning("FAT_Read - Offset is past end of cluster chain mark");\r
482                         LEAVE('i', 0);\r
483                         return 0;\r
484                 }\r
485         }\r
486         \r
487         // Get Count of Clusters to read\r
488         count = ((offset%bpc+length) / bpc) + 1;\r
489         \r
490         // Get buffer Position after 1st cluster\r
491         pos = bpc - offset%bpc;\r
492         \r
493         // Read 1st Cluster\r
494         FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
495         memcpy(\r
496                 buffer,\r
497                 (void*)( tmpBuf + (bpc-pos) ),\r
498                 (pos < length ? pos : length)\r
499                 );\r
500         \r
501         if (count == 1) {\r
502                 free(tmpBuf);\r
503                 LEAVE('i', 1);\r
504                 return length;\r
505         }\r
506         \r
507         cluster = FAT_int_GetFatValue(disk, cluster);\r
508         \r
509         #if DEBUG\r
510         LOG("pos=%i\n", pos);\r
511         LOG("Reading the rest of the clusters\n");\r
512         #endif\r
513         \r
514         \r
515         //Read the rest of the cluster data\r
516         for( i = 1; i < count-1; i++ )\r
517         {\r
518                 FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
519                 memcpy((void*)(buffer+pos), tmpBuf, bpc);\r
520                 pos += bpc;\r
521                 cluster = FAT_int_GetFatValue(disk, cluster);\r
522                 if(cluster == -1) {\r
523                         Warning("FAT_Read - Read past End of Cluster Chain");\r
524                         free(tmpBuf);\r
525                         LEAVE('i', 0);\r
526                         return 0;\r
527                 }\r
528         }\r
529         \r
530         FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf);\r
531         memcpy((void*)(buffer+pos), tmpBuf, length-pos);\r
532         \r
533         #if DEBUG\r
534         LOG("Free tmpBuf(0x%x) and Return\n", tmpBuf);\r
535         #endif\r
536         \r
537         free(tmpBuf);\r
538         LEAVE('X', length);\r
539         return length;\r
540 }\r
541 \r
542 /**\r
543  * \brief Write to a file\r
544  * \param Node  File Node\r
545  * \param Offset        Offset within file\r
546  * \param Length        Size of data to write\r
547  * \param Buffer        Data source\r
548  */\r
549 Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
550 {\r
551         tFAT_VolInfo    *disk = Node->ImplPtr;\r
552         void    *tmpBuf;\r
553          int    remLength = Length;\r
554         Uint32  cluster, tmpCluster;\r
555          int    bNewCluster = 0;\r
556         \r
557         if(Offset > Node->Size) return 0;\r
558         \r
559         // Seek Clusters\r
560         cluster = Node->Inode & 0xFFFFFFFF;\r
561         while( Offset > disk->BytesPerCluster )\r
562         {\r
563                 cluster = FAT_int_GetFatValue( disk, cluster );\r
564                 if(cluster == -1) {\r
565                         Log_Warning("FAT", "EOC Unexpectedly Reached");\r
566                         return 0;\r
567                 }\r
568                 Offset -= disk->BytesPerCluster;\r
569         }\r
570         if( Offset == disk->BytesPerCluster )\r
571         {\r
572                 Uint32  tmp = FAT_int_AllocateCluster(disk, cluster);\r
573                 if(!tmp)        return 0;\r
574                 cluster = tmp;\r
575                 Offset -= disk->BytesPerCluster;\r
576         }\r
577         \r
578         if( Offset + Length < disk->BytesPerCluster )\r
579         {\r
580                 tmpBuf = malloc( disk->BytesPerCluster );\r
581                 \r
582                 // Read-Modify-Write\r
583                 FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
584                 memcpy( tmpBuf + Offset, Buffer, Length );\r
585                 FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
586                 \r
587                 free(tmpBuf);\r
588                 return Length;\r
589         }\r
590         \r
591         // Clean up changes within a cluster\r
592         if( Offset )\r
593         {\r
594                 tmpBuf = malloc( disk->BytesPerCluster );\r
595                 \r
596                 // Read-Modify-Write\r
597                 FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
598                 memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset );\r
599                 FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
600                 \r
601                 free(tmpBuf);\r
602                 \r
603                 remLength -= disk->BytesPerCluster - Offset;\r
604                 Buffer += disk->BytesPerCluster - Offset;\r
605                 \r
606                 // Get next cluster (allocating if needed)\r
607                 tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
608                 if(tmpCluster == -1) {\r
609                         tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
610                         if( tmpCluster == 0 ) {\r
611                                 return Length - remLength;\r
612                         }\r
613                 }\r
614                 cluster = tmpCluster;\r
615         }\r
616         \r
617         while( remLength > disk->BytesPerCluster )\r
618         {\r
619                 FAT_int_WriteCluster( disk, cluster, Buffer );\r
620                 Buffer += disk->BytesPerCluster;\r
621                 \r
622                 // Get next cluster (allocating if needed)\r
623                 tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
624                 if(tmpCluster == -1) {\r
625                         bNewCluster = 1;\r
626                         tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
627                         if( tmpCluster == 0 ) {\r
628                                 return Length - remLength;\r
629                         }\r
630                 }\r
631                 cluster = tmpCluster;\r
632         }\r
633         \r
634         // Finish off\r
635         tmpBuf = malloc( disk->BytesPerCluster );\r
636         if( bNewCluster )\r
637                 memset(tmpBuf, 0, disk->BytesPerCluster);\r
638         else\r
639                 FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
640         memcpy( tmpBuf, Buffer, remLength );\r
641         FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
642         free( tmpBuf );\r
643         \r
644         return Length;\r
645 }\r
646 \r
647 /* ====================\r
648  *  File Names & Nodes\r
649  * ====================\r
650  */\r
651 /**\r
652  * \fn void FAT_int_ProperFilename(char *dest, char *src)\r
653  * \brief Converts a FAT directory entry name into a proper filename\r
654  */\r
655 void FAT_int_ProperFilename(char *dest, char *src)\r
656 {\r
657          int    a, b;\r
658         \r
659         for( a = 0; a < 8; a++) {\r
660                 if(src[a] == ' ')       break;\r
661                 dest[a] = src[a];\r
662         }\r
663         b = a;\r
664         a = 8;\r
665         if(src[8] != ' ')\r
666                 dest[b++] = '.';\r
667         for( ; a < 11; a++, b++)        {\r
668                 if(src[a] == ' ')       break;\r
669                 dest[b] = src[a];\r
670         }\r
671         dest[b] = '\0';\r
672         #if DEBUG\r
673         //LOG("dest='%s'", dest);\r
674         #endif\r
675 }\r
676 \r
677 /**\r
678  * \fn char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
679  * \brief Converts either a LFN or a 8.3 Name into a proper name\r
680  */\r
681 char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
682 {\r
683         char    *ret;\r
684          int    len;\r
685         #if USE_LFN\r
686         if(LongFileName && LongFileName[0] != '\0')\r
687         {       \r
688                 len = strlen(LongFileName);\r
689                 ret = malloc(len+1);\r
690                 strcpy(ret, LongFileName);\r
691         }\r
692         else\r
693         {\r
694         #endif\r
695                 ret = (char*) malloc(13);\r
696                 memset(ret, 13, '\0');\r
697                 FAT_int_ProperFilename(ret, ft->name);\r
698         #if USE_LFN\r
699         }\r
700         #endif\r
701         return ret;\r
702 }\r
703 \r
704 /**\r
705  * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
706  * \brief Creates a tVFS_Node structure for a given file entry\r
707  */\r
708 tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)\r
709 {\r
710         tVFS_Node       node = {0};\r
711         tVFS_Node       *ret;\r
712         tFAT_VolInfo    *disk = parent->ImplPtr;\r
713         \r
714         ENTER("pParent pFT sLongFileName", parent, ft, LongFileName);\r
715         \r
716         // Set Other Data\r
717         node.Inode = ft->cluster | (ft->clusterHi<<16);\r
718         node.Size = ft->size;\r
719         LOG("ft->size = %i", ft->size);\r
720         node.ImplPtr = parent->ImplPtr;\r
721         node.UID = 0;   node.GID = 0;\r
722         node.NumACLs = 1;\r
723         \r
724         node.Flags = 0;\r
725         if(ft->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY;\r
726         if(ft->attrib & ATTR_READONLY) {\r
727                 node.Flags |= VFS_FFLAG_READONLY;\r
728                 node.ACLs = &gVFS_ACL_EveryoneRX;       // R-XR-XR-X\r
729         }\r
730         else {\r
731                 node.ACLs = &gVFS_ACL_EveryoneRWX;      // RWXRWXRWX\r
732         }\r
733         \r
734         node.ATime = timestamp(0,0,0,\r
735                         ((ft->adate&0x1F)-1),   //Days\r
736                         ((ft->adate&0x1E0)-1),          //Months\r
737                         1980+((ft->adate&0xFF00)>>8));  //Years\r
738         \r
739         node.CTime = ft->ctimems * 10;  //Miliseconds\r
740         node.CTime += timestamp(\r
741                         (ft->ctime&0x1F)<<1,    //Seconds\r
742                         ((ft->ctime&0x3F0)>>5), //Minutes\r
743                         ((ft->ctime&0xF800)>>11),       //Hours\r
744                         ((ft->cdate&0x1F)-1),           //Days\r
745                         ((ft->cdate&0x1E0)-1),          //Months\r
746                         1980+((ft->cdate&0xFF00)>>8));  //Years\r
747                         \r
748         node.MTime = timestamp(\r
749                         (ft->mtime&0x1F)<<1,    //Seconds\r
750                         ((ft->mtime&0x3F0)>>5), //Minuites\r
751                         ((ft->mtime&0xF800)>>11),       //Hours\r
752                         ((ft->mdate&0x1F)-1),           //Days\r
753                         ((ft->mdate&0x1E0)-1),          //Months\r
754                         1980+((ft->mdate&0xFF00)>>8));  //Years\r
755         \r
756         if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
757                 node.ReadDir = FAT_ReadDir;\r
758                 node.FindDir = FAT_FindDir;\r
759                 node.MkNod = FAT_Mknod;\r
760                 node.Size = -1;\r
761         } else {\r
762                 node.Read = FAT_Read;\r
763                 node.Write = FAT_Write;\r
764         }\r
765         node.Close = FAT_CloseFile;\r
766         node.Relink = FAT_Relink;\r
767         \r
768         ret = Inode_CacheNode(disk->inodeHandle, &node);\r
769         LEAVE('p', ret);\r
770         return ret;\r
771 }\r
772 \r
773 #if USE_LFN\r
774 /**\r
775  \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
776  \brief Return pointer to LFN cache entry\r
777  */\r
778 char *FAT_int_GetLFN(tVFS_Node *node)\r
779 {\r
780         t_lfncache      *tmp;\r
781         tmp = fat_lfncache;\r
782         while(tmp)\r
783         {\r
784                 if(tmp->Inode == node->Inode && tmp->Disk == node->ImplPtr)\r
785                         return tmp->Name;\r
786                 tmp = tmp->Next;\r
787         }\r
788         tmp = malloc(sizeof(t_lfncache));\r
789         tmp->Inode = node->Inode;\r
790         tmp->Disk = node->ImplPtr;\r
791         memset(tmp->Name, 0, 256);\r
792         \r
793         tmp->Next = fat_lfncache;\r
794         fat_lfncache = tmp;\r
795         \r
796         return tmp->Name;\r
797 }\r
798 \r
799 /**\r
800  \fn void FAT_int_DelLFN(tVFS_Node *node)\r
801  \brief Delete a LFN cache entry\r
802 */\r
803 void FAT_int_DelLFN(tVFS_Node *node)\r
804 {\r
805         t_lfncache      *tmp;\r
806         \r
807         if(!fat_lfncache)       return;\r
808         \r
809         if(!fat_lfncache->Next)\r
810         {\r
811                 tmp = fat_lfncache;\r
812                 fat_lfncache = tmp->Next;\r
813                 free(tmp);\r
814                 return;\r
815         }\r
816         tmp = fat_lfncache;\r
817         while(tmp && tmp->Next)\r
818         {\r
819                 if(tmp->Inode == node->Inode && tmp->Disk == node->ImplPtr)\r
820                 {\r
821                         free(tmp->Next);\r
822                         tmp->Next = tmp->Next->Next;\r
823                         return;\r
824                 }\r
825                 tmp = tmp->Next;\r
826         }\r
827 }\r
828 #endif\r
829 \r
830 /* ====================\r
831  *     Directory IO\r
832  * ====================\r
833  */\r
834 /**\r
835  \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
836  \param Node    Node structure of directory\r
837  \param ID      Directory position\r
838 **/\r
839 char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
840 {\r
841         fat_filetable   fileinfo[16];   //Sizeof=32, 16 per sector\r
842          int    a=0;\r
843         tFAT_VolInfo    *disk = Node->ImplPtr;\r
844         Uint32  cluster, offset;\r
845          int    preSkip;\r
846         char    *ret;\r
847         #if USE_LFN\r
848         char    *lfn = NULL;\r
849         #endif\r
850         \r
851         ENTER("pNode iID", Node, ID);\r
852         \r
853         // Get Byte Offset and skip\r
854         offset = ID * sizeof(fat_filetable);\r
855         preSkip = offset / (512 * disk->bootsect.spc);\r
856         LOG("disk->bootsect.spc = %i", disk->bootsect.spc);\r
857         LOG("Node->size = %i", Node->Size);\r
858         cluster = Node->Inode & 0xFFFFFFFF;     // Cluster ID\r
859         \r
860         // Do Cluster Skip\r
861         // - Pre FAT32 had a reserved area for the root.\r
862         if( disk->type == FAT32 || cluster != disk->rootOffset )\r
863         {\r
864                 //Skip previous clusters\r
865                 for(a=preSkip;a--;)     {\r
866                         cluster = FAT_int_GetFatValue(disk, cluster);\r
867                         // Check for end of cluster chain\r
868                         if(cluster == -1) {     LEAVE('n');     return NULL;}\r
869                 }\r
870         }\r
871         \r
872         // Bounds Checking (Used to spot heap overflows)\r
873         if(cluster > disk->ClusterCount + 2)\r
874         {\r
875                 Log_Warning("FAT", "Cluster ID is over cluster count (0x%x>0x%x)",\r
876                         cluster, disk->ClusterCount+2);\r
877                 LEAVE('n');\r
878                 return NULL;\r
879         }\r
880         \r
881         LOG("cluster=0x%x, ID=%i", cluster, ID);\r
882         \r
883         // Compute Offsets\r
884         // - Pre FAT32 cluster base (in sectors)\r
885         if( cluster == disk->rootOffset && disk->type != FAT32 )\r
886                 offset = disk->bootsect.resvSectCount + cluster*disk->bootsect.spc;\r
887         else\r
888         {       // FAT32 cluster base (in sectors)\r
889                 offset = disk->firstDataSect;\r
890                 offset += (cluster - 2) * disk->bootsect.spc;\r
891         }\r
892         // Sector in cluster\r
893         if(disk->bootsect.spc != 1)\r
894                 offset += (ID / 16) % disk->bootsect.spc;\r
895         // Offset in sector\r
896         a = ID % 16;\r
897 \r
898         LOG("offset=%i, a=%i", offset, a);\r
899         \r
900         // Read Sector\r
901         VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo);        // Read Dir Data\r
902         \r
903         LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]);\r
904         //Check if this is the last entry\r
905         if( fileinfo[a].name[0] == '\0' ) {\r
906                 Node->Size = ID;\r
907                 LOG("End of list");\r
908                 LEAVE('n');\r
909                 return NULL;    // break\r
910         }\r
911         \r
912         // Check for empty entry\r
913         if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
914                 LOG("Empty Entry");\r
915                 LEAVE('p', VFS_SKIP);\r
916                 return VFS_SKIP;        // Skip\r
917         }\r
918         \r
919         #if USE_LFN\r
920         // Get Long File Name Cache\r
921         lfn = FAT_int_GetLFN(Node);\r
922         if(fileinfo[a].attrib == ATTR_LFN)\r
923         {\r
924                 fat_longfilename        *lfnInfo;\r
925                  int    len;\r
926                 \r
927                 lfnInfo = (fat_longfilename *) &fileinfo[a];\r
928                 if(lfnInfo->id & 0x40)  memset(lfn, 0, 256);\r
929                 // Get the current length\r
930                 len = strlen(lfn);\r
931                 \r
932                 // Sanity Check (FAT implementations should not allow >255 bytes)\r
933                 if(len + 13 > 255)      return VFS_SKIP;\r
934                 // Rebase all bytes\r
935                 for(a=len+1;a--;)       lfn[a+13] = lfn[a];\r
936                 \r
937                 // Append new bytes\r
938                 lfn[ 0] = lfnInfo->name1[0];    lfn[ 1] = lfnInfo->name1[1];\r
939                 lfn[ 2] = lfnInfo->name1[2];    lfn[ 3] = lfnInfo->name1[3];\r
940                 lfn[ 4] = lfnInfo->name1[4];    \r
941                 lfn[ 5] = lfnInfo->name2[0];    lfn[ 6] = lfnInfo->name2[1];\r
942                 lfn[ 7] = lfnInfo->name2[2];    lfn[ 8] = lfnInfo->name2[3];\r
943                 lfn[ 9] = lfnInfo->name2[4];    lfn[10] = lfnInfo->name2[5];\r
944                 lfn[11] = lfnInfo->name3[0];    lfn[12] = lfnInfo->name3[1];\r
945                 LEAVE('p', VFS_SKIP);\r
946                 return VFS_SKIP;\r
947         }\r
948         #endif\r
949         \r
950         //Check if it is a volume entry\r
951         if(fileinfo[a].attrib & 0x08) {\r
952                 LEAVE('p', VFS_SKIP);\r
953                 return VFS_SKIP;\r
954         }\r
955         // Ignore . and ..\r
956         if(fileinfo[a].name[0] == '.') {\r
957                 LEAVE('p', VFS_SKIP);\r
958                 return VFS_SKIP;\r
959         }       \r
960         \r
961         LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'\n",\r
962                 fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
963                 fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
964                 fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
965         \r
966         #if USE_LFN\r
967         //node = FAT_int_CreateNode(Node, &fileinfo[a], lfn);\r
968         ret = FAT_int_CreateName(Node, &fileinfo[a], lfn);\r
969         lfn[0] = '\0';\r
970         #else\r
971         //node = FAT_int_CreateNode(Node, &fileinfo[a], NULL);\r
972         ret = FAT_int_CreateName(Node, &fileinfo[a], NULL);\r
973         #endif\r
974         \r
975         LEAVE('s', ret);\r
976         return ret;\r
977 }\r
978 \r
979 /**\r
980  * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
981  * \brief Finds an entry in the current directory\r
982  */\r
983 tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name)\r
984 {\r
985         fat_filetable   fileinfo[16];\r
986         char    tmpName[11];\r
987         #if USE_LFN\r
988         fat_longfilename        *lfnInfo;\r
989         char    *lfn = NULL;\r
990          int    lfnPos=255, lfnId = -1;\r
991         #endif\r
992          int    i=0;\r
993         tVFS_Node       *tmpNode;\r
994         Uint64  diskOffset;\r
995         tFAT_VolInfo    *disk = Node->ImplPtr;\r
996         Uint32  dirCluster;\r
997         Uint32  cluster;\r
998         \r
999         ENTER("pNode sname", Node, name);\r
1000         \r
1001         // Fast Returns\r
1002         if(!name || name[0] == '\0') {\r
1003                 LEAVE('n');\r
1004                 return NULL;\r
1005         }\r
1006         \r
1007         #if USE_LFN\r
1008         lfn = FAT_int_GetLFN(Node);\r
1009         #endif\r
1010         \r
1011         dirCluster = Node->Inode & 0xFFFFFFFF;\r
1012         // Seek to Directory\r
1013         if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
1014                 diskOffset = (disk->bootsect.resvSectCount+dirCluster*disk->bootsect.spc) << 9;\r
1015         else\r
1016                 diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc) << 9;\r
1017         \r
1018         for(;;i++)\r
1019         {\r
1020                 // Load sector\r
1021                 if((i & 0xF) == 0) {\r
1022                         //Log("FAT_FindDir: diskOffset = 0x%x", diskOffset);\r
1023                         VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo);\r
1024                         diskOffset += 512;\r
1025                 }\r
1026                 \r
1027                 //Check if the files are free\r
1028                 if(fileinfo[i&0xF].name[0] == '\0')     break;          //Free and last\r
1029                 if(fileinfo[i&0xF].name[0] == '\xE5')   goto loadCluster;       //Free\r
1030                 \r
1031                 \r
1032                 #if USE_LFN\r
1033                 // Long File Name Entry\r
1034                 if(fileinfo[i&0xF].attrib == ATTR_LFN)\r
1035                 {\r
1036                         lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
1037                         if(lfnInfo->id & 0x40) {\r
1038                                 memset(lfn, 0, 256);\r
1039                                 lfnPos = 255;\r
1040                         }\r
1041                         lfn[lfnPos--] = lfnInfo->name3[1];      lfn[lfnPos--] = lfnInfo->name3[0];\r
1042                         lfn[lfnPos--] = lfnInfo->name2[5];      lfn[lfnPos--] = lfnInfo->name2[4];\r
1043                         lfn[lfnPos--] = lfnInfo->name2[3];      lfn[lfnPos--] = lfnInfo->name2[2];\r
1044                         lfn[lfnPos--] = lfnInfo->name2[1];      lfn[lfnPos--] = lfnInfo->name2[0];\r
1045                         lfn[lfnPos--] = lfnInfo->name1[4];      lfn[lfnPos--] = lfnInfo->name1[3];\r
1046                         lfn[lfnPos--] = lfnInfo->name1[2];      lfn[lfnPos--] = lfnInfo->name1[1];\r
1047                         lfn[lfnPos--] = lfnInfo->name1[0];\r
1048                         if((lfnInfo->id&0x3F) == 1)\r
1049                         {\r
1050                                 memcpy(lfn, lfn+lfnPos+1, 256-lfnPos);\r
1051                                 lfnId = i+1;\r
1052                         }\r
1053                 }\r
1054                 else\r
1055                 {\r
1056                         // Remove LFN if it does not apply\r
1057                         if(lfnId != i)  lfn[0] = '\0';\r
1058                 #endif\r
1059                         // Get Real Filename\r
1060                         FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
1061                 \r
1062                         LOG("tmpName = '%s'", tmpName);\r
1063                 \r
1064                         //Only Long name is case sensitive, 8.3 is not\r
1065                         #if USE_LFN\r
1066                         if(strucmp(tmpName, name) == 0 || strcmp(lfn, name) == 0) {\r
1067                         #else\r
1068                         if(strucmp(tmpName, name) == 0) {\r
1069                         #endif\r
1070                                 cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
1071                                 tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
1072                                 if(tmpNode == NULL)     // Node is not cached\r
1073                                 {\r
1074                                         #if USE_LFN\r
1075                                         tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], lfn);\r
1076                                         #else\r
1077                                         tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], NULL);\r
1078                                         #endif\r
1079                                 }\r
1080                                 #if USE_LFN\r
1081                                 lfn[0] = '\0';\r
1082                                 #endif\r
1083                                 LEAVE('p', tmpNode);\r
1084                                 return tmpNode;\r
1085                         }\r
1086                 #if USE_LFN\r
1087                 }\r
1088                 #endif\r
1089                 \r
1090         loadCluster:\r
1091                 //Load Next cluster?\r
1092                 if( ((i+1) >> 4) % disk->bootsect.spc == 0 && ((i+1) & 0xF) == 0)\r
1093                 {\r
1094                         if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
1095                                 continue;\r
1096                         dirCluster = FAT_int_GetFatValue(disk, dirCluster);\r
1097                         if(dirCluster == -1)    break;\r
1098                         diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512;\r
1099                 }\r
1100         }\r
1101         \r
1102         LEAVE('n');\r
1103         return NULL;\r
1104 }\r
1105 \r
1106 /**\r
1107  * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
1108  * \brief Create a new node\r
1109  */\r
1110 int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
1111 {\r
1112         return 0;\r
1113 }\r
1114 \r
1115 /**\r
1116  * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
1117  * \brief Rename / Delete a file\r
1118  */\r
1119 int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
1120 {\r
1121         return 0;\r
1122 }\r
1123 \r
1124 /**\r
1125  * \fn void FAT_CloseFile(tVFS_Node *Node)\r
1126  * \brief Close an open file\r
1127  */\r
1128 void FAT_CloseFile(tVFS_Node *Node)\r
1129 {\r
1130         tFAT_VolInfo    *disk = Node->ImplPtr;\r
1131         if(Node == NULL)        return ;\r
1132         \r
1133         Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
1134         #if USE_LFN\r
1135         // If node has been uncached and is a directory, delete the LFN cache\r
1136         if(     !Inode_GetCache(disk->inodeHandle, Node->Inode) && Node->Flags & VFS_FFLAG_DIRECTORY)\r
1137                 FAT_int_DelLFN(Node);\r
1138         else    // Get Cache references the node, so dereference it\r
1139                 Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
1140         #endif\r
1141         return ;\r
1142 }\r

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