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

📄 stdwrap.c

📁 包装了一个开源的FAT16文件系统
💻 C
字号:
//file: stdwrap.c
//功能:stdio的接口包装,包括了以下常用函数:
//		FILE*	->	CXFILE*
//		fopen	->	cx_fopen,目前只支持rb, wb, wb+, rb+
//		fread	->	cx_fread
//		fwrite	->	cx_fwrite
//		fseek	->	cx_fseek
//		ftell	->	cx_ftell
//		feof	->	cx_feof
//		fclose	->	cx_fclose
//	上述函数的使用方法同C语言标准库的用法一致
//  使用时,要先调用StdioWrapperStartup()来初始化本封皮,而在使用完设备后要使用StdioWrapperCleanup()来做清理工作
//  注意:一定不要忘记在用完后调用StdioWrapperCleanup(),否则当BlkMdd启用cache,会有脏数据滞留在cache中未写回
//  这有可能导致优盘或SD卡上的数据崩溃!(我就曾因此弄丢了一块优盘上的数据)
//  本封皮会使用BlkMdd的功能进行读写,
//  与fat16.c交互时,花了很多时间在于弄清楚各指针参数的使用方法,最主要的就是指针所指的内存是由谁来负责分配及回收
//  因为其说明文档都没有说明,幸好对于指针的IN或是OUT还是谈到了
//  我对于读写速度做了测试。我的物理设备是用CH375驱动的朗科1GB优盘
//  读取速度约220KB/s。我嫌慢,就曾经写过一个ch375模块的测试函数,这个函数连续读取10000扇区的内容,约5MB,速度250KB/s
//  写入速度只有22KB/s左右。我也类似地做了测试,对1000个扇区调用CH375的扇区写函数做扇区写操作,大约38KB/s
//  后来我翻出一个很早的(4年前)的优盘,写速度只有9KB/s
//  我觉得ch375不应这么慢。我用的平台是AT91SAM7S128, 48MHz主频,I/O模拟的8位总线。可能是我模拟的不太好
//  后来我关掉了I/O统计功能,并且把一些小函数的调用在主调函数中就地展开,大约提高了24%左右的写入速度

//  使用这个文件系统,一定要打开BlkMdd的cache支持。有条件的最好配上2个cache,对于需要写入的场合尤其重要
//  另外,如果要对物理设备上的两个文件同时读写,比如像copy命令干的这种事,一定要配上3个cache,否则命中率只有60%左右
//  按照这种要求配置好cache,如果一次写入32个字节的话,cache命中率通常可高达96.5%

//注:这个文件系统有一个缺陷,就是对长文件名支持的不到位。如果长文件名/目录名是纯英文的,它和windows都能正常读取
//  如果长文件/目录名带中文,则依然能正常读取,但是在windows下会显示乱码
//  而且不能正确识别windows的中文长目录名


//#include <stdio.h>
#include <string.h>
#include "fsdefs.h"
#include "fat16.h"
#include "partition.h"
#include "partition_config.h"
#include "blkmdd.h"
#include "stdwrap.h"

BOOL BlkMdd_Flush(void);

static struct partition_struct* sg_pPart;
struct fat16_fs_struct* sg_fs;
struct fat16_dir_struct* sg_dd;

static DS_StdWrapCB sg_swcb;
static BOOL sg_isFsInited=FALSE;

BOOL StdioWrapperStartup(void)
{
	IFAV i;
	if ( sg_isFsInited) return TRUE;
	if(!BlkMdd_Startup())
	{
		return FALSE;
	}	
	sg_pPart = partition_open(BlkMdd_read,
		BlkMdd_read_interval,
		BlkMdd_write,
		BlkMdd_write_interval,
		0
		);

	if(!sg_pPart)
	{
		/* If the partition did not open, assume the storage device
		* is a "superfloppy", i.e. has no MBR.
		*/
		sg_pPart = partition_open(BlkMdd_read,
			BlkMdd_read_interval,
			BlkMdd_write,
			BlkMdd_write_interval,
			(int8_t) -1
			);
		if(!sg_pPart)
		{
			return FALSE;
		}
	}

	/* open file system */
	sg_fs = fat16_open(sg_pPart);
	if(!sg_fs)
	{
		BlkMdd_Cleanup();
		return FALSE;
	}

	for (i=0;i<CFG_MaxFile;i++)
	{
		sg_swcb.fileAry[i].flags=0;
	}

	sg_isFsInited=TRUE;
	
	return TRUE;
}	

void StdWrap_FormatPath(char *psz)
{
	if (psz[1]==':' && psz[2]=='\\')
	{
		psz+=2;	//忽略前面的"x:"
	}
	//把所有的"\"整理为"/"
	while (*psz)
	{
		if (*psz=='\\')
		{
			*psz='/';
		}
		if ( *psz>='a' && *psz<='z')
		{
			*psz-=0x20;	//小写转大写
		}
		psz++;
	}
}

//pFat16Ent: OUT。如果找到指定的文件,则被填充为在FAT16分配表中的入口内容,删除文件时需要此内容
//
BOOL StdWrap_FindFileInDir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* OUT pFat16Ent)
{
	while(fat16_read_dir(dd, pFat16Ent))
	{
		if(strcmp(pFat16Ent->long_name, name) == 0)
		{
			fat16_reset_dir(dd);
			return TRUE;
		}
	}
	return FALSE;
}

//返回值:文件名的第一个字符在整个路径字符串中的位置
U32 StdWrap_GetFileNameFromPath(char *pOriPath, char** IN ppPath)
{
	I32 len;
	len=(U32) strlen(pOriPath);
	if (!len) return CON_MaxU32;
	while(--len)
	{
		if (pOriPath[len]=='/')
		{
			break;
		}
	}
	if (len==0)
	{
		if (pOriPath[0]=='/')
		{
			++len;
			*ppPath= pOriPath+len;
		}
	}
	else
	{
		++len;
		*ppPath= pOriPath+len;
	}
	//如果len==0,则直接给出了文件名
	return (U32) len;
}

CXFILE* StdWrap_AllocCXFILE(void)
{
	IFAV i;
	CXFILE *fp;
	for ( i=0; i<CFG_MaxFile ; i++ )
	{
		if ( sg_swcb.fileAry[i].flags & FPFLAG_Inuse )
		{
			continue;
		}
		break;
	}
	if (i>=CFG_MaxFile)
	{
		return NULL;
	}
	fp= sg_swcb.fileAry+i;
	fp->flags|= FPFLAG_Inuse;
	fp->pdd=sg_dd;
	fp->pfs=sg_fs;
	return fp;
}
BOOL StdWrap_FreeCXFILE(CXFILE *fp)
{
	if (fp)
	{
		fp->flags=0;
	}	
	return TRUE;
}

//文件路径必须是绝对路径,根目录名字是"/"或者是"\", 但不应同时出现
//举例: 
CXFILE* cx_fopen(const char *pszOriFilePath, const char *pszIODesc)
{
	CXFILE *fp;
	BOOL isToCreateFile=FALSE;
	UFAV fileNameIdx;
	struct fat16_dir_struct *pDir;
	struct fat16_dir_entry_struct dirEnt, fileEnt;
	char szFilePath[64], *pszFileName, *pszPathName;
	char szRoot[]="/";
	strcpy(szFilePath, pszOriFilePath);
	StdWrap_FormatPath(szFilePath);	
	fileNameIdx= StdWrap_GetFileNameFromPath(szFilePath, &pszFileName);
	//删除分开目录与文件之间的"/"
	if (fileNameIdx==0)
	{
		//必须以"/"开头,因为只支持绝对路径
		return NULL;
	}
	if (fileNameIdx>1)
	{
		szFilePath[fileNameIdx-1]=0;
		pszPathName=szFilePath;
	}
	else
	{
		//在根目录下创建文件
		pszPathName=szRoot;
	}

	
	//打开目录
	if ( !fat16_get_dir_entry_of_path(sg_fs,pszPathName, &dirEnt) )
	{
		return NULL;
	}
	pDir=fat16_open_dir(sg_fs, &dirEnt);
	if (NULL==pDir)
	{
		return NULL;
	}
	fp= StdWrap_AllocCXFILE();
	if (NULL==fp)
	{
		fat16_close_dir(pDir);
		return NULL;
	}
	fp->pdd=pDir;
	fp->pfs=sg_fs;
	

	
	if (pszIODesc[0]=='r' && pszIODesc[1]=='b' && pszIODesc[2]=='0')
	{
		fp->flags|= FPFLAG_Rd;
		isToCreateFile=FALSE;
	}
	else if (pszIODesc[0]=='r' && pszIODesc[1]=='b' && pszIODesc[2]=='+')
	{
		fp->flags|= FPFLAG_Rd | FPFLAG_Wr;
		isToCreateFile=FALSE;
	}
	else if (pszIODesc[0]=='w' && pszIODesc[1]=='b')
	{
		if (StdWrap_FindFileInDir(sg_fs,pDir,pszFileName, &fileEnt))
		{
			if (fileEnt.attributes & FAT16_ATTRIB_DIR)
			{
				goto cx_fopen_Cleanup;	//该文件其实是个目录,不允许
			}
			if (!fat16_delete_file(sg_fs, &fileEnt))
			{
				goto cx_fopen_Cleanup;
			}
		}
		fp->flags|= FPFLAG_Wr;
		if (pszIODesc[2]=='+')
		{
			fp->flags|= FPFLAG_Rd;
		}
		isToCreateFile=TRUE;
	}
	if (pszIODesc[1]=='b' || pszIODesc[2]=='b')
	{
		fp->flags|= FPFLAG_Bin;
	}

	if (isToCreateFile)
	{
		if (!fat16_create_file(fp->pdd, pszFileName, &fileEnt))
		{
			goto cx_fopen_Cleanup;
		}
		fp->pfd=fat16_open_file(sg_fs,&fileEnt);
		if (!fp->pfd)
		{
			goto cx_fopen_Cleanup;
		}
	}
	else
	{
		if (!StdWrap_FindFileInDir(sg_fs,pDir,pszFileName,&fileEnt))
		{
			goto cx_fopen_Cleanup;
		}
		fp->pfd=fat16_open_file(sg_fs,&fileEnt);
		if (!fp->pfd)
		{
			goto cx_fopen_Cleanup;
		}
	}
	return fp;		
cx_fopen_Cleanup:
	fat16_close_dir(pDir);
	StdWrap_FreeCXFILE(fp);
	return NULL;
}

//返回值:0成功,-1失败
int cx_fclose(CXFILE* fp)
{
	if (!fp) return -1;
	if (!fp->pfd) return -1;
	fat16_close_file(fp->pfd);
	fat16_close_dir(fp->pdd);
	fp->flags=0;
	BlkMdd_Flush();
	return 0;
}

int cx_fseek(CXFILE* fp, long newPos, int rel)
{
	long offset;
	if (!fp) return -1;
	offset=newPos;
	if (rel==SEEK_SET)
	{
		return fat16_seek_file(fp->pfd,&offset,FAT16_SEEK_SET);
	}
	else if (rel==SEEK_CUR)
	{
		return fat16_seek_file(fp->pfd,&offset,FAT16_SEEK_CUR);
	}
	else if (rel==SEEK_END)
	{
		return fat16_seek_file(fp->pfd,&offset,FAT16_SEEK_END);
	}
	return -1;
}

size_t cx_fread(void *pvBuf, size_t unitSize, size_t unitCnt, CXFILE *fp)
{
	if (!fp) return (size_t) CON_MaxU32;
	return (size_t) fat16_read_file(fp->pfd,pvBuf,(U16) (unitCnt*unitSize));
}

size_t cx_fwrite(const void *pvBuf, size_t unitSize, size_t unitCnt, CXFILE *fp)
{
	if (!fp) return (size_t) CON_MaxU32;
	return (size_t) fat16_write_file(fp->pfd,pvBuf,(U16) (unitCnt*unitSize));
}

long cx_ftell(CXFILE *fp)
{
	if (!fp) return -1;
	return fp->pfd->pos;
}

int cx_feof(CXFILE *fp)
{
	if (!fp) return 0;
	if ( fp->pfd->pos== fp->pfd->dir_entry.file_size)
	{
		return 1;
	}
	return 0;
}

extern U8* tab8x8Icons;

BOOL StdWrap_Test(char *pPath)
{
	CXFILE *cfp, *cfp2;
	U8 buf[32];
	U32 fLen;
	U32 unitLen;
	fLen=128*1024;
	unitLen=32;
	cfp=cx_fopen(pPath,"rb");
	if (!cfp) return FALSE;
	cfp2=cx_fopen("/testout.txt","wb+");	
	if (!cfp2)
	{
		cx_fclose(cfp);
		return FALSE;
	}
	
	cx_fseek(cfp,0, SEEK_END);
	fLen=cx_ftell(cfp);
	cx_fseek(cfp,0, SEEK_SET);
	while (fLen)
	{
		if (fLen>unitLen)
		{
			cx_fread(buf,1,unitLen,cfp);
			//cx_fwrite(buf,1,unitLen,cfp2);
			fLen-=unitLen;
		}
		else
		{
			cx_fread(buf,1,fLen,cfp);
			//cx_fwrite(buf,1,fLen,cfp2);
			fLen=0;
		}
	}
	cx_fclose(cfp);
	cx_fclose(cfp2);
	return TRUE;
}

BOOL StdWrap_TestWR(char *pPath)
{
	CXFILE *cfp;
	U8 *p= (U8 *) 0x00200000;
	U32 fLen;
	U32 unitLen;
	fLen=256*1024;
	unitLen=64;
	cfp=cx_fopen(pPath,"wb");
	while (fLen)
	{
		if (fLen>unitLen)
		{
			cx_fwrite(p,1,unitLen,cfp);
			fLen-=unitLen;
			p+=unitLen;
			if (p>=(U8 *) 0x00203f00)
			{
				p=(U8 *) 0x00200000;
			}
		}
		else
		{
			cx_fwrite(p,1,fLen,cfp);
			fLen=0;
		}
	}
	
	cx_fclose(cfp);
	//CXFILE *cfp;
	//FILE *fp;
	//long fLen;
	//char testBuf[128];
	//sg_fs=fs;	

	//fp=fopen("testOri.jpg","rb");
	//fseek(fp,0,SEEK_END);
	//fLen=ftell(fp);
	//fseek(fp,0,SEEK_SET);
	//
	//cfp=cx_fopen(pPath, "wb+");
	//if (!cfp) return FALSE;
	//while (fLen)
	//{
	//	if (fLen>128)
	//	{
	//		fread(testBuf,1,128,fp);
	//		cx_fwrite(testBuf,1,128,cfp);
	//		fLen-=128;
	//	}
	//	else
	//	{
	//		fread(testBuf,1,fLen,fp);
	//		cx_fwrite(testBuf,1,fLen,cfp);
	//		fLen=0;
	//	}
	//}

	//cx_fclose(cfp);
	//fclose(fp);

	//fp=fopen("testDst.jpg","wb");
	//cfp=cx_fopen(pPath, "rb+");

	//cx_fseek(cfp,0,SEEK_END);
	//fLen=cx_ftell(cfp);
	//cx_fseek(cfp,0,SEEK_SET);

	//while (fLen)
	//{
	//	if (fLen>128)
	//	{
	//		cx_fread(testBuf,1,128,cfp);
	//		fwrite(testBuf,1,128,fp);
	//		fLen-=128;
	//	}
	//	else
	//	{
	//		cx_fread(testBuf,1,fLen,cfp);
	//		fwrite(testBuf,1,fLen,fp);
	//		fLen=0;
	//	}
	//}
	//fclose(fp);
	//cx_fclose(cfp);

	return TRUE;
}

BOOL StdioWrapperCleanup(void)
{
	if (!sg_isFsInited)	return TRUE;
	/* close file system */
	fat16_close(sg_fs);
	/* close partition */
	partition_close(sg_pPart);
	BlkMdd_Cleanup();
	return TRUE;	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -