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

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