⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.c

📁 一个小型的FAT文件系统,支持FAT12/16和目录
💻 C
📖 第 1 页 / 共 5 页
字号:


#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 + -