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

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