/*\r
- * Acess2\r
+ * Acess 2\r
* FAT12/16/32 Driver Version (Incl LFN)\r
*/\r
-//INCLUDES\r
-#include <common.h>\r
-#include <modules.h>\r
-#include <vfs.h>\r
-#include "fs_fat.h"\r
-\r
-#define DEBUG 1\r
+#define DEBUG 0\r
#define VERBOSE 1\r
\r
-#if DEBUG\r
-# define DEBUGS(v...) Log(v)\r
-#else\r
-# define DEBUGS(v...)\r
-# undef ENTER\r
-# undef LOG\r
-# undef LEAVE\r
-# define ENTER(...)\r
-# define LOG(...)\r
-# define LEAVE(...)\r
-#endif\r
-\r
#define CACHE_FAT 1 //!< Caches the FAT in memory\r
#define USE_LFN 1 //!< Enables the use of Long File Names\r
\r
+#include <acess.h>\r
+#include <modules.h>\r
+#include <vfs.h>\r
+#include "fs_fat.h"\r
+\r
+\r
// === TYPES ===\r
#if USE_LFN\r
typedef struct s_lfncache {\r
\r
// === PROTOTYPES ===\r
int FAT_Install(char **Arguments);\r
-tVFS_Node *FAT_InitDevice(char *device, char *options);\r
+tVFS_Node *FAT_InitDevice(char *device, char **options);\r
void FAT_Unmount(tVFS_Node *Node);\r
Uint64 FAT_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
Uint64 FAT_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);\r
void FAT_CloseFile(tVFS_Node *node);\r
\r
// === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, 0x5B /*v0.90*/, FAT32, FAT_Install, NULL);\r
+MODULE_DEFINE(0, 0x51 /*v0.80*/, VFAT, FAT_Install, NULL, NULL);\r
tFAT_VolInfo gFAT_Disks[8];\r
int giFAT_PartCount = 0;\r
-#if CACHE_FAT\r
-Uint32 *fat_cache[8];\r
-#endif\r
#if USE_LFN\r
t_lfncache *fat_lfncache;\r
#endif\r
int FAT_Install(char **Arguments)\r
{\r
VFS_AddDriver( &gFAT_FSInfo );\r
- return 0;\r
+ return MODULE_ERR_OK;\r
}\r
\r
/**\r
- * \fn tVFS_Node *FAT_InitDevice(char *Device, char *options)\r
+ * \fn tVFS_Node *FAT_InitDevice(char *Device, char **options)\r
* \brief Reads the boot sector of a disk and prepares the structures for it\r
*/\r
-tVFS_Node *FAT_InitDevice(char *Device, char *options)\r
+tVFS_Node *FAT_InitDevice(char *Device, char **options)\r
{\r
fat_bootsect *bs;\r
int i;\r
case FAT12: sFatType = "FAT12"; break;\r
case FAT16: sFatType = "FAT16"; break;\r
case FAT32: sFatType = "FAT32"; break;\r
+ default: sFatType = "UNKNOWN"; break;\r
}\r
if(iSize <= 2*1024) {\r
sSize = "KiB";\r
#if CACHE_FAT\r
{\r
Uint32 Ofs;\r
- fat_cache[ giFAT_PartCount ] = (Uint32*)malloc(sizeof(Uint32)*CountofClusters);\r
- if(fat_cache[giFAT_PartCount] == NULL) {\r
+ diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*CountofClusters);\r
+ if(diskInfo->FATCache == NULL) {\r
Warning("FAT_InitDisk - Heap Exhausted\n");\r
return NULL;\r
}\r
Ofs += 3*512;\r
}\r
val = *((int*)(buf+j*3));\r
- fat_cache[giFAT_PartCount][i*2] = val & 0xFFF;\r
- fat_cache[giFAT_PartCount][i*2+1] = (val>>12) & 0xFFF;\r
+ diskInfo->FATCache[i*2] = val & 0xFFF;\r
+ diskInfo->FATCache[i*2+1] = (val>>12) & 0xFFF;\r
}\r
}\r
if(diskInfo->type == FAT16) {\r
VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
Ofs += 512;\r
}\r
- fat_cache[giFAT_PartCount][i] = buf[i&255];\r
+ diskInfo->FATCache[i] = buf[i&255];\r
}\r
}\r
if(diskInfo->type == FAT32) {\r
VFS_ReadAt(diskInfo->fileHandle, Ofs, 512, buf);\r
Ofs += 512;\r
}\r
- fat_cache[giFAT_PartCount][i] = buf[i&127];\r
+ diskInfo->FATCache[i] = buf[i&127];\r
}\r
}\r
- DEBUGS(" FAT_InitDisk: FAT Fully Cached\n");\r
+ LOG("FAT Fully Cached");\r
}\r
#endif /*CACHE_FAT*/\r
\r
//Initalise inode cache for FAT\r
- gFAT_Disks[giFAT_PartCount].inodeHandle = Inode_GetHandle();\r
- \r
- #if DEBUG\r
- Log(" FAT_InitDisk: Inode Cache handle is %i\n", gFAT_Disks[giFAT_PartCount].inodeHandle);\r
- #endif\r
+ diskInfo->inodeHandle = Inode_GetHandle();\r
+ LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
\r
// == VFS Interface\r
- node = &gFAT_Disks[giFAT_PartCount].rootNode;\r
+ node = &diskInfo->rootNode;\r
node->Inode = diskInfo->rootOffset;\r
node->Size = bs->files_in_root; // Unknown - To be set on readdir\r
node->ImplInt = giFAT_PartCount;\r
}\r
\r
/**\r
- * \fn static Uint32 FAT_int_GetFatValue(int handle, Uint32 cluster)\r
+ * \fn static Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
* \brief Fetches a value from the FAT\r
*/\r
-static Uint32 FAT_int_GetFatValue(int handle, Uint32 cluster)\r
+static Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
{\r
- Uint32 val;\r
- ENTER("iHandle xCluster", handle, cluster);\r
+ Uint32 val = 0;\r
+ #if !CACHE_FAT\r
+ Uint32 ofs = Disk->bootsect.resvSectCount*512;\r
+ #endif\r
+ ENTER("pDisk xCluster", Disk, cluster);\r
#if CACHE_FAT\r
- val = fat_cache[handle][cluster];\r
+ val = Disk->FATCache[cluster];\r
+ if(Disk->type == FAT12 && val == EOC_FAT12) val = -1;\r
+ if(Disk->type == FAT16 && val == EOC_FAT16) val = -1;\r
+ if(Disk->type == FAT32 && val == EOC_FAT32) val = -1;\r
#else\r
- if(gFAT_Disks[handle].type == FAT12) {\r
- VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+(cluster&~1)*3, 3, &val);\r
+ if(Disk->type == FAT12) {\r
+ VFS_ReadAt(Disk->fileHandle, ofs+(cluster>>1)*3, 3, &val);\r
val = (cluster&1 ? val&0xFFF : val>>12);\r
- } else if(gFAT_Disks[handle].type == FAT16) {\r
- VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+cluster*2, 2, &val);\r
+ if(val == EOC_FAT12) val = -1;\r
+ } else if(Disk->type == FAT16) {\r
+ VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
+ if(val == EOC_FAT16) val = -1;\r
} else {\r
- VFS_ReadAt(gFAT_Disks[handle].fileHandle, 512+cluster*4, 4, &val);\r
+ VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
+ if(val == EOC_FAT32) val = -1;\r
}\r
#endif /*CACHE_FAT*/\r
LEAVE('x', val);\r
*/\r
static void FAT_int_ReadCluster(int Handle, Uint32 Cluster, int Length, void *Buffer)\r
{\r
- #if DEBUG\r
ENTER("iHandle xCluster iLength pBuffer", Handle, Cluster, Length, Buffer);\r
- #endif\r
+ //Log("Cluster = %i (0x%x)", Cluster, Cluster);\r
VFS_ReadAt(\r
gFAT_Disks[Handle].fileHandle,\r
(gFAT_Disks[Handle].firstDataSect + (Cluster-2)*gFAT_Disks[Handle].bootsect.spc )\r
Length,\r
Buffer\r
);\r
- #if DEBUG\r
LEAVE('-');\r
- #endif\r
}\r
\r
/**\r
int i, cluster, pos;\r
int bpc;\r
void *tmpBuf;\r
- Uint eocMarker;\r
tFAT_VolInfo *disk = &gFAT_Disks[node->ImplInt];\r
\r
ENTER("Xoffset Xlength pbuffer", offset, length, buffer);\r
// Cluster is stored in Inode Field\r
cluster = node->Inode;\r
\r
- // Get EOC Marker\r
- if (disk->type == FAT12) eocMarker = EOC_FAT12;\r
- else if(disk->type == FAT16) eocMarker = EOC_FAT16;\r
- else if(disk->type == FAT32) eocMarker = EOC_FAT32;\r
- else {\r
- Log("ERROR: Unsupported FAT Variant.\n");\r
- free(tmpBuf);\r
+ // Sanity Check offset\r
+ if(offset > node->Size) {\r
+ //LOG("Reading past EOF (%i > %i)", offset, node->Size);\r
LEAVE('i', 0);\r
return 0;\r
}\r
+ // Clamp Size\r
+ if(offset + length > node->Size) {\r
+ //LOG("Reading past EOF (%lli + %lli > %lli), clamped to %lli",\r
+ // offset, length, node->Size, node->Size - offset);\r
+ length = node->Size - offset;\r
+ }\r
\r
// Single Cluster including offset\r
if(length + offset < bpc)\r
memcpy( buffer, (void*)( tmpBuf + offset%bpc ), length );\r
free(tmpBuf);\r
LEAVE('i', 1);\r
- return 1;\r
+ return length;\r
}\r
\r
preSkip = offset / bpc;\r
\r
//Skip previous clusters\r
for(i=preSkip;i--;) {\r
- cluster = FAT_int_GetFatValue(handle, cluster);\r
- if(cluster == eocMarker) {\r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
+ if(cluster == -1) {\r
Warning("FAT_Read - Offset is past end of cluster chain mark");\r
+ LEAVE('i', 0);\r
+ return 0;\r
}\r
}\r
\r
if (count == 1) {\r
free(tmpBuf);\r
LEAVE('i', 1);\r
- return 1;\r
+ return length;\r
}\r
\r
- cluster = FAT_int_GetFatValue(handle, cluster);\r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
\r
#if DEBUG\r
LOG("pos=%i\n", pos);\r
FAT_int_ReadCluster(handle, cluster, bpc, tmpBuf);\r
memcpy((void*)(buffer+pos), tmpBuf, bpc);\r
pos += bpc;\r
- cluster = FAT_int_GetFatValue(handle, cluster);\r
- if(cluster == eocMarker) {\r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
+ if(cluster == -1) {\r
Warning("FAT_Read - Read past End of Cluster Chain");\r
free(tmpBuf);\r
LEAVE('i', 0);\r
// Set Other Data\r
node.Inode = ft->cluster | (ft->clusterHi<<16);\r
node.Size = ft->size;\r
+ LOG("ft->size = %i", ft->size);\r
node.ImplInt = parent->ImplInt;\r
node.UID = 0; node.GID = 0;\r
node.NumACLs = 1;\r
node.ReadDir = FAT_ReadDir;\r
node.FindDir = FAT_FindDir;\r
node.MkNod = FAT_Mknod;\r
+ node.Size = -1;\r
} else {\r
node.Read = FAT_Read;\r
node.Write = FAT_Write;\r
\r
// Get Byte Offset and skip\r
offset = dirpos * sizeof(fat_filetable);\r
- preSkip = (offset >> 9) / disk->bootsect.spc; // >>9 == /512\r
+ preSkip = offset / (512 * disk->bootsect.spc);\r
+ LOG("disk->bootsect.spc = %i", disk->bootsect.spc);\r
+ LOG("dirNode->size = %i", dirNode->Size);\r
cluster = dirNode->Inode; // Cluster ID\r
\r
// Do Cluster Skip\r
// - Pre FAT32 had a reserved area for the root.\r
- if( !(disk->type != FAT32 && cluster == disk->rootOffset) )\r
+ if( disk->type == FAT32 || cluster != disk->rootOffset )\r
{\r
//Skip previous clusters\r
for(a=preSkip;a--;) {\r
- cluster = FAT_int_GetFatValue(dirNode->ImplInt, cluster);\r
+ cluster = FAT_int_GetFatValue(disk, cluster);\r
+ // Check for end of cluster chain\r
+ if(cluster == -1) { LEAVE('n'); return NULL;}\r
}\r
}\r
\r
- // Check for end of cluster chain\r
- if((disk->type == FAT12 && cluster == EOC_FAT12)\r
- || (disk->type == FAT16 && cluster == EOC_FAT16)\r
- || (disk->type == FAT32 && cluster == EOC_FAT32))\r
- return NULL;\r
- \r
// Bounds Checking (Used to spot heap overflows)\r
if(cluster > disk->clusterCount + 2)\r
{\r
return NULL;\r
}\r
\r
- LOG("cluster=0x%x, dirpos=%i\n", cluster, dirpos);\r
+ LOG("cluster=0x%x, dirpos=%i", cluster, dirpos);\r
\r
// Compute Offsets\r
// - Pre FAT32 cluster base (in sectors)\r
offset += (cluster - 2) * disk->bootsect.spc;\r
}\r
// Sector in cluster\r
- if(disk->bootsect.spc == 1)\r
- offset += (dirpos / 16);\r
- else\r
+ if(disk->bootsect.spc != 1)\r
offset += (dirpos / 16) % disk->bootsect.spc;\r
// Offset in sector\r
- a = dirpos & 0xF;\r
+ a = dirpos % 16;\r
\r
- LOG("offset=%i, a=%i\n", (Uint)offset, a);\r
+ LOG("offset=%i, a=%i", offset, a);\r
\r
// Read Sector\r
VFS_ReadAt(disk->fileHandle, offset*512, 512, fileinfo); // Read Dir Data\r
\r
- LOG("name[0] = 0x%x\n", (Uint8)fileinfo[a].name[0]);\r
+ LOG("name[0] = 0x%x", (Uint8)fileinfo[a].name[0]);\r
//Check if this is the last entry\r
- if(fileinfo[a].name[0] == '\0') {\r
+ if( fileinfo[a].name[0] == '\0' ) {\r
dirNode->Size = dirpos;\r
- LOG("End of list\n");\r
+ LOG("End of list");\r
LEAVE('n');\r
return NULL; // break\r
}\r
\r
// Check for empty entry\r
- if((Uint8)fileinfo[a].name[0] == 0xE5) {\r
- LOG("Empty Entry\n");\r
+ if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
+ LOG("Empty Entry");\r
LEAVE('p', VFS_SKIP);\r
return VFS_SKIP; // Skip\r
}\r
#endif\r
\r
LEAVE('s', ret);\r
- return VFS_FREEPLZ(ret);\r
+ return ret;\r
}\r
\r
/**\r
ENTER("pnode sname", node, name);\r
\r
// Fast Returns\r
- if(!name) return NULL;\r
- if(name[0] == '\0') return NULL;\r
+ if(!name || name[0] == '\0') {\r
+ LEAVE('n');\r
+ return NULL;\r
+ }\r
\r
#if USE_LFN\r
lfn = FAT_int_GetLFN(node);\r
{\r
// Load sector\r
if((i & 0xF) == 0) {\r
+ //Log("FAT_FindDir: diskOffset = 0x%x", diskOffset);\r
VFS_ReadAt(disk->fileHandle, diskOffset, 512, fileinfo);\r
diskOffset += 512;\r
}\r
// Get Real Filename\r
FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
\r
- LOG("tmpName = '%s'\n", tmpName);\r
+ LOG("tmpName = '%s'", tmpName);\r
\r
//Only Long name is case sensitive, 8.3 is not\r
#if USE_LFN\r
{\r
if( dirCluster == disk->rootOffset && disk->type != FAT32 )\r
continue;\r
- dirCluster = FAT_int_GetFatValue(node->ImplInt, dirCluster);\r
+ dirCluster = FAT_int_GetFatValue(disk, dirCluster);\r
+ if(dirCluster == -1) break;\r
diskOffset = (disk->firstDataSect+(dirCluster-2)*disk->bootsect.spc)*512;\r
}\r
}\r