X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FFilesystems%2FFAT%2Ffat.c;h=93911de607acffbe69464c901238a22ca78100c7;hb=83612bb37fbd8e84d90ecb9e6a7157aadd1e2175;hp=92aa431a1968b6d43f93b71030a9ed2dbcde537f;hpb=d46fe712d92551c0084346e6d2627a13f0d45df0;p=tpg%2Facess2.git diff --git a/Modules/Filesystems/FAT/fat.c b/Modules/Filesystems/FAT/fat.c index 92aa431a..93911de6 100644 --- a/Modules/Filesystems/FAT/fat.c +++ b/Modules/Filesystems/FAT/fat.c @@ -1,6 +1,12 @@ /* * Acess 2 * FAT12/16/32 Driver Version (Incl LFN) + * + * NOTE: This driver will only support _reading_ long file names, not + * writing. I don't even know why I'm adding write-support. FAT sucks. + * + * Known Bugs: + * - LFN Is buggy in FAT_ReadDir */ /** * \todo Implement changing of the parent directory when a file is written to @@ -11,6 +17,7 @@ #define CACHE_FAT 1 //!< Caches the FAT in memory #define USE_LFN 1 //!< Enables the use of Long File Names +#define SUPPORT_WRITE 0 #include #include @@ -41,16 +48,21 @@ Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster); Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous); void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer); -void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer); - Uint64 FAT_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); +#if SUPPORT_WRITE +void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer); Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); +#endif + char *FAT_ReadDir(tVFS_Node *Node, int ID); tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *Name); int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags); int FAT_Relink(tVFS_Node *node, char *OldName, char *NewName); void FAT_CloseFile(tVFS_Node *node); +// === Options === + int giFAT_MaxCachedClusters = 1024*512/4; + // === SEMI-GLOBALS === MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL); tFAT_VolInfo gFAT_Disks[8]; @@ -96,7 +108,7 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options) VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs); if(bs->bps == 0 || bs->spc == 0) { - Log_Notice("FAT", "Error in FAT Boot Sector\n"); + Log_Notice("FAT", "Error in FAT Boot Sector"); return NULL; } @@ -167,53 +179,54 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options) //Allow for Caching the FAT #if CACHE_FAT + if( diskInfo->ClusterCount <= giFAT_MaxCachedClusters ) { - Uint32 Ofs; - diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount); - if(diskInfo->FATCache == NULL) { - Log_Warning("FAT", "Heap Exhausted\n"); - return NULL; - } - Ofs = bs->resvSectCount*512; - if(diskInfo->type == FAT12) - { - Uint32 val; - int j; - char buf[1536]; - for(i = 0; i < diskInfo->ClusterCount/2; i++) { - j = i & 511; //%512 - if( j == 0 ) { - VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf); - Ofs += 3*512; + Uint32 Ofs; + diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount); + if(diskInfo->FATCache == NULL) { + Log_Warning("FAT", "Heap Exhausted"); + return NULL; + } + Ofs = bs->resvSectCount*512; + if(diskInfo->type == FAT12) + { + Uint32 val; + int j; + char buf[1536]; + for(i = 0; i < diskInfo->ClusterCount/2; i++) { + j = i & 511; //%512 + if( j == 0 ) { + VFS_ReadAt(diskInfo->fileHandle, Ofs, 3*512, buf); + Ofs += 3*512; + } + val = *((int*)(buf+j*3)); + diskInfo->FATCache[i*2] = val & 0xFFF; + diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF; } - val = *((int*)(buf+j*3)); - diskInfo->FATCache[i*2] = val & 0xFFF; - diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF; } - } - else if(diskInfo->type == FAT16) - { - Uint16 buf[256]; - for(i=0;iClusterCount;i++) { - if( (i & 255) == 0 ) { - VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf); - Ofs += 512; + else if(diskInfo->type == FAT16) + { + Uint16 buf[256]; + for(i=0;iClusterCount;i++) { + if( (i & 255) == 0 ) { + VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf); + Ofs += 512; + } + diskInfo->FATCache[i] = buf[i&255]; } - diskInfo->FATCache[i] = buf[i&255]; } - } - else if(diskInfo->type == FAT32) - { - Uint32 buf[128]; - for(i=0;iClusterCount;i++) { - if( (i & 127) == 0 ) { - VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf); - Ofs += 512; + else if(diskInfo->type == FAT32) + { + Uint32 buf[128]; + for(i=0;iClusterCount;i++) { + if( (i & 127) == 0 ) { + VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf); + Ofs += 512; + } + diskInfo->FATCache[i] = buf[i&127]; } - diskInfo->FATCache[i] = buf[i&127]; } - } - LOG("FAT Fully Cached"); + LOG("FAT Fully Cached"); } #endif /*CACHE_FAT*/ @@ -225,7 +238,8 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options) // == VFS Interface node = &diskInfo->rootNode; - node->Size = bs->files_in_root; + //node->Size = bs->files_in_root; + node->Size = -1; node->Inode = diskInfo->rootOffset; // 0:31 - Cluster, 32:63 - Parent Directory Cluster node->ImplPtr = diskInfo; // Disk info pointer node->ImplInt = 0; // 0:15 - Directory Index, 16: Dirty Flag, 17: Deletion Flag @@ -241,8 +255,13 @@ tVFS_Node *FAT_InitDevice(char *Device, char **Options) node->Read = node->Write = NULL; node->ReadDir = FAT_ReadDir; node->FindDir = FAT_FindDir; + #if SUPPORT_WRITE node->Relink = FAT_Relink; node->MkNod = FAT_Mknod; + #else + node->Relink = NULL; + node->MkNod = NULL; + #endif //node->Close = FAT_Unmount; giFAT_PartCount ++; @@ -290,12 +309,14 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu ENTER("pNode XOffset", Node, Offset); cluster = Node->Inode & 0xFFFFFFFF; // Cluster ID + LOG("cluster = %08x", cluster); // Do Cluster Skip // - Pre FAT32 had a reserved area for the root. if( disk->type == FAT32 || cluster != disk->rootOffset ) { skip = Offset / disk->BytesPerCluster; + LOG("skip = %i", skip); // Skip previous clusters for(; skip-- ; ) { @@ -307,6 +328,8 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu if(Cluster) *Cluster = cluster; } + LOG("cluster = %08x", cluster); + // Bounds Checking (Used to spot corruption) if(cluster > disk->ClusterCount + 2) { @@ -323,11 +346,12 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu addr += cluster * disk->BytesPerCluster; } else { - addr = disk->firstDataSect; + addr = disk->firstDataSect * disk->bootsect.bps; addr += (cluster - 2) * disk->BytesPerCluster; } addr += Offset % disk->BytesPerCluster; + LOG("addr = 0x%08x", addr); *Addr = addr; LEAVE('i', 0); return 0; @@ -345,27 +369,33 @@ int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Clu Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster) { Uint32 val = 0; - #if !CACHE_FAT - Uint32 ofs = Disk->bootsect.resvSectCount*512; - #endif + Uint32 ofs; ENTER("pDisk xCluster", Disk, cluster); LOCK( &Disk->lFAT ); #if CACHE_FAT - val = Disk->FATCache[cluster]; - if(Disk->type == FAT12 && val == EOC_FAT12) val = -1; - if(Disk->type == FAT16 && val == EOC_FAT16) val = -1; - if(Disk->type == FAT32 && val == EOC_FAT32) val = -1; - #else - if(Disk->type == FAT12) { - VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val); - val = (cluster&1 ? val&0xFFF : val>>12); - if(val == EOC_FAT12) val = -1; - } else if(Disk->type == FAT16) { - VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val); - if(val == EOC_FAT16) val = -1; - } else { - VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val); - if(val == EOC_FAT32) val = -1; + if( Disk->ClusterCount <= giFAT_MaxCachedClusters ) + { + val = Disk->FATCache[cluster]; + if(Disk->type == FAT12 && val == EOC_FAT12) val = -1; + if(Disk->type == FAT16 && val == EOC_FAT16) val = -1; + if(Disk->type == FAT32 && val == EOC_FAT32) val = -1; + } + else + { + #endif + ofs = Disk->bootsect.resvSectCount*512; + if(Disk->type == FAT12) { + VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val); + val = (cluster&1 ? val&0xFFF : val>>12); + if(val == EOC_FAT12) val = -1; + } else if(Disk->type == FAT16) { + VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val); + if(val == EOC_FAT16) val = -1; + } else { + VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val); + if(val == EOC_FAT32) val = -1; + } + #if CACHE_FAT } #endif /*CACHE_FAT*/ RELEASE( &Disk->lFAT ); @@ -373,6 +403,7 @@ Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster) return val; } +#if SUPPORT_WRITE /** * \brief Allocate a new cluster */ @@ -380,78 +411,85 @@ Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous) { Uint32 ret = Previous; #if CACHE_FAT - Uint32 eoc; - - LOCK(Disk->lFAT); - for(ret = Previous; ret < Disk->ClusterCount; ret++) - { - if(Disk->FATCache[ret] == 0) - goto append; - } - for(ret = 0; ret < Previous; ret++) + if( Disk->ClusterCount <= giFAT_MaxCachedClusters ) { - if(Disk->FATCache[ret] == 0) - goto append; - } - - RELEASE(Disk->lFAT); - return 0; - -append: - switch(Disk->type) - { - case FAT12: eoc = EOC_FAT12; break; - case FAT16: eoc = EOC_FAT16; break; - case FAT32: eoc = EOC_FAT32; break; - default: return 0; - } - - Disk->FATCache[ret] = eoc; - Disk->FATCache[Previous] = ret; - - RELEASE(Disk->lFAT); - return ret; - #else - Uint32 val; - //Uint8 buf[512]; - Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT"); - return 0; - - switch(Disk->type) - { - case FAT12: - VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); - if( Previous & 1 ) { - val &= 0xFFF000; - val |= ret; + Uint32 eoc; + + LOCK(Disk->lFAT); + for(ret = Previous; ret < Disk->ClusterCount; ret++) + { + if(Disk->FATCache[ret] == 0) + goto append; } - else { - val &= 0xFFF; - val |= ret<<12; + for(ret = 0; ret < Previous; ret++) + { + if(Disk->FATCache[ret] == 0) + goto append; } - VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); - VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val); - if( Cluster & 1 ) { - val &= 0xFFF000; - val |= eoc; + RELEASE(Disk->lFAT); + return 0; + + append: + switch(Disk->type) + { + case FAT12: eoc = EOC_FAT12; break; + case FAT16: eoc = EOC_FAT16; break; + case FAT32: eoc = EOC_FAT32; break; + default: return 0; } - else { - val &= 0x000FFF; - val |= eoc<<12; + + Disk->FATCache[ret] = eoc; + Disk->FATCache[Previous] = ret; + + RELEASE(Disk->lFAT); + return ret; + } + else + { + #endif + Uint32 val; + Uint32 ofs = Disk->bootsect.resvSectCount*512; + Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT"); + return 0; + + switch(Disk->type) + { + case FAT12: + VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); + if( Previous & 1 ) { + val &= 0xFFF000; + val |= ret; + } + else { + val &= 0xFFF; + val |= ret<<12; + } + VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); + + VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val); + if( Cluster & 1 ) { + val &= 0xFFF000; + val |= eoc; + } + else { + val &= 0x000FFF; + val |= eoc<<12; + } + VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val); + break; + case FAT16: + VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret); + VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc); + break; + case FAT32: + VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret); + VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc); + break; } - VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val); - break; - case FAT16: - VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret); - VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc); - break; - case FAT32: - VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret); - VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc); - break; + return ret; + #if CACHE_FAT } - return ret; #endif } @@ -463,47 +501,56 @@ Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster) { Uint32 ret; #if CACHE_FAT - LOCK(Disk->lFAT); - - ret = Disk->FATCache[Cluster]; - Disk->FATCache[Cluster] = 0; - - RELEASE(Disk->lFAT); - #else - Uint32 val; - LOCK(Disk->lFAT); - switch(Disk->type) + if( Disk->ClusterCount <= giFAT_MaxCachedClusters ) { - case FAT12: - VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val); - if( Cluster & 1 ) { - ret = val & 0xFFF0000; - val &= 0xFFF; - } - else { - ret = val & 0xFFF; - val &= 0xFFF000; + LOCK(Disk->lFAT); + + ret = Disk->FATCache[Cluster]; + Disk->FATCache[Cluster] = 0; + + RELEASE(Disk->lFAT); + } + else + { + #endif + Uint32 val; + Uint32 ofs = Disk->bootsect.resvSectCount*512; + LOCK(Disk->lFAT); + switch(Disk->type) + { + case FAT12: + VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val); + if( Cluster & 1 ) { + ret = val & 0xFFF0000; + val &= 0xFFF; + } + else { + ret = val & 0xFFF; + val &= 0xFFF000; + } + VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); + break; + case FAT16: + VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret); + val = 0; + VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val); + break; + case FAT32: + VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret); + val = 0; + VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val); + break; } - VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val); - break; - case FAT16: - VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret); - val = 0; - VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val); - break; - case FAT32: - VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret); - val = 0; - VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val); - break; + RELEASE(Disk->lFAT); + #if CACHE_FAT } - RELEASE(Disk->lFAT); #endif if(Disk->type == FAT12 && ret == EOC_FAT12) ret = -1; if(Disk->type == FAT16 && ret == EOC_FAT16) ret = -1; if(Disk->type == FAT32 && ret == EOC_FAT32) ret = -1; return ret; } +#endif /* * ==================== @@ -527,22 +574,6 @@ void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *B LEAVE('-'); } -/** - * \brief Write a cluster to disk - */ -void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer) -{ - ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer); - VFS_ReadAt( - Disk->fileHandle, - (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc ) - * Disk->bootsect.bps, - Disk->BytesPerCluster, - Buffer - ); - LEAVE('-'); -} - /* ==================== * File IO * ==================== @@ -571,14 +602,14 @@ Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer) // Sanity Check offset if(offset > Node->Size) { - //LOG("Reading past EOF (%i > %i)", offset, node->Size); + LOG("Reading past EOF (%i > %i)", offset, Node->Size); LEAVE('i', 0); return 0; } // Clamp Size if(offset + length > Node->Size) { - //LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli", - // offset, length, node->Size, node->Size - offset); + LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli", + offset, length, Node->Size, Node->Size - offset); length = Node->Size - offset; } @@ -592,13 +623,22 @@ Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer) return length; } + #if 0 + if( FAT_int_GetAddress(Node, offset, &addr) ) + { + Log_Warning("FAT", "Offset is past end of cluster chain mark"); + LEAVE('i', 0); + return 0; + } + #endif + preSkip = offset / bpc; //Skip previous clusters for(i=preSkip;i--;) { cluster = FAT_int_GetFatValue(disk, cluster); if(cluster == -1) { - Warning("FAT_Read - Offset is past end of cluster chain mark"); + Log_Warning("FAT", "Offset is past end of cluster chain mark"); LEAVE('i', 0); return 0; } @@ -627,12 +667,12 @@ Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer) cluster = FAT_int_GetFatValue(disk, cluster); #if DEBUG - LOG("pos=%i\n", pos); - LOG("Reading the rest of the clusters\n"); + LOG("pos = %i", pos); + LOG("Reading the rest of the clusters"); #endif - //Read the rest of the cluster data + // Read the rest of the cluster data for( i = 1; i < count-1; i++ ) { FAT_int_ReadCluster(disk, cluster, bpc, tmpBuf); @@ -651,7 +691,7 @@ Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer) memcpy((void*)(buffer+pos), tmpBuf, length-pos); #if DEBUG - LOG("Free tmpBuf(0x%x) and Return\n", tmpBuf); + LOG("Free tmpBuf(0x%x) and Return", tmpBuf); #endif free(tmpBuf); @@ -659,6 +699,23 @@ Uint64 FAT_Read(tVFS_Node *Node, Uint64 offset, Uint64 length, void *buffer) return length; } +#if SUPPORT_WRITE +/** + * \brief Write a cluster to disk + */ +void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer) +{ + ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer); + VFS_ReadAt( + Disk->fileHandle, + (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc ) + * Disk->bootsect.bps, + Disk->BytesPerCluster, + Buffer + ); + LEAVE('-'); +} + /** * \brief Write to a file * \param Node File Node @@ -763,6 +820,7 @@ Uint64 FAT_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) return Length; } +#endif /* ==================== * File Names & Nodes @@ -795,19 +853,17 @@ void FAT_int_ProperFilename(char *dest, char *src) } /** - * \fn char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) + * \fn char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName) * \brief Converts either a LFN or a 8.3 Name into a proper name */ -char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) +char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName) { char *ret; - int len; + ENTER("pft sLongFileName", ft, LongFileName); #if USE_LFN if(LongFileName && LongFileName[0] != '\0') { - len = strlen(LongFileName); - ret = malloc(len+1); - strcpy(ret, LongFileName); + ret = strdup(LongFileName); } else { @@ -818,32 +874,35 @@ char *FAT_int_CreateName(tVFS_Node *parent, fat_filetable *ft, char *LongFileNam #if USE_LFN } #endif + LEAVE('s', ret); return ret; } /** - * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) + * \fn tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft) * \brief Creates a tVFS_Node structure for a given file entry */ -tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFileName) +tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos) { tVFS_Node node = {0}; tVFS_Node *ret; - tFAT_VolInfo *disk = parent->ImplPtr; + tFAT_VolInfo *disk = Parent->ImplPtr; - ENTER("pParent pFT sLongFileName", parent, ft, LongFileName); + ENTER("pParent pFT", Parent, Entry); // Set Other Data - node.Inode = ft->cluster | (ft->clusterHi<<16); - node.Size = ft->size; - LOG("ft->size = %i", ft->size); - node.ImplPtr = parent->ImplPtr; + node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32); + LOG("node.Inode = %llx", node.Inode); + node.ImplInt = Pos & 0xFFFF; + node.ImplPtr = disk; + node.Size = Entry->size; + LOG("Entry->size = %i", Entry->size); node.UID = 0; node.GID = 0; node.NumACLs = 1; node.Flags = 0; - if(ft->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY; - if(ft->attrib & ATTR_READONLY) { + if(Entry->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY; + if(Entry->attrib & ATTR_READONLY) { node.Flags |= VFS_FFLAG_READONLY; node.ACLs = &gVFS_ACL_EveryoneRX; // R-XR-XR-X } @@ -852,38 +911,46 @@ tVFS_Node *FAT_int_CreateNode(tVFS_Node *parent, fat_filetable *ft, char *LongFi } node.ATime = timestamp(0,0,0, - ((ft->adate&0x1F)-1), //Days - ((ft->adate&0x1E0)-1), //Months - 1980+((ft->adate&0xFF00)>>8)); //Years + ((Entry->adate&0x1F) - 1), // Days + ((Entry->adate&0x1E0) - 1), // Months + 1980+((Entry->adate&0xFF00)>>8) // Years + ); - node.CTime = ft->ctimems * 10; //Miliseconds + node.CTime = Entry->ctimems * 10; // Miliseconds node.CTime += timestamp( - (ft->ctime&0x1F)<<1, //Seconds - ((ft->ctime&0x3F0)>>5), //Minutes - ((ft->ctime&0xF800)>>11), //Hours - ((ft->cdate&0x1F)-1), //Days - ((ft->cdate&0x1E0)-1), //Months - 1980+((ft->cdate&0xFF00)>>8)); //Years + ((Entry->ctime&0x1F)<<1), // Seconds + ((Entry->ctime&0x3F0)>>5), // Minutes + ((Entry->ctime&0xF800)>>11), // Hours + ((Entry->cdate&0x1F)-1), // Days + ((Entry->cdate&0x1E0)-1), // Months + 1980+((Entry->cdate&0xFF00)>>8) // Years + ); node.MTime = timestamp( - (ft->mtime&0x1F)<<1, //Seconds - ((ft->mtime&0x3F0)>>5), //Minuites - ((ft->mtime&0xF800)>>11), //Hours - ((ft->mdate&0x1F)-1), //Days - ((ft->mdate&0x1E0)-1), //Months - 1980+((ft->mdate&0xFF00)>>8)); //Years + ((Entry->mtime&0x1F)<<1), // Seconds + ((Entry->mtime&0x3F0)>>5), // Minutes + ((Entry->mtime&0xF800)>>11), // Hours + ((Entry->mdate&0x1F)-1), // Days + ((Entry->mdate&0x1E0)-1), // Months + 1980+((Entry->mdate&0xFF00)>>8) // Years + ); if(node.Flags & VFS_FFLAG_DIRECTORY) { + //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size); node.ReadDir = FAT_ReadDir; node.FindDir = FAT_FindDir; + #if SUPPORT_WRITE node.MkNod = FAT_Mknod; + node.Relink = FAT_Relink; + #endif node.Size = -1; } else { node.Read = FAT_Read; + #if SUPPORT_WRITE node.Write = FAT_Write; + #endif } node.Close = FAT_CloseFile; - node.Relink = FAT_Relink; ret = Inode_CacheNode(disk->inodeHandle, &node); LEAVE('p', ret); @@ -903,7 +970,7 @@ int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer) Uint64 addr; tFAT_VolInfo *disk = Node->ImplPtr; - ENTER("pNode iSector pEntry", Node, Sector, Buffer) + ENTER("pNode iSector pEntry", Node, Sector, Buffer); if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL)) { @@ -911,13 +978,19 @@ int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer) return 1; } + LOG("addr = 0x%llx", addr); // Read Sector - VFS_ReadAt(disk->fileHandle, addr, 512, Buffer); // Read Dir Data + if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512) + { + LEAVE('i', 1); + return 1; + } LEAVE('i', 0); return 0; } +#if SUPPORT_WRITE /** * \brief Writes an entry to the disk * \todo Support expanding a directory @@ -954,8 +1027,14 @@ int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry) LEAVE('i', 0); return 0; } +#endif #if USE_LFN +// I should probably more tightly associate the LFN cache with the node +// somehow, maybe by adding a field to tVFS_Node before locking it +// Maybe .Cache or something like that (something that is free'd by the +// Inode_UncacheNode function) + /** * \fn char *FAT_int_GetLFN(tVFS_Node *node) * \brief Return pointer to LFN cache entry @@ -1028,8 +1107,9 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID) ENTER("pNode iID", Node, ID); - if(FAT_int_ReadDirSector(Node, ID, fileinfo)) + if(FAT_int_ReadDirSector(Node, ID/16, fileinfo)) { + LOG("End of chain, end of dir"); LEAVE('n'); return NULL; } @@ -1037,9 +1117,7 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID) // Offset in sector a = ID % 16; - LOG("a = %i", a); - - LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]); + LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]); // Check if this is the last entry if( fileinfo[a].name[0] == '\0' ) { @@ -1052,8 +1130,13 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID) // Check for empty entry if( (Uint8)fileinfo[a].name[0] == 0xE5 ) { LOG("Empty Entry"); + #if 0 // Stop on empty entry? + LEAVE('n'); + return NULL; // Stop + #else LEAVE('p', VFS_SKIP); return VFS_SKIP; // Skip + #endif } #if USE_LFN @@ -1082,6 +1165,7 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID) lfn[ 7] = lfnInfo->name2[2]; lfn[ 8] = lfnInfo->name2[3]; lfn[ 9] = lfnInfo->name2[4]; lfn[10] = lfnInfo->name2[5]; lfn[11] = lfnInfo->name3[0]; lfn[12] = lfnInfo->name3[1]; + LOG("lfn = '%s'", lfn); LEAVE('p', VFS_SKIP); return VFS_SKIP; } @@ -1098,16 +1182,16 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID) return VFS_SKIP; } - LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'\n", + LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'", fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3], fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7], fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] ); #if USE_LFN - ret = FAT_int_CreateName(Node, &fileinfo[a], lfn); + ret = FAT_int_CreateName(&fileinfo[a], lfn); lfn[0] = '\0'; #else - ret = FAT_int_CreateName(Node, &fileinfo[a], NULL); + ret = FAT_int_CreateName(&fileinfo[a], NULL); #endif LEAVE('s', ret); @@ -1118,32 +1202,32 @@ char *FAT_ReadDir(tVFS_Node *Node, int ID) * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name) * \brief Finds an entry in the current directory */ -tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name) +tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *Name) { fat_filetable fileinfo[16]; - char tmpName[11]; + char tmpName[13]; #if USE_LFN fat_longfilename *lfnInfo; char lfn[256]; int lfnPos=255, lfnId = -1; #endif - int i=0; + int i; tVFS_Node *tmpNode; tFAT_VolInfo *disk = Node->ImplPtr; Uint32 cluster; - ENTER("pNode sname", Node, name); + ENTER("pNode sname", Node, Name); // Fast Returns - if(!name || name[0] == '\0') { + if(!Name || Name[0] == '\0') { LEAVE('n'); return NULL; } - for(;;i++) + for( i = 0; ; i++ ) { if((i & 0xF) == 0) { - if(FAT_int_ReadDirSector(Node, i, fileinfo)) + if(FAT_int_ReadDirSector(Node, i/16, fileinfo)) { LEAVE('n'); return NULL; @@ -1151,8 +1235,8 @@ tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name) } //Check if the files are free - if(fileinfo[i&0xF].name[0] == '\0') break; //Free and last - if(fileinfo[i&0xF].name[0] == '\xE5') continue; //Free + if(fileinfo[i&0xF].name[0] == '\0') break; // End of List marker + if(fileinfo[i&0xF].name[0] == '\xE5') continue; // Free entry #if USE_LFN @@ -1181,31 +1265,26 @@ tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name) { // Remove LFN if it does not apply if(lfnId != i) lfn[0] = '\0'; + #else + if(fileinfo[i&0xF].attrib == ATTR_LFN) continue; #endif // Get Real Filename FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name); - LOG("tmpName = '%s'", tmpName); - //Only Long name is case sensitive, 8.3 is not + // Only the long name is case sensitive, 8.3 is not #if USE_LFN - if(strucmp(tmpName, name) == 0 || strcmp(lfn, name) == 0) { + if(strucmp(tmpName, Name) == 0 || strcmp(lfn, Name) == 0) #else - if(strucmp(tmpName, name) == 0) { + if(strucmp(tmpName, Name) == 0) #endif + { cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16); tmpNode = Inode_GetCache(disk->inodeHandle, cluster); if(tmpNode == NULL) // Node is not cached { - #if USE_LFN - tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], lfn); - #else - tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], NULL); - #endif + tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], i); } - #if USE_LFN - lfn[0] = '\0'; - #endif LEAVE('p', tmpNode); return tmpNode; } @@ -1218,6 +1297,7 @@ tVFS_Node *FAT_FindDir(tVFS_Node *Node, char *name) return NULL; } +#if SUPPORT_WRITE /** * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags) * \brief Create a new node @@ -1235,27 +1315,36 @@ int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName) { tVFS_Node *child; fat_filetable ft = {0}; - Uint32 cluster; - int ofs; + int ret; child = FAT_FindDir(Node, OldName); - if(!child) return 0; + if(!child) return ENOTFOUND; // Delete? if( NewName == NULL ) { child->ImplInt |= FAT_FLAG_DELETE; // Mark for deletion on close - cluster = Node->Inode & 0xFFFFFFFF; - ofs = child->ImplInt & 0xFFFF; + + // Delete from the directory ft.name[0] = '\xE9'; + FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft); + + // Return success + ret = EOK; } // Rename else { + Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')", + Node, OldName, NewName); + ret = ENOTIMPL; } - return 0; + // Close child + child->Close( child ); + return ret; } +#endif /** * \fn void FAT_CloseFile(tVFS_Node *Node) @@ -1266,16 +1355,25 @@ void FAT_CloseFile(tVFS_Node *Node) tFAT_VolInfo *disk = Node->ImplPtr; if(Node == NULL) return ; - if( Node->ImplInt & FAT_FLAG_DIRTY ) { - #if 0 - // Write back - FAT_int_UpdateDirEntry( - Node->Inode >> 32, Node->ImplInt & 0xFFFF, - Node - ); - #endif + #if SUPPORT_WRITE + // Update the node if it's dirty (don't bother if it's marked for + // deletion) + if( Node->ImplInt & FAT_FLAG_DIRTY && !(Node->ImplInt & FAT_FLAG_DELETE) ) + { + tFAT_VolInfo buf[16]; + tFAT_VolInfo *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ]; + + FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf); + ft->size = Node->Size; + // TODO: update adate, mtime, mdate + FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft); + + Node->ImplInt &= ~FAT_FLAG_DIRTY; } + #endif + // TODO: Make this more thread safe somehow, probably by moving the + // Inode_UncacheNode higher up and saving the cluster value somewhere if( Node->ReferenceCount == 1 ) { // Delete LFN Cache @@ -1284,6 +1382,7 @@ void FAT_CloseFile(tVFS_Node *Node) FAT_int_DelLFN(Node); #endif + #if SUPPORT_WRITE // Delete File if( Node->ImplInt & FAT_FLAG_DELETE ) { // Since the node is marked, we only need to remove it's data @@ -1291,6 +1390,7 @@ void FAT_CloseFile(tVFS_Node *Node) while( cluster != -1 ) cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster); } + #endif } Inode_UncacheNode(disk->inodeHandle, Node->Inode);