建立FAT文件系统学习笔记

FAT文件系统的概况图
在这里插入图片描述
1、MBR
进行百度得到,计算机在按下power键以后,开始执行主板bios程序。进行完一系列检测和配置以后。开始按bios中设定的系统引导顺序引导系统。假定现在是硬盘。Bios执行完自己的程序后如何 把执行权交给硬盘呢。交给硬盘后又执行存储在哪里的程序呢。其实,称为mbr的一段代码起着举足轻重的作用。MBR(masterboot record),即主引导记录,有时也称主引导扇区。位于整个硬盘的 0 柱面 0磁头 1 扇区(可以看作是硬盘的第一个扇区),bios在执行自己固有的程序以后就会jump到mbr中的第一条指令。将系统的控制权交由mbr来执行。在总共512byte的主引导记录中,MBR的引导程序占了其中的前 446 个字节(偏移 0H~偏移 1BDH),随后的 64 个字节(偏移 1BEH~偏移 1FDH)为DPT(DiskPartitionTable,硬盘分区表),最后的两个字节“55 AA”(偏移 1FEH~偏移1FFH)是分区有效结束标志。但是如果是裸机的话,前面的446个字节的引导就无所谓了

2、DBR
用于记录分区的一些信息,例如:
在这里插入图片描述
【1】0x00~0x02:3 个字节,跳转指令。
【2】0x03~0x0A:8 个字节,文件系统标志和版本号,这里为 MSDOC5.0。
【3】0x0B~0x0C:2 个字节,每扇区字节数,512(0X02 00)。
【4】0x0D~0x0D:1 个字节,每簇扇区数,8(0x08)。
【5】0x0E~0x0F:2 个字节,保留扇区数,704(0x02 C0)。
【6】0x10~0x10:1 个字节,FAT 表个数,2。
【7】0x11~0x12:2 个字节,根目录最多可容纳的目录项数,FAT12/16 通常为 512。FAT32 不使用此处值,置 0。
【8】0x13~0x14:2 个字节,扇区总数,小于 32MB 时使用该处存放。超过 32MB 时使用偏移 0x20~0x23 字
节处的 4 字节存放。笔者的 SD 卡容量为 2GB,所以不使用该处,置 0.
【9】0x15~0x15:1 个字节,介质描述符,0xF8 表示本地硬盘。
【10】0x16~0x17:2 个字节,每个 FAT 表的大小扇区数(FAT12/16 使用,FAT32 不使用此处,置 0)。
【11】0x18~0x19:2 个字节,每磁道扇区数,63(0x00 3F)。
【12】0x1A~0x1B:2 个字节磁头数,255(0x00 FF)。
【13】0x1C~0x1F:4 个字节,分区前已使用扇区数,137(0x00 00 00 89)
【14】0x20~0x23:4 个字节,文件系统大小扇区数,3841911(0x 00 3A 9F 77)。
【15】0x24~0x27:4 个字节,每个 FAT 表的大小扇区数,3744(0x 00 00 0E A0)。
【16】0x28~0x29:2 个字节,标记。
【17】0x2A~0x2B:2 个字节,版本号。
【18】0x2C~0x2F:4 个字节,根目录簇号,2。(虽然在 FAT32 文件系统下,根目录可以存放在数据区的任
何位置,但是通常情况下还是起始于 2 号簇)
【19】0x30~0x31:2 个字节,FSINFO(文件系统信息扇区)扇区号,1。(上图的标注即用黄色条纹的标注
有误,请读者注意)该扇区为操作系统提供关于空簇总数及下一可用簇的信息。
【20】0x32~0x33:2 个字节,备份引导扇区的位置,6。(上图的标注即用黄色条纹的标注有误,请读者注
意)备份引导扇区总是位于文件系统的 6 号扇区。
【21】0x34~0x3F:12 个字节,未使用。
【22】0x40~0x40:1 个字节,BIOS INT 13H 设备号,0x80。(这个我也不知道什么意思☺)
【23】0x41~0x41:1 个字节,未用。
【24】0x42~0x42:1 个字节,扩展引导标志。0x29。
【25】0x43~0x46:1 个字节,卷序列号。通常为一个随机值。
【26】0x47~0x51:11 个字节,卷标(ASCII 码),如果建立文件系统的时候指定了卷标,会保存在此。笔
者当时没有指定卷表,上图中的 YCY 是后来指定的。
【27】0x52~0x59:8 个字节,文件系统格式的 ASCII 码,FAT32。
【28】0x5A~0x1FD:410 个字节,未使用。该部分没有明确的用途。
【29】0x1FE~0x1FF:签名标志“55 AA”。

