📄 fat.c
字号:
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
char return OUT: true if successful.
-----------------------------------------------------------------*/
char 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
unsigned int 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 ( unsigned int dirCluster, int entry, int origin)
{
DIR_ENT dir;
DIR_ENT_LFN lfn;
int firstSector = 0;
char notFound = false;
char found = false;
//int maxSectors;
int lfnPos, aliasPos;
unsigned char 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] = ((unsigned char*)&lfn)[(int)(lfn_offset_table[i])] /* | ((unsigned char*)&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
char return OUT: return true if successful
-----------------------------------------------------------------*/
char 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
char return OUT: return true if successful
-----------------------------------------------------------------*/
char 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
char return OUT: return true if successful
-----------------------------------------------------------------*/
char 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
unsigned int return OUT: the file size
-----------------------------------------------------------------*/
unsigned int 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.
unsigned int return OUT: the file start cluster
-----------------------------------------------------------------*/
unsigned int 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.
unsigned char return OUT: the file's attributes
-----------------------------------------------------------------*/
unsigned char 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
unsigned char attributes IN: The attribute values to assign
unsigned char mask IN: Detemines which attributes are changed
unsigned char return OUT: the file's new attributes
-----------------------------------------------------------------*/
unsigned char FAT_SetFileAttributes (const char* filename, unsigned char attributes, unsigned char 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 (unsigned short fileTime, unsigned short 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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -