diff options
Diffstat (limited to 'backends/platform/ds/arm9/source/fat/gba_nds_fat.c')
-rw-r--r-- | backends/platform/ds/arm9/source/fat/gba_nds_fat.c | 3333 |
1 files changed, 0 insertions, 3333 deletions
diff --git a/backends/platform/ds/arm9/source/fat/gba_nds_fat.c b/backends/platform/ds/arm9/source/fat/gba_nds_fat.c index b3b2858e41..46aff1ced9 100644 --- a/backends/platform/ds/arm9/source/fat/gba_nds_fat.c +++ b/backends/platform/ds/arm9/source/fat/gba_nds_fat.c @@ -3325,3336 +3325,3 @@ int FAT_fputs (const char *string, FAT_FILE* file) return writtenBytes ; } #endif - - - -/* - gba_nds_fat.c - By chishm (Michael Chisholm) - - Routines for reading a compact flash card - using the GBA Movie Player or M3. - - Some FAT routines are based on those in fat.c, which - is part of avrlib by Pascal Stang. - - This software is completely free. No warranty is provided. - If you use it, please give me credit and email me about your - project at chishm@hotmail.com - - See gba_nds_fat.txt for help and license details. -*/ - -//--------------------------------------------------------------- -// Includes - -#include "gba_nds_fat.h" -#include "disc_io.h" -#include <string.h> -#ifdef NDS - #include <nds/ipc.h> // Time on the NDS -#endif -//---------------------------------------------------------------- -// Data types -#ifndef NULL - #define NULL 0 -#endif - -//---------------------------------------------------------------- -// NDS memory access control register -#ifdef NDS - #ifndef WAIT_CR - #define WAIT_CR (*(vu16*)0x04000204) - #endif -#endif - -//--------------------------------------------------------------- -// Appropriate placement of CF functions and data -#ifdef NDS - #define _VARS_IN_RAM -#else - #define _VARS_IN_RAM __attribute__ ((section (".sbss"))) -#endif - - -//----------------------------------------------------------------- -// FAT constants -#define CLUSTER_EOF_16 0xFFFF -#define CLUSTER_EOF 0x0FFFFFFF -#define CLUSTER_FREE 0x0000 -#define CLUSTER_FIRST 0x0002 - -#define FILE_LAST 0x00 -#define FILE_FREE 0xE5 - -#define FAT16_ROOT_DIR_CLUSTER 0x00 - - -//----------------------------------------------------------------- -// long file name constants -#define LFN_END 0x40 -#define LFN_DEL 0x80 - -//----------------------------------------------------------------- -// Data Structures - -// Take care of packing for GCC - it doesn't obey pragma pack() -// properly for ARM targets. -#ifdef __GNUC__ - #define __PACKED __attribute__ ((__packed__)) -#else - #define __PACKED - #pragma pack(1) -#endif - -// Boot Sector - must be packed -typedef struct -{ - u8 jmpBoot[3]; - u8 OEMName[8]; - // BIOS Parameter Block - u16 bytesPerSector; - u8 sectorsPerCluster; - u16 reservedSectors; - u8 numFATs; - u16 rootEntries; - u16 numSectorsSmall; - u8 mediaDesc; - u16 sectorsPerFAT; - u16 sectorsPerTrk; - u16 numHeads; - u32 numHiddenSectors; - u32 numSectors; - union // Different types of extended BIOS Parameter Block for FAT16 and FAT32 - { - struct - { - // Ext BIOS Parameter Block for FAT16 - u8 driveNumber; - u8 reserved1; - u8 extBootSig; - u32 volumeID; - u8 volumeLabel[11]; - u8 fileSysType[8]; - // Bootcode - u8 bootCode[448]; - } __PACKED fat16; - struct - { - // FAT32 extended block - u32 sectorsPerFAT32; - u16 extFlags; - u16 fsVer; - u32 rootClus; - u16 fsInfo; - u16 bkBootSec; - u8 reserved[12]; - // Ext BIOS Parameter Block for FAT16 - u8 driveNumber; - u8 reserved1; - u8 extBootSig; - u32 volumeID; - u8 volumeLabel[11]; - u8 fileSysType[8]; - // Bootcode - u8 bootCode[420]; - } __PACKED fat32; - } __PACKED extBlock; - - u16 bootSig; - -} __PACKED BOOT_SEC; - -// Directory entry - must be packed -typedef struct -{ - u8 name[8]; - u8 ext[3]; - u8 attrib; - u8 reserved; - u8 cTime_ms; - u16 cTime; - u16 cDate; - u16 aDate; - u16 startClusterHigh; - u16 mTime; - u16 mDate; - u16 startCluster; - u32 fileSize; -} __PACKED DIR_ENT; - -// Long file name directory entry - must be packed -typedef struct -{ - u8 ordinal; // Position within LFN - u16 char0; - u16 char1; - u16 char2; - u16 char3; - u16 char4; - u8 flag; // Should be equal to ATTRIB_LFN - u8 reserved1; // Always 0x00 - u8 checkSum; // Checksum of short file name (alias) - u16 char5; - u16 char6; - u16 char7; - u16 char8; - u16 char9; - u16 char10; - u16 reserved2; // Always 0x0000 - u16 char11; - u16 char12; -} __PACKED DIR_ENT_LFN; - -const char lfn_offset_table[13]={0x01,0x03,0x05,0x07,0x09,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E}; - -// End of packed structs -#ifdef __PACKED - #undef __PACKED -#endif -#ifndef __GNUC__ - #pragma pack() -#endif - -//----------------------------------------------------------------- -// Global Variables - -// _VARS_IN_RAM variables are stored in the largest section of WRAM -// available: IWRAM on NDS ARM7, EWRAM on NDS ARM9 and GBA - -// Files -_VARS_IN_RAM FAT_FILE openFiles[MAX_FILES_OPEN]; - -// Long File names -_VARS_IN_RAM char lfnName[MAX_FILENAME_LENGTH]; -bool lfnExists; - -// Locations on card -int filesysRootDir; -int filesysRootDirClus; -int filesysFAT; -int filesysSecPerFAT; -int filesysNumSec; -int filesysData; -int filesysBytePerSec; -int filesysSecPerClus; -int filesysBytePerClus; - -FS_TYPE filesysType = FS_UNKNOWN; -u32 filesysTotalSize; - -// Info about FAT -u32 fatLastCluster; -u32 fatFirstFree; - -// fatBuffer used to reduce wear on the CF card from multiple writes -_VARS_IN_RAM char fatBuffer[BYTE_PER_READ]; -u32 fatBufferCurSector; - -// Current working directory -u32 curWorkDirCluster; - -// Position of the directory entry last retreived with FAT_GetDirEntry -u32 wrkDirCluster; -int wrkDirSector; -int wrkDirOffset; - -// Global sector buffer to save on stack space -_VARS_IN_RAM unsigned char globalBuffer[BYTE_PER_READ]; - -//----------------------------------------------------------------- -// Functions contained in this file - predeclarations -char ucase (char character); -u16 getRTCtoFileTime (void); -u16 getRTCtoFileDate (void); - -bool FAT_AddDirEntry (const char* path, DIR_ENT newDirEntry); -bool FAT_ClearLinks (u32 cluster); -DIR_ENT FAT_DirEntFromPath (const char* path); -u32 FAT_FirstFreeCluster(void); -DIR_ENT FAT_GetDirEntry ( u32 dirCluster, int entry, int origin); -u32 FAT_LinkFreeCluster(u32 cluster); -u32 FAT_NextCluster(u32 cluster); -bool FAT_WriteFatEntry (u32 cluster, u32 value); -bool FAT_GetFilename (DIR_ENT dirEntry, char* alias); - -bool FAT_InitFiles (void); -bool FAT_FreeFiles (void); -int FAT_remove (const char* path); -bool FAT_chdir (const char* path); -FILE_TYPE FAT_FindFirstFile (char* filename); -FILE_TYPE FAT_FindNextFile (char* filename); -FILE_TYPE FAT_FileExists (const char* filename); -bool FAT_GetAlias (char* alias); -bool FAT_GetLongFilename (char* filename); -u32 FAT_GetFileSize (void); -u32 FAT_GetFileCluster (void); - -FAT_FILE* FAT_fopen(const char* path, const char* mode); -bool FAT_fclose (FAT_FILE* file); -bool FAT_feof(FAT_FILE* file); -int FAT_fseek(FAT_FILE* file, s32 offset, int origin); -u32 FAT_ftell (FAT_FILE* file); -u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file); -u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file); -char FAT_fgetc (FAT_FILE* file); -char FAT_fputc (char c, FAT_FILE* file); - -/*----------------------------------------------------------------- -ucase -Returns the uppercase version of the given char -char IN: a character -char return OUT: uppercase version of character ------------------------------------------------------------------*/ -char ucase (char character) -{ - if ((character > 0x60) && (character < 0x7B)) - character = character - 0x20; - return (character); -} - - -/*----------------------------------------------------------------- -getRTCtoFileTime and getRTCtoFileDate -Returns the time / date in Dir Entry styled format -u16 return OUT: time / date in Dir Entry styled format ------------------------------------------------------------------*/ -u16 getRTCtoFileTime (void) -{ -#ifdef NDS - return ( - ( ( (IPC->rtc_hours > 11 ? IPC->rtc_hours - 40 : IPC->rtc_hours) & 0x1F) << 11) | - ( (IPC->rtc_minutes & 0x3F) << 5) | - ( (IPC->rtc_seconds >> 1) & 0x1F) ); -#else - return 0; -#endif -} - -u16 getRTCtoFileDate (void) -{ -#ifdef NDS - return ( - ( ((IPC->rtc_year + 20) & 0x7F) <<9) | - ( (IPC->rtc_month & 0xF) << 5) | - (IPC->rtc_day & 0x1F) ); -#else - return 0; -#endif -} - - -/*----------------------------------------------------------------- -Disc level FAT routines ------------------------------------------------------------------*/ -#define FAT_ClustToSect(m) \ - (((m-2) * filesysSecPerClus) + filesysData) - -/*----------------------------------------------------------------- -FAT_NextCluster -Internal function - gets the cluster linked from input cluster ------------------------------------------------------------------*/ -u32 FAT_NextCluster(u32 cluster) -{ - u32 nextCluster = CLUSTER_FREE; - u32 sector; - int offset; - - switch (filesysType) - { - case FS_UNKNOWN: - nextCluster = CLUSTER_FREE; - break; - - case FS_FAT12: - sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ); - offset = ((cluster * 3) / 2) % BYTE_PER_READ; - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - nextCluster = ((u8*)fatBuffer)[offset]; - offset++; - - if (offset >= BYTE_PER_READ) { - offset = 0; - fatBufferCurSector++; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - nextCluster |= (((u8*)fatBuffer)[offset]) << 8; - - if (cluster & 0x01) { - nextCluster = nextCluster >> 4; - } else { - nextCluster &= 0x0FFF; - } - - if (nextCluster >= 0x0FF7) - { - nextCluster = CLUSTER_EOF; - } - - break; - - case FS_FAT16: - sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ); - offset = cluster % (BYTE_PER_READ >> 1); - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - // read the nextCluster value - nextCluster = ((u16*)fatBuffer)[offset]; - - if (nextCluster >= 0xFFF7) - { - nextCluster = CLUSTER_EOF; - } - break; - - case FS_FAT32: - sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ); - offset = cluster % (BYTE_PER_READ >> 2); - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - // read the nextCluster value - nextCluster = (((u32*)fatBuffer)[offset]) & 0x0FFFFFFF; - - if (nextCluster >= 0x0FFFFFF7) - { - nextCluster = CLUSTER_EOF; - } - break; - - default: - nextCluster = CLUSTER_FREE; - break; - } - - return nextCluster; -} - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_WriteFatEntry -Internal function - writes FAT information about a cluster ------------------------------------------------------------------*/ -bool FAT_WriteFatEntry (u32 cluster, u32 value) -{ - u32 sector; - int offset; - - if ((cluster < 0x0002) || (cluster > fatLastCluster)) - { - return false; - } - - switch (filesysType) - { - case FS_UNKNOWN: - return false; - break; - - case FS_FAT12: - sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ); - offset = ((cluster * 3) / 2) % BYTE_PER_READ; - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - if (cluster & 0x01) { - - ((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0x0F) | ((value & 0x0F) << 4); - - offset++; - if (offset >= BYTE_PER_READ) { - offset = 0; - // write the buffer back to disc - disc_WriteSector(fatBufferCurSector, fatBuffer); - // read the next sector - fatBufferCurSector++; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - ((u8*)fatBuffer)[offset] = (value & 0x0FF0) >> 4; - - } else { - - ((u8*)fatBuffer)[offset] = value & 0xFF; - - offset++; - if (offset >= BYTE_PER_READ) { - offset = 0; - // write the buffer back to disc - disc_WriteSector(fatBufferCurSector, fatBuffer); - // read the next sector - fatBufferCurSector++; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - ((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0xF0) | ((value >> 8) & 0x0F); - } - - break; - - case FS_FAT16: - sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ); - offset = cluster % (BYTE_PER_READ >> 1); - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - // write the value to the FAT buffer - ((u16*)fatBuffer)[offset] = (value & 0xFFFF); - - break; - - case FS_FAT32: - sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ); - offset = cluster % (BYTE_PER_READ >> 2); - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - // write the value to the FAT buffer - (((u32*)fatBuffer)[offset]) = value; - - break; - - default: - return false; - break; - } - - // write the buffer back to disc - disc_WriteSector(fatBufferCurSector, fatBuffer); - - return true; -} -#endif - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_ReadWriteFatEntryBuffered -Internal function - writes FAT information about a cluster to a - buffer that should then be flushed to disc using - FAT_WriteFatEntryFlushBuffer() - Call FAT_WriteFatEntry first so as not to ruin the disc. - Also returns the entry being replaced ------------------------------------------------------------------*/ -u32 FAT_ReadWriteFatEntryBuffered (u32 cluster, u32 value) -{ - u32 sector; - int offset; - u32 oldValue; - - if ((cluster < 0x0002) || (cluster > fatLastCluster)) - return CLUSTER_FREE; - - - switch (filesysType) - { - case FS_UNKNOWN: - oldValue = CLUSTER_FREE; - break; - - case FS_FAT12: - sector = filesysFAT + (((cluster * 3) / 2) / BYTE_PER_READ); - offset = ((cluster * 3) / 2) % BYTE_PER_READ; - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // write the old buffer to disc - if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT))) - disc_WriteSector(fatBufferCurSector, fatBuffer); - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - if (cluster & 0x01) { - - oldValue = (((u8*)fatBuffer)[offset] & 0xF0) >> 4; - ((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0x0F) | ((value & 0x0F) << 4); - - offset++; - if (offset >= BYTE_PER_READ) { - offset = 0; - // write the buffer back to disc - disc_WriteSector(fatBufferCurSector, fatBuffer); - // read the next sector - fatBufferCurSector++; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - oldValue |= ((((u8*)fatBuffer)[offset]) << 4) & 0x0FF0; - ((u8*)fatBuffer)[offset] = (value & 0x0FF0) >> 4; - - } else { - - oldValue = ((u8*)fatBuffer)[offset] & 0xFF; - ((u8*)fatBuffer)[offset] = value & 0xFF; - - offset++; - if (offset >= BYTE_PER_READ) { - offset = 0; - // write the buffer back to disc - disc_WriteSector(fatBufferCurSector, fatBuffer); - // read the next sector - fatBufferCurSector++; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - oldValue |= (((u8*)fatBuffer)[offset] & 0x0F) << 8; - ((u8*)fatBuffer)[offset] = (((u8*)fatBuffer)[offset] & 0xF0) | ((value >> 8) & 0x0F); - } - - if (oldValue >= 0x0FF7) - { - oldValue = CLUSTER_EOF; - } - - break; - - case FS_FAT16: - sector = filesysFAT + ((cluster << 1) / BYTE_PER_READ); - offset = cluster % (BYTE_PER_READ >> 1); - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // write the old buffer to disc - if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT))) - disc_WriteSector(fatBufferCurSector, fatBuffer); - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - // write the value to the FAT buffer - oldValue = ((u16*)fatBuffer)[offset]; - ((u16*)fatBuffer)[offset] = value; - - if (oldValue >= 0xFFF7) - { - oldValue = CLUSTER_EOF; - } - - break; - - case FS_FAT32: - sector = filesysFAT + ((cluster << 2) / BYTE_PER_READ); - offset = cluster % (BYTE_PER_READ >> 2); - - // If FAT buffer contains wrong sector - if (sector != fatBufferCurSector) - { - // write the old buffer to disc - if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT))) - disc_WriteSector(fatBufferCurSector, fatBuffer); - // Load correct sector to buffer - fatBufferCurSector = sector; - disc_ReadSector(fatBufferCurSector, fatBuffer); - } - - // write the value to the FAT buffer - oldValue = ((u32*)fatBuffer)[offset]; - ((u32*)fatBuffer)[offset] = value; - - if (oldValue >= 0x0FFFFFF7) - { - oldValue = CLUSTER_EOF; - } - - break; - - default: - oldValue = CLUSTER_FREE; - break; - } - - return oldValue; -} -#endif - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_WriteFatEntryFlushBuffer -Flush the FAT buffer back to the disc ------------------------------------------------------------------*/ -bool FAT_WriteFatEntryFlushBuffer (void) -{ - // write the buffer disc - if ((fatBufferCurSector >= filesysFAT) && (fatBufferCurSector < (filesysFAT + filesysSecPerFAT))) - { - disc_WriteSector(fatBufferCurSector, fatBuffer); - return true; - } else { - return false; - } -} -#endif - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_FirstFreeCluster -Internal function - gets the first available free cluster ------------------------------------------------------------------*/ -u32 FAT_FirstFreeCluster(void) -{ - // Start at first valid cluster - if (fatFirstFree < CLUSTER_FIRST) - fatFirstFree = CLUSTER_FIRST; - - while ((FAT_NextCluster(fatFirstFree) != CLUSTER_FREE) && (fatFirstFree <= fatLastCluster)) - { - fatFirstFree++; - } - if (fatFirstFree > fatLastCluster) - { - return CLUSTER_EOF; - } - return fatFirstFree; -} -#endif - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_LinkFreeCluster -Internal function - gets the first available free cluster, sets it -to end of file, links the input cluster to it then returns the -cluster number ------------------------------------------------------------------*/ -u32 FAT_LinkFreeCluster(u32 cluster) -{ - u32 firstFree; - u32 curLink; - - if (cluster > fatLastCluster) - { - return CLUSTER_FREE; - } - - // Check if the cluster already has a link, and return it if so - curLink = FAT_NextCluster (cluster); - if ((curLink >= CLUSTER_FIRST) && (curLink < fatLastCluster)) - { - return curLink; // Return the current link - don't allocate a new one - } - - // Get a free cluster - firstFree = FAT_FirstFreeCluster(); - - // If couldn't get a free cluster then return - if (firstFree == CLUSTER_EOF) - { - return CLUSTER_FREE; - } - - if ((cluster >= CLUSTER_FIRST) && (cluster < fatLastCluster)) - { - // Update the linked from FAT entry - FAT_WriteFatEntry (cluster, firstFree); - } - // Create the linked to FAT entry - FAT_WriteFatEntry (firstFree, CLUSTER_EOF); - - return firstFree; -} -#endif - - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_ClearLinks -Internal function - frees any cluster used by a file ------------------------------------------------------------------*/ -bool FAT_ClearLinks (u32 cluster) -{ - u32 nextCluster; - - if ((cluster < 0x0002) || (cluster > fatLastCluster)) - return false; - - // Store next cluster before erasing the link - nextCluster = FAT_NextCluster (cluster); - - // Erase the link - FAT_WriteFatEntry (cluster, CLUSTER_FREE); - - // Move onto next cluster - cluster = nextCluster; - - while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE)) - { - cluster = FAT_ReadWriteFatEntryBuffered (cluster, CLUSTER_FREE); - } - - // Flush fat write buffer - FAT_WriteFatEntryFlushBuffer (); - - return true; -} -#endif - - -/*----------------------------------------------------------------- -FAT_InitFiles -Reads the FAT information from the CF card. -You need to call this before reading any files. -bool return OUT: true if successful. ------------------------------------------------------------------*/ -bool FAT_InitFiles (void) -{ - int i; - int bootSector; - BOOT_SEC* bootSec; - - if (!disc_Init()) - { - return (false); - } - - // Read first sector of CF card - if ( !disc_ReadSector(0, globalBuffer)) { - return false; - } - - // Make sure it is a valid MBR or boot sector - if ( (globalBuffer[0x1FE] != 0x55) || (globalBuffer[0x1FF] != 0xAA)) { - return false; - } - - // Check if there is a FAT string, which indicates this is a boot sector - if ((globalBuffer[0x36] == 'F') && (globalBuffer[0x37] == 'A') && (globalBuffer[0x38] == 'T')) - { - bootSector = 0; - } - // Check for FAT32 - else if ((globalBuffer[0x52] == 'F') && (globalBuffer[0x53] == 'A') && (globalBuffer[0x54] == 'T')) - { - bootSector = 0; - } - else // This is an MBR - { - // Find first valid partition from MBR - // First check for an active partition - for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i] != 0x80); i+= 0x10); - // If it didn't find an active partition, search for any valid partition - if (i == 0x1FE) - for (i=0x1BE; (i < 0x1FE) && (globalBuffer[i+0x04] == 0x00); i+= 0x10); - - // Go to first valid partition - if ( i != 0x1FE) // Make sure it found a partition - { - bootSector = globalBuffer[0x8 + i] + (globalBuffer[0x9 + i] << 8) + (globalBuffer[0xA + i] << 16) + ((globalBuffer[0xB + i] << 24) & 0x0F); - } else { - bootSector = 0; // No partition found, assume this is a MBR free disk - } - } - - // Read in boot sector - bootSec = (BOOT_SEC*) globalBuffer; - if (!disc_ReadSector (bootSector, bootSec)) { - return false; - } - - // Store required information about the file system - if (bootSec->sectorsPerFAT != 0) - { - filesysSecPerFAT = bootSec->sectorsPerFAT; - } - else - { - filesysSecPerFAT = bootSec->extBlock.fat32.sectorsPerFAT32; - } - - if (bootSec->numSectorsSmall != 0) - { - filesysNumSec = bootSec->numSectorsSmall; - } - else - { - filesysNumSec = bootSec->numSectors; - } - - filesysBytePerSec = BYTE_PER_READ; // Sector size is redefined to be 512 bytes - filesysSecPerClus = bootSec->sectorsPerCluster * bootSec->bytesPerSector / BYTE_PER_READ; - filesysBytePerClus = filesysBytePerSec * filesysSecPerClus; - filesysFAT = bootSector + bootSec->reservedSectors; - - filesysRootDir = filesysFAT + (bootSec->numFATs * filesysSecPerFAT); - filesysData = filesysRootDir + ((bootSec->rootEntries * sizeof(DIR_ENT)) / filesysBytePerSec); - - filesysTotalSize = (filesysNumSec - filesysData) * filesysBytePerSec; - - // Store info about FAT - fatLastCluster = (filesysNumSec - filesysData) / bootSec->sectorsPerCluster; - fatFirstFree = CLUSTER_FIRST; - fatBufferCurSector = 0; - disc_ReadSector(fatBufferCurSector, fatBuffer); - - if (fatLastCluster < 4085) - { - filesysType = FS_FAT12; // FAT12 volume - unsupported - } - else if (fatLastCluster < 65525) - { - filesysType = FS_FAT16; // FAT16 volume - } - else - { - filesysType = FS_FAT32; // FAT32 volume - } - - if (filesysType != FS_FAT32) - { - filesysRootDirClus = FAT16_ROOT_DIR_CLUSTER; - } - else // Set up for the FAT32 way - { - filesysRootDirClus = bootSec->extBlock.fat32.rootClus; - // Check if FAT mirroring is enabled - if (!(bootSec->extBlock.fat32.extFlags & 0x80)) - { - // Use the active FAT - filesysFAT = filesysFAT + ( filesysSecPerFAT * (bootSec->extBlock.fat32.extFlags & 0x0F)); - } - } - - // Set current directory to the root - curWorkDirCluster = filesysRootDirClus; - wrkDirCluster = filesysRootDirClus; - wrkDirSector = 0; - wrkDirOffset = 0; - - // Set all files to free - for (i=0; i < MAX_FILES_OPEN; i++) - { - openFiles[i].inUse = false; - } - - // No long filenames so far - lfnExists = false; - for (i = 0; i < MAX_FILENAME_LENGTH; i++) - { - lfnName[i] = '\0'; - } - - return (true); -} - -/*----------------------------------------------------------------- -FAT_FreeFiles -Closes all open files then resets the CF card. -Call this before exiting back to the GBAMP -bool return OUT: true if successful. ------------------------------------------------------------------*/ -bool FAT_FreeFiles (void) -{ - int i; - - // Close all open files - for (i=0; i < MAX_FILES_OPEN; i++) - { - if (openFiles[i].inUse == true) - { - FAT_fclose(&openFiles[i]); - } - } - - // Flush any sectors in disc cache - disc_CacheFlush(); - - // Clear card status - disc_ClearStatus(); - - // Return status of card - return disc_IsInserted(); -} - - -/*----------------------------------------------------------------- -FAT_GetDirEntry -Return the file info structure of the next valid file entry -u32 dirCluster: IN cluster of subdirectory table -int entry: IN the desired file entry -int origin IN: relative position of the entry -DIR_ENT return OUT: desired dirEntry. First char will be FILE_FREE if - the entry does not exist. ------------------------------------------------------------------*/ -DIR_ENT FAT_GetDirEntry ( u32 dirCluster, int entry, int origin) -{ - DIR_ENT dir; - DIR_ENT_LFN lfn; - int firstSector = 0; - bool notFound = false; - bool found = false; - int maxSectors; - int lfnPos, aliasPos; - u8 lfnChkSum, chkSum; - - int i; - - dir.name[0] = FILE_FREE; // default to no file found - dir.attrib = 0x00; - - // Check if fat has been initialised - if (filesysBytePerSec == 0) - { - return (dir); - } - - switch (origin) - { - case SEEK_SET: - wrkDirCluster = dirCluster; - wrkDirSector = 0; - wrkDirOffset = -1; - break; - case SEEK_CUR: // Don't change anything - break; - case SEEK_END: // Find entry signifying end of directory - // Subtraction will never reach 0, so it keeps going - // until reaches end of directory - wrkDirCluster = dirCluster; - wrkDirSector = 0; - wrkDirOffset = -1; - entry = -1; - break; - default: - return dir; - } - - lfnChkSum = 0; - maxSectors = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? (filesysData - filesysRootDir) : filesysSecPerClus); - - // Scan Dir for correct entry - firstSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)); - disc_ReadSector (firstSector + wrkDirSector, globalBuffer); - found = false; - notFound = false; - do { - wrkDirOffset++; - if (wrkDirOffset == BYTE_PER_READ / sizeof (DIR_ENT)) - { - wrkDirOffset = 0; - wrkDirSector++; - if ((wrkDirSector == filesysSecPerClus) && (wrkDirCluster != FAT16_ROOT_DIR_CLUSTER)) - { - wrkDirSector = 0; - wrkDirCluster = FAT_NextCluster(wrkDirCluster); - if (wrkDirCluster == CLUSTER_EOF) - { - notFound = true; - } - firstSector = FAT_ClustToSect(wrkDirCluster); - } - else if ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER) && (wrkDirSector == (filesysData - filesysRootDir))) - { - notFound = true; // Got to end of root dir - } - disc_ReadSector (firstSector + wrkDirSector, globalBuffer); - } - dir = ((DIR_ENT*) globalBuffer)[wrkDirOffset]; - if ((dir.name[0] != FILE_FREE) && (dir.name[0] > 0x20) && ((dir.attrib & ATTRIB_VOL) != ATTRIB_VOL)) - { - entry--; - if (lfnExists) - { - // Calculate file checksum - chkSum = 0; - for (aliasPos=0; aliasPos < 11; aliasPos++) - { - // NOTE: The operation is an unsigned char rotate right - chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + (aliasPos < 8 ? dir.name[aliasPos] : dir.ext[aliasPos - 8]); - } - if (chkSum != lfnChkSum) - { - lfnExists = false; - lfnName[0] = '\0'; - } - } - if (entry == 0) - { - if (!lfnExists) - { - FAT_GetFilename (dir, lfnName); - } - found = true; - } - } - else if (dir.name[0] == FILE_LAST) - { - if (origin == SEEK_END) - { - found = true; - } - else - { - notFound = true; - } - } - else if (dir.attrib == ATTRIB_LFN) - { - lfn = ((DIR_ENT_LFN*) globalBuffer)[wrkDirOffset]; - if (lfn.ordinal & LFN_DEL) - { - lfnExists = false; - } - else if (lfn.ordinal & LFN_END) // Last part of LFN, make sure it isn't deleted (Thanks MoonLight) - { - lfnExists = true; - lfnName[(lfn.ordinal & ~LFN_END) * 13] = '\0'; // Set end of lfn to null character - lfnChkSum = lfn.checkSum; - } - if (lfnChkSum != lfn.checkSum) - { - lfnExists = false; - } - if (lfnExists) - { - lfnPos = ((lfn.ordinal & ~LFN_END) - 1) * 13; - for (i = 0; i < 13; i++) { - lfnName[lfnPos + i] = ((u8*)&lfn)[(int)(lfn_offset_table[i])] /* | ((u8*)&lfn)[(int)(lfn_offset_table[i]) + 1] include this for unicode support*/; - } - } - } - } while (!found && !notFound); - - // If no file is found, return FILE_FREE - if (notFound) - { - dir.name[0] = FILE_FREE; - } - - return (dir); -} - - -/*----------------------------------------------------------------- -FAT_GetLongFilename -Get the long name of the last file or directory retrived with - GetDirEntry. Also works for FindFirstFile and FindNextFile. - If a long name doesn't exist, it returns the short name - instead. -char* filename: OUT will be filled with the filename, should be at - least 256 bytes long -bool return OUT: return true if successful ------------------------------------------------------------------*/ -bool FAT_GetLongFilename (char* filename) -{ - if (filename == NULL) - return false; - - strncpy (filename, lfnName, MAX_FILENAME_LENGTH - 1); - filename[MAX_FILENAME_LENGTH - 1] = '\0'; - - return true; -} - - -/*----------------------------------------------------------------- -FAT_GetFilename -Get the alias (short name) of the file or directory stored in - dirEntry -DIR_ENT dirEntry: IN a valid directory table entry -char* alias OUT: will be filled with the alias (short filename), - should be at least 13 bytes long -bool return OUT: return true if successful ------------------------------------------------------------------*/ -bool FAT_GetFilename (DIR_ENT dirEntry, char* alias) -{ - int i=0; - int j=0; - - alias[0] = '\0'; - if (dirEntry.name[0] != FILE_FREE) - { - if (dirEntry.name[0] == '.') - { - alias[0] = '.'; - if (dirEntry.name[1] == '.') - { - alias[1] = '.'; - alias[2] = '\0'; - } - else - { - alias[1] = '\0'; - } - } - else - { - // Copy the filename from the dirEntry to the string - for (i = 0; (i < 8) && (dirEntry.name[i] != ' '); i++) - { - alias[i] = dirEntry.name[i]; - } - // Copy the extension from the dirEntry to the string - if (dirEntry.ext[0] != ' ') - { - alias[i++] = '.'; - for ( j = 0; (j < 3) && (dirEntry.ext[j] != ' '); j++) - { - alias[i++] = dirEntry.ext[j]; - } - } - alias[i] = '\0'; - } - } - - return (alias[0] != '\0'); -} - -/*----------------------------------------------------------------- -FAT_GetAlias -Get the alias (short name) of the last file or directory entry read - using GetDirEntry. Works for FindFirstFile and FindNextFile -char* alias OUT: will be filled with the alias (short filename), - should be at least 13 bytes long -bool return OUT: return true if successful ------------------------------------------------------------------*/ -bool FAT_GetAlias (char* alias) -{ - if (alias == NULL) - { - return false; - } - // Read in the last accessed directory entry - disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - return FAT_GetFilename (((DIR_ENT*)globalBuffer)[wrkDirOffset], alias); -} - -/*----------------------------------------------------------------- -FAT_GetFileSize -Get the file size of the last file found or openned. -This idea is based on a modification by MoonLight -u32 return OUT: the file size ------------------------------------------------------------------*/ -u32 FAT_GetFileSize (void) -{ - // Read in the last accessed directory entry - disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - return ((DIR_ENT*)globalBuffer)[wrkDirOffset].fileSize; -} - -/*----------------------------------------------------------------- -FAT_GetFileCluster -Get the first cluster of the last file found or openned. -u32 return OUT: the file start cluster ------------------------------------------------------------------*/ -u32 FAT_GetFileCluster (void) -{ - // Read in the last accessed directory entry - disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - return (((DIR_ENT*)globalBuffer)[wrkDirOffset].startCluster) | (((DIR_ENT*)globalBuffer)[wrkDirOffset].startClusterHigh << 16); -} - -/*----------------------------------------------------------------- -FAT_GetFileAttributes -Get the attributes of the last file found or openned. -u8 return OUT: the file's attributes ------------------------------------------------------------------*/ -u8 FAT_GetFileAttributes (void) -{ - // Read in the last accessed directory entry - disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - return ((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib; -} - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_SetFileAttributes -Set the attributes of a file. -const char* filename IN: The name and path of the file to modify -u8 attributes IN: The attribute values to assign -u8 mask IN: Detemines which attributes are changed -u8 return OUT: the file's new attributes ------------------------------------------------------------------*/ -u8 FAT_SetFileAttributes (const char* filename, u8 attributes, u8 mask) -{ - // Get the file - if (!FAT_FileExists(filename)) { - return 0xff; - } - - // Read in the last accessed directory entry - disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - ((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib = (((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib & ~(mask & 0x27)) | (attributes & 0x27); // 0x27 is he settable attributes - - disc_WriteSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - return ((DIR_ENT*)globalBuffer)[wrkDirOffset].attrib; -} -#endif - -#ifdef FILE_TIME_SUPPORT -time_t FAT_FileTimeToCTime (u16 fileTime, u16 fileDate) -{ - struct tm timeInfo; - - timeInfo.tm_year = (fileDate >> 9) + 80; // years since midnight January 1970 - timeInfo.tm_mon = ((fileDate >> 5) & 0xf) - 1; // Months since january - timeInfo.tm_mday = fileDate & 0x1f; // Day of the month - - timeInfo.tm_hour = fileTime >> 11; // hours past midnight - timeInfo.tm_min = (fileTime >> 5) & 0x3f; // minutes past the hour - timeInfo.tm_sec = (fileTime & 0x1f) * 2; // seconds past the minute - - return mktime(&timeInfo); -} - -/*----------------------------------------------------------------- -FAT_GetFileCreationTime -Get the creation time of the last file found or openned. -time_t return OUT: the file's creation time ------------------------------------------------------------------*/ -time_t FAT_GetFileCreationTime (void) -{ - // Read in the last accessed directory entry - disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - return FAT_FileTimeToCTime(((DIR_ENT*)globalBuffer)[wrkDirOffset].cTime, ((DIR_ENT*)globalBuffer)[wrkDirOffset].cDate); -} - -/*----------------------------------------------------------------- -FAT_GetFileLastWriteTime -Get the creation time of the last file found or openned. -time_t return OUT: the file's creation time ------------------------------------------------------------------*/ -time_t FAT_GetFileLastWriteTime (void) -{ - // Read in the last accessed directory entry - disc_ReadSector ((wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector, globalBuffer); - - return FAT_FileTimeToCTime(((DIR_ENT*)globalBuffer)[wrkDirOffset].mTime, ((DIR_ENT*)globalBuffer)[wrkDirOffset].mDate); -} -#endif - -/*----------------------------------------------------------------- -FAT_DirEntFromPath -Finds the directory entry for a file or directory from a path -Path separator is a forward slash / -const char* path: IN null terminated string of path. -DIR_ENT return OUT: dirEntry of found file. First char will be FILE_FREE - if the file was not found ------------------------------------------------------------------*/ -DIR_ENT FAT_DirEntFromPath (const char* path) -{ - int pathPos; - char name[MAX_FILENAME_LENGTH]; - char alias[13]; - int namePos; - bool found, notFound; - DIR_ENT dirEntry; - u32 dirCluster; - bool flagLFN, dotSeen; - - // Start at beginning of path - pathPos = 0; - - if (path[pathPos] == '/') - { - dirCluster = filesysRootDirClus; // Start at root directory - } - else - { - dirCluster = curWorkDirCluster; // Start at current working dir - } - - // Eat any slash / - while ((path[pathPos] == '/') && (path[pathPos] != '\0')) - { - pathPos++; - } - - // Search until can't continue - found = false; - notFound = false; - while (!notFound && !found) - { - flagLFN = false; - // Copy name from path - namePos = 0; - if ((path[pathPos] == '.') && ((path[pathPos + 1] == '\0') || (path[pathPos + 1] == '/'))) { - // Dot entry - name[namePos++] = '.'; - pathPos++; - } else if ((path[pathPos] == '.') && (path[pathPos + 1] == '.') && ((path[pathPos + 2] == '\0') || (path[pathPos + 2] == '/'))){ - // Double dot entry - name[namePos++] = '.'; - pathPos++; - name[namePos++] = '.'; - pathPos++; - } else { - // Copy name from path - if (path[pathPos] == '.') { - flagLFN = true; - } - dotSeen = false; - while ((namePos < MAX_FILENAME_LENGTH - 1) && (path[pathPos] != '\0') && (path[pathPos] != '/')) - { - name[namePos] = ucase(path[pathPos]); - if ((name[namePos] <= ' ') || ((name[namePos] >= ':') && (name[namePos] <= '?'))) // Invalid character - { - flagLFN = true; - } - if (name[namePos] == '.') { - if (!dotSeen) { - dotSeen = true; - } else { - flagLFN = true; - } - } - namePos++; - pathPos++; - } - // Check if a long filename was specified - if (namePos > 12) - { - flagLFN = true; - } - } - - // Add end of string char - name[namePos] = '\0'; - - // Move through path to correct place - while ((path[pathPos] != '/') && (path[pathPos] != '\0')) - pathPos++; - // Eat any slash / - while ((path[pathPos] == '/') && (path[pathPos] != '\0')) - { - pathPos++; - } - - // Search current Dir for correct entry - dirEntry = FAT_GetDirEntry (dirCluster, 1, SEEK_SET); - while ( !found && !notFound) - { - // Match filename - found = true; - for (namePos = 0; (namePos < MAX_FILENAME_LENGTH) && found && (name[namePos] != '\0') && (lfnName[namePos] != '\0'); namePos++) - { - if (name[namePos] != ucase(lfnName[namePos])) - { - found = false; - } - } - if ((name[namePos] == '\0') != (lfnName[namePos] == '\0')) - { - found = false; - } - - // Check against alias as well. - if (!found) - { - FAT_GetFilename(dirEntry, alias); - found = true; - for (namePos = 0; (namePos < 13) && found && (name[namePos] != '\0') && (alias[namePos] != '\0'); namePos++) - { - if (name[namePos] != ucase(alias[namePos])) - { - found = false; - } - } - if ((name[namePos] == '\0') != (alias[namePos] == '\0')) - { - found = false; - } - } - - if (dirEntry.name[0] == FILE_FREE) - // Couldn't find specified file - { - found = false; - notFound = true; - } - if (!found && !notFound) - { - dirEntry = FAT_GetDirEntry (dirCluster, 1, SEEK_CUR); - } - } - - if (found && ((dirEntry.attrib & ATTRIB_DIR) == ATTRIB_DIR) && (path[pathPos] != '\0')) - // It has found a directory from within the path that needs to be followed - { - found = false; - dirCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16); - } - } - - if (notFound) - { - dirEntry.name[0] = FILE_FREE; - dirEntry.attrib = 0x00; - } - - return (dirEntry); -} - - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_AddDirEntry -Creates a new dir entry for a file -Path separator is a forward slash / -const char* path: IN null terminated string of path to file. -DIR_ENT newDirEntry IN: The directory entry to use. -int file IN: The file being added (optional, use -1 if not used) -bool return OUT: true if successful ------------------------------------------------------------------*/ -bool FAT_AddDirEntry (const char* path, DIR_ENT newDirEntry) -{ - char filename[MAX_FILENAME_LENGTH]; - int filePos, pathPos, aliasPos; - char tempChar; - bool flagLFN, dotSeen; - char fileAlias[13] = {0}; - int tailNum; - - unsigned char chkSum = 0; - - u32 oldWorkDirCluster; - - DIR_ENT* dirEntries = (DIR_ENT*)globalBuffer; - u32 dirCluster; - int secOffset; - int entryOffset; - int maxSectors; - u32 firstSector; - - DIR_ENT_LFN lfnEntry; - int lfnPos = 0; - - int dirEntryLength = 0; - int dirEntryRemain = 0; - u32 tempDirCluster; - int tempSecOffset; - int tempEntryOffset; - bool dirEndFlag = false; - - int i; - - // Store current working directory - oldWorkDirCluster = curWorkDirCluster; - - // Find filename within path and change to correct directory - if (path[0] == '/') - { - curWorkDirCluster = filesysRootDirClus; - } - - pathPos = 0; - filePos = 0; - flagLFN = false; - - while (path[pathPos + filePos] != '\0') - { - if (path[pathPos + filePos] == '/') - { - filename[filePos] = '\0'; - if (FAT_chdir(filename) == false) - { - curWorkDirCluster = oldWorkDirCluster; - return false; // Couldn't change directory - } - pathPos += filePos + 1; - filePos = 0; - } - filename[filePos] = path[pathPos + filePos]; - filePos++; - } - - // Skip over last slashes - while (path[pathPos] == '/') - pathPos++; - - // Check if the filename has a leading "." - // If so, it is an LFN - if (path[pathPos] == '.') { - flagLFN = true; - } - - // Copy name from path - filePos = 0; - dotSeen = false; - - while ((filePos < MAX_FILENAME_LENGTH - 1) && (path[pathPos] != '\0')) - { - filename[filePos] = path[pathPos]; - if ((filename[filePos] <= ' ') || ((filename[filePos] >= ':') && (filename[filePos] <= '?'))) // Invalid character - { - flagLFN = true; - } - if (filename[filePos] == '.') { - if (!dotSeen) { - dotSeen = true; - } else { - flagLFN = true; - } - } - filePos++; - pathPos++; - if ((filePos > 8) && !dotSeen) { - flagLFN = true; - } - } - - if (filePos == 0) // No filename - { - return false; - } - - // Check if a long filename was specified - if (filePos > 12) - { - flagLFN = true; - } - - // Check if extension is > 3 characters long - if (!flagLFN && (strrchr (filename, '.') != NULL) && (strlen(strrchr(filename, '.')) > 4)) { - flagLFN = true; - } - - lfnPos = (filePos - 1) / 13; - - // Add end of string char - filename[filePos++] = '\0'; - // Clear remaining chars - while (filePos < MAX_FILENAME_LENGTH) - filename[filePos++] = 0x01; // Set for LFN compatibility - - - if (flagLFN) - { - // Generate short filename - always a 2 digit number for tail - // Get first 5 chars of alias from LFN - aliasPos = 0; - filePos = 0; - if (filename[filePos] == '.') { - filePos++; - } - for ( ; (aliasPos < 5) && (filename[filePos] != '\0') && (filename[filePos] != '.') ; filePos++) - { - tempChar = ucase(filename[filePos]); - if (((tempChar > ' ' && tempChar < ':') || tempChar > '?') && tempChar != '.') - fileAlias[aliasPos++] = tempChar; - } - // Pad Alias with underscores - while (aliasPos < 5) - fileAlias[aliasPos++] = '_'; - - fileAlias[5] = '~'; - fileAlias[8] = '.'; - fileAlias[9] = ' '; - fileAlias[10] = ' '; - fileAlias[11] = ' '; - if (strchr (filename, '.') != NULL) { - while(filename[filePos] != '\0') - { - filePos++; - if (filename[filePos] == '.') - { - pathPos = filePos; - } - } - filePos = pathPos + 1; //pathPos is used as a temporary variable - // Copy first 3 characters of extension - for (aliasPos = 9; (aliasPos < 12) && (filename[filePos] != '\0'); filePos++) - { - tempChar = ucase(filename[filePos]); - if ((tempChar > ' ' && tempChar < ':') || tempChar > '?') - fileAlias[aliasPos++] = tempChar; - } - } else { - aliasPos = 9; - } - - // Pad Alias extension with spaces - while (aliasPos < 12) - fileAlias[aliasPos++] = ' '; - - fileAlias[12] = '\0'; - - - // Get a valid tail number - tailNum = 0; - do { - tailNum++; - fileAlias[6] = 0x30 + ((tailNum / 10) % 10); // 10's digit - fileAlias[7] = 0x30 + (tailNum % 10); // 1's digit - } while ((FAT_DirEntFromPath(fileAlias).name[0] != FILE_FREE) && (tailNum < 100)); - - if (tailNum < 100) // Found an alias not being used - { - // Calculate file checksum - chkSum = 0; - for (aliasPos=0; aliasPos < 12; aliasPos++) - { - // Skip '.' - if (fileAlias[aliasPos] == '.') - aliasPos++; - // NOTE: The operation is an unsigned char rotate right - chkSum = ((chkSum & 1) ? 0x80 : 0) + (chkSum >> 1) + fileAlias[aliasPos]; - } - } - else // Couldn't find a valid alias - { - return false; - } - - dirEntryLength = lfnPos + 2; - } - else // Its not a long file name - { - // Just copy alias straight from filename - for (aliasPos = 0; aliasPos < 13; aliasPos++) - { - tempChar = ucase(filename[aliasPos]); - if ((tempChar > ' ' && tempChar < ':') || tempChar > '?') - fileAlias[aliasPos] = tempChar; - } - fileAlias[12] = '\0'; - - lfnPos = -1; - - dirEntryLength = 1; - } - - // Change dirEntry name to match alias - for (aliasPos = 0; ((fileAlias[aliasPos] != '.') && (fileAlias[aliasPos] != '\0') && (aliasPos < 8)); aliasPos++) - { - newDirEntry.name[aliasPos] = fileAlias[aliasPos]; - } - while (aliasPos < 8) - { - newDirEntry.name[aliasPos++] = ' '; - } - aliasPos = 0; - while ((fileAlias[aliasPos] != '.') && (fileAlias[aliasPos] != '\0')) - aliasPos++; - filePos = 0; - while (( filePos < 3 ) && (fileAlias[aliasPos] != '\0')) - { - tempChar = fileAlias[aliasPos++]; - if ((tempChar > ' ' && tempChar < ':' && tempChar!='.') || tempChar > '?') - newDirEntry.ext[filePos++] = tempChar; - } - while (filePos < 3) - { - newDirEntry.ext[filePos++] = ' '; - } - - // Scan Dir for free entry - dirCluster = curWorkDirCluster; - secOffset = 0; - entryOffset = 0; - maxSectors = (dirCluster == FAT16_ROOT_DIR_CLUSTER ? (filesysData - filesysRootDir) : filesysSecPerClus); - firstSector = (dirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(dirCluster)); - disc_ReadSector (firstSector + secOffset, dirEntries); - - dirEntryRemain = dirEntryLength; - tempDirCluster = dirCluster; - tempSecOffset = secOffset; - tempEntryOffset = entryOffset; - - // Search for a large enough space to fit in new directory entry - while ((dirEntries[entryOffset].name[0] != FILE_LAST) && (dirEntryRemain > 0)) - { - - entryOffset++; - - if (entryOffset == BYTE_PER_READ / sizeof (DIR_ENT)) - { - entryOffset = 0; - secOffset++; - if ((secOffset == filesysSecPerClus) && (dirCluster != FAT16_ROOT_DIR_CLUSTER)) - { - secOffset = 0; - if (FAT_NextCluster(dirCluster) == CLUSTER_EOF) - { - dirCluster = FAT_LinkFreeCluster(dirCluster); - dirEntries[0].name[0] = FILE_LAST; - } - else - { - dirCluster = FAT_NextCluster(dirCluster); - } - firstSector = FAT_ClustToSect(dirCluster); - } - else if ((dirCluster == FAT16_ROOT_DIR_CLUSTER) && (secOffset == (filesysData - filesysRootDir))) - { - return false; // Got to end of root dir - can't fit in more files - } - disc_ReadSector (firstSector + secOffset, dirEntries); - } - - if ((dirEntries[entryOffset].name[0] == FILE_FREE) || (dirEntries[entryOffset].name[0] == FILE_LAST) ) - { - dirEntryRemain--; - } else { - dirEntryRemain = dirEntryLength; - tempDirCluster = dirCluster; - tempSecOffset = secOffset; - tempEntryOffset = entryOffset; - } - } - - // Modifying the last directory is a special case - have to erase following entries - if (dirEntries[entryOffset].name[0] == FILE_LAST) - { - dirEndFlag = true; - } - - // Recall last used entry - dirCluster = tempDirCluster; - secOffset = tempSecOffset; - entryOffset = tempEntryOffset; - dirEntryRemain = dirEntryLength; - - // Re-read in first sector that will be written to - if (dirEndFlag && (entryOffset == 0)) { - memset (dirEntries, FILE_LAST, BYTE_PER_READ); - } else { - disc_ReadSector (firstSector + secOffset, dirEntries); - } - - // Add new directory entry - while (dirEntryRemain > 0) - { - // Move to next entry, first pass advances from last used entry - entryOffset++; - if (entryOffset == BYTE_PER_READ / sizeof (DIR_ENT)) - { - // Write out the current sector if we need to - entryOffset = 0; - if (dirEntryRemain < dirEntryLength) // Don't write out sector on first pass - { - disc_WriteSector (firstSector + secOffset, dirEntries); - } - secOffset++; - if ((secOffset == filesysSecPerClus) && (dirCluster != FAT16_ROOT_DIR_CLUSTER)) - { - secOffset = 0; - if (FAT_NextCluster(dirCluster) == CLUSTER_EOF) - { - dirCluster = FAT_LinkFreeCluster(dirCluster); - dirEntries[0].name[0] = FILE_LAST; - } - else - { - dirCluster = FAT_NextCluster(dirCluster); - } - firstSector = FAT_ClustToSect(dirCluster); - } - else if ((dirCluster == FAT16_ROOT_DIR_CLUSTER) && (secOffset == (filesysData - filesysRootDir))) - { - return false; // Got to end of root dir - can't fit in more files - } - if (dirEndFlag) - { - memset (dirEntries, FILE_LAST, BYTE_PER_READ); - } else { - disc_ReadSector (firstSector + secOffset, dirEntries); - } - } - - // Generate LFN entries - if (lfnPos >= 0) - { - lfnEntry.ordinal = (lfnPos + 1) | (dirEntryRemain == dirEntryLength ? LFN_END : 0); - for (i = 0; i < 13; i++) { - if (filename [lfnPos * 13 + i] == 0x01) { - ((u8*)&lfnEntry)[(int)lfn_offset_table[i]] = 0xff; - ((u8*)&lfnEntry)[(int)(lfn_offset_table[i]) + 1] = 0xff; - } else { - ((u8*)&lfnEntry)[(int)lfn_offset_table[i]] = filename [lfnPos * 13 + i]; - ((u8*)&lfnEntry)[(int)(lfn_offset_table[i]) + 1] = 0x00; - } - } - - lfnEntry.checkSum = chkSum; - lfnEntry.flag = ATTRIB_LFN; - lfnEntry.reserved1 = 0; - lfnEntry.reserved2 = 0; - - *((DIR_ENT_LFN*)&dirEntries[entryOffset]) = lfnEntry; - lfnPos --; - lfnEntry.ordinal = 0; - } // end writing long filename entries - else - { - dirEntries[entryOffset] = newDirEntry; - if (dirEndFlag && (entryOffset < (BYTE_PER_READ / sizeof (DIR_ENT))) ) - dirEntries[entryOffset+1].name[0] = FILE_LAST; - } - - dirEntryRemain--; - } - - // Write directory back to disk - disc_WriteSector (firstSector + secOffset, dirEntries); - - // Change back to Working DIR - curWorkDirCluster = oldWorkDirCluster; - - return true; -} -#endif - -/*----------------------------------------------------------------- -FAT_FindNextFile -Gets the name of the next directory entry - (can be a file or subdirectory) -char* filename: OUT filename, must be at least 13 chars long -FILE_TYPE return: OUT returns FT_NONE if failed, - FT_FILE if it found a file and FT_DIR if it found a directory ------------------------------------------------------------------*/ -FILE_TYPE FAT_FindNextFile(char* filename) -{ - // Get the next directory entry - DIR_ENT file; - file = FAT_GetDirEntry (curWorkDirCluster, 1, SEEK_CUR); - - if (file.name[0] == FILE_FREE) - { - return FT_NONE; // Did not find a file - } - - // Get the filename - if (filename != NULL) - FAT_GetFilename (file, filename); - - if ((file.attrib & ATTRIB_DIR) != 0) - { - return FT_DIR; // Found a directory - } - else - { - return FT_FILE; // Found a file - } -} - -/*----------------------------------------------------------------- -FAT_FindFirstFile -Gets the name of the first directory entry and resets the count - (can be a file or subdirectory) -char* filename: OUT filename, must be at least 13 chars long -FILE_TYPE return: OUT returns FT_NONE if failed, - FT_FILE if it found a file and FT_DIR if it found a directory ------------------------------------------------------------------*/ -FILE_TYPE FAT_FindFirstFile(char* filename) -{ - // Get the first directory entry - DIR_ENT file; - file = FAT_GetDirEntry (curWorkDirCluster, 1, SEEK_SET); - - if (file.name[0] == FILE_FREE) - { - return FT_NONE; // Did not find a file - } - - // Get the filename - if (filename != NULL) - FAT_GetFilename (file, filename); - - if ((file.attrib & ATTRIB_DIR) != 0) - { - return FT_DIR; // Found a directory - } - else - { - return FT_FILE; // Found a file - } -} - -/*----------------------------------------------------------------- -FAT_FindFirstFileLFN -Gets the long file name of the first directory entry and resets - the count (can be a file or subdirectory) -char* lfn: OUT long file name, must be at least 256 chars long -FILE_TYPE return: OUT returns FT_NONE if failed, - FT_FILE if it found a file and FT_DIR if it found a directory ------------------------------------------------------------------*/ -FILE_TYPE FAT_FindFirstFileLFN(char* lfn) -{ - FILE_TYPE type; - type = FAT_FindFirstFile(NULL); - FAT_GetLongFilename (lfn); - return type; -} - -/*----------------------------------------------------------------- -FAT_FindNextFileLFN -Gets the long file name of the next directory entry - (can be a file or subdirectory) -char* lfn: OUT long file name, must be at least 256 chars long -FILE_TYPE return: OUT returns FT_NONE if failed, - FT_FILE if it found a file and FT_DIR if it found a directory ------------------------------------------------------------------*/ -FILE_TYPE FAT_FindNextFileLFN(char* lfn) -{ - FILE_TYPE type; - type = FAT_FindNextFile(NULL); - FAT_GetLongFilename (lfn); - return type; -} - - -/*----------------------------------------------------------------- -FAT_FileExists -Returns the type of file -char* filename: IN filename of the file to look for -FILE_TYPE return: OUT returns FT_NONE if there is now file with - that name, FT_FILE if it is a file and FT_DIR if it is a directory ------------------------------------------------------------------*/ -FILE_TYPE FAT_FileExists(const char* filename) -{ - DIR_ENT dirEntry; - // Get the dirEntry for the path specified - dirEntry = FAT_DirEntFromPath (filename); - - if (dirEntry.name[0] == FILE_FREE) - { - return FT_NONE; - } - else if (dirEntry.attrib & ATTRIB_DIR) - { - return FT_DIR; - } - else - { - return FT_FILE; - } -} - -/*----------------------------------------------------------------- -FAT_GetFileSystemType -FS_TYPE return: OUT returns the current file system type ------------------------------------------------------------------*/ -FS_TYPE FAT_GetFileSystemType (void) -{ - return filesysType; -} - -/*----------------------------------------------------------------- -FAT_GetFileSystemTotalSize -u32 return: OUT returns the total disk space (used + free) ------------------------------------------------------------------*/ -u32 FAT_GetFileSystemTotalSize (void) -{ - return filesysTotalSize; -} - - - -/*----------------------------------------------------------------- -FAT_chdir -Changes the current working directory -const char* path: IN null terminated string of directory separated by - forward slashes, / is root -bool return: OUT returns true if successful ------------------------------------------------------------------*/ -bool FAT_chdir (const char* path) -{ - DIR_ENT dir; - if (path[0] == '/' && path[1] == '\0') - { - curWorkDirCluster = filesysRootDirClus; - return true; - } - if (path[0] == '\0') // Return true if changing relative to nothing - { - return true; - } - - dir = FAT_DirEntFromPath (path); - - if (((dir.attrib & ATTRIB_DIR) == ATTRIB_DIR) && (dir.name[0] != FILE_FREE)) - { - // Change directory - curWorkDirCluster = dir.startCluster | (dir.startClusterHigh << 16); - - // Move to correct cluster for root directory - if (curWorkDirCluster == FAT16_ROOT_DIR_CLUSTER) - { - curWorkDirCluster = filesysRootDirClus; - } - - // Reset file position in directory - wrkDirCluster = curWorkDirCluster; - wrkDirSector = 0; - wrkDirOffset = -1; - return true; - } - else - { - // Couldn't change directory - wrong path specified - return false; - } -} - -/*----------------------------------------------------------------- -FAT_fopen(filename, mode) -Opens a file -const char* path: IN null terminated string of filename and path - separated by forward slashes, / is root -const char* mode: IN mode to open file in - Supported modes: "r", "r+", "w", "w+", "a", "a+", don't use - "b" or "t" in any mode, as all files are openned in binary mode -FAT_FILE* return: OUT handle to open file, returns NULL if the file - couldn't be openned ------------------------------------------------------------------*/ -FAT_FILE* FAT_fopen(const char* path, const char* mode) -{ - int fileNum; - FAT_FILE* file; - DIR_ENT dirEntry; -#ifdef CAN_WRITE_TO_DISC - u32 startCluster; - int clusCount; -#endif - - char* pchTemp; - // Check that a valid mode was specified - pchTemp = strpbrk ( mode, "rRwWaA" ); - if (pchTemp == NULL) - { - return NULL; - } - if (strpbrk ( pchTemp+1, "rRwWaA" ) != NULL) - { - return NULL; - } - - // Get the dirEntry for the path specified - dirEntry = FAT_DirEntFromPath (path); - - // Check that it is not a directory - if (dirEntry.attrib & ATTRIB_DIR) - { - return NULL; - } - -#ifdef CAN_WRITE_TO_DISC - // Check that it is not a read only file being openned in a writing mode - if ( (strpbrk(mode, "wWaA+") != NULL) && (dirEntry.attrib & ATTRIB_RO)) - { - return NULL; - } -#else - if ( (strpbrk(mode, "wWaA+") != NULL)) - { - return NULL; - } -#endif - - // Find a free file buffer - for (fileNum = 0; (fileNum < MAX_FILES_OPEN) && (openFiles[fileNum].inUse == true); fileNum++); - - if (fileNum == MAX_FILES_OPEN) // No free files - { - return NULL; - } - - file = &openFiles[fileNum]; - // Remember where directory entry was - file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector; - file->dirEntOffset = wrkDirOffset; - - if ( strpbrk(mode, "rR") != NULL ) //(ucase(mode[0]) == 'R') - { - if (dirEntry.name[0] == FILE_FREE) // File must exist - { - return NULL; - } - - file->read = true; -#ifdef CAN_WRITE_TO_DISC - file->write = ( strchr(mode, '+') != NULL ); //(mode[1] == '+'); -#else - file->write = false; -#endif - file->append = false; - - // Store information about position within the file, for use - // by FAT_fread, FAT_fseek, etc. - file->firstCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16); - -#ifdef CAN_WRITE_TO_DISC - // Check if file is openned for random. If it is, and currently has no cluster, one must be - // assigned to it. - if (file->write && file->firstCluster == CLUSTER_FREE) - { - file->firstCluster = FAT_LinkFreeCluster (CLUSTER_FREE); - if (file->firstCluster == CLUSTER_FREE) // Couldn't get a free cluster - { - return NULL; - } - - // Store cluster position into the directory entry - dirEntry.startCluster = (file->firstCluster & 0xFFFF); - dirEntry.startClusterHigh = ((file->firstCluster >> 16) & 0xFFFF); - disc_ReadSector (file->dirEntSector, globalBuffer); - ((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry; - disc_WriteSector (file->dirEntSector, globalBuffer); - } -#endif - - file->length = dirEntry.fileSize; - file->curPos = 0; - file->curClus = dirEntry.startCluster | (dirEntry.startClusterHigh << 16); - file->curSect = 0; - file->curByte = 0; - - // Not appending - file->appByte = 0; - file->appClus = 0; - file->appSect = 0; - - disc_ReadSector( FAT_ClustToSect( file->curClus), file->readBuffer); - file->inUse = true; // We're using this file now - - return file; - } // mode "r" - -#ifdef CAN_WRITE_TO_DISC - if ( strpbrk(mode, "wW") != NULL ) // (ucase(mode[0]) == 'W') - { - if (dirEntry.name[0] == FILE_FREE) // Create file if it doesn't exist - { - dirEntry.attrib = ATTRIB_ARCH; - dirEntry.reserved = 0; - - // Time and date set to system time and date - dirEntry.cTime_ms = 0; - dirEntry.cTime = getRTCtoFileTime(); - dirEntry.cDate = getRTCtoFileDate(); - dirEntry.aDate = getRTCtoFileDate(); - dirEntry.mTime = getRTCtoFileTime(); - dirEntry.mDate = getRTCtoFileDate(); - } - else // Already a file entry - { - // Free any clusters used - FAT_ClearLinks (dirEntry.startCluster | (dirEntry.startClusterHigh << 16)); - } - - // Get a cluster to use - startCluster = FAT_LinkFreeCluster (CLUSTER_FREE); - if (startCluster == CLUSTER_FREE) // Couldn't get a free cluster - { - return NULL; - } - - // Store cluster position into the directory entry - dirEntry.startCluster = (startCluster & 0xFFFF); - dirEntry.startClusterHigh = ((startCluster >> 16) & 0xFFFF); - - // The file has no data in it - its over written so should be empty - dirEntry.fileSize = 0; - - if (dirEntry.name[0] == FILE_FREE) // No file - { - // Have to create a new entry - if(!FAT_AddDirEntry (path, dirEntry)) - { - return NULL; - } - // Get the newly created dirEntry - dirEntry = FAT_DirEntFromPath (path); - - // Remember where directory entry was - file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector; - file->dirEntOffset = wrkDirOffset; - } - else // Already a file - { - // Just modify the old entry - disc_ReadSector (file->dirEntSector, globalBuffer); - ((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry; - disc_WriteSector (file->dirEntSector, globalBuffer); - } - - - // Now that file is created, open it - file->read = ( strchr(mode, '+') != NULL ); //(mode[1] == '+'); - file->write = true; - file->append = false; - - // Store information about position within the file, for use - // by FAT_fread, FAT_fseek, etc. - file->firstCluster = startCluster; - file->length = 0; // Should always have 0 bytes if openning in "w" mode - file->curPos = 0; - file->curClus = startCluster; - file->curSect = 0; - file->curByte = 0; - - // Not appending - file->appByte = 0; - file->appClus = 0; - file->appSect = 0; - - // Empty file, so empty read buffer - memset (file->readBuffer, 0, BYTE_PER_READ); - file->inUse = true; // We're using this file now - - return file; - } - - if ( strpbrk(mode, "aA") != NULL ) // (ucase(mode[0]) == 'A') - { - if (dirEntry.name[0] == FILE_FREE) // Create file if it doesn't exist - { - dirEntry.attrib = ATTRIB_ARCH; - dirEntry.reserved = 0; - - // Time and date set to system time and date - dirEntry.cTime_ms = 0; - dirEntry.cTime = getRTCtoFileTime(); - dirEntry.cDate = getRTCtoFileDate(); - dirEntry.aDate = getRTCtoFileDate(); - dirEntry.mTime = getRTCtoFileTime(); - dirEntry.mDate = getRTCtoFileDate(); - - // The file has no data in it - dirEntry.fileSize = 0; - - // Get a cluster to use - startCluster = FAT_LinkFreeCluster (CLUSTER_FREE); - if (startCluster == CLUSTER_FREE) // Couldn't get a free cluster - { - return NULL; - } - dirEntry.startCluster = (startCluster & 0xFFFF); - dirEntry.startClusterHigh = ((startCluster >> 16) & 0xFFFF); - - if(!FAT_AddDirEntry (path, dirEntry)) - return NULL; - - // Get the newly created dirEntry - dirEntry = FAT_DirEntFromPath (path); - - // Store append cluster - file->appClus = startCluster; - - // Remember where directory entry was - file->dirEntSector = (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector; - file->dirEntOffset = wrkDirOffset; - } - else // File already exists - reuse the old directory entry - { - startCluster = dirEntry.startCluster | (dirEntry.startClusterHigh << 16); - // If it currently has no cluster, one must be assigned to it. - if (startCluster == CLUSTER_FREE) - { - file->firstCluster = FAT_LinkFreeCluster (CLUSTER_FREE); - if (file->firstCluster == CLUSTER_FREE) // Couldn't get a free cluster - { - return NULL; - } - - // Store cluster position into the directory entry - dirEntry.startCluster = (file->firstCluster & 0xFFFF); - dirEntry.startClusterHigh = ((file->firstCluster >> 16) & 0xFFFF); - disc_ReadSector (file->dirEntSector, globalBuffer); - ((DIR_ENT*) globalBuffer)[file->dirEntOffset] = dirEntry; - disc_WriteSector (file->dirEntSector, globalBuffer); - - // Store append cluster - file->appClus = startCluster; - - } else { - - // Follow cluster list until last one is found - clusCount = dirEntry.fileSize / filesysBytePerClus; - file->appClus = startCluster; - while ((clusCount--) && (FAT_NextCluster (file->appClus) != CLUSTER_FREE) && (FAT_NextCluster (file->appClus) != CLUSTER_EOF)) - { - file->appClus = FAT_NextCluster (file->appClus); - } - if (clusCount >= 0) // Check if ran out of clusters - { - // Set flag to allocate new cluster when needed - file->appSect = filesysSecPerClus; - file->appByte = 0; - } - } - } - - // Now that file is created, open it - file->read = ( strchr(mode, '+') != NULL ); - file->write = false; - file->append = true; - - // Calculate the sector and byte of the current position, - // and store them - file->appSect = (dirEntry.fileSize % filesysBytePerClus) / BYTE_PER_READ; - file->appByte = dirEntry.fileSize % BYTE_PER_READ; - - // Store information about position within the file, for use - // by FAT_fread, FAT_fseek, etc. - file->firstCluster = startCluster; - file->length = dirEntry.fileSize; - file->curPos = dirEntry.fileSize; - file->curClus = file->appClus; - file->curSect = file->appSect; - file->curByte = file->appByte; - - // Read into buffer - disc_ReadSector( FAT_ClustToSect(file->curClus) + file->curSect, file->readBuffer); - file->inUse = true; // We're using this file now - return file; - } -#endif - - // Can only reach here if a bad mode was specified - return NULL; -} - -/*----------------------------------------------------------------- -FAT_fclose(file) -Closes a file -FAT_FILE* file: IN handle of the file to close -bool return OUT: true if successful, false if not ------------------------------------------------------------------*/ -bool FAT_fclose (FAT_FILE* file) -{ - // Clear memory used by file information - if ((file != NULL) && (file->inUse == true)) - { -#ifdef CAN_WRITE_TO_DISC - if (file->write || file->append) - { - // Write new length, time and date back to directory entry - disc_ReadSector (file->dirEntSector, globalBuffer); - - ((DIR_ENT*)globalBuffer)[file->dirEntOffset].fileSize = file->length; - ((DIR_ENT*)globalBuffer)[file->dirEntOffset].mTime = getRTCtoFileTime(); - ((DIR_ENT*)globalBuffer)[file->dirEntOffset].mDate = getRTCtoFileDate(); - ((DIR_ENT*)globalBuffer)[file->dirEntOffset].aDate = getRTCtoFileDate(); - - disc_WriteSector (file->dirEntSector, globalBuffer); - - // Flush any sectors in disc cache - disc_CacheFlush(); - } -#endif - file->inUse = false; - return true; - } - else - { - return false; - } -} - -/*----------------------------------------------------------------- -FAT_ftell(file) -Returns the current position in a file -FAT_FILE* file: IN handle of an open file -u32 OUT: Current position ------------------------------------------------------------------*/ -u32 FAT_ftell (FAT_FILE* file) -{ - // Return the position as specified in the FAT_FILE structure - if ((file != NULL) && (file->inUse == true)) - { - return file->curPos; - } - else - { - // Return -1 if no file was given - return -1; - } -} - -/*----------------------------------------------------------------- -FAT_fseek(file, offset, origin) -Seeks to specified byte position in file -FAT_FILE* file: IN handle of an open file -s32 offset IN: position to seek to, relative to origin -int origin IN: origin to seek from -int OUT: Returns 0 if successful, -1 if not ------------------------------------------------------------------*/ -int FAT_fseek(FAT_FILE* file, s32 offset, int origin) -{ - u32 cluster, nextCluster; - int clusCount; - u32 position; - u32 curPos; - - if ((file == NULL) || (file->inUse == false)) // invalid file - { - return -1; - } - - // Can't seek in append only mode - if (!file->read && !file->write) - { - return -1; - } - - curPos = file->curPos; - - switch (origin) - { - case SEEK_SET: - if (offset >= 0) - { - position = offset; - } else { - // Tried to seek before start of file - position = 0; - } - break; - case SEEK_CUR: - if (offset >= 0) - { - position = curPos + offset; - } - else if ( (u32)(offset * -1) >= curPos ) - { - // Tried to seek before start of file - position = 0; - } - else - { - // Using u32 to maintain 32 bits of accuracy - position = curPos - (u32)(offset * -1); - } - break; - case SEEK_END: - if (offset >= 0) - { - // Seeking to end of file - position = file->length; // Fixed thanks to MoonLight - } - else if ( (u32)(offset * -1) >= file->length ) - { - // Tried to seek before start of file - position = 0; - } - else - { - // Using u32 to maintain 32 bits of accuracy - position = file->length - (u32)(offset * -1); - } - break; - default: - return -1; - } - - if (position > file->length) - { - // Tried to go past end of file - position = file->length; - } - - // Save position - file->curPos = position; - - - // Calculate where the correct cluster is - if (position > curPos) - { - clusCount = (position - curPos + (file->curSect * filesysBytePerSec) + file->curByte) / filesysBytePerClus; // Fixed thanks to AgentQ - cluster = file->curClus; - } else { - clusCount = position / filesysBytePerClus; - cluster = file->firstCluster; - } - - // Calculate the sector and byte of the current position, - // and store them - file->curSect = (position % filesysBytePerClus) / BYTE_PER_READ; - file->curByte = position % BYTE_PER_READ; - - // Follow cluster list until desired one is found - if (clusCount > 0) // Only look at next cluster if need to - { - nextCluster = FAT_NextCluster (cluster); - } else { - nextCluster = cluster; - } - while ((clusCount--) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF)) - { - cluster = nextCluster; - nextCluster = FAT_NextCluster (cluster); - } - // Check if ran out of clusters, and the file is being written to - if ((clusCount >= 0) && (file->write || file->append)) - { - // Set flag to allocate a new cluster - file->curSect = filesysSecPerClus; - file->curByte = 0; - } - file->curClus = cluster; - - // Reload sector buffer for new position in file, if it is a different sector - if ((curPos ^ position) >= BYTE_PER_READ) - { - disc_ReadSector( file->curSect + FAT_ClustToSect(file->curClus), file->readBuffer); - } - - return 0; -} - -/*----------------------------------------------------------------- -FAT_fread(buffer, size, count, file) -Reads in size * count bytes into buffer from file, starting - from current position. It then sets the current position to the - byte after the last byte read. If it reaches the end of file - before filling the buffer then it stops reading. -void* buffer OUT: Pointer to buffer to fill. Should be at least as - big as the number of bytes required -u32 size IN: size of each item to read -u32 count IN: number of items to read -FAT_FILE* file IN: Handle of an open file -u32 OUT: returns the actual number of bytes read ------------------------------------------------------------------*/ -u32 FAT_fread (void* buffer, u32 size, u32 count, FAT_FILE* file) -{ - int curByte; - int curSect; - u32 curClus; - u32 tempNextCluster; - - int tempVar; - - char* data = (char*)buffer; - - u32 length = size * count; - u32 remain; - - bool flagNoError = true; - - // Can't read non-existant files - if ((file == NULL) || (file->inUse == false) || size == 0 || count == 0 || buffer == NULL) - return 0; - - // Can only read files openned for reading - if (!file->read) - return 0; - - // Don't read past end of file - if (length + file->curPos > file->length) - length = file->length - file->curPos; - - remain = length; - - curByte = file->curByte; - curSect = file->curSect; - curClus = file->curClus; - - // Align to sector - tempVar = BYTE_PER_READ - curByte; - if (tempVar > remain) - tempVar = remain; - - if ((tempVar < BYTE_PER_READ) && flagNoError) - { - memcpy(data, &(file->readBuffer[curByte]), tempVar); - remain -= tempVar; - data += tempVar; - - curByte += tempVar; - if (curByte >= BYTE_PER_READ) - { - curByte = 0; - curSect++; - } - } - - // align to cluster - // tempVar is number of sectors to read - if (remain > (filesysSecPerClus - curSect) * BYTE_PER_READ) - { - tempVar = filesysSecPerClus - curSect; - } else { - tempVar = remain / BYTE_PER_READ; - } - - if ((tempVar > 0) && flagNoError) - { - disc_ReadSectors ( curSect + FAT_ClustToSect(curClus), tempVar, data); - data += tempVar * BYTE_PER_READ; - remain -= tempVar * BYTE_PER_READ; - - curSect += tempVar; - } - - // Move onto next cluster - // It should get to here without reading anything if a cluster is due to be allocated - if (curSect >= filesysSecPerClus) - { - tempNextCluster = FAT_NextCluster(curClus); - if ((remain == 0) && (tempNextCluster == CLUSTER_EOF)) - { - curSect = filesysSecPerClus; - } else { - curSect = 0; - curClus = tempNextCluster; - if (curClus == CLUSTER_FREE) - { - flagNoError = false; - } - } - } - - // Read in whole clusters - while ((remain >= filesysBytePerClus) && flagNoError) - { - disc_ReadSectors (FAT_ClustToSect(curClus), filesysSecPerClus, data); - data += filesysBytePerClus; - remain -= filesysBytePerClus; - - // Advance to next cluster - tempNextCluster = FAT_NextCluster(curClus); - if ((remain == 0) && (tempNextCluster == CLUSTER_EOF)) - { - curSect = filesysSecPerClus; - } else { - curSect = 0; - curClus = tempNextCluster; - if (curClus == CLUSTER_FREE) - { - flagNoError = false; - } - } - } - - // Read remaining sectors - tempVar = remain / BYTE_PER_READ; // Number of sectors left - if ((tempVar > 0) && flagNoError) - { - disc_ReadSectors (FAT_ClustToSect(curClus), tempVar, data); - data += tempVar * BYTE_PER_READ; - remain -= tempVar * BYTE_PER_READ; - curSect += tempVar; - } - - // Last remaining sector - // Check if sector wanted is different to the one started with - if ( ((file->curByte + length) >= BYTE_PER_READ) && flagNoError) - { - disc_ReadSector( curSect + FAT_ClustToSect( curClus), file->readBuffer); - if (remain > 0) - { - memcpy(data, file->readBuffer, remain); - curByte += remain; - remain = 0; - } - } - - // Length read is the wanted length minus the stuff not read - length = length - remain; - - // Update file information - file->curByte = curByte; - file->curSect = curSect; - file->curClus = curClus; - file->curPos = file->curPos + length; - return length; -} - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_fwrite(buffer, size, count, file) -Writes size * count bytes into file from buffer, starting - from current position. It then sets the current position to the - byte after the last byte written. If the file was openned in - append mode it always writes to the end of the file. -const void* buffer IN: Pointer to buffer containing data. Should be - at least as big as the number of bytes to be written. -u32 size IN: size of each item to write -u32 count IN: number of items to write -FAT_FILE* file IN: Handle of an open file -u32 OUT: returns the actual number of bytes written ------------------------------------------------------------------*/ -u32 FAT_fwrite (const void* buffer, u32 size, u32 count, FAT_FILE* file) -{ - int curByte; - int curSect; - u32 curClus; - - u32 tempNextCluster; - int tempVar; - u32 length = size * count; - u32 remain = length; - char* data = (char*)buffer; - - char* writeBuffer; - - bool flagNoError = true; - bool flagAppending = false; - - if ((file == NULL) || (file->inUse == false) || length == 0 || buffer == NULL) - return 0; - - if (file->write) - { - // Write at current read pointer - curByte = file->curByte; - curSect = file->curSect; - curClus = file->curClus; - - // Use read buffer as write buffer - writeBuffer = file->readBuffer; - - // If it is writing past the current end of file, set appending flag - if (length + file->curPos > file->length) - { - flagAppending = true; - } - } - else if (file->append) - { - // Write at end of file - curByte = file->appByte; - curSect = file->appSect; - curClus = file->appClus; - flagAppending = true; - - // Use global buffer as write buffer, don't touch read buffer - writeBuffer = (char*)globalBuffer; - disc_ReadSector(curSect + FAT_ClustToSect(curClus), writeBuffer); - } - else - { - return 0; - } - - // Move onto next cluster if needed - if (curSect >= filesysSecPerClus) - { - curSect = 0; - tempNextCluster = FAT_NextCluster(curClus); - if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE)) - { - // Ran out of clusters so get a new one - curClus = FAT_LinkFreeCluster(curClus); - if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort - { - flagNoError = false; - } - memset(writeBuffer, 0, BYTE_PER_READ); - } else { - curClus = tempNextCluster; - disc_ReadSector( FAT_ClustToSect( curClus), writeBuffer); - } - } - - // Align to sector - tempVar = BYTE_PER_READ - curByte; - if (tempVar > remain) - tempVar = remain; - - if ((tempVar < BYTE_PER_READ) && flagNoError) - { - memcpy(&(writeBuffer[curByte]), data, tempVar); - remain -= tempVar; - data += tempVar; - curByte += tempVar; - - // Write buffer back to disk - disc_WriteSector (curSect + FAT_ClustToSect(curClus), writeBuffer); - - // Move onto next sector - if (curByte >= BYTE_PER_READ) - { - curByte = 0; - curSect++; - } - } - - // Align to cluster - // tempVar is number of sectors to write - if (remain > (filesysSecPerClus - curSect) * BYTE_PER_READ) - { - tempVar = filesysSecPerClus - curSect; - } else { - tempVar = remain / BYTE_PER_READ; - } - - if ((tempVar > 0) && flagNoError) - { - disc_WriteSectors ( curSect + FAT_ClustToSect(curClus), tempVar, data); - data += tempVar * BYTE_PER_READ; - remain -= tempVar * BYTE_PER_READ; - curSect += tempVar; - } - - if (((curSect >= filesysSecPerClus) && flagNoError) && (remain > 0)) - { - curSect = 0; - tempNextCluster = FAT_NextCluster(curClus); - if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE)) - { - // Ran out of clusters so get a new one - curClus = FAT_LinkFreeCluster(curClus); - if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort - { - flagNoError = false; - } - } else { - curClus = tempNextCluster; - } - } - - // Write whole clusters - while ((remain >= filesysBytePerClus) && flagNoError) - { - disc_WriteSectors (FAT_ClustToSect(curClus), filesysSecPerClus, data); - data += filesysBytePerClus; - remain -= filesysBytePerClus; - if (remain > 0) - { - tempNextCluster = FAT_NextCluster(curClus); - if ((tempNextCluster == CLUSTER_EOF) || (tempNextCluster == CLUSTER_FREE)) - { - // Ran out of clusters so get a new one - curClus = FAT_LinkFreeCluster(curClus); - if (curClus == CLUSTER_FREE) // Couldn't get a cluster, so abort - { - flagNoError = false; - break; - } - } else { - curClus = tempNextCluster; - } - } else { - // Allocate a new cluster when next writing the file - curSect = filesysSecPerClus; - } - } - - // Write remaining sectors - tempVar = remain / BYTE_PER_READ; // Number of sectors left - if ((tempVar > 0) && flagNoError) - { - disc_WriteSectors (FAT_ClustToSect(curClus), tempVar, data); - data += tempVar * BYTE_PER_READ; - remain -= tempVar * BYTE_PER_READ; - curSect += tempVar; - } - - // Last remaining sector - // Check if sector wanted is different to the one started with - if ( (( (file->append ? file->appByte : file->curByte) + length) >= BYTE_PER_READ) && flagNoError) - { - if (flagAppending) - { - // Zero sector before using it - memset (writeBuffer, 0, BYTE_PER_READ); - } else { - // Modify existing sector - disc_ReadSector( curSect + FAT_ClustToSect( curClus), writeBuffer); - } - if (remain > 0) { - memcpy(writeBuffer, data, remain); - curByte += remain; - remain = 0; - disc_WriteSector( curSect + FAT_ClustToSect( curClus), writeBuffer); - } - } - - // Amount read is the originally requested amount minus stuff remaining - length = length - remain; - - // Update file information - if (file->write) // Writing also shifts the read pointer - { - file->curByte = curByte; - file->curSect = curSect; - file->curClus = curClus; - file->curPos = file->curPos + length; - if (file->length < file->curPos) - { - file->length = file->curPos; - } - } - else if (file->append) // Appending doesn't affect the read pointer - { - file->appByte = curByte; - file->appSect = curSect; - file->appClus = curClus; - file->length = file->length + length; - } - - return length; -} -#endif - - -/*----------------------------------------------------------------- -FAT_feof(file) -Returns true if the end of file has been reached -FAT_FILE* file IN: Handle of an open file -bool return OUT: true if EOF, false if not ------------------------------------------------------------------*/ -bool FAT_feof(FAT_FILE* file) -{ - if ((file == NULL) || (file->inUse == false)) - return true; // Return eof on invalid files - - return (file->length == file->curPos); -} - - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_remove (path) -Deletes the file or empty directory sepecified in path -const char* path IN: Path of item to delete -int return OUT: zero if successful, non-zero if not ------------------------------------------------------------------*/ -int FAT_remove (const char* path) -{ - DIR_ENT dirEntry; - u32 oldWorkDirCluster; - char checkFilename[13]; - FILE_TYPE checkFiletype; - - dirEntry = FAT_DirEntFromPath (path); - - if (dirEntry.name[0] == FILE_FREE) - { - return -1; - } - - // Only delete directories if the directory is entry - if (dirEntry.attrib & ATTRIB_DIR) - { - // Change to the directory temporarily - oldWorkDirCluster = curWorkDirCluster; - FAT_chdir(path); - - // Search for files or directories, excluding the . and .. entries - checkFiletype = FAT_FindFirstFile (checkFilename); - while ((checkFilename[0] == '.') && (checkFiletype != FT_NONE)) - { - checkFiletype = FAT_FindNextFile (checkFilename); - } - - // Change back to working directory - curWorkDirCluster = oldWorkDirCluster; - - // Check that the directory is empty - if (checkFiletype != FT_NONE) - { - // Directory isn't empty - return -1; - } - } - - // Refresh directory information - dirEntry = FAT_DirEntFromPath (path); - - // Free any clusters used - FAT_ClearLinks (dirEntry.startCluster | (dirEntry.startClusterHigh << 16)); - - // Remove Directory entry - disc_ReadSector ( (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector , globalBuffer); - ((DIR_ENT*)globalBuffer)[wrkDirOffset].name[0] = FILE_FREE; - disc_WriteSector ( (wrkDirCluster == FAT16_ROOT_DIR_CLUSTER ? filesysRootDir : FAT_ClustToSect(wrkDirCluster)) + wrkDirSector , globalBuffer); - - // Flush any sectors in disc cache - disc_CacheFlush(); - - return 0; -} -#endif - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_mkdir (path) -Makes a new directory, so long as no other directory or file has - the same name. -const char* path IN: Path and filename of directory to make -int return OUT: zero if successful, non-zero if not ------------------------------------------------------------------*/ -int FAT_mkdir (const char* path) -{ - u32 newDirCluster; - u32 parentDirCluster; - DIR_ENT dirEntry; - DIR_ENT* entries = (DIR_ENT*)globalBuffer; - int i; - - int pathPos, filePos; - char pathname[MAX_FILENAME_LENGTH]; - u32 oldDirCluster; - - if (FAT_FileExists(path) != FT_NONE) - { - return -1; // File or directory exists with that name - } - - // Find filename within path and change to that directory - oldDirCluster = curWorkDirCluster; - if (path[0] == '/') - { - curWorkDirCluster = filesysRootDirClus; - } - - pathPos = 0; - filePos = 0; - - while (path[pathPos + filePos] != '\0') - { - if (path[pathPos + filePos] == '/') - { - pathname[filePos] = '\0'; - if (FAT_chdir(pathname) == false) - { - curWorkDirCluster = oldDirCluster; - return -1; // Couldn't change directory - } - pathPos += filePos + 1; - filePos = 0; - } - pathname[filePos] = path[pathPos + filePos]; - filePos++; - } - - // Now grab the parent directory's cluster - parentDirCluster = curWorkDirCluster; - curWorkDirCluster = oldDirCluster; - - // Get a new cluster for the file - newDirCluster = FAT_LinkFreeCluster(CLUSTER_FREE); - - if (newDirCluster == CLUSTER_FREE) - { - return -1; // Couldn't get a new cluster for the directory - } - // Fill in directory entry's information - dirEntry.attrib = ATTRIB_DIR; - dirEntry.reserved = 0; - // Time and date set to system time and date - dirEntry.cTime_ms = 0; - dirEntry.cTime = getRTCtoFileTime(); - dirEntry.cDate = getRTCtoFileDate(); - dirEntry.aDate = getRTCtoFileDate(); - dirEntry.mTime = getRTCtoFileTime(); - dirEntry.mDate = getRTCtoFileDate(); - // Store cluster position into the directory entry - dirEntry.startCluster = (newDirCluster & 0xFFFF); - dirEntry.startClusterHigh = ((newDirCluster >> 16) & 0xFFFF); - // The file has no data in it - its over written so should be empty - dirEntry.fileSize = 0; - - if (FAT_AddDirEntry (path, dirEntry) == false) - { - return -1; // Couldn't add the directory entry - } - - // Create the new directory itself - memset(entries, FILE_LAST, BYTE_PER_READ); - - // Create . directory entry - dirEntry.name[0] = '.'; - // Fill name and extension with spaces - for (i = 1; i < 11; i++) - { - dirEntry.name[i] = ' '; - } - - memcpy(entries, &dirEntry, sizeof(dirEntry)); - - // Create .. directory entry - dirEntry.name[1] = '.'; - dirEntry.startCluster = (parentDirCluster & 0xFFFF); - dirEntry.startClusterHigh = ((parentDirCluster >> 16) & 0xFFFF); - - memcpy(&entries[1], &dirEntry, sizeof(dirEntry)); - - // Write entry to disc - disc_WriteSector(FAT_ClustToSect(newDirCluster), entries); - - // Flush any sectors in disc cache - disc_CacheFlush(); - return 0; -} -#endif - -/*----------------------------------------------------------------- -FAT_fgetc (handle) -Gets the next character in the file -FAT_FILE* file IN: Handle of open file -bool return OUT: character if successful, EOF if not ------------------------------------------------------------------*/ -char FAT_fgetc (FAT_FILE* file) -{ - char c; - return (FAT_fread(&c, 1, 1, file) == 1) ? c : EOF; -} - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_fputc (character, handle) -Writes the given character into the file -char c IN: Character to be written -FAT_FILE* file IN: Handle of open file -bool return OUT: character if successful, EOF if not ------------------------------------------------------------------*/ -char FAT_fputc (char c, FAT_FILE* file) -{ - return (FAT_fwrite(&c, 1, 1, file) == 1) ? c : EOF; -} -#endif - -/*----------------------------------------------------------------- -FAT_fgets (char *tgtBuffer, int num, FAT_FILE* file) -Gets a up to num bytes from file, stopping at the first - newline. - -CAUTION: does not do strictly streaming. I.e. it's - reading more then needed bytes and seeking back. - shouldn't matter for random access - -char *tgtBuffer OUT: buffer to write to -int num IN: size of target buffer -FAT_FILE* file IN: Handle of open file -bool return OUT: character if successful, EOF if not - - Written by MightyMax - Modified by Chishm - 2005-11-17 - * Added check for unix style text files - * Removed seek when no newline is found, since it isn't necessary --------------------------------------------------------------------*/ -char *FAT_fgets(char *tgtBuffer, int num, FAT_FILE* file) -{ - u32 curPos; - u32 readLength; - char *returnChar; - - // invalid filehandle - if (file == NULL) - { - return NULL ; - } - - // end of file - if (FAT_feof(file)==true) - { - return NULL ; - } - - // save current position - curPos = FAT_ftell(file); - - // read the full buffer (max string chars is num-1 and one end of string \0 - readLength = FAT_fread(tgtBuffer,1,num-1,file) ; - - // mark least possible end of string - tgtBuffer[readLength] = '\0' ; - - if (readLength==0) { - // return error - return NULL ; - } - - // get position of first return '\r' - returnChar = strchr(tgtBuffer,'\r'); - - // if no return is found, search for a newline - if (returnChar == NULL) - { - returnChar = strchr(tgtBuffer,'\n'); - } - - // Mark the return, if existant, as end of line/string - if (returnChar!=NULL) { - *returnChar++ = 0 ; - if (*returnChar=='\n') { // catch newline too when jumping over the end - // return to location after \r\n (strlen+2) - FAT_fseek(file,curPos+strlen(tgtBuffer)+2,SEEK_SET) ; - return tgtBuffer ; - } else { - // return to location after \r (strlen+1) - FAT_fseek(file,curPos+strlen(tgtBuffer)+1,SEEK_SET) ; - return tgtBuffer ; - } - } - - return tgtBuffer ; -} - -#ifdef CAN_WRITE_TO_DISC -/*----------------------------------------------------------------- -FAT_fputs (const char *string, FAT_FILE* file) -Writes string to file, excluding end of string character -const char *string IN: string to write -FAT_FILE* file IN: Handle of open file -bool return OUT: number of characters written if successful, - EOF if not - - Written by MightyMax - Modified by Chishm - 2005-11-17 - * Uses FAT_FILE instead of int - * writtenBytes is now u32 instead of int --------------------------------------------------------------------*/ -int FAT_fputs (const char *string, FAT_FILE* file) -{ - u32 writtenBytes; - // save string except end of string '\0' - writtenBytes = FAT_fwrite((void *)string, 1, strlen(string), file); - - // check if we had an error - if (writtenBytes != strlen(string)) - { - // return EOF error - return EOF; - } - - // return the charcount written - return writtenBytes ; -} -#endif - - - |