static U8 BPB_Data [BytesPerSector]={
				0xeb,0x3c,0x90,//偏移0:相当于JUMP 0X3C 语句,表明系统引导代码在0X3C+2=0X3F处,在FAT32时要改为EB5890
				'L','F','A','T','V','1','.','0',///偏移3:厂家代码
				LOWBYTE(BytesPerSector),HIGHBYTE(BytesPerSector),	//偏移11: 每个扇区的大小,这里为512个字节,
				SectorPerClus,//偏移13,                              
				LOWBYTE(RSD_Sector),HIGHBYTE(RSD_Sector),//偏移14
				FAT_NUM,//偏移16
				LOWBYTE(Directory_Number),HIGHBYTE(Directory_Number),//偏移17
				0,0,//偏移19:小扇区才用,大于16位的扇区数不用LOWBYTE(Total_Sector),HIGHBYTE(Total_Sector),
				0xf8,
				0,0,//偏移22:LOWBYTE(Fat_Sector_Num),HIGHBYTE(Fat_Sector_Num),//偏移每个FAT表占的字节数,对于FAT32为0

				0x00,0x00,// 偏移24:每个磁道扇区数
				0x00,0x00,//偏移24:磁头数
				0x01,0x00,0x00,0x00,//偏移28:FAT表前的隐藏扇区数,一般不使用
				LOWBYTE(Total_Sector),HIGHBYTE(Total_Sector),HIGH_LOWBYTE(Total_Sector),HIGH_HIGHBYTE(Total_Sector),//0x00,0x00,0x00,0x00,// 偏移32:大扇区总扇区数,FAT32为非零//This field is the new 32-bit total count of sectors on the  //
				//对于FAT32,下面4个字节为FAT扇区数										
				LOWBYTE(Fat_Sector_Num),//0x00,//偏移:36	驱动器号,软盘为0
				HIGHBYTE(Fat_Sector_Num),//0x00,//偏移:37	保留
				HIGH_LOWBYTE(Fat_Sector_Num),//0x29,//偏移:38	扩展引导记录0X29,指示后三项可用
				HIGH_HIGHBYTE(Fat_Sector_Num),//'N',
				LOWBYTE(Fat_BeginClust),HIGHBYTE(Fat_BeginClust),HIGH_LOWBYTE(Fat_BeginClust),HIGH_HIGHBYTE(Fat_BeginClust),//偏移:40	FAT32的扩展标志和文件系统版本,这里用作FAT起始簇号
				LOWBYTE(Fat_BeginClust1),HIGHBYTE(Fat_BeginClust1),HIGH_LOWBYTE(Fat_BeginClust1),HIGH_HIGHBYTE(Fat_BeginClust1),//偏移:44	
				LOWBYTE(Directory_BeginClust),HIGHBYTE(Directory_BeginClust),HIGH_LOWBYTE(Directory_BeginClust),HIGH_HIGHBYTE(Directory_BeginClust),//偏移:48	在FAT32中用于根目录起始簇号一般固为2,这里借用它,但是是浮动的
				LOWBYTE(Directory_BeginClust1),HIGHBYTE(Directory_BeginClust1),HIGH_LOWBYTE(Directory_BeginClust1),HIGH_HIGHBYTE(Directory_BeginClust1),//偏移:52	在FAT32中用于根目录起始簇号一般固为2,这里借用它,但是是浮动的
				'J','F','A','T','1','6',//偏移:56	FAT12,FAT16,FAT32标志
				//Executable Code//引导代码
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	

				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,	
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,
				//DPT硬盘分区表
				0x00,//0X1BE//active partion
				0x00,//head
				0x00,//partion begin
				0x00,//cylinder
				0x06,//is partion used//分区类型标志,FAT16=0X06
				0x00,//end head
				0x00,//partion end 
				0x00,//end cylinder
				0x00,0x00,0x00,0x00,
				0x00,0x80,0x00,0x00,//fist partion//扇区总数

				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,//second partion
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,//third partion
				0,0,0,0,0,		0,0,0,0,0,		0,0,0,0,0,		0,//forth partion

				0x55,0xAA	// Offset_U16_Signature		510	//0x55AA           

				}

3、FAT表:
这个表是用来对簇的管理,标志磁盘上的簇号是否已经是用过的了。并具有指向下一个簇号的功能
我们现在来尝试读取起始于 3 号簇的文件:
第一步:由该文件的目录项中得知它的第一簇存储在 3 号簇,到 3 号簇读取它的内容后,查看 3 号 FAT 表
项。
第二步:3 号表项内的表项值为 4,即存储文件的下一个簇为 4 号簇,读取 4 号簇中的内容,查看 4 号簇对
应的 4 号 FAT 表项。
第三步:4 号表项内的表项值为 5,即存储文件的下一个簇为 5 号簇,读取 5 号簇中的内容,查看 5 号簇对
应的 5 号 FAT 表项。
第四步:5 号表项内的表项值为 6,即存储文件的下一个簇为 6 号簇,读取 6 号簇中的内容,查看 6 号簇对
应的 6 号 FAT 表项。
第五步:6 号表项内的表项值为 7,即存储文件的下一个簇为 7 号簇,读取 7 号簇中的内容,查看 7 号簇对
应的 7 号 FAT 表项。
第六步:7 号表项内的表项值为 8,即存储文件的下一个簇为 8 号簇,读取 8 号簇中的内容,查看 8 号簇对
应的 8 号 FAT 表项。
第七步:8 号表项内的表项值为 9,即存储文件的下一个簇为 9 号簇,读取 9 号簇中的内容,查看 9 号簇对
应的 9 号 FAT 表项。
第八步:这时发现 9 号 FAT 表项中的值已是结束标志:0x0FFFFFFF,说明 9 号簇已经是最后一簇了。
也就是说每个表象都是存储下一簇的功能。

__align(4) static unsigned char FileSystemFAT[Fat_Sector_Num*BytesPerSector]={0,};//存储系统FAT16表


接下来研究FAT代码的实现

//根文件名的定义
typedef struct _FileRoot{
	char filename[11];	//0-10
	char Attribute;		//11		Attribute
	char pad[10];			//12-21
	U16 time;			//22,23	MSB??
	U16 date;			//24,25	MSB??
	U16 cluster;			//26,27	first cluster	LSB//文件起始簇号
	U32 filelength;		//28-31	file length 		LSB//文件大小
}FileRoot,*PFileRoot;//根目录结构表
__align(4) static FileRoot FileSystemRoot[FILEROOT_MAX_BUFFER];//根目录缓冲区

1、格式化程序

DBR分区如下:
typedef struct _DiskPart_t{
unsigned int TotalCluster;//(19-20)/(13)
unsigned int  BootSector;//启动扇区号为0
unsigned int  RsdSector;// 14-15//保留扇区数RSD_Sector 1
unsigned int  SectorofFatSize;每个分区表占用的扇区数2
unsigned int  TotalCapacity;//(19-20)*(11*12)分区上数据区的字节数
unsigned int  RootEntry;//17-18//根目录项数Directory_Number 0X3B0=944
unsigned int  SecPerClus;//13//每簇扇区数64
unsigned int  TotalSector;//19-20//当前分区的数据扇区总数Total_sector 系统:12224;用户:16320
unsigned int  BytesPerSec;//11-12//每个扇区的大小BytesPerSector,这里为512个字节,
unsigned int Begin_Cluster;//当前分区起始簇
unsigned int Fat_BeginCluster;//FAT起始簇
unsigned int Fat_BeginCluster1;//FAT起始簇
unsigned int Directory_BeginCluster;//根目录起始簇
unsigned int Directory_BeginCluster1;//根目录起始簇
//		数据起始扇区64					0+1+(2*2)+(944*32+511)/512=64	
} DiskPart_t;


static int Format_Fat(void)
{	
	int i=0;
	int startsecoff=0;//起始扇区偏移预定位置
	__align(4) 	DISK_ENTRY  parttion;
	//-----------------建立分区表-----------------
	while(Erase_Cluster(Begin_Clust+i)==FALSE) 
	i++;                   //试擦除当前分区的起始块,直到找到好块为止
	startsecoff=i;
	parttion.start_block=Begin_Clust+i;//找到第一个好块作为当前区的起始扇区
	DiskPart.Begin_Cluster=parttion.start_block;
	i++;
	parttion.boot_flag=0X804C594A;
	parttion.partition_start_sect=0;//记录好上面的当前块信息
	Fdisk_Fun(FATPART, &parttion);//设立分区表,将其写入NANDFLASH,建立MBR
	memset(FileSystemFAT,0,Fat_Sector_Num*BytesPerSector);//初始化FAF文件表
	memset(FileSystemRoot,0,sizeof(FileSystemRoot));
		//FAT表应该从第一个簇算起,第一个被启动扇区占领
	FileSystemFAT[0] = 0xf8;    //FAT12表以"F8 FF FF " 开头,此3字节为介质描述单元,并不参与FAT表簇链关系
	FileSystemFAT[1] = 0xff;
	//----------------建立FAT---------------------
	//找到可用块作为第一个FAT表,每个FAT表一个块
	while(Erase_Cluster(Begin_Clust+i)==FALSE) //查找一个好块
	{	i++;
		if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) )
		{
			Uart_Printf("\ndisk is bad!");
			return FALSE;
		}
	}
	//之所以减去startsecoff是因为前面建立的DBR不属于FAT表管理
	FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据
	FileSystemFAT[(i-startsecoff)*2+1]=0xff;
	DiskPart.Fat_BeginCluster=Begin_Clust+i;//FAT表起始地址
	//写FAT起始簇
	writedword(&BPB_Data[40],Begin_Clust+i); //将FAT起始信息写入DBR
	i++;	
	//找到可用块作为第二个FAT表,每个FAT表一个块
	while(Erase_Cluster(Begin_Clust+i)==FALSE)
	{	i++;
		if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) )
		{
			Uart_Printf("\ndisk is bad!");
			return FALSE;
		}
	}
	FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据
	FileSystemFAT[(i-startsecoff)*2+1]=0xff;
	DiskPart.Fat_BeginCluster1=Begin_Clust+i;//FAT1表起始地址
	//写FAT起始簇
	writedword(&BPB_Data[44],Begin_Clust+i);
	i++;	

	//找到连续的二个块作为根目录,每个FAT表一个块
	while(Erase_Cluster(Begin_Clust+i)==FALSE)
	{	i++;
		if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) )
		{
			Uart_Printf("\ndisk is bad!");
			return FALSE;
		}
	}
	FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据
	FileSystemFAT[(i-startsecoff)*2+1]=0xff;
	FileSystemFAT[FAT_TABLE_SIZE]=0xa5;
	DiskPart.Directory_BeginCluster=Begin_Clust+i;//目录的起始地址
	//写根目录起始簇
	writedword(&BPB_Data[48],Begin_Clust+i);
	i++;	
	while(Erase_Cluster(Begin_Clust+i)==FALSE)
	{	i++;
		if(i>=(Disk_Size/(SectorPerClus*BytesPerSector)) )
		{
			Uart_Printf("\ndisk is bad!");
			return FALSE;
		}
	}
	FileSystemFAT[(i-startsecoff)*2]=0xff;//标示此簇已经占据
	FileSystemFAT[(i-startsecoff)*2+1]=0xff;
	DiskPart.Directory_BeginCluster1=Begin_Clust+i; //目录的起始地址
	Uart_Printf("\nFormat_Fat5");
	//写根目录起始簇
	writedword(&BPB_Data[52],Begin_Clust+i);
	i++;	
	WriteMBR2Flash();                                 //写启动扇区写到第一块第个分区的启动扇区,完成了MBR写入

	CreatFAT16();                                     //写FAT表	
	CreatDirectoryEntry();                            //创建3B0目录项//3B个根目录扇区
	Init_FAT_Info(FALSE);                             //不进行自动格式化

	Uart_Printf ("\nFormat Finished!");

	return TRUE;
}

以上是将FAT的信息将其写入了nandflash

2、程序启动进行的初始化

static int Init_FAT_Info(int AutoFormat)
{
	int i;
	INT8U err;
	DISK_MBR *pMbr;
	__align(4) unsigned char databuff[BytesPerSector]; 
///
//读引导扇区
	if(IsFdisk(databuff)!=TRUE)//判断是否要格式化 //读出MBR的数据
		goto nofat;
	pMbr=(DISK_MBR *)databuff; 
	memcpy(&mrb_data,databuff,512);
	DiskPart.Begin_Cluster=pMbr->partition_entry[FATPART].start_block;//得到起始块
	if(pMbr->partition_entry[FATPART].boot_flag!=0x804c594a)//看分区表是格式化
		goto nofat;
	memcpy(&mrb_data.partition_entry[FATPART],&databuff[0x1bc]+FATPART*sizeof(DISK_ENTRY),sizeof(DISK_ENTRY));
	ReadPage(pMbr->partition_entry[FATPART].start_block,pMbr->partition_entry[FATPART].partition_start_sect,databuff);//读出DBR
	if(databuff[0]!=0xeb||databuff[1]!=0x3c||databuff[2]!=0x90||
		databuff[3]!='L'||databuff[4]!='F'||databuff[5]!='A'||databuff[6]!='T'||databuff[7]!='V'||databuff[8]!='1'||databuff[9]!='.'||databuff[10]!='0'){	//分区表错误
		Uart_Printf("File Partition Error!\n");
		goto nofat;
	}
	goto fat;
nofat://分区表错需要格式化
		if (AutoFormat==1)	//自动格式化
			return Format_Fat();
		else
			return FALSE;
fat:
	DiskPart.BootSector=0;
	///
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
	
	
	//得到保留扇区数,总扇区数,总扇区数/每簇扇区数得到簇数,是FAT类型的依据
	ReadPage(DiskPart.Begin_Cluster,DiskPart.BootSector,databuff);//读一个扇区
	DiskPart.RsdSector=databuff[14]+databuff[15]*256;//保留扇数为1
	DiskPart.SecPerClus=databuff[13];//每簇扇区数

	DiskPart.BytesPerSec=databuff[12]*256+databuff[11];//每个扇区大小
	//使用FAT32的一些功能
	//DiskPart.TotalSector=databuff[20]*256+databuff[19];//总扇区数
	DiskPart.TotalSector=(databuff[32]+databuff[33]*256+databuff[34]*256*256+databuff[35]*256*256*256);
	
	DiskPart.TotalCapacity=DiskPart.TotalSector*DiskPart.BytesPerSec;//总字节数
	DiskPart.TotalCluster=DiskPart.TotalSector/DiskPart.SecPerClus;//FAT16的簇总数=扇区总数/每簇扇区数
	//使用FAT32的一些功能
	//DiskPart.SectorofFatSize=((databuff[22]+databuff[23]*256));//FAT扇区数
	DiskPart.SectorofFatSize=(databuff[36]+databuff[37]*256+databuff[38]*256*256+databuff[39]*256*256*256);

	DiskPart.RootEntry=(databuff[18]*256+databuff[17]);

	//加FAT和根目录起始簇
	DiskPart.Fat_BeginCluster=(databuff[40]+databuff[41]*256+databuff[42]*256*256+databuff[43]*256*256*256);
	DiskPart.Fat_BeginCluster1=(databuff[44]+databuff[45]*256+databuff[46]*256*256+databuff[47]*256*256*256);
	DiskPart.Directory_BeginCluster=(databuff[48]+databuff[49]*256+databuff[50]*256*256+databuff[51]*256*256*256);
	DiskPart.Directory_BeginCluster1=(databuff[52]+databuff[53]*256+databuff[54]*256*256+databuff[55]*256*256*256);

	FAT_TYPE=FAT16;//FAT12;

	ReadFAT2Mem();//读取FAT分区表到内存的缓冲区中
	ReadFileRoot2Mem();//读取根目录表到缓冲区中
	return TRUE;
}

3、打开文件

static CNCFILE* OpenOSFile(char filename[], U32 OpenMode)
{

	int i=0,j=0,s=0;
	U32 Pre_Cluster;                                            //当前文件读写的到的簇号
	__align(4) unsigned char databuff[BytesPerSector];
	unsigned int CurrentCluster,CurrentSector;
	unsigned int nFileLength;                                   //文件剩余长度
	unsigned int k;
	unsigned int SecNumOfClus;                                 //当前簇已读写扇区数

	CNCFILE* pfile;
	INT8U err;
	char filename1[12]={0};
	int emptyrootpos=-1;                                           //记录空根目录处

	FormatFileName(filename1,filename);                   //格式化文件名称,filename1中为11位文件名

	for(j=0; j<DiskPart.RootEntry;j++){	                          //每个扇区有多个目录项
		if( (FileSystemRoot[j].filename[0]==0 || FileSystemRoot[j].filename[0]==OSFILE_DELETEMARK) && emptyrootpos==-1)//如果找到第一个空根目录
			emptyrootpos=j;	                               //记录空根目录处
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&文件名存在的情况&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
		if(!MemcmpNoUpper(filename1, FileSystemRoot[j].filename,11)){	//如果找到某项符合条件寻找文件
		//	Lcd_Printf("\nFile %s found!",filename1);
			//Uart_Printf("\nFile %s have been found!NEW",filename1);//JING TEST
			pfile=(CNCFILE*)OSMemGet(pFileMem,&err);//分配一个内存块,用于存文件缓冲区
			if(pfile==NULL) return NULL;    //验证是否分配到文件指针
			pfile->fileCluster=FileSystemRoot[j].cluster;
			pfile->filesize=nFileLength=FileSystemRoot[j].filelength;
			pfile->filebufnum=0;
			pfile->fileCurpos=0;//当前文件读写的偏移
			pfile->filemode=OpenMode;
			pfile->rootpos=j;

			switch(OpenMode){
				//&&&&&&&&&&&&&&&&&&&&&&&
				//只读模式,只读一个扇区,指针指向开始,簇指针指向下一个簇
			case FILEMODE_READ:
				while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)){
					CurrentSector=(pfile->fileCluster)*DiskPart.SecPerClus;
					for(SecNumOfClus=0;(SecNumOfClus<DiskPart.SecPerClus)&&(pfile->filesize>pfile->filebufnum);//(当前簇已读取的扇区数到当前簇最后一个扇区)&&(当前读入的长读已经到达文件长度)
									SecNumOfClus++)//读一个簇
						{//读完文件,如果大于一簇,则先读一簇
						//DiskPart.Begin_Cluster 文件系统的起始块
						ReadPage(DiskPart.Begin_Cluster+(CurrentSector+SecNumOfClus)/SectorPerClus,(CurrentSector+SecNumOfClus)%SectorPerClus,databuff);//读取当前簇的当前扇区SecNumOfClus的数据到扇区数据缓冲区中databuff
						if(nFileLength>BytesPerSector) memcpy(pfile->Buffer+pfile->filebufnum, databuff,BytesPerSector);//文件剩余长度nFileLength是否大于一扇区
						else memcpy(pfile->Buffer+pfile->filebufnum, databuff,nFileLength);
						nFileLength-=BytesPerSector;
						pfile->filebufnum+=BytesPerSector;//当前已经读入的字节数
						}
									
					if(pfile->filebufnum>=Block_Size) //当前文件缓冲区是否已经读满
						{//读到1个簇后即中止缓冲区满
						pfile->filebufnum=0;//缓冲区指针重新指向开头			
						break;//缓冲区慢时中止
						}
					//根据当前的块号去查找下一个的FAT地址
 					else pfile->fileCluster=NextCluster(pfile->fileCluster);//如果缓冲区没满则继续读下一个簇,??????????
				}
				//Uart_Printf("\nFile %s have been read!\n",filename1);
				pfile->filebufnum=0;//缓冲区指针重新指向开头			
			break;
			//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
			//只写模式:文件大小为0
			case FILEMODE_WRITE:
			//无等待取得的邮箱,当取不到写文件邮箱时,直接出错
			 if(!OSMboxAccept(pFileMbox))  
                    {
                        OSMemPut(pFileMem, pfile);
						pfile=(CNCFILE *)0;
						return NULL;
                    }
				pfile->filesize=0;
			//这里删除原来的簇链,重新分配一个簇给当前文件
			//将之前的簇全部进行删除
				DeleteFATList(pfile->fileCluster);
				pfile->fileCluster=AllocateCluster(0);//查找一个新簇
				FileSystemRoot[pfile->rootpos].cluster=pfile->fileCluster;
				FileSystemRoot[pfile->rootpos].filelength=0;
				memset(pfile->Buffer, sizeof(pfile->Buffer), 0xff);
			break;
/**修改内容:增加对pfile 指针的安全释放--修改人: caigh--日期:----------------*/
            default:         
               if(pfile!=NULL) OSMemPut(pFileMem, pfile);
				return NULL;	//可能是创建模式,不能重名???????
		}
/**修改内容:在调试时增加对文件结构的保存--修改人: caigh--日期:-----  -*/
#ifdef __debugfile__
                    for(j=0;j<10;j++)    //查找未使用的结构;
                    	{   if(TFileStr[j].useflags==0)  
                    	     {  OSSchedLock();
				  TFileStr[j].useflags=1;
				  OSSchedUnlock();
				   memcpy(TFileStr[j].filename, filename1, 11);
				   TFileStr[j].filemode=pfile->filemode;
				    TFileStr[j].PFile=pfile;
				    //Uart_Printf("\nFile %s have been opennow! The File ID is %d\n->",TFileStr[j].filename,pfile);

                    	          break;
                    	      }
                    	}
			if(j<10)
#endif
			return pfile;	//找到文件
		}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
	}//

//&&&&&&&&&&&&&&&&&&&&&&&&&文件未找到,是创建文件目录表到缓冲区中&&&&&&&&&&&&&&&&&&&
	if(OpenMode== (FILEMODE_WRITE|FILEMODE_CREATE) ){	//创建文件
		//如果没有找到同名文件则创建文件,
		//创建的时候先建立root目录的数据,在最后,Close的时候
		//把数据写入root,所以,创建文件以后如果掉电,因为
		//没有Close,所以,文件对root目录没有影响。----by threewater
	//	Lcd_Printf("\nCreating CNCFILE %s !\n->",filename1);
		//Uart_Printf("\nCreating CNCFILE %s !\n->",filename1);//JING TEST
		pfile=(CNCFILE*)OSMemGet(pFileMem,&err);

		if(pfile) {
			 //Uart_Printf("\nfile ok");
			//无等待取得的邮箱,当取不到写文件邮箱时,直接出错//by zb
			 if(!OSMboxAccept(pFileMbox))  
                    {
                        OSMemPut(pFileMem, pfile);
						pfile=(CNCFILE *)0;
						return NULL;
                    }
            //---------------------------------------------------
			pfile->fileCluster=AllocateCluster(0);//自动寻找下一个空的簇,如入口为零,则返回第一个可用簇
		//	Lcd_Printf("\nThe new cluster is %d\n->",pfile->fileCluster);
		//	Uart_Printf("\nThe new cluster is %d\n->",pfile->fileCluster);//JING TEST
			pfile->filebufnum=0;
			pfile->fileCurpos=0;
			pfile->filemode=OpenMode;
		}else{
			Uart_Printf("\nfile NO ok");
			return NULL;
		}
			
		if(pfile->fileCluster){
				//接下来在刚才找到的空根目录处创建文件项
/**-------------------------------------------------------------------------------------------------------
**修改内容:增加对没有空簇的判断
**修改人: caigh
** 日 期: 
**------------------------------------------------------------------------------------------------------*/				
				if(emptyrootpos==-1){//目录不够
				     if(pfile!=NULL) OSMemPut(pFileMem, pfile);
					 Uart_Printf("\nDirectory is full!");
					 OSMboxPost(pFileMbox, (void *)1);
			            return NULL;
				}
/**-----------------------------------------------------------------------------*/
/**-----------------------------------------------------------------------------*/
				//建立根目录到缓冲区
				//这里好像有点问题,没判断emptyrootpos是否为-1
				memcpy(FileSystemRoot[emptyrootpos].filename, filename1, 11);
				FileSystemRoot[emptyrootpos].Attribute=0x20;//Attribute
				FileSystemRoot[emptyrootpos].time=0x1612;//Create time
				FileSystemRoot[emptyrootpos].date=0x2ea2;//Create date
				FileSystemRoot[emptyrootpos].cluster=pfile->fileCluster;
				FileSystemRoot[emptyrootpos].filelength=0;
				pfile->filesize=0;
				pfile->rootpos=emptyrootpos;

			//	Uart_Printf("\nCreat CNCFILE %s Succeed!",filename1);
/**修改内容:在调试时增加对文件结构的保存--修改人: caigh--日期:-----  -*/
#ifdef __debugfile__
                    for(j=0;j<10;j++)    //查找未使用的结构;
                    	{   if(TFileStr[j].useflags==0)  
                    	     {  OSSchedLock();
								TFileStr[j].useflags=1;
								OSSchedUnlock();
								memcpy(TFileStr[j].filename, filename1, 11);
								TFileStr[j].filemode=pfile->filemode;
								TFileStr[j].PFile=pfile;
                    	        break;
                    	      }
                    	}
			if(j<10)
#endif
				return pfile;
		}
		else{//磁盘满?????????
                        if(pfile!=NULL) OSMemPut(pFileMem, pfile);
			    Uart_Printf("Disk is Full!!\n");
				OSMboxPost(pFileMbox, (void *)1);
				return NULL;
		}
	}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
	//没找到文件
	Uart_Printf("\nFile %s is not found!\n->",filename1);
	return NULL;
}

读文件

static U32 ReadOSFile(CNCFILE* pfile ,U8* ReadBuffer, U32 nReadbyte)

