📄 fat.c
字号:
#include <stdlib.h>
#include <string.h>
#include "filesys.h"
#include "fat.h"
#include "fatdef.h"
#if (OS_SUPPORT == 1)
#include "otime.h"
#endif
/********************************************************************************
MACRO DEFINE
********************************************************************************/
#define PATH_LEN_MAX 63
#define FILE_LEN_MAX 12
#define TOP_CLUSTER 2
#define MAX_CLUSTER 0xFFF5
#define END_CLUSTER 0xFFF8 /* 0xFFF8 to 0xFFFF */
#define FREE_CLUSTER 0
#define DELETE_MARK 0xE5
#define TYPE_FAT12 0
#define TYPE_FAT16 1
#define GET_USHORT(x) x
#define GET_ULONG(x) x
#define ushort(x) *(USHORT *)&x
#define ulong(x) *(ULONG *)&x
#define FAT_FILE_MAX 5
#define FAT_DRIVE_MAX 2
#define CFG_DEFAULT_YEAR fatConfig.year
#define CFG_DEFAULT_MONTH fatConfig.month
#define CFG_DEFAULT_DAY fatConfig.day
#define CFG_DEFAULT_HOUR fatConfig.hour
#define CFG_DEFAULT_MINUTE fatConfig.minute
#define CFG_DEFAULT_SECOND fatConfig.second
#define CFG_CACHE_NUM fatConfig.cacheNum
/********************************************************************************
TYPE DEFINE
********************************************************************************/
#pragma pack(1)
typedef struct boot_info {
UCHAR jumpcode[3];
UCHAR name[8];
USHORT bytePerSector;
UCHAR sectorPerClu;
USHORT reservedSector;
UCHAR numFAT;
USHORT rootDirEntry;
USHORT totalSector;
UCHAR mediaDiscriptor;
USHORT sectorPerFAT;
USHORT sectorPerTrack;
USHORT numHead;
USHORT hiddenSector;
ULONG bigTotalSector;
UCHAR driveNum;
UCHAR reserved1;
UCHAR bootSignature;
ULONG serialNum;
UCHAR volumeLabel[11];
UCHAR reserved2[8];
}BOOT_INFO;
typedef struct dir_ent {
UCHAR filename[11];
UCHAR attrib;
UCHAR reserved[10];
USHORT upTime;
USHORT upDate;
USHORT cluster;
ULONG size;
}DIR_ENT;
typedef struct fat_res {
UCHAR use_flag :1;
UCHAR openmode;
UCHAR drive;
USHORT currClu;
UCHAR buffer[SECTOR_SIZE];
ULONG filepos;
ULONG entrySector;
USHORT entryOffset;
DIR_ENT dirEntry;
ULONG topSector;
USHORT secOffset;
}FATFILE_RES;
typedef struct drive_res {
UCHAR ready_flag :1;
USHORT freeClu;
USHORT maxClu;
ULONG totalSector;
UCHAR sectorPerClu;
UCHAR numFAT;
USHORT numRootSector;
USHORT sectorPerFAT;
UCHAR fileType; //FAT12/16
ULONG bootSector;
ULONG fatSector;
ULONG rootSector;
// ULONG dataSector; rootSector+numRootSector
UCHAR currPath[PATH_LEN_MAX+1];
USHORT currClu; //0偺応崌儖乕僩
}FATDRIVE_RES;
typedef struct dir_list {
UCHAR buffer[SECTOR_SIZE];
UCHAR drive;
USHORT cluster;
ULONG topSector;
USHORT secOffset;
USHORT byteOffset;
}DIR_LIST;
/********************************************************************************
VARIABLE DATA DEFINE
********************************************************************************/
#ifdef FILE_DEBUG
#define STATIC
#else
#define STATIC static
#endif /* NET_DEBUG */
STATIC char useTopList;
STATIC UCHAR workBuffer[SECTOR_SIZE];
STATIC UCHAR workPath[PATH_LEN_MAX+1];
STATIC UCHAR fatInit_flag;
STATIC FATDRIVE_RES fatDriveRes[FAT_DRIVE_MAX];
STATIC FATFILE_RES fatFileRes[FAT_FILE_MAX];
STATIC DIR_LIST dirRes;
/********************************************************************************
PROTO TYPE DECLARATION
********************************************************************************/
static int DriveInit(UCHAR driveNum);
static void InitFileRes(void);
static void InitDriveRes(void);
static void InitCache(void);
static ULONG CluToSector(UCHAR driveNum, USHORT cluster);
static int ReadFATEntry(UCHAR driveNum, USHORT cluster, USHORT *value);
static int _ReadFATEntry12(UCHAR driveNum, USHORT cluster, USHORT *value);
static int _ReadFATEntry16(UCHAR driveNum, USHORT cluster, USHORT *value);
static int ReadSector(UCHAR driveNum, ULONG sector, UCHAR *buf);
static int GetBlankCache(void);
static int WriteSector(UCHAR driveNum, ULONG sector, UCHAR *buf);
static int FlushCache(void);
static int WriteFATEntry(UCHAR driveNum, USHORT cluster, USHORT value);
static int _WriteFATEntry12(UCHAR driveNum, USHORT cluster, USHORT value);
static int _WriteFATEntry16(UCHAR driveNum, USHORT cluster, USHORT value);
static int CopyFATSector(UCHAR driveNum, USHORT secOffset, UCHAR *buf);
static int GetTotalFreeClu(UCHAR driveNum, ULONG *freeCnt);
static int _GetTotalFreeClu12(UCHAR driveNum, ULONG *freeCnt);
static int _GetTotalFreeClu16(UCHAR driveNum, ULONG *freeCnt);
static int GetFreeClu(UCHAR driveNum, USHORT *freeClu);
static int _GetFreeClu12(UCHAR driveNum, USHORT *freeClu);
static int _GetFreeClu16(UCHAR driveNum, USHORT *freeClu);
static int AddDirEntry(UCHAR driveNum, USHORT cluster, DIR_ENT *enrty);
static int _AddDirEntry(UCHAR driveNum, USHORT cluster, DIR_ENT *enrty);
static int NextFATEntry(UCHAR driveNum, USHORT cluster, USHORT *next);
static int GetDirEntry(UCHAR driveNum, USHORT cluster, DIR_ENT *entry, ULONG *sector, USHORT *offset);
static int _GetDirEntry(UCHAR driveNum, USHORT cluster, DIR_ENT *entry, ULONG *secNum, USHORT *offset);
static int RelCluster(UCHAR driveNum, USHORT cluster);
static int PathUpper(const UCHAR *path, UCHAR *path2, int len);
static void EntryToName(UCHAR *name, UCHAR *name2);
static int NameToEntry(UCHAR *name, UCHAR *name2);
static int SearchFile(UCHAR driveNum, UCHAR *path, DIR_ENT *entry, ULONG *sector, USHORT *offset, USHORT *clu);
static int SearchPath(UCHAR driveNum, UCHAR *path, USHORT *cluster);
static int ParsePath(UCHAR *path, UCHAR *name, UCHAR **path2);
static int ParseDirFile(UCHAR *path, UCHAR *file);
static int PosToCluster(UCHAR driveNum, ULONG pos, USHORT topClu, USHORT *cluster, USHORT *secOffset);
static int GetNextEntry(DIR_ENT *dirEntry);
static int CheckDirEmpty(UCHAR driveNum, USHORT cluster);
static int _CheckDirEmpty(UCHAR driveNum, USHORT cluster);
static void EntryToInfo(DIR_ENT *entry, FILE_INFO *finfo);
static void ChangePath(UCHAR *path, UCHAR *path2);
static void SetEntryTime(USHORT *date, USHORT *time);
/********************************************************************************
TABLE DATA
********************************************************************************/
/********************************************************************************
GLOBAL FUNCTIONS
********************************************************************************/
/*-----------------------------------------------------------------------------*/
int FATInit(char driveNum)
{
int ret;
if (driveNum >= FAT_DRIVE_MAX || driveNum < -1) {
return E_FILE_DRIVE;
}
if (driveNum == -1) {
fatInit_flag = 0;
return E_FILE_OK;
}
// resource initialize
if (fatInit_flag == 0) {
fatInit_flag = 1;
InitFileRes();
InitDriveRes();
InitCache();
}
ret = DriveInit((UCHAR)driveNum);
return ret;
}
/*-----------------------------------------------------------------------------*/
int FATCreate(UCHAR driveNum, const UCHAR *path)
{
FATDRIVE_RES *drive;
UCHAR filename[FILE_LEN_MAX+1];
DIR_ENT entry;
USHORT newClu, cluster;
int ret;
if (driveNum >= FAT_DRIVE_MAX) {
return E_FILE_DRIVE;
}
drive= &fatDriveRes[driveNum];
if (drive->ready_flag == 0) { /* drive not ready */
return E_FILE_NOT_READY;
}
if (PathUpper(path, workPath, PATH_LEN_MAX) < 0) {
return E_FILE_PATH_LEN;
}
ret = ParseDirFile(workPath, filename);
if (ret < 0) {
return E_FILE_NAME_LEN;
}
if (SearchPath(driveNum, workPath, &cluster) < 0) {
return E_FILE_PATH;
}
if (strcmp((char*)filename, ".") == 0 || strcmp((char*)filename, "..") == 0) {
return E_FILE_NAME;
}
if (NameToEntry(filename, entry.filename) < 0) {
return E_FILE_NAME_LEN;
}
if (GetDirEntry(driveNum, cluster, &entry, NULL, NULL) == 0) {
return E_FILE_EXIST;
}
if (GetFreeClu(driveNum, &newClu) < 0) { /* for new file contents */
return E_FILE_DISK_FULL;
}
entry.attrib = FA_ARCHIVE;
memset(entry.reserved, 0, 10);
SetEntryTime(&(entry.upDate), &(entry.upTime));
entry.cluster = newClu;
entry.size = 0;
if (AddDirEntry(driveNum, cluster, &entry) < 0) {
WriteFATEntry(driveNum, newClu, FREE_CLUSTER); /* release new cluster */
FlushCache();
return E_FILE_DISK_FULL;
}
FlushCache();
return E_FILE_OK;
}
/*-----------------------------------------------------------------------------*/
int FATOpen(UCHAR driveNum, const UCHAR *path, int mode)
{
FATDRIVE_RES *drive;
int i, fd;
FATFILE_RES *file, *file2;
if (!(mode == OPEN_RD || mode == OPEN_WR)) {
return E_FILE_PARAMETER;
}
if (driveNum >= FAT_DRIVE_MAX) {
return E_FILE_DRIVE;
}
drive = &fatDriveRes[driveNum];
if (drive->ready_flag == 0) { /* drive not ready */
return E_FILE_NOT_READY;
}
if (PathUpper(path, workPath, PATH_LEN_MAX) < 0) {
return E_FILE_PATH_LEN;
}
/* Get file resource */
for(fd = 0; fd < FAT_FILE_MAX; fd++) {
file = &fatFileRes[fd];
if (file->use_flag == 0) {
break;
}
}
if (fd == FAT_FILE_MAX) {
return E_FILE_RESOURCE;
}
/* Check path */
if (SearchFile(driveNum, workPath, &(file->dirEntry), &(file->entrySector), &(file->entryOffset), NULL) < 0) {
return E_FILE_PATH;
}
if (!((file->dirEntry.attrib & FA_DIRECTORY) == 0 &&
(file->dirEntry.attrib & FA_VOLUME) == 0))
{
return E_FILE_PATH; /* not file attribution */
}
if (mode == OPEN_WR) {
/* Check attribution */
if ((file->dirEntry.attrib & FA_READ_ONLY) != 0) {
return E_FILE_ATTRIB;
}
/* Check multiple open */
for(i = 0; i < FAT_FILE_MAX; i++) {
file2 = &fatFileRes[i];
if (file2->use_flag == 1 && file2->openmode == OPEN_WR) {
if (file2->drive == driveNum && file2->entrySector == file->entrySector &&
file2->entryOffset == file->entryOffset) {
return E_FILE_LOCKED;
}
}
}
}
file->use_flag = 1;
file->openmode = (UCHAR)mode;
file->drive = driveNum;
file->filepos = 0;
file->currClu = file->dirEntry.cluster;
file->topSector = CluToSector(driveNum, file->currClu);
file->secOffset = 0;
ReadSector(driveNum, file->topSector, file->buffer);
return fd;
}
/*-----------------------------------------------------------------------------*/
int FATClose(int fd)
{
FATFILE_RES *file;
if (fd >= FAT_FILE_MAX) {
return E_FILE_DESCRIPTOR;
}
file = &fatFileRes[fd];
if (file->use_flag == 0) {
return E_FILE_CLOSED;
}
if (file->openmode == OPEN_WR) {
/* Flush */
WriteSector(file->drive, file->topSector+file->secOffset, file->buffer);
/* Update directory entry */
ReadSector(file->drive, file->entrySector, workBuffer);
SetEntryTime(&(file->dirEntry.upDate), &(file->dirEntry.upTime));
*(DIR_ENT*)(workBuffer+file->entryOffset) = file->dirEntry;
WriteSector(file->drive, file->entrySector, workBuffer);
FlushCache();
}
file->use_flag = 0;
return E_FILE_OK;
}
/*-----------------------------------------------------------------------------*/
int FATRead(UCHAR *buf, int len, int fd)
{
FATFILE_RES *file;
ULONG fsize, fpos;
USHORT offset, next;
int readlen;
if (fd >= FAT_FILE_MAX) {
return E_FILE_DESCRIPTOR;
}
file = &fatFileRes[fd];
if (file->use_flag == 0) {
return E_FILE_CLOSED;
}
if (file->openmode != OPEN_RD) {
return E_FILE_MODE;
}
fsize = file->dirEntry.size;
fpos = file->filepos;
offset = (USHORT)(fpos%SECTOR_SIZE);
readlen = 0;
while(len > readlen) {
if (fpos >= fsize) {
break;
}
*buf = file->buffer[offset++];
buf ++;
readlen ++;
fpos ++;
if (offset >= SECTOR_SIZE) {
offset = 0;
file->secOffset ++;
if (file->secOffset >= fatDriveRes[file->drive].sectorPerClu) {
file->secOffset = 0;
if (NextFATEntry(file->drive, file->currClu, &next) <= 0) { /* error or end */
fpos = fsize; /* 僼傽僀儖僒僀僘傛傝僋儔僗僞偑彮側偄応崌偺懳墳乮晄惓僼傽僀儖乯 */
break;
}
file->currClu = next;
file->topSector = CluToSector(file->drive, next);
}
ReadSector(file->drive, file->topSector+file->secOffset, file->buffer);
}
}
file->filepos = fpos;
return readlen;
}
/*-----------------------------------------------------------------------------*/
int FATWrite(const UCHAR *buf, int len, int fd)
{
FATFILE_RES *file;
ULONG fpos;
USHORT offset, next;
int writelen, ret;
if (fd >= FAT_FILE_MAX) {
return E_FILE_DESCRIPTOR;
}
file = &fatFileRes[fd];
if (file->use_flag == 0) {
return E_FILE_CLOSED;
}
if (file->openmode != OPEN_WR) {
return E_FILE_MODE;
}
fpos = file->filepos;
offset = (USHORT)(fpos%SECTOR_SIZE);
writelen = 0;
while(len > writelen) {
file->buffer[offset++] = *buf;
buf ++;
if (offset >= SECTOR_SIZE) {
WriteSector(file->drive, file->topSector+file->secOffset, file->buffer);
offset = 0;
file->secOffset ++;
if (file->secOffset >= fatDriveRes[file->drive].sectorPerClu) {
file->secOffset = 0;
if (GetFreeClu(file->drive, &next) < 0) {
break; /* Disk Full */
}
WriteFATEntry(file->drive, file->currClu, next);
file->currClu = next;
file->topSector = CluToSector(file->drive, next);
}
ReadSector(file->drive, file->topSector+file->secOffset, file->buffer);
}
writelen ++;
fpos ++;
}
file->filepos = fpos;
if (fpos > file->dirEntry.size) { /* Update file size */
file->dirEntry.size = fpos;
}
return writelen;
}
/*-----------------------------------------------------------------------------*/
int FATFlush(int fd)
{
FATFILE_RES *file;
int ret;
if (fd >= FAT_FILE_MAX) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -