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

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