{
	U32 i,CurrentSector,SecNumOfClus,Current_Cluster;//,nFileLength;
	__align(4) unsigned char databuff[BytesPerSector];
	if(pfile->filemode!=FILEMODE_READ)   //非只读模式则退出
		return 0;
	
	for(i=0;i<nReadbyte;i++){
		if(pfile->filesize<=pfile->fileCurpos)
			return i;
		(*ReadBuffer)=pfile->Buffer[(pfile->fileCurpos++)%Block_Size];//
		ReadBuffer++;
		pfile->filebufnum++;//文件当前缓冲区的读写位置
		
		if(pfile->filebufnum==Block_Size){//如果到了缓冲区末尾,那就重新读取下一个缓冲区
			pfile->filebufnum=0;		
			pfile->fileCluster=Current_Cluster=NextCluster(pfile->fileCluster);  //查找下一个文件的簇
			while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)){
					CurrentSector=(pfile->fileCluster)*DiskPart.SecPerClus;
					for(SecNumOfClus=0;(SecNumOfClus<DiskPart.SecPerClus)&&(pfile->filesize>pfile->filebufnum);//(当前簇已读取的扇区数到当前簇最后一个扇区)&&(当前读入的长读已经到达文件长度)
									SecNumOfClus++)//读一个簇
						{//读完文件,如果大于一簇,则先读一簇
						ReadPage(DiskPart.Begin_Cluster+(CurrentSector+SecNumOfClus)/SectorPerClus,(CurrentSector+SecNumOfClus)%SectorPerClus,databuff);//读取当前簇的当前扇区SecNumOfClus的数据到扇区数据缓冲区中databuff
						memcpy(pfile->Buffer+pfile->filebufnum, databuff,BytesPerSector);//文件剩余长度nFileLength是否大于一扇区
						pfile->filebufnum+=BytesPerSector;//当前已经读入的字节数
						}
									
					if(pfile->filebufnum>=Block_Size) //???当前文件缓冲区是否已经读满
						{//读到1个簇后即中止缓冲区满
						pfile->filebufnum=0;//缓冲区指针重新指向开头			
						break;//缓冲区慢时中止
						}
 					else pfile->fileCluster=NextCluster(pfile->fileCluster);//如果缓冲区没满则继续读下一个簇,??????????
				}
				//Uart_Printf("\nFile %s have been read!\n",filename1);
				pfile->filebufnum=0;//缓冲区指针重新指向开头
		}
		
	}
	return i;
}

写操作,也是先写入缓冲区,找过缓冲区之后就写入磁盘中

static U8 WriteOSFile(CNCFILE* pfile, U8* WriteBuffer, U32 nWritebyte)
{
	int i=0,j=0;
	U32 Pre_Cluster,Current_Cluster;
//	if((pfile->filemode&0xf) !=FILEMODE_WRITE)
//		return FALSE;
    if(pfile->fileCluster==0) return FALSE;
	Current_Cluster=pfile->fileCluster;
	for(i=0;i<nWritebyte;i++){
		pfile->Buffer[(pfile->fileCurpos++)%(SectorPerClus*BytesPerSector)]=*WriteBuffer;
		WriteBuffer++;
		pfile->filebufnum++;
	
		if(pfile->filebufnum>=(SectorPerClus*BytesPerSector)){	//超过一个簇大小
			//Erase_FileCluster(Current_Cluster);//擦除一个簇,这里不用擦除了,因为在自动分配时已经擦除
			if(WriteBlock(DiskPart.Begin_Cluster+Current_Cluster,&pfile->Buffer[0])==FALSE)//将当前簇写入FLASH中
				Uart_Printf("writepage erro!\n");//如果出现这个,则要加自动分配下一簇的代码
			pfile->filebufnum=0;
			
			Pre_Cluster=pfile->fileCluster;
			pfile->fileCluster=Current_Cluster=NextCluster(pfile->fileCluster);
			if(((pfile->fileCluster&0xffff)==0xffff)||(pfile->fileCluster==0xffffffff))
				pfile->fileCluster=Current_Cluster=AllocateCluster(Pre_Cluster);   //查找下一个可用簇,并链接

			//没有簇可分配了
			if(pfile->fileCluster==0){//
				pfile->filesize+=i;	
				Uart_Printf("disk is full!\n");
				return FALSE;
			}
		}
	}
	pfile->filesize+=nWritebyte;	//by threewater
	return TRUE;
}

定位文件:

1、将输入的偏移量/缓冲量,看看有几个缓冲量
2、找到对应的块缓冲
3、再讲偏移量%缓冲量求余即可
static U32 SeekOSFile(CNCFILE* pfile ,U32 nCurPos)
{
	U32 i,CurrentSector,SecNumOfClus,Pre_Cluster;
//	if(pfile->filemode!=FILEMODE_READ)
//		return 0;
    u32 n;
    __align(4) unsigned char databuff[BytesPerSector];
	if(nCurPos>=pfile->filesize)//文件大小越界
		return pfile->fileCurpos;
  
	n=nCurPos/Block_Size;//(SectorPerClus*BytesPerSector);这里对齐块的边界,因为一个块有可能是几个簇
	n=n*(Block_Size/(SectorPerClus*BytesPerSector));//算出簇的定位,对齐块边界
	pfile->fileCluster=FileSystemRoot[pfile->rootpos].cluster;
	Pre_Cluster=pfile->fileCluster;
    
	while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)&&(n>0))
	{   
	  //  Uart_Printf("->%d",pfile->fileCluster);
	    Pre_Cluster=pfile->fileCluster;
        pfile->fileCluster=NextCluster(pfile->fileCluster);
        n--;
       }
	if((pfile->fileCluster==0xffff)||(pfile->fileCluster==0xffffffff)) pfile->fileCluster=Pre_Cluster;
	CurrentSector=pfile->fileCluster*DiskPart.SecPerClus;
	pfile->filebufnum=0;
	while((pfile->fileCluster!=0xffff)&&(pfile->fileCluster!=0xffffffff)){
		CurrentSector=(pfile->fileCluster)*DiskPart.SecPerClus;
		for(SecNumOfClus=0;(SecNumOfClus<DiskPart.SecPerClus)&&(pfile->filesize>pfile->filebufnum);//(当前簇已读取的扇区数到当前簇最后一个扇区)&&(当前读入的长读已经到达文件长度)
									SecNumOfClus++)//读一个簇
		{//读完文件,如果大于一簇,则先读一簇
			ReadPage(DiskPart.Begin_Cluster+(CurrentSector+SecNumOfClus)/SectorPerClus,(CurrentSector+SecNumOfClus)%SectorPerClus,databuff);//读取当前簇的当前扇区SecNumOfClus的数据到扇区数据缓冲区中databuff
			memcpy(pfile->Buffer+pfile->filebufnum, databuff,BytesPerSector);//文件剩余长度nFileLength是否大于一扇区
				pfile->filebufnum+=BytesPerSector;//当前已经读入的字节数
		}
		if(pfile->filebufnum>=Block_Size) //???当前文件缓冲区是否已经读满
		{//读到1个簇后即中止缓冲区满
			pfile->filebufnum=0;//缓冲区指针重新指向开头			
			break;//缓冲区慢时中止
		}
 			else pfile->fileCluster=NextCluster(pfile->fileCluster);//如果缓冲区没满则继续读下一个簇,??????????
	}
    pfile->filebufnum=(nCurPos%Block_Size);//对齐块的边界//(DiskPart.SecPerClus*512));
	pfile->fileCurpos=nCurPos;
	return nCurPos;
}

关闭文件
如果是写方式的话,那就将其写入nandflsh中,并更新FAT表
其他方式的话回收内存就可以了

static int CloseOSFile(CNCFILE* pfile)
{
    int j,i;
    U32 Current_Cluster;
   int syear, smonth,sdate, shour, smin, ssec;

    if(pfile==NULL) return FALSE;
    switch(pfile->filemode&0xf){
    case FILEMODE_WRITE:
        if(pfile->fileCluster==0)
	    {
	         FileSystemRoot[pfile->rootpos].filename[0]=OSFILE_DELETEMARK;//删除目录
	         DeleteFATList(FileSystemRoot[pfile->rootpos].cluster);//删除文件的链表
	         OSMboxPost(pFileMbox, (void *)1);
	         break;
	    }
        Current_Cluster=pfile->fileCluster;
        if(Current_Cluster!=0)
        //Erase_FileCluster(Current_Cluster);//不用擦除当前簇,因为已经分配时擦除过
       {	 if(WriteBlock(DiskPart.Begin_Cluster+Current_Cluster,&pfile->Buffer[0])==FALSE)
				Uart_Printf("writepage erro!\n");
        //写入root表
        	FileSystemRoot[pfile->rootpos].filelength=pfile->filesize;
          		GetRtcTime(&syear, &smonth, &sdate, &shour, &smin, &ssec);
        	FileSystemRoot[pfile->rootpos].time=RtcTimeToFileTime(shour,smin,ssec);//Create time
        	FileSystemRoot[pfile->rootpos].date=RtcDateToFileDate(syear-1980,smonth,sdate);//Create date
			WriteFATFromMem();// 将FAT写入FLASH中
        	WriteFileRootFromMem();//将根目录写入FALSH中
		}else{
			DeleteFATList(FileSystemRoot[pfile->rootpos].cluster);
			FileSystemRoot[pfile->rootpos].filename[0]=OSFILE_DELETEMARK;
		}
        //释放写文件邮箱//
        OSMboxPost(pFileMbox, (void *)1);
        //-------------------------------------------
        break;
    default:
        break;
    }
    
/**修改内容:在调试时增加对文件结构的保存--修改人: caigh--日期:-----  -*/
#ifdef __debugfile__
                    for(j=0;j<10;j++)    //查找未使用的结构;
                    {   if(TFileStr[j].useflags==1)
                         if(TFileStr[j].PFile==pfile)  
                         {  OSSchedLock();
                 TFileStr[j].useflags=0;
                OSSchedUnlock();
                   //Uart_Printf("\nFile %s have been CLOSEED!now The File ID is %d\n->",TFileStr[j].filename,pfile);
                            break;
                            }
                        }
#endif
    OSMemPut(pFileMem, pfile);
    //<--------add by threewater

    return TRUE;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值