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

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