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

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