3 * FAT12/16/32 Driver Version (Incl LFN)
\r
13 #define CACHE_FAT 1 //!< Caches the FAT in memory
\r
14 #define USE_LFN 1 //!< Enables the use of Long File Names
\r
18 typedef struct s_lfncache {
\r
22 struct s_lfncache *Next;
\r
26 // === PROTOTYPES ===
\r
27 int FAT_Install(char **Arguments);
\r
28 tVFS_Node *FAT_InitDevice(char *device, char **options);
\r
29 void FAT_Unmount(tVFS_Node *Node);
\r
30 Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
\r
31 Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
\r
32 char *FAT_ReadDir(tVFS_Node *dirNode, int dirpos);
\r
33 tVFS_Node *FAT_FindDir(tVFS_Node *dirNode, char *file);
\r
34 int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags);
\r
35 int FAT_Relink(tVFS_Node *node, char *OldName, char *NewName);
\r
36 void FAT_CloseFile(tVFS_Node *node);
\r
38 // === SEMI-GLOBALS ===
\r
39 MODULE_DEFINE(0, 0x51 /*v0.80*/, FAT32, FAT_Install, NULL, NULL);
\r
40 tFAT_VolInfo gFAT_Disks[8];
\r
41 int giFAT_PartCount = 0;
\r
43 Uint32 *fat_cache[8];
\r
46 t_lfncache *fat_lfncache;
\r
48 tVFS_Driver gFAT_FSInfo = {
\r
49 "fat", 0, FAT_InitDevice, FAT_Unmount, NULL
\r
54 * \fn int FAT_Install(char **Arguments)
\r
57 int FAT_Install(char **Arguments)
\r
59 VFS_AddDriver( &gFAT_FSInfo );
\r
64 * \fn tVFS_Node *FAT_InitDevice(char *Device, char **options)
\r
65 * \brief Reads the boot sector of a disk and prepares the structures for it
\r
67 tVFS_Node *FAT_InitDevice(char *Device, char **options)
\r
71 Uint32 FATSz, RootDirSectors, TotSec, CountofClusters;
\r
72 tVFS_Node *node = NULL;
\r
73 tFAT_VolInfo *diskInfo = &gFAT_Disks[giFAT_PartCount];
\r
76 bs = &diskInfo->bootsect;
\r
78 //Open device and read boot sector
\r
79 diskInfo->fileHandle = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);
\r
80 if(diskInfo->fileHandle == -1) {
\r
81 Warning("FAT_InitDisk - Unable to open device '%s'", Device);
\r
85 VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);
\r
87 if(bs->bps == 0 || bs->spc == 0) {
\r
88 Warning("FAT_InitDisk - Error in FAT Boot Sector\n");
\r
92 //FAT Type Determining
\r
93 // From Microsoft FAT Specifcation
\r
94 RootDirSectors = ((bs->files_in_root*32) + (bs->bps - 1)) / bs->bps;
\r
96 if(bs->fatSz16 != 0) FATSz = bs->fatSz16;
\r
97 else FATSz = bs->spec.fat32.fatSz32;
\r
99 if(bs->totalSect16 != 0) TotSec = bs->totalSect16;
\r
100 else TotSec = bs->totalSect32;
\r
102 CountofClusters = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;
\r
104 if(CountofClusters < 4085)
\r
105 diskInfo->type = FAT12;
\r
106 else if(CountofClusters < 65525)
\r
107 diskInfo->type = FAT16;
\r
109 diskInfo->type = FAT32;
\r
113 char *sFatType, *sSize;
\r
114 Uint iSize = CountofClusters * bs->spc / 2;
\r
116 switch(diskInfo->type)
\r
118 case FAT12: sFatType = "FAT12"; break;
\r
119 case FAT16: sFatType = "FAT16"; break;
\r
120 case FAT32: sFatType = "FAT32"; break;
\r
122 if(iSize <= 2*1024) {
\r
125 else if(iSize <= 2*1024*1024) {
\r
133 Log("[FAT ] '%s' %s, %i %s", Device, sFatType, iSize, sSize);
\r
138 if(diskInfo->type == FAT32) {
\r
140 diskInfo->name[i] = (bs->spec.fat32.label[i] == ' ' ? '\0' : bs->spec.fat32.label[i]);
\r
144 diskInfo->name[i] = (bs->spec.fat16.label[i] == ' ' ? '\0' : bs->spec.fat16.label[i]);
\r
146 diskInfo->name[11] = '\0';
\r
148 //Compute Root directory offset
\r
149 if(diskInfo->type == FAT32)
\r
150 diskInfo->rootOffset = bs->spec.fat32.rootClust;
\r
152 diskInfo->rootOffset = (FATSz * bs->fatCount) / bs->spc;
\r
154 diskInfo->clusterCount = CountofClusters;
\r
156 diskInfo->firstDataSect = bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors;
\r
158 //Allow for Caching the FAT
\r
162 fat_cache[ giFAT_PartCount ] = (Uint32*)malloc(sizeof(Uint32)*CountofClusters);
\r
163 if(fat_cache[giFAT_PartCount] == NULL) {
\r
164 Warning("FAT_InitDisk - Heap Exhausted\n");
\r
167 Ofs = bs->resvSectCount*512;
\r
168 if(diskInfo->type == FAT12) {
\r
172 for(i=0;i<CountofClusters/2;i++) {
\r
173 j = i & 511; //%512
\r
175 VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf);
\r
178 val = *((int*)(buf+j*3));
\r
179 fat_cache[giFAT_PartCount][i*2] = val & 0xFFF;
\r
180 fat_cache[giFAT_PartCount][i*2+1] = (val>>12) & 0xFFF;
\r
183 if(diskInfo->type == FAT16) {
\r
185 for(i=0;i<CountofClusters;i++) {
\r
186 if( (i & 255) == 0 ) {
\r
187 VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);
\r
190 fat_cache[giFAT_PartCount][i] = buf[i&255];
\r
193 if(diskInfo->type == FAT32) {
\r
195 for(i=0;i<CountofClusters;i++) {
\r
196 if( (i & 127) == 0 ) {
\r
197 VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);
\r
200 fat_cache[giFAT_PartCount][i] = buf[i&127];
\r
203 LOG("FAT Fully Cached");
\r
205 #endif /*CACHE_FAT*/
\r
207 //Initalise inode cache for FAT
\r
208 gFAT_Disks[giFAT_PartCount].inodeHandle = Inode_GetHandle();
\r
209 LOG("Inode Cache handle is %i", gFAT_Disks[giFAT_PartCount].inodeHandle);
\r
211 // == VFS Interface
\r
212 node = &gFAT_Disks[giFAT_PartCount].rootNode;
\r
213 node->Inode = diskInfo->rootOffset;
\r
214 node->Size = bs->files_in_root; // Unknown - To be set on readdir
\r
215 node->ImplInt = giFAT_PartCount;
\r
217 node->ReferenceCount = 1;
\r
219 node->UID = 0; node->GID = 0;
\r
221 node->ACLs = &gVFS_ACL_EveryoneRWX;
\r
222 node->Flags = VFS_FFLAG_DIRECTORY;
\r
223 node->CTime = node->MTime = node->ATime = now();
\r
225 node->Read = node->Write = NULL;
\r
226 node->ReadDir = FAT_ReadDir;
\r
227 node->FindDir = FAT_FindDir;
\r
228 node->Relink = FAT_Relink;
\r
229 node->MkNod = FAT_Mknod;
\r
230 //node->Close = FAT_CloseDevice;
\r
232 giFAT_PartCount ++;
\r
237 * \fn void FAT_Unmount(tVFS_Node *Node)
\r
238 * \brief Closes a mount and marks it as free
\r
240 void FAT_Unmount(tVFS_Node *Node)
\r
242 // Close Disk Handle
\r
243 VFS_Close( gFAT_Disks[Node->ImplInt].fileHandle );
\r
244 // Clear Node Cache
\r
245 Inode_ClearCache(gFAT_Disks[Node->ImplInt].inodeHandle);
\r
247 gFAT_Disks[Node->ImplInt].fileHandle = -2;
\r
252 * \fn static Uint32 FAT_int_GetFatValue(int handle, Uint32 cluster)
\r
253 * \brief Fetches a value from the FAT
\r
255 static Uint32 FAT_int_GetFatValue(int handle, Uint32 cluster)
\r
258 ENTER("iHandle xCluster", handle, cluster);
\r
260 val = fat_cache[handle][cluster];
\r
262 if(gFAT_Disks[handle].type == FAT12) {
\r
263 VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+(cluster&~1)*3, 3, &val);
\r
264 val = (cluster&1 ? val&0xFFF : val>>12);
\r
265 } else if(gFAT_Disks[handle].type == FAT16) {
\r
266 VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+cluster*2, 2, &val);
\r
268 VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+cluster*4, 4, &val);
\r
270 #endif /*CACHE_FAT*/
\r
275 /* Reads a cluster's data
\r
277 static void FAT_int_ReadCluster(int Handle, Uint32 Cluster, int Length, void *Buffer)
\r
279 ENTER("iHandle xCluster iLength pBuffer", Handle, Cluster, Length, Buffer);
\r
281 gFAT_Disks[Handle].fileHandle,
\r
282 (gFAT_Disks[Handle].firstDataSect + (Cluster-2)*gFAT_Disks[Handle].bootsect.spc )
\r
283 * gFAT_Disks[Handle].bootsect.bps,
\r
291 * \fn Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)
\r
292 * \brief Reads data from a specified file
\r
294 Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)
\r
296 int preSkip, count;
\r
297 int handle = node->ImplInt;
\r
298 int i, cluster, pos;
\r
302 tFAT_VolInfo *disk = &gFAT_Disks[node->ImplInt];
\r
304 ENTER("Xoffset Xlength pbuffer", offset, length, buffer);
\r
306 // Calculate and Allocate Bytes Per Cluster
\r
307 bpc = disk->bootsect.spc * disk->bootsect.bps;
\r
308 tmpBuf = (void*) malloc(bpc);
\r
309 LOG("malloc'd %i bytes", bpc);
\r
311 // Cluster is stored in Inode Field
\r
312 cluster = node->Inode;
\r
315 if (disk->type == FAT12) eocMarker = EOC_FAT12;
\r
316 else if(disk->type == FAT16) eocMarker = EOC_FAT16;
\r
317 else if(disk->type == FAT32) eocMarker = EOC_FAT32;
\r
319 Log("ERROR: Unsupported FAT Variant.\n");
\r
325 // Sanity Check offset
\r
326 if(offset > node->Size) {
\r
327 //LOG("Reading past EOF (%i > %i)", offset, node->Size);
\r
331 if(offset + length > node->Size) {
\r
332 //LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli",
\r
333 // offset, length, node->Size, node->Size - offset);
\r
334 length = node->Size - offset;
\r
337 // Single Cluster including offset
\r
338 if(length + offset < bpc)
\r
340 FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);
\r
341 memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length );
\r
347 preSkip = offset / bpc;
\r
349 //Skip previous clusters
\r
350 for(i=preSkip;i--;) {
\r
351 cluster = FAT_int_GetFatValue(handle, cluster);
\r
352 if(cluster == eocMarker) {
\r
353 Warning("FAT_Read - Offset is past end of cluster chain mark");
\r
357 // Get Count of Clusters to read
\r
358 count = ((offset%bpc+length) / bpc) + 1;
\r
360 // Get buffer Position after 1st cluster
\r
361 pos = bpc - offset%bpc;
\r
363 // Read 1st Cluster
\r
364 FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);
\r
367 (void*)( tmpBuf + (bpc-pos) ),
\r
368 (pos < length ? pos : length)
\r
377 cluster = FAT_int_GetFatValue(handle, cluster);
\r
380 LOG("pos=%i\n", pos);
\r
381 LOG("Reading the rest of the clusters\n");
\r
385 //Read the rest of the cluster data
\r
386 for( i = 1; i < count-1; i++ )
\r
388 FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);
\r
389 memcpy((void*)(buffer+pos), tmpBuf, bpc);
\r
391 cluster = FAT_int_GetFatValue(handle, cluster);
\r
392 if(cluster == eocMarker) {
\r
393 Warning("FAT_Read - Read past End of Cluster Chain");
\r
400 FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);
\r
401 memcpy((void*)(buffer+pos), tmpBuf, length-pos);
\r
404 LOG("Free tmpBuf(0x%x) and Return\n", tmpBuf);
\r
408 LEAVE('X', length);
\r
413 * \fn Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)
\r
415 Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer)
\r
421 * \fn static void FAT_int_ProperFilename(char *dest, char *src)
\r
422 * \brief Converts a FAT directory entry name into a proper filename
\r
424 static void FAT_int_ProperFilename(char *dest, char *src)
\r
428 for( a = 0; a < 8; a++) {
\r
429 if(src[a] == ' ') break;
\r
436 for( ; a < 11; a++, b++) {
\r
437 if(src[a] == ' ') break;
\r
442 //Log("FAT_int_ProperFilename: dest='%s'", dest);
\r
447 * \fn char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)
\r
448 * \brief Converts either a LFN or a 8.3 Name into a proper name
\r
450 char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)
\r
455 if(LongFileName && LongFileName[0] != '\0')
\r
457 len = strlen(LongFileName);
\r
458 ret = malloc(len+1);
\r
459 strcpy(ret, LongFileName);
\r
464 ret = (char*) malloc(13);
\r
465 memset(ret, 13, '\0');
\r
466 FAT_int_ProperFilename(ret, ft->name);
\r
474 * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)
\r
475 * \brief Creates a tVFS_Node structure for a given file entry
\r
477 tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName)
\r
479 tVFS_Node node = {0};
\r
482 ENTER("pParent pFT sLongFileName", parent, ft, LongFileName);
\r
485 node.Inode = ft->cluster | (ft->clusterHi<<16);
\r
486 node.Size = ft->size;
\r
487 node.ImplInt = parent->ImplInt;
\r
488 node.UID = 0; node.GID = 0;
\r
490 node.ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX
\r
493 if(ft->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY;
\r
494 if(ft->attrib & ATTR_READONLY) node.Flags |= VFS_FFLAG_READONLY;
\r
496 node.ATime = timestamp(0,0,0,
\r
497 ((ft->adate&0x1F)-1), //Days
\r
498 ((ft->adate&0x1E0)-1), //Months
\r
499 1980+((ft->adate&0xFF00)>>8)); //Years
\r
501 node.CTime = ft->ctimems * 10; //Miliseconds
\r
502 node.CTime += timestamp(
\r
503 (ft->ctime&0x1F)<<1, //Seconds
\r
504 ((ft->ctime&0x3F0)>>5), //Minutes
\r
505 ((ft->ctime&0xF800)>>11), //Hours
\r
506 ((ft->cdate&0x1F)-1), //Days
\r
507 ((ft->cdate&0x1E0)-1), //Months
\r
508 1980+((ft->cdate&0xFF00)>>8)); //Years
\r
510 node.MTime = timestamp(
\r
511 (ft->mtime&0x1F)<<1, //Seconds
\r
512 ((ft->mtime&0x3F0)>>5), //Minuites
\r
513 ((ft->mtime&0xF800)>>11), //Hours
\r
514 ((ft->mdate&0x1F)-1), //Days
\r
515 ((ft->mdate&0x1E0)-1), //Months
\r
516 1980+((ft->mdate&0xFF00)>>8)); //Years
\r
518 if(node.Flags & VFS_FFLAG_DIRECTORY) {
\r
519 node.ReadDir = FAT_ReadDir;
\r
520 node.FindDir = FAT_FindDir;
\r
521 node.MkNod = FAT_Mknod;
\r
524 node.Read = FAT_Read;
\r
525 node.Write = FAT_Write;
\r
527 node.Close = FAT_CloseFile;
\r
528 node.Relink = FAT_Relink;
\r
530 ret = Inode_CacheNode(gFAT_Disks[parent->ImplInt].inodeHandle, &node);
\r
537 \fn char *FAT_int_GetLFN(tVFS_Node *node)
\r
538 \brief Return pointer to LFN cache entry
\r
540 char *FAT_int_GetLFN(tVFS_Node *node)
\r
543 tmp = fat_lfncache;
\r
546 if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt)
\r
550 tmp = malloc(sizeof(t_lfncache));
\r
551 tmp->Inode = node->Inode;
\r
552 tmp->Impl = node->ImplInt;
\r
553 memset(tmp->Name, 0, 256);
\r
555 tmp->Next = fat_lfncache;
\r
556 fat_lfncache = tmp;
\r
562 \fn void FAT_int_DelLFN(tVFS_Node *node)
\r
563 \brief Delete a LFN cache entry
\r
565 void FAT_int_DelLFN(tVFS_Node *node)
\r
569 if(!fat_lfncache) return;
\r
571 if(!fat_lfncache->Next)
\r
573 tmp = fat_lfncache;
\r
574 fat_lfncache = tmp->Next;
\r
578 tmp = fat_lfncache;
\r
579 while(tmp && tmp->Next)
\r
581 if(tmp->Inode == node->Inode && tmp->Impl == node->ImplInt)
\r
584 tmp->Next = tmp->Next->Next;
\r
593 \fn char *FAT_ReadDir(tVFS_Node *dirNode, int dirPos)
\r
594 \param dirNode Node structure of directory
\r
595 \param dirPos Directory position
\r
597 char *FAT_ReadDir(tVFS_Node *dirNode, int dirpos)
\r
599 fat_filetable fileinfo[16]; //Sizeof=32, 16 per sector
\r
601 tFAT_VolInfo *disk = &gFAT_Disks[dirNode->ImplInt&7];
\r
602 Uint32 cluster, offset;
\r
609 ENTER("pDirNode iDirPos", dirNode, dirpos);
\r
611 // Get Byte Offset and skip
\r
612 offset = dirpos * sizeof(fat_filetable);
\r
613 preSkip = (offset >> 9) / disk->bootsect.spc; // >>9 == /512
\r
614 cluster = dirNode->Inode; // Cluster ID
\r
617 // - Pre FAT32 had a reserved area for the root.
\r
618 if( !(disk->type != FAT32 && cluster == disk->rootOffset) )
\r
620 //Skip previous clusters
\r
621 for(a=preSkip;a--;) {
\r
622 cluster = FAT_int_GetFatValue(dirNode->ImplInt, cluster);
\r
626 // Check for end of cluster chain
\r
627 if((disk->type == FAT12 && cluster == EOC_FAT12)
\r
628 || (disk->type == FAT16 && cluster == EOC_FAT16)
\r
629 || (disk->type == FAT32 && cluster == EOC_FAT32))
\r
632 // Bounds Checking (Used to spot heap overflows)
\r
633 if(cluster > disk->clusterCount + 2)
\r
635 Warning("FAT_ReadDir - Cluster ID is over cluster count (0x%x>0x%x)",
\r
636 cluster, disk->clusterCount+2);
\r
641 LOG("cluster=0x%x, dirpos=%i\n", cluster, dirpos);
\r
644 // - Pre FAT32 cluster base (in sectors)
\r
645 if( cluster == disk->rootOffset && disk->type != FAT32 )
\r
646 offset = disk->bootsect.resvSectCount + cluster*disk->bootsect.spc;
\r
648 { // FAT32 cluster base (in sectors)
\r
649 offset = disk->firstDataSect;
\r
650 offset += (cluster - 2) * disk->bootsect.spc;
\r
652 // Sector in cluster
\r
653 if(disk->bootsect.spc == 1)
\r
654 offset += (dirpos / 16);
\r
656 offset += (dirpos / 16) % disk->bootsect.spc;
\r
657 // Offset in sector
\r
660 LOG("offset=%i, a=%i", (Uint)offset, a);
\r
663 VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo); // Read Dir Data
\r
665 LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]);
\r
666 //Check if this is the last entry
\r
667 if(fileinfo[a].name[0] == '\0') {
\r
668 dirNode->Size = dirpos;
\r
669 LOG("End of list");
\r
671 return NULL; // break
\r
674 // Check for empty entry
\r
675 if((Uint8)fileinfo[a].name[0] == 0xE5) {
\r
676 LOG("Empty Entry\n");
\r
677 LEAVE('p', VFS_SKIP);
\r
678 return VFS_SKIP; // Skip
\r
682 // Get Long File Name Cache
\r
683 lfn = FAT_int_GetLFN(dirNode);
\r
684 if(fileinfo[a].attrib == ATTR_LFN)
\r
686 fat_longfilename *lfnInfo;
\r
689 lfnInfo = (fat_longfilename *) &fileinfo[a];
\r
690 if(lfnInfo->id & 0x40) memset(lfn, 0, 256);
\r
691 // Get the current length
\r
694 // Sanity Check (FAT implementations should not allow >255 bytes)
\r
695 if(len + 13 > 255) return VFS_SKIP;
\r
696 // Rebase all bytes
\r
697 for(a=len+1;a--;) lfn[a+13] = lfn[a];
\r
699 // Append new bytes
\r
700 lfn[ 0] = lfnInfo->name1[0]; lfn[ 1] = lfnInfo->name1[1];
\r
701 lfn[ 2] = lfnInfo->name1[2]; lfn[ 3] = lfnInfo->name1[3];
\r
702 lfn[ 4] = lfnInfo->name1[4];
\r
703 lfn[ 5] = lfnInfo->name2[0]; lfn[ 6] = lfnInfo->name2[1];
\r
704 lfn[ 7] = lfnInfo->name2[2]; lfn[ 8] = lfnInfo->name2[3];
\r
705 lfn[ 9] = lfnInfo->name2[4]; lfn[10] = lfnInfo->name2[5];
\r
706 lfn[11] = lfnInfo->name3[0]; lfn[12] = lfnInfo->name3[1];
\r
707 LEAVE('p', VFS_SKIP);
\r
712 //Check if it is a volume entry
\r
713 if(fileinfo[a].attrib & 0x08) {
\r
714 LEAVE('p', VFS_SKIP);
\r
718 if(fileinfo[a].name[0] == '.') {
\r
719 LEAVE('p', VFS_SKIP);
\r
723 LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'\n",
\r
724 fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],
\r
725 fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],
\r
726 fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );
\r
729 //node = FAT_int_CreateNode(dirNode, &fileinfo[a], lfn);
\r
730 ret = FAT_int_CreateName(dirNode, &fileinfo[a], lfn);
\r
733 //node = FAT_int_CreateNode(dirNode, &fileinfo[a], NULL);
\r
734 ret = FAT_int_CreateName(dirNode, &fileinfo[a], NULL);
\r
742 * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)
\r
743 * \brief Finds an entry in the current directory
\r
745 tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)
\r
747 fat_filetable fileinfo[16];
\r
750 fat_longfilename *lfnInfo;
\r
752 int lfnPos=255, lfnId = -1;
\r
755 tVFS_Node *tmpNode;
\r
757 tFAT_VolInfo *disk = &gFAT_Disks[node->ImplInt];
\r
761 ENTER("pnode sname", node, name);
\r
764 if(!name) return NULL;
\r
765 if(name[0] == '\0') return NULL;
\r
768 lfn = FAT_int_GetLFN(node);
\r
771 dirCluster = node->Inode;
\r
772 // Seek to Directory
\r
773 if( dirCluster == disk->rootOffset && disk->type != FAT32 )
\r
774 diskOffset = (disk->bootsect.resvSectCount+dirCluster*disk->bootsect.spc) << 9;
\r
776 diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc) << 9;
\r
781 if((i & 0xF) == 0) {
\r
782 VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo);
\r
786 //Check if the files are free
\r
787 if(fileinfo[i&0xF].name[0] == '\0') break; //Free and last
\r
788 if(fileinfo[i&0xF].name[0] == '\xE5') goto loadCluster; //Free
\r
792 // Long File Name Entry
\r
793 if(fileinfo[i&0xF].attrib == ATTR_LFN)
\r
795 lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];
\r
796 if(lfnInfo->id & 0x40) {
\r
797 memset(lfn, 0, 256);
\r
800 lfn[lfnPos--] = lfnInfo->name3[1]; lfn[lfnPos--] = lfnInfo->name3[0];
\r
801 lfn[lfnPos--] = lfnInfo->name2[5]; lfn[lfnPos--] = lfnInfo->name2[4];
\r
802 lfn[lfnPos--] = lfnInfo->name2[3]; lfn[lfnPos--] = lfnInfo->name2[2];
\r
803 lfn[lfnPos--] = lfnInfo->name2[1]; lfn[lfnPos--] = lfnInfo->name2[0];
\r
804 lfn[lfnPos--] = lfnInfo->name1[4]; lfn[lfnPos--] = lfnInfo->name1[3];
\r
805 lfn[lfnPos--] = lfnInfo->name1[2]; lfn[lfnPos--] = lfnInfo->name1[1];
\r
806 lfn[lfnPos--] = lfnInfo->name1[0];
\r
807 if((lfnInfo->id&0x3F) == 1)
\r
809 memcpy(lfn, lfn+lfnPos+1, 256-lfnPos);
\r
815 // Remove LFN if it does not apply
\r
816 if(lfnId != i) lfn[0] = '\0';
\r
818 // Get Real Filename
\r
819 FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);
\r
821 LOG("tmpName = '%s'\n", tmpName);
\r
823 //Only Long name is case sensitive, 8.3 is not
\r
825 if(strucmp(tmpName, name) == 0 || strcmp(lfn, name) == 0) {
\r
827 if(strucmp(tmpName, name) == 0) {
\r
829 cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);
\r
830 tmpNode = Inode_GetCache(disk->inodeHandle, cluster);
\r
831 if(tmpNode == NULL) // Node is not cached
\r
834 tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], lfn);
\r
836 tmpNode = FAT_int_CreateNode(node, &fileinfo[i&0xF], NULL);
\r
842 LEAVE('p', tmpNode);
\r
850 //Load Next cluster?
\r
851 if( ((i+1) >> 4) % disk->bootsect.spc == 0 && ((i+1) & 0xF) == 0)
\r
853 if( dirCluster == disk->rootOffset && disk->type != FAT32 )
\r
855 dirCluster = FAT_int_GetFatValue(node->ImplInt, dirCluster);
\r
856 diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512;
\r
865 * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)
\r
866 * \brief Create a new node
\r
868 int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)
\r
874 * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)
\r
875 * \brief Rename / Delete a file
\r
877 int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)
\r
883 * \fn void FAT_CloseFile(tVFS_Node *Node)
\r
884 * \brief Close an open file
\r
886 void FAT_CloseFile(tVFS_Node *Node)
\r
888 if(Node == NULL) return ;
\r
890 Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode);
\r
892 if( !Inode_GetCache(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode)
\r
893 && Node->Flags & VFS_FFLAG_DIRECTORY)
\r
894 FAT_int_DelLFN(Node);
\r
895 else // Get Cache references the node, so dereference it
\r
896 Inode_UncacheNode(gFAT_Disks[Node->ImplInt].inodeHandle, Node->Inode);
\r
902 * \fn void fat_install()
\r
903 * \brief Add the FAT Filesystem to the VFS
\r
907 VFS_AddDriver( &gFAT_FSInfo );
\r