OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 19020|回复: 17

嵌入式FAT16/32文件系统大揭秘

[复制链接]

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
77
金钱
77
注册时间
2011-11-18
在线时间
3 小时
发表于 2011-11-18 14:56:20 | 显示全部楼层 |阅读模式
 这个是本人写的一个文件系统,它的功能比较全,如支持FAT16,FAT32,支持长文件名,支持子目录,支持中文,支持文件的读取,写入,创建,删除,等许多有用的功能!
最初这个文件系统是为深圳的一个公司开发的,后来索性把这个文件系统公布出来,供更多的人学习,使用,研究!以期它能够得到大家的认可,得到大家的赞予!
下面是这个文件系统的说明书,供大家学习和了解这个文件系统的功能,使用。我还可以提供它的免费的FAT16源代码,你可以用于学习,用于项目上,都没有限制的,
如果你需要源代码,就与我联系吧,我的联系方式是e-mail:tony_yang123@sina.com.cn,qq:292942278.欢迎啦

嵌入式FAT16/32文件系统

1.         总则fficeffice" />

本文件系统兼容FAT16/FAT32文件系统格式,兼容长文件名,兼容GB2312/UNICODE汉字编码(支持中文),并且实现了对子目录的支持,实现了文件的读取,写入,创建,删除等文件系统的常用功能。另外,代码都使用C编写,可以移植到各种单片机平台上来实现文件系统模块。

 

2.         文件系统字符串规则

1)        盘符规则

a)         盘符规则,盘符的命名C开始到Z结束

2)        文件名规则(长文件名不超过255字节)

a)         文件名由文件和扩展名组成, 1)短文件名不超过8个字节,长文件名不超过255字节 2)扩展名一般为3个字节

b)        文件名英文字母、数字和下划线的组合

c)         文件名首字符不能为数字

d)        文件名字符不区分大小写

 

3.         文件系统功能列举

1)        文件系统实现了兼容FAT16/FAT32兼容长文件名,兼容GB2312/UNICODE汉字编码,并且实现了对子目录的支持,实现了文件的读取,写入,创建,删除等文件系统的常用功能

2)        代码都使用C编写,可以移植到单片机上运行。在单片机上运行程序员需要把虚拟磁盘驱动替换为SD卡或磁盘驱动。

3)        实现了文件读写的缓冲内存:文件缓冲内存越大,读写文件越快,其大小可以编译宏EnableFileBufTotalFileBUFsQTYeachFCBFileBUFSize设置(fat_cfg.h

 

4.         程序源文件说明

1)        fat.c—文件系统的源代码

2)        fat.h—文件系统API函数的declare文件

3)        Fat_cfg.h—文件系统配置文件

4)        Types.h—文件系统的数据类型替换定义

5)        Flash_management.c—虚拟磁盘的驱动

6)        Time.c—RTC时钟驱动,提供文件的存储,创建,修改时间

 

5.         文件系统的数据结构(仅供参考,实际的情况可参考文件系统配置文件fat_cfg.h)

1)        分区数据结构支持FAT16/FAT32

   struct partition_BPB{

   char partition_id; //C开始到Z结束

   char system_id; //分区类型  ffice:smarttags" />0C-FAT32,06-FAT16 ect..

   long relative_sector; //分区起始扇区号

   long total_sector;   //分区总扇区数

   int bytes_per_sector;//每扇区字节数

   char sector_per_cluster; //每簇扇区数

   int reserved sector;  //保留扇区数

   char numbers_of_FAT;//FAT副本数

   int boot_entries;//根目录项数,供FAT12/16使用

   int small_sector; //小扇区簇

   char media_descriptor; //媒体描述符

   int sectors_per_FAT; //FAT扇区数,供FAT12/16使用

   int sectors_per_track; //每道扇区数

   int number_of_head; //磁头数

   long hidden_sectors; //隐藏扇区数

   long large_sector;//总扇区数,包含FAT32总扇区数

   long sector_per_FAT32;//FAT扇区数,供FAT32使用

   int extended flag;// 扩展标志,供FAT32使用

   int file_system_version; //文件系统版本

   long root_cluster_number;//根目录簇号

   int file_system_information_sectornumber; //文件系统信息扇区号

   int copy_of_boot_sector;//备份引导扇区

       char reserved[12];//保留,,供FAT32使用

       };

2)        文件数据结构支持FAT16/FAT32

   struct file_{

   char filename[256];//支持长文件名

   char file_extention[3]; //文件扩展名

   char file_attribute;//属性

   char reserved;

   char create_time_10ms;//创建时间的10毫秒位

   int file_created_time;//文件创建时间

   int file_created_date;//文件创建日期

   int last_access_date;//文件最后访问日期

   int first_cluster_number_high2bytes; //文件首簇号高16

   int recent_modified_time;//文件最近修改时间

   int recent_modified_data;//文件最近修改日期

   int first_cluster_number_low2bytes; //文件首簇号低16

   long file_length;//文件长度

3)        Core数据结构

   struct core_{

   current_folder[256];//存放当前目录

   char file_openned_flag;//标记struct file_已打开

   }

 

6.         文件API函数

1)        自动格式化FAT16函数FAT16_filesystem_autoformat()—该函数在U盘启动时运行,它首先会读取Flash 0扇区的MBR,判断MBR有效标记0x55aa,如果MBR有效标记不是0x55aa,该函数将把Flash自动格式化成FAT16文件系统;起用自动格式化处理,Flash上原有的数据将被迫丢失,因此从安全的角度考虑,建议慎用本函数。

 

2)        FAT文件系统初始化函数char FAT_filesystem_initialiation()—该函数是在U盘启动时调用Flash中默认的第一个分区的信息读入struct partition_BPB中,和初始化struct CORE

 

3)        文件建立函数u8 create_file(u8 * filename)—该函数用于在文件系统中建立一个文件,文件名及其路径通过形参char *filename来指定

 

4)        目录建立函数u8 create_floder(u8 * foldername)—该函数用于在文件系统建立一个目录,目录名通过形参char *foldername来指定

 

5)        文件重命名函数u8 rename_file(u8 * oldfilename,u8 * newfilename)—该函数用于文件系统中的一个文件重命名,原文件名由参数u8 * oldfilename来指定,新文件名由参数u8 * newfilename来指定

 

6)        文件打开函数u8 open_file(u8 * filename)—该函数用于在文件系统中的打开一个文件,文件名通过参数u8 * filename来指定,如果打开文件成功,返回为当前文件操作句柄FCBsn(FCB sequential number),或0xff—文件打开错误,在错误打开的情况下,建议先使用close_file关闭一个打开的文件后再打开文件。

 

7)        文件关闭函数u8 close_file(u8 FCBsn)—函数调用关闭一个已打开的文件,并释放当前文件占用的文件操作句柄,文件操作句柄FCBsn指定。

 

8)        当前目录改变函数u8 cd_folder(u8 * foldername,u8 mode)—该函数用于改变文件系统的当前目录,改变至目录由参数u8 * foldername来指定。函数有两种的操作模式分别为1)参数mode= 0:为进入目录;2)参考mode=1为返回上层目录。

 

9)        文件读写位置设定函数u8 f_seek(u8 FCBsn, s32 offset, u8 origin)—该函数用于文件读写当前位置的设定;FCBsn –是已打开文件的文件柄offset--相对origin位置偏移量;origin 指定位置移动的参考起始参考位置共有三个 SEEK_SET(0) 文件的开始位置 SEEK_CUR(1) 文件的当前位置SEEK_END(2) 文件的结束位置。

 

10)     文件读函数u16 read_file(u8 FCBsn,8* buffer, u16 length)—该函数完成已打开文件的当前位置读取指定的长度数据,读取的数据存缓冲区buffer中,读取数据长度由参数u16 length来指定,缓冲区首地址由参数u8 * buffer来指定,该函数返回成功读取的字节数;

 

11)     文件写函数u16 write_file(u8 FCBsn,u8* buffer, u16 length)- 该函数实现将缓冲区buffer中指定长度的数据写入一个已打开文件的当前位置,,写数据长度由参数u16 length指定,缓冲区首地址由参数char* buffer指定,该函数的返回值为成功写入的字节数;

 

12)     遍历目录函数u8 folder_enumeration(u8 *return_string,u8 mode,u8 *ATTR)—该函数用于遍历当前目录下所有的文件项和目录项,调用一次将返回一个文件项或目录项,同时定义有二种遍历模式,mode(0)-调用后将复位到目录的第一个文件项或目录项重新开始,mode(1)-继续上一遍历后的目录项,遍历模式由参数char mode传递,遍历返回的文件项或目录名存储于缓冲区中,其首地址由参数u8 *return_string指定,返回文件目录的类型由u8 *ATTR传递,其值为返回文件或目录directory entryattribute字段;

 

 

13)     遍历DISK函数u8 disk_enumeration(u8 disk_,u8 *return_string,u8 mode,u8* ATTR)—该函数可以用于遍历指定DISK下所有的文件与目录,一次调用返回一个文件项或目录项,同时定义有二种遍历模式,mode(0)-调用后将复位到目录的第一个文件项或目录项重新开始,mode(1)-继续上一遍历后的目录项,被枚举磁盘IDID编号由0开始,到Maximum_Disks – 1)由参数u8 disk_来指定遍历模式由参数char mode来指定遍历返回的文件项或目录名存储于缓冲区中,其首地址由参数u8 *return_string指定,返回文件目录的类型由u8 *ATTR传递,其值为返回文件或目录directory entryattribute字段;

 

14)     文件删除函数-- u8 delete_file(u8 *filename)—该函数用于删除文件系统中的一个文件,删除文件名通过参数char *filename指定。

 

15)     目录删除函数-- u8 delete_folder(u8 * foldername)—该函数用于删除文件系统中的一个目录,删除目录名通过参数u8 *foldername指定,被删除目录必须是空目录;

 

16)     文件查找函数—u8 find_file(u8 * filename,u8 mode, u8* folder_name )—文件查找函数支持2种模式:1mode = 0:当前目录下查找;2mode=1:在整个磁盘中查找;查找文件名通过参数char * filename来指定,查找模式通过参数u8 mode来指定,查找成功后文件加上其所在的目录的完整路径名字符串通过参数folder_name返回。

 

17)     查询分区容量和剩余容量函数—u8 volume_inquiry(u8  partition_id,u32 *volume_capacity, u32 *volume_free_space);—该函数用于查询指定分区的分区容量与剩余空间,分区通过参数u8 partition_id来指定,查询的结果分区容量将存入在参数u32 *volume_capacity中,查询的结果剩余容量将存入在参数u32 *volume_free_space

 

 

1.         例程

1) 使用volume_inquiry(),查看分区容量和分区剩余容量

volume_inquiry('c',&cc,&bb);

  printf("Volume C Capacity: %ld\n",cc);

  printf("Volume C FreeSpace: %ld\n",bb);

 

2) 在当前目录{C:\\}下建立一个目录:CREATE_FOLDER_TEST

 create_floder("CREATE_FOLDER_TEST");

 

3) 目录CREATE_FOLDER_TEST下建立一个文件:created_file.txt

create_file("C:\\CREATE_FOLDER_TEST\\created_file.txt"); 

 

4) 进入目录d:\\CREATE_FOLDER_TEST,并遍历目录d:\\CREATE_FOLDER_TEST的所有文件

  cd_folder("d:\\CREATE_FOLDER_TEST",0);

  mode = 0;

  while(folder_enumeration(buf,mode,&ATTR) == SUCC)

  {

     printf("\nreaded entry=%s Attr = %x",buf,ATTR);

     mode = 1;

  }

 

5) 返回根目录,并遍历根目录的所有文件

  cd_folder(" ",1);

  mode = 0;

  while(folder_enumeration(buf,mode,&ATTR) == SUCC)

  {

     printf("\nreaded entry=%s Attr = %x",buf,ATTR);

     mode = 1;

  }

 

6) /* DISK0  拷贝至DISK1 */

  mode = 0;  //设置disk_enumeration列举mode(0)-复位至第一个文件项或目录项开始枚举

  while(disk_enumeration(0,buf,mode,&ATTR) == SUCC)       //枚举一个目录项或目录项

  {

     printf("\nreaded entry=%s Attr = %x",buf,ATTR);  //打印被枚举的一个目录项或目录项

      

     if(mode == 0)

          mode = 1;//设置disk_enumeration列举mode(1)- 继续上一枚举后的目录项或目录项

        if(ATTR & ATTR_DIRECTORY)

        {

          buf[0]++;                                          //盘符由C1,成为D

          create_floder(buf);                            //建一个disk_enumeration的目录

          continue;

        }

        else                                                            //复制文件

     { HANDLE1 = open_file(buf);                                      //打开文件

          buf[0]++;                                          //盘符由C1,成为D

          create_file(buf);                                    //DISK1上建立文件,

        }

       if (HANDLE1 != FAIL)

       {HANDLE2 = open_file(buf);                          //打开DISK1上建立的文件

         do{                                                            //复制文件

           cc = read_file(HANDLE1,buf+400,50000);                            //读文件

              printf("\nreaded chars = %ld ",cc);                   //打印读文件读取的字节数

        write_file(HANDLE2,buf+400,cc);          //将读取的字节写去DISK1上的文件

              if(cc != 50000)                            //检查读取的字节数,确认文件尾

              {

               close_file(HANDLE1);                           //文件复制结束,关闭文件

               close_file(HANDLE2);

              break;  

              }

         }while(1);

       }

    else

       {

         printf("Openfile failed!");

       }

  }

       {

         printf("Openfile failed!");

       }

  }

 


 

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
77
金钱
77
注册时间
2011-11-18
在线时间
3 小时
 楼主| 发表于 2011-11-18 15:12:32 | 显示全部楼层
源代码也一并公布了吧,这个源码写了有3个月,我用人格保证它是可以用的,它是稳定的,是经过了严格测试的,它是值得你信赖的,是文件系统开发程序员的权威参考书,我有完整的工程,这里没方便贴出来,来信索取吧

/*
+FHDR------------------------------------------------------------------
Copyright (c),
Tony Yang –Specialized in USB,FAT firmware development
Contact:qq 292942278  e-mail:tony_yang123@sina.com.cn

Abstract:
$Id: main.C,v 1.1.1.1 2007/01/01 10:35:32 tony Exp $
-FHDR-------------------------------------------------------------------
*/     
#include<stdio.h>
#include<include\types.h>
#include<Flash_Management\Flash_Management.h>   
#include<include\FAT_cfg.h>
//CORE of FAT filesystem
static struct core_ CORE;
//BPB
static struct partition_bpb BPB; 
//Define FCBs for File Reading/Writing 
struct FileControlBlock FCB[MaximumFCB];
/*
===============================================================================
函数
字符串转换成大写
入口:*string:字符串首地址
出口:SUCC
===============================================================================
*/ 
static u8 UPCASE(u8* string) 

 while(*string) 
 { 
     if(*string >='a' && *string <= 'z')
      {//如果字符为小写,则-32变成大写
      *string -= 32;
      }
 string++;
   }    
 return(SUCC);
}
/*
===============================================================================
函数
计算字符串长度
入口:*string:字符串首地址
出口:字符串长度
===============================================================================
*/ 
static u16 LengthofString(u8 * string)

 u16 i;
 i = 0;
 while(*string)//计数字符数,直到=0
  {
    i++;
    string++;
  }
 return(i);

/*
===============================================================================
函数
连接字符串2到字符串1之后,连接后字符串2无变化
入口:*string1:字符串1首地址,*string2:字符串2首地址
出口:SUCC,FAIL
===============================================================================
*/ 
static u8 concanenateString(u8 *string1,u8 *string2)
{
  u8 len,i;
  len = LengthofString(string1);
  i = 0;
  while(string2)
  {  //将字符串2拷贝到字符串1尾
    string1[len] = string2;  
    len++;
i++;
  }
  string1[len] = 0;
  return(SUCC);
}

/*
===============================================================================
函数
字符串copy,将字符串1拷贝至字符串2
入口:*string1:源字符串首地址;*string2:目标字符串首地址
出口:SUCC
===============================================================================
*/ 
static u8 stringcpy(u8 *string1,u8 *string2)
{
 while(*string1) 
   { //逐字拷贝字符串
     *string2 = *string1;
     string1++;
     string2++;
   }  
 *string2 = 0;
 return(SUCC);
}
/*
===============================================================================
函数
字符串比较(大小写不区分)
入口:*string1:字符串1首地址;*string2:字符串2首地址
出口:SUCC,FAIL
===============================================================================
*/ 
static u8 stringcmp(u8 *string1,u8 *string2)
{
 UPCASE(string1);
 UPCASE(string2);  
 while((*string1) && (*string2)) 
   {
     if((*string1) == (*string2))
 {   //逐字比较字符串
         string1++;
         string2++;
      }
     else
       return(FAIL);
   }   
 //根据串尾是否都是0  
 if( ((*string1) == 0) && ((*string2) == 0))
 {
     return(SUCC);
 }
 else
     return(FAIL);
}

/*
===============================================================================
函数
在簇链里找到当前簇的下一簇
入口:Cluster:当前簇号
出口: 返回下一簇号
===============================================================================
*/ 
static u32 Get_Next_Cluster_From_Current_Cluster(u32 Cluster)
{
   u8 buf[512]; 
   u32 ThisFATSecNum,ThisFATEntOffset;
   //FAT16每个簇占用两个字节
   ThisFATEntOffset = Cluster * 2;
   //计算当前簇所在扇区
   ThisFATSecNum = CORE.relative_sector + BPB.reserved_sector 
                   + (ThisFATEntOffset / BPB.bytes_per_sector);
   //计算当前簇所在扇区的偏移量
   ThisFATEntOffset = ThisFATEntOffset % BPB.bytes_per_sector; 
   //读取当前簇所在扇区
   read_flash_sector(buf,ThisFATSecNum);
   //返回当前簇的下一簇
   return((u32)buf[ThisFATEntOffset] + ((u32)buf[ThisFATEntOffset + 1]) * 256);
}
/*
===============================================================================
函数
在簇链里找到当前簇上一的簇号
入口:Cluster:当前簇号
出口: 返回当前簇之前的簇号
===============================================================================
*/ 
static u32 Get_Previous_Cluster_From_Current_Cluster(u32 Cluster)
{
  u8 buf[512];
  u32 CUR_FATSecNum,CUR_FATEntOffset;
  u32 CUR_Checking_Cluster_No;
  //从簇号0开始找
  CUR_Checking_Cluster_No = 0;
  CUR_FATEntOffset = 0;
  CUR_FATSecNum = CORE.FirstSectorofFAT1; 
  read_flash_sector(buf,CUR_FATSecNum); 
  do{ 
 //超出最大簇号,查找失败
 if( CUR_Checking_Cluster_No == (CORE.CountofClusters + 2))
         {
          return(FAIL);
         } 
 //检查下一簇是否是当前簇号?
     if( (u16)(buf[CUR_FATEntOffset] + buf[CUR_FATEntOffset + 1] * 256) == (u16)Cluster)
          return(CUR_Checking_Cluster_No);  //返回簇号
     CUR_Checking_Cluster_No++;
     CUR_FATEntOffset += 2;

     if(CUR_FATEntOffset >= 512)//检查了一个扇区,继续到下一扇区检查
      {
        CUR_FATSecNum++;

        read_flash_sector(buf,CUR_FATSecNum); 
        CUR_FATEntOffset = 0;     
      }
  }while(1);
}
/*
===============================================================================
函数
删除一个簇链
入口:Cluster:首簇号
出口: SUCC,FAIL
===============================================================================
*/ 
static u8 FreeClusterChain(u32 Cluster)
{
 u8 buf[512],i; 
 u32 ThisFAT1SecNum,ThisFATEntOffset,ThisFAT2SecNum;    
 do{
   
   //FAT16每个簇占用两个字节
   ThisFATEntOffset = Cluster * 2;
   //计算当前簇所在扇区
   ThisFAT1SecNum = CORE.relative_sector + BPB.reserved_sector 
                   + (ThisFATEntOffset / BPB.bytes_per_sector);
   ThisFAT2SecNum = ThisFAT1SecNum + BPB.sectors_per_FAT;

   //计算当前簇所在扇区的偏移量
   ThisFATEntOffset = (ThisFATEntOffset) % BPB.bytes_per_sector; 
   read_flash_sector(buf,ThisFAT1SecNum);
   //Cluster置为其下一簇
   Cluster = (u32)buf[ThisFATEntOffset]+ (u32)buf[ThisFATEntOffset + 1] * 256;  
   //将簇值清0,
   buf[ThisFATEntOffset] = 0x0;  
   buf[ThisFATEntOffset + 1] = 0x0;
   //回写FAT1
   write_flash_sector(buf,ThisFAT1SecNum); 
   //回写FAT2及所有FAT表
   for(i = 1;i < BPB.numbers_of_FAT;i++) 
     {
      write_flash_sector(buf,ThisFAT2SecNum);
      ThisFAT2SecNum = ThisFAT2SecNum + BPB.sectors_per_FAT;
     } 
   //判断簇链是否结束?
   if(Cluster >= 0xfff6)
     return(SUCC);   
  }while(1);  
}
/*
===============================================================================
函数
返回簇N的首扇区
入口:N:簇号
出口: 返回簇N的首扇区
===============================================================================
*/  
static u32 FirstSectorofCluster(u32 N)
{
 return((N - 2) * BPB.sector_per_cluster + CORE.FirstDataSector);
}
/*
===============================================================================
函数
从FAT中分配一个簇到簇链当前簇之后
入口:Cluster:当前簇号,added_cluster被分配的簇
出口: 加入的簇号
===============================================================================
*/ 
u8 Allocate_EMPTY_CLUSTER_TO_CUR_CLUSTER_CHAIN(u32 Cluster,u32 *Added_Cluster,u8 *buf)
{
  u32 temp,EMPTY_CLUSTER,ThisFAT1SecNum,ThisFATEntOffset,ThisFAT2SecNum;
  u16 i; 
  EMPTY_CLUSTER = 0;
  //从起始FAT表的起始扇区,找空簇以完成分配
  ThisFAT1SecNum = CORE.relative_sector + BPB.reserved_sector;
  ThisFAT2SecNum = ThisFAT1SecNum + BPB.sectors_per_FAT;
  do{    
  //从偏移量0开始找   
  ThisFATEntOffset = 0; 
  read_flash_sector(buf,ThisFAT1SecNum);   
  for(i = 0;i < 256;i++)
  {  
     if(buf[ThisFATEntOffset] == 0 && buf[ThisFATEntOffset + 1] == 0)
      {//找到空簇,将当前簇的下一簇放到找到空簇的下一簇
       temp = Get_Next_Cluster_From_Current_Cluster(Cluster);
       buf[ThisFATEntOffset] = (u8)(temp & 0xff);  
       buf[ThisFATEntOffset + 1] = (u8)((temp >> 8) & 0xff);
       //回写FAT1
   write_flash_sector(buf,ThisFAT1SecNum);  
       temp = ThisFAT2SecNum;
       //回写其它FAT2及所有的FAT表
   for(i = 1;i < BPB.numbers_of_FAT;i++)
         {
          write_flash_sector(buf,temp);
          temp +=  BPB.sectors_per_FAT;
         }  
       temp = Get_Next_Cluster_From_Current_Cluster(Cluster);
       //将当前簇的下一簇填写指定找到的空簇
   ThisFATEntOffset = Cluster * 2;
       //计算当前簇所在扇区
   ThisFAT1SecNum = CORE.relative_sector + BPB.reserved_sector 
                   + (ThisFATEntOffset / BPB.bytes_per_sector);
       
    //计算当前簇所在扇区的偏移量
   ThisFATEntOffset = ThisFATEntOffset % BPB.bytes_per_sector;
       ThisFAT2SecNum = ThisFAT1SecNum + BPB.sectors_per_FAT; 
       read_flash_sector(buf,ThisFAT1SecNum);
       buf[ThisFATEntOffset] = (u8)(EMPTY_CLUSTER & 0xff);//Add to cluster chain
       buf[ThisFATEntOffset + 1] = (u8)((EMPTY_CLUSTER >> 8) & 0xff); 
       //回写FAT1
   write_flash_sector(buf,ThisFAT1SecNum);  
       //回写其它FAT2及所有的FAT表
   temp = ThisFAT2SecNum;
       for(i = 1;i < BPB.numbers_of_FAT;i++)  //update backup FAT2,etc..
         {          
   read_flash_sector(buf,temp);
           buf[ThisFATEntOffset] = (u8)(EMPTY_CLUSTER & 0xff);//Add to cluster chain
           buf[ThisFATEntOffset + 1] = (u8)((EMPTY_CLUSTER >> 8) & 0xff); 
           write_flash_sector(buf,temp);
           temp +=  BPB.sectors_per_FAT;
         } 
    //将空簇的数据清空
   for(i = 0;i< 512;i++)
   buf = 0;
       ThisFAT1SecNum = FirstSectorofCluster(EMPTY_CLUSTER);
   for(i = 0;i < BPB.sector_per_cluster;i++)
           write_flash_sector(buf,ThisFAT1SecNum + i);
       *Added_Cluster = EMPTY_CLUSTER;                  
       return(SUCC);
      }
     else
      {
        ThisFATEntOffset += 2;
        EMPTY_CLUSTER ++;
//超出最大簇号,查找失败
        if( EMPTY_CLUSTER == (CORE.CountofClusters + 2))
         {
          return(FAIL);
         } 
      }
   }
  ThisFAT1SecNum ++;
  ThisFAT2SecNum ++;
  }while(1);     
}

/*
===============================================================================
函数
从FAT中分配一个空簇
入口:cluster--被分配的簇
出口: SUCC,FAIL
===============================================================================
*/ 
u8 Allocate_An_Empty_cluster(u32 * cluster,u8 * buf)
{
  u32 temp,EMPTY_CLUSTER,ThisFAT1SecNum,ThisFATEntOffset,ThisFAT2SecNum;
  u16 i; 

  //从起始FAT表的起始扇区,找空簇以完成分配
  EMPTY_CLUSTER = 0;
  ThisFAT1SecNum = CORE.relative_sector + BPB.reserved_sector;
  ThisFAT2SecNum = ThisFAT1SecNum + BPB.sectors_per_FAT;
  do{      
  ThisFATEntOffset = 0; 
  read_flash_sector(buf,ThisFAT1SecNum);   
  for(i = 0;i < 256;i++)
   {
     if(buf[ThisFATEntOffset] == 0 && buf[ThisFATEntOffset + 1] == 0)
      {//找到空簇,设置空簇为0XFFFF,即占用状态
       buf[ThisFATEntOffset] = 0xff;   
       buf[ThisFATEntOffset + 1] = 0xff;
       //回写FAT1
   write_flash_sector(buf,ThisFAT1SecNum);  
       //回写其它FAT2及所有的FAT表
   temp = ThisFAT2SecNum;
       for(i = 1;i < BPB.numbers_of_FAT;i++)  //update backup FAT2,etc..
         {
          write_flash_sector(buf,temp);
          temp +=  BPB.sectors_per_FAT;
         }  
   //将空簇的数据清空
   for(i = 0;i< 512;i++)
   buf = 0;
       ThisFAT1SecNum = FirstSectorofCluster(EMPTY_CLUSTER);
   for(i = 0; i < BPB.sector_per_cluster;i++)
           write_flash_sector(buf,ThisFAT1SecNum + i);
       *cluster = EMPTY_CLUSTER;                  
       return(SUCC);
      }
     else
      {
        ThisFATEntOffset += 2;
        EMPTY_CLUSTER ++; 
//超出最大簇号,查找失败
        if( EMPTY_CLUSTER == (CORE.CountofClusters + 2))
         {
          return(FAIL);
         } 
      }
   }
  ThisFAT1SecNum ++;
  ThisFAT2SecNum ++;
  }while(1);     

}

  
/*
===============================================================================
函数(CORE_INIT_2)
从root sector BPB计算FirstDataSector,FirstRootDirSecNum等等
入口:无
出口: 无
===============================================================================
*/
static void BPB_INIT_2(void)
{ //计算根目录占用的扇区数 
  CORE.RootDirSectors = (BPB.boot_entries * 32 + (BPB.bytes_per_sector - 1)) / BPB.bytes_per_sector;                             
  //计算数据区的起始扇区                            
  CORE.FirstDataSector = CORE.relative_sector + BPB.reserved_sector + BPB.sectors_per_FAT
                               * BPB.numbers_of_FAT + CORE.RootDirSectors;
  //计算根目录的起始扇区
  CORE.FirstRootDirSecNum = CORE.relative_sector + BPB.reserved_sector+ BPB.sectors_per_FAT
                               * BPB.numbers_of_FAT;
  //计算数据区占用扇区数
  CORE.DataSec = CORE.total_sector - BPB.reserved_sector - CORE.RootDirSectors
                 - BPB.sectors_per_FAT * BPB.numbers_of_FAT;
  //计算数据区对应的簇数
  CORE.CountofClusters = CORE.DataSec / BPB.sector_per_cluster;
  //计算FAT1,FAT2的起始扇区
  CORE.FirstSectorofFAT1 = CORE.relative_sector + BPB.reserved_sector;
  CORE.FirstSectorofFAT2 = CORE.relative_sector + BPB.reserved_sector + BPB.sectors_per_FAT;
}
/*
===============================================================================
函数
Read artition BP
入口:Partition ID
出口:无
===============================================================================
*/ 
static u8 Read_partition_PBP(u8 partition_ID)
{  
  u8 *ptr1,*ptr2; 
  u16 i; 
  u8 buf[512];  
   if ((CORE.PartitionID - 'C') ==  partition_ID) 
    { 
  //指定的BPB已经在缓冲中,直接返回
      return(SUCC);
    } 
   //读取MBR,即扇区0
   read_flash_sector(buf,0); //read MBR 
   if ( buf[0x1be] == 0x00 || buf[0x1be] == 0x80) // check boot indicator 00 or 0x80
   {
   
   }
   else
   {
   CORE.relative_sector = 0; 
       CORE.total_sector =  *((u32*) (buf+32));//保存分区容量
       CORE.system_id = buf[0x1c2]; //保存分区类型 0C-FAT32,06-FAT16 ect..
       CORE.PartitionID= 'C' + partition_ID; //从C开始到Z结束 
   //保存BPB数据
   if ( buf[510] == 0x55 && buf[511] == 0xaa)
       {
        //每扇区字节数
        BPB.bytes_per_sector = buf[0xb] + buf[0xc] * 256;
        
        //每簇扇区数
        BPB.sector_per_cluster = buf[0xd];
        //保留扇区数
        BPB.reserved_sector = buf[14] + buf[15] * 256;

        //FAT副本数
        BPB.numbers_of_FAT = buf[16];
        //根目录项数,供FAT12/16使用
        BPB.boot_entries = buf[17] + buf[18] * 256;
        //This field is the old 16-bit total count of sectors on the volume.
        BPB.TotSec16 = buf[19] + buf[20] * 256;
        BPB.TotSec16 = 0xffff;
        //媒体描述符
        BPB.media_descriptor = buf[21];
        //每个FAT表占用的扇区数,供FAT12/16使用
        BPB.sectors_per_FAT =  buf[22] + buf[23] * 256;
        CORE.system_id = 0x6; //保存分区类型 0C-FAT32,06-FAT16 ect..
        BPB_INIT_2();
        return(SUCC);
       } 
 }
    
  return(FAIL);
}  

/*
===============================================================================
函数
从路径中读一个entry
入口:
出口:SUCC,FAIL
===============================================================================
*/
static u8 SplitNameFromPath(u8 *Path,u8 *Return_Entry_Name,u8 *FileExtension,u8 *RemovedCharsFromPath)
{  
  u8 i,flag,j;
  flag = FILE_NAME;
  *RemovedCharsFromPath = 0; 
  CORE.CurPathType = DirectoryPath; 
  i = 0; 
  j = 0;
  do{           
     if( ( * ath) != 0 && ( * ath ) != '\\') //Path分离得到Entry name and file extension 
       { 
        (*RemovedCharsFromPath)++; 
        //分离ENTRY NAME
if( flag == FILE_NAME)
         {            
          if(*Path == '.')
             {//遇到".",则开始分离file extension 
              flag  = FILE_EXTENSION;
              ath ++; 
             }  
          else
            {
             Return_Entry_Name =  *Path;
             i++; 
             ath++;
            }
          }
        else if( flag  == FILE_EXTENSION)
         {//分离file extension
          if( j >= 3 )
            return(FAIL);
          FileExtension[j] =  *Path;
          j++;
          ath++;
         } 
      }
    else
      {//分离结束,检查是否是最后的一个ENTRY?
       if(!( * ath))
        {
          if(CORE.FullPathType == FilePath)
  {
  CORE.CurPathType = FilePath;
  }
          FileExtension[j] = 0;
          Return_Entry_Name = 0;
  //最后一个ENTRY,返回LastSplitedNameofPath
          return(LastSplitedNameofPath);  
        } 
       (*RemovedCharsFromPath)++; 
       FileExtension[j] = 0;
       Return_Entry_Name = 0;    
       break;
      }
 }while(1); 
 return(SUCC);

/*
===============================================================================
函数
Directory Entry的位置+32,转向下一个ENTRY 
入口:无
出口:SUCC,FAIL
===============================================================================
*/             
static u8 CORE_offset_add_32(u8 *buf)
{ //位置+32
  CORE.offset += 32;
  if (CORE.offset >= 512)
  {
  //位置越过一个扇区
  if (CORE.DirectoryType == RootDirectory)
  {     //针对根目录的处理
        if (CORE.SectorNum < ( CORE.RootDirSectors +  CORE.FirstRootDirSecNum))
         {
           CORE.SectorNum++;
           CORE.offset = 0; 
           read_flash_sector(buf,CORE.SectorNum);
   if(buf[CORE.offset] == 0 && buf[CORE.offset+1] == 0)  //End of the directory
     return(FAIL);//已没有ENTRY,返回FAIL
           return(SUCC);
         }
        else
           return(FAIL);
     }
    else  
     {
        if( (CORE.SectorNum - FirstSectorofCluster(CORE.ClusterNum) + 1) >= BPB.sector_per_cluster)
{ //位置越过一个簇, 取下一簇,继续处理
           CORE.ClusterNum = Get_Next_Cluster_From_Current_Cluster(CORE.ClusterNum);
           if( CORE.ClusterNum >= 2 && CORE.ClusterNum <= 0xfff7)
            {
               CORE.SectorNum = FirstSectorofCluster(CORE.ClusterNum); 
               CORE.offset = 0;
               read_flash_sector(buf,CORE.SectorNum);
   if(buf[CORE.offset] == 0 && buf[CORE.offset+1] == 0)  //End of the directory
                   return(FAIL);//已没有ENTRY,返回FAIL
               return(SUCC);
            }
           else
 return(FAIL);
         }
        else
         {
            CORE.SectorNum++; 
            CORE.offset = 0;
            read_flash_sector(buf,CORE.SectorNum);
if(buf[CORE.offset] == 0 && buf[CORE.offset+1] == 0)  //End of the directory
                return(FAIL);//已没有ENTRY,返回FAIL
            return(SUCC);
         }
     }
  }
  if(buf[CORE.offset] == 0 && buf[CORE.offset+1] == 0)  //End of the directory
       return(FAIL);//已没有ENTRY,返回FAIL
  return(SUCC);
}
/*
===============================================================================
函数
从目录读取短文件名
入口:EntryName-返回文件名,Extension=返回扩展名
出口:SUCC,FAIL
===============================================================================
*/ 
static u8 GetEntryWith8_3Name(u8 *buf,u8* EntryName,u8 *Extension)
{
  u8 j;
  struct Directory_Entry_  *Directory_Entry_Local;  
  u8 *pointer;
  pointer = buf;
  Directory_Entry_Local = (struct Directory_Entry_ *) (pointer + CORE.offset);
  //从DIRECTORY 中读取EntryName  
  for(j = 0;j < 8;j++)
   {
    if(Directory_Entry_Local->filename[j] == 0x20)
      break;
    EntryName[j] = Directory_Entry_Local->filename[j];
   }   
  EntryName[j] = 0; 
  //从DIRECTORY 中读取Extension
  for(j = 0;j < 3;j++)
   {  
    if(Directory_Entry_Local->file_extention[j] == 0x20)
        break;
    Extension[j] = Directory_Entry_Local->file_extention[j]; 
   }
  Extension[j] = 0;

  if(CORE.FullPathType == FilePath && CORE.CurPathType == FilePath)
     CORE.FileSize = *(u32*)Directory_Entry_Local->file_length;//保存文件长度
  Directory_Entry_Local->file_length[0] = 0;
  Directory_Entry_Local->file_length[0] = 0;
  //保存文件首簇号
  CORE.ClusterOfDirectoryEntry = (Directory_Entry_Local->first_cluster_number_low2bytes[0]) + 
  (Directory_Entry_Local->first_cluster_number_low2bytes[1]) * 256;
  CORE.PreEntrySectorNum = CORE.SectorNum;
  CORE.PreEntryoffset = CORE.offset;
  CORE_offset_add_32(buf);//Directory Entry的位置+32 
  return(SUCC);
}
/*
===============================================================================
函数
从目录读取长文件名
入口:longFileName-返回文件名,Extension=返回扩展名
出口:SUCC,FAIL
===============================================================================
*/ 
static u8 GetEntryWithLongFileName(u8 *buf,u8* longFileName,u8 *Extension)
{
 u8 j,FileNameOffset;
                   
 u8 flag,k,i;
 u16 len;
 struct LongNameDirectoryEntry *LongNameDirectoryEntry_Local;
 *Extension = 0;

 FileNameOffset = 242;
 LongNameDirectoryEntry_Local = (struct LongNameDirectoryEntry *) (buf + CORE.offset);
 do{
 k = FileNameOffset;
 //读取longNameDirectoryEntry中的前5个字节
     for(j = 1;j < 10;j+=2)
      {        
       if (LongNameDirectoryEntry_Local->dir_lname1[j] == 0)
          break; //遇0结束退出  
       longFileName[k] = LongNameDirectoryEntry_Local->dir_lname1[j];
       k ++;                 
      } 
 longFileName[k] = 0;
       if(j >= 10)
         { //读取longNameDirectoryEntry中的第二6个字节
           for(j = 0;j < 12;j += 2)
            {  
              if (LongNameDirectoryEntry_Local->dir_lname2[j] == 0)
                 break;

                 longFileName[k] = LongNameDirectoryEntry_Local->dir_lname2[j];
                 k++;           
            }
           if(j >= 12)   
                for(j = 0;j < 4;j += 2)//读取longNameDirectoryEntry中的第三大作2个字节
                 { 
                  if (LongNameDirectoryEntry_Local->dir_lname3[j] == 0)
                     break;       
                    longFileName[k] = LongNameDirectoryEntry_Local->dir_lname3[j];
                    k ++;                   
                 }
          }
 if(k > 242)
  longFileName[k] = 0;
CORE.PreEntrySectorNum = CORE.SectorNum;
    CORE.PreEntryoffset = CORE.offset;
if(CORE_offset_add_32(buf) == FAIL) 
       return(FAIL);//Directory Entry的位置+32 
    FileNameOffset -= 13;
    k = FileNameOffset;
    LongNameDirectoryEntry_Local = (struct LongNameDirectoryEntry *) (buf + CORE.offset);
    if(LongNameDirectoryEntry_Local->dir_attr != ATTR_LONG_NAME)
{      //遇到非ATTR_LONG_NAME表示一个LONG FILE NAME读怒即将结束,处理最后的short entry
           if ( ! (LongNameDirectoryEntry_Local->dir_attr & ATTR_VOLUME_ID)) 
           {//保存首簇号
CORE.ClusterOfDirectoryEntry = LongNameDirectoryEntry_Local->dir_first[0]+
LongNameDirectoryEntry_Local->dir_first[1] * 256;
//保存文件长度
            CORE.FileSize = *((u32*)LongNameDirectoryEntry_Local->dir_lname3);
//拷贝longFileName到变量longFileName
stringcpy(longFileName+FileNameOffset+13,longFileName);
//分离文件扩展名
len =  LengthofString(longFileName);
len --;
i = 0;
do{
if(longFileName[len] == '.')
{
  longFileName[len] = 0;
                  stringcpy(longFileName + len + 1,Extension);
  break;
}
   len--;
   i++;
   if(i >= 15 || len == 0 )
 break;
}while(1);
            break;
           }
       flag = FILE_NAME;
       FileNameOffset = 256 - 13;
       k = FileNameOffset; 
   do{
  CORE.PreEntrySectorNum = CORE.SectorNum;
          CORE.PreEntryoffset = CORE.offset;
          if(CORE_offset_add_32(buf) == FAIL) 
            return(FAIL); //Directory Entry的位置+32 
          LongNameDirectoryEntry_Local = (struct LongNameDirectoryEntry *) (buf + CORE.offset);
      if(LongNameDirectoryEntry_Local->dir_lname1[0] == 0xe5)
             continue;//过滤已删除ENTRY
      if(LongNameDirectoryEntry_Local->dir_attr != ATTR_LONG_NAME)
  {
       if ( ! (LongNameDirectoryEntry_Local->dir_attr & ATTR_VOLUME_ID)) 
            return(GetEntryWith8_3Name(buf,longFileName,Extension));
   else
 continue;
  }
      else
   break;
   } while(1);
     } 
  }while(1); 

  return(SUCC);
 }

              
/*
===============================================================================
函数
从目录读取一个Entry
入口:mode = 0:返回所有directory entry
出口:SUCC,FAIL
===============================================================================
*/     
static u8 GetEntryFromDirectory(u8 *EntryName, u8 *Extension,u8 mode)

struct Directory_Entry_  *Directory_Entry_Local; 
struct LongNameDirectoryEntry *LongNameDirectoryEntry_Local; 
u8 flag; 
u8 buf[512];
read_flash_sector(buf,CORE.SectorNum);
do{ 
  if(CORE.offset == 512)
  {
    return(FAIL);
  }
  flag = FILE_NAME; 
  Directory_Entry_Local = (struct Directory_Entry_ *) (buf + CORE.offset);
  if(Directory_Entry_Local->filename[0] == 0x0)//遇目录结尾,读取已至结尾,退出返回FAIL
  return(FAIL);
  if(Directory_Entry_Local->filename[0] == 0xe5)//过滤已删除ENTRY
  {
   CORE.PreEntrySectorNum = CORE.SectorNum;
   CORE.PreEntryoffset = CORE.offset;
   if(CORE_offset_add_32(buf) == FAIL) //Directory Entry的位置+32 
     return(FAIL);
   continue;
  }  
  switch(Directory_Entry_Local->file_attribute) //检查file_attribute, 
    {
       case ATTR_LONG_NAME:{ //从目录读取长文件名
          if(GetEntryWithLongFileName(buf,EntryName,Extension) == SUCC)
          {
   read_flash_sector(buf,CORE.SectorNum);
           LongNameDirectoryEntry_Local = (struct LongNameDirectoryEntry *)(buf + CORE.offset);
   CORE.Entry_Attr = LongNameDirectoryEntry_Local->dir_attr;
   if(mode == Get_Selected_ENTRIES)
   {
             if(CORE.CurPathType == DirectoryPath && 
               (LongNameDirectoryEntry_Local->dir_attr & ATTR_DIRECTORY))
 { 
               CORE.ClusterOfDirectoryEntry = *(u16*)LongNameDirectoryEntry_Local->dir_first;
               CORE.PreEntrySectorNum = CORE.SectorNum;
               CORE.PreEntryoffset = CORE.offset;
   CORE_offset_add_32(buf);///Directory Entry的位置+32 
               return(SUCC);
 }
             else if ( ! (LongNameDirectoryEntry_Local->dir_attr & ATTR_VOLUME_ID)) 
 {
              CORE.PreEntrySectorNum = CORE.SectorNum;
             CORE.PreEntryoffset = CORE.offset;
 CORE_offset_add_32(buf);//Directory Entry的位置+32 
             return(SUCC);
             }    
   }
   else
   {
CORE.PreEntrySectorNum = CORE.SectorNum;
            CORE.PreEntryoffset = CORE.offset;
    CORE.ClusterOfDirectoryEntry = *(u16*)LongNameDirectoryEntry_Local->dir_first;
            CORE_offset_add_32(buf);//Directory Entry的位置+32 
            
return(SUCC);
   }
          }
          break;
        }
       case ATTR_DIRECTORY:{//从目录读取目录(短文件名)
  CORE.Entry_Attr = Directory_Entry_Local->file_attribute;
  if(mode == Get_Selected_ENTRIES)
           if(CORE.FullPathType == FilePath && CORE.CurPathType == FilePath)
             break;
          if(GetEntryWith8_3Name(buf,EntryName,Extension)  == SUCC)
             return(SUCC);       
          break;
       }
       case ATTR_VOLUME_ID:CORE.Entry_Attr = Directory_Entry_Local->file_attribute;
       //case 0:break;
       default:
        {//从目录读取文件(短文件名)
 CORE.Entry_Attr = Directory_Entry_Local->file_attribute;
     if(mode == Get_Selected_ENTRIES)
          if(CORE.FullPathType == DirectoryPath)
             break;
          return(GetEntryWith8_3Name(buf,EntryName,Extension)); 
        }
     } 
  CORE.PreEntrySectorNum = CORE.SectorNum;
  CORE.PreEntryoffset = CORE.offset;
  if(CORE_offset_add_32(buf) == FAIL) 
    return(FAIL);//Directory Entry的位置+32 
 }while(1); 
return(SUCC);
}  
/*
===============================================================================
函数
从目录中查找一个Entry
入口:floder_name-文件名,file_extension-扩展名
出口:SUCC,FAIL
===============================================================================
*/
static u8 FindEntryStruct(u8 *floder_name,u8 *file_extension)
{  
   u8 EntryName[256],Extension[20]; 
   u8 Name_Compare_OK,Extension_Compare_OK;   
   do{   //从目录读取一个Entry    
          if(GetEntryFromDirectory(EntryName,Extension,Get_Selected_ENTRIES) != SUCC)
  {
            return(FAIL);
  }
       Name_Compare_OK = OK;
   //检查文件名
       if(stringcmp(EntryName,floder_name) != SUCC)
             Name_Compare_OK = unOK;        
       if(Name_Compare_OK == OK)  //检查文件扩展名
         {      
           if(CORE.FullPathType == FilePath && CORE.CurPathType == FilePath)
              { 

                  Extension_Compare_OK = OK;     
                  if(stringcmp(Extension,file_extension) != SUCC)
                     Extension_Compare_OK = unOK;
                  else
                     break;  
              }
            else
{  
                if(Extension[0] == 0) 
                 break;

              }  
          }
     }while(1);
   return(SUCC);
}
/*
===============================================================================
函数
相对的路径转换成Sector,SectorOffset,Cluster
入口:u8 *filename
出口:SUCC,FAIL
===============================================================================
*/
static u8 RelativePathToSectorCluster(u8 *RelativePath)

  u8 floder_name[256],file_extension[20]; 
  u8 Splited_Count;
  u8 Splited_Status;
   //调用SplitNameFromPath()从RelativePath分离出一个目录或文件元素
  Splited_Status = SplitNameFromPath(RelativePath,floder_name,file_extension,&Splited_Count);
  if(Splited_Status == FAIL)
      return(FAIL);
  RelativePath += Splited_Count;  
   //从目录中查找一个Entry
  if(FindEntryStruct(floder_name,file_extension) != SUCC)
  {
   return(FAIL); //查找失败退出
  }//DirectoryType置为非RootDirectory
   if(CORE.CurPathType == DirectoryPath)
     if(CORE.DirectoryType == RootDirectory)
  {
  CORE.DirectoryType = NoneRootDirectory; 
  }
      
  if(Splited_Status == LastSplitedNameofPath)
  {
   return(SUCC); 
  }    
  do{ //调用SplitNameFromPath()从RelativePath分离出一个目录或文件元素
     Splited_Status = SplitNameFromPath(RelativePath,floder_name,file_extension,&Splited_Count);
     if(Splited_Status == FAIL)
  return(FAIL);    
     else 
       { //设置变量,进入目录去查找
         CORE.ClusterNum = CORE.ClusterOfDirectoryEntry;
         CORE.SectorNum = FirstSectorofCluster(CORE.ClusterNum);
         CORE.offset = 0;  
       }
     RelativePath += Splited_Count;
 //DirectoryType置为非RootDirectory
     if(CORE.CurPathType == DirectoryPath)
      if(CORE.DirectoryType == RootDirectory)
  {
  CORE.DirectoryType = NoneRootDirectory; 
  }
  //从目录中查找一个Entry
     if(FindEntryStruct(floder_name,file_extension) != SUCC)
 {
       return(FAIL); //查找失败退出
 }
     else if(Splited_Status == LastSplitedNameofPath)
 {
      return(SUCC);
 }  

    }while(1);
    return(SUCC);
}
/*
===============================================================================
函数
完整的路径转换成Sector,SectorOffset,Cluster,可用于检查文件是否存在
入口:u8 *filename
出口:SUCC,FAIL
===============================================================================
*/
static u8 FullPathToSectorCluster(u8 * filename1)
{
   u8 buf[260],* filename;
   stringcpy(filename1,buf);
   filename = buf;
   UPCASE(filename);

     if( ((* filename) >= 'A' && ( * filename ) <= 'Z')||
((* filename) >= 'a' && ( * filename ) <= 'z') )  
       {
         if(( * (filename + 1)) == ':')
          {                          
           if( *( filename + 2 ) == '\\')
            { //绝对路径,从根目录进行转换
              if(LengthofString(filename) > Maximum_File_Path_Name)
      return(EpathLengthsOVERFLOW);
              if(Read_partition_PBP((u8)((*filename) - 'C')) != SUCC)
                 return(FAIL);
              filename += 3; 
  //设置参数,根目录寻址
              CORE.SectorNum = CORE.FirstRootDirSecNum; 
              CORE.DirectoryType =  RootDirectory;
              CORE.offset = 0;   
             }
          }
         else 
 {   //相对路径,从当前目录进行转换  
             if((LengthofString(filename) + LengthofString(CORE.current_folder)) > Maximum_File_Path_Name)
                   return(EpathLengthsOVERFLOW);
             //设置参数
 if(CORE.CurrentDirectoryType ==  RootDirectory)
 {
    CORE.SectorNum = CORE.FirstRootDirSecNum;
 }  
             else
              {
                 CORE.ClusterNum = CORE.ClusterNOofCurrentFolder;
                 CORE.SectorNum = FirstSectorofCluster(CORE.ClusterNum); 
              }
             CORE.DirectoryType = CORE.CurrentDirectoryType;
             CORE.offset = 0;  

          }  
       }
       else if((* filename) == '\\')//从当前盘符进行转换
            {
             if((LengthofString(filename) + 1) > Maximum_File_Path_Name)
                   return(EpathLengthsOVERFLOW); 
              //设置参数,根目录寻址
             filename ++;    
             CORE.SectorNum = CORE.FirstRootDirSecNum; 
             CORE.DirectoryType = RootDirectory;
             CORE.offset = 0;

            } 
  if(*filename)
     return(RelativePathToSectorCluster(filename));
  else
return(SUCC);
   
}
/*
===============================================================================
函数
检查文件是否已打开?
入口:FirstClusterOfFile-文件首簇号
出口:FileAlreadyopenedByOtherHandle,FileUnopenedByOtherHandle
===============================================================================
*/ 
u8 Check_FileOpened_Status(u32 FirstClusterOfFile,u16 j)
{
  u8 i;
  for(i = 0;i < MaximumFCB;i++)
  {
    if(i == j)
continue;
   if(FCB.file_openned_flag == UsedFlag)
   { //FCB的首簇号与文件首簇号相同,则文件已被打开
     if(FCB.FirstClusterOfFile == FirstClusterOfFile)
        return(FileAlreadyopenedByOtherHandle);
   }
  }
  //未发现相同首簇号,文件未打开,返回
  return(FileUnopenedByOtherHandle);

/*
===============================================================================
函数
将file buffer回写磁盘
入口:u8 FCBsn
出口:SUCC,FAIL
===============================================================================
*/ 
#if EnableFileBuf
u8 Writeback_FCB_file_buffer(u8 FCBsn)

  u16 i;
  u16 ClusterQTY,BUFoffset,TEMP;
  u32 FCBbufSize,sector,NEXTCluster,qty; 
  u8  buf[512];
  u32 FILESIZE;
  u16 wrote_sectors_count;
  
  if(FCB[FCBsn].FirstClusterOfFile == 0)
  { //未分配文件首簇号,则执行分配
if( Allocate_An_Empty_cluster(&FCB[FCBsn].FirstClusterOfFile,buf)== FAIL)
  return(FAIL);
//将首簇号写入文件的ENTRY内
read_flash_sector(buf,FCB[FCBsn].Entry_Storedin_Sector);
    i = FCB[FCBsn].Entry_Storedin_Sector_Offset + 26;
buf = (u8)(FCB[FCBsn].FirstClusterOfFile & 0xff);
buf[i+1] = (u8)((FCB[FCBsn].FirstClusterOfFile >> 8) & 0xff);
write_flash_sector(buf,FCB[FCBsn].Entry_Storedin_Sector);
    FCB[FCBsn].CurClusterInBUF = FCB[FCBsn].FirstClusterOfFile;
  }
  //根据当前CurBlockInBUF计算需要移动CLUSTER数量
  ClusterQTY = FCB[FCBsn].CurBlockInBUF / BPB.sector_per_cluster;
  NEXTCluster = FCB[FCBsn].FirstClusterOfFile; 
  //计算需要移动CLUSTER数量
  qty = ClusterQTY;
  if(FCB[FCBsn].ClusterSNInBUF <= ClusterQTY)
  {
    ClusterQTY -= FCB[FCBsn].ClusterSNInBUF;
    NEXTCluster = FCB[FCBsn].CurClusterInBUF;
  }
  else
  {
    NEXTCluster = FCB[FCBsn].FirstClusterOfFile; 
  }
  //移动CLUSTER
  while(ClusterQTY)
  {TEMP = NEXTCluster;
   NEXTCluster =  Get_Next_Cluster_From_Current_Cluster(NEXTCluster);
   ClusterQTY--;
   if(NEXTCluster >= 0xfff4 && NEXTCluster <= 0xffff)
   {
    if (Allocate_EMPTY_CLUSTER_TO_CUR_CLUSTER_CHAIN(TEMP,&NEXTCluster,buf) == FAIL)
return(FAIL);
   }
  } 

  //保存当前CurClusterInBUF及ClusterSNInBUF
  FCB[FCBsn].CurClusterInBUF = NEXTCluster;
  FCB[FCBsn].ClusterSNInBUF = qty; 
  //将file buffer回写磁盘
  FCBbufSize = FileBUFSize * TotalFileBUFsQTYeachFCB; 
  BUFoffset = 0;
  i = FCB[FCBsn].CurBlockInBUF % BPB.sector_per_cluster;
  //获取首扇区
  sector = FirstSectorofCluster(NEXTCluster);
  wrote_sectors_count = 0; 
  do{ 
     write_flash_sector(FCB[FCBsn].FileBUF + BUFoffset,sector + i); 
     wrote_sectors_count++;
 i++;
 //超过FILE SIZE直接退出
 if(((wrote_sectors_count + FCB[FCBsn].CurBlockInBUF) * 512) >= FCB[FCBsn].FileSize)
 {
    break;
 }
     BUFoffset += FileBUFSize;
     FCBbufSize -= FileBUFSize;
     if(FCBbufSize == 0)
 {
 break;
 }
     if(i >= BPB.sector_per_cluster)
 { //超过簇边界, 转到下一簇继续写 
   TEMP = NEXTCluster; 
       NEXTCluster = Get_Next_Cluster_From_Current_Cluster(NEXTCluster);
       if(NEXTCluster >= 0xfff4 && NEXTCluster <= 0xffff)
   {
    if (Allocate_EMPTY_CLUSTER_TO_CUR_CLUSTER_CHAIN(TEMP,&NEXTCluster,buf) == FAIL)
return(FAIL);
   }
   sector = FirstSectorofCluster(NEXTCluster);
       i = 0;
      }    
  }while(1);
  //清除Modified_Flag
  FCB[FCBsn].Modified_Flag = 0;
  //读取文件目录项, 从而更新文件大小
  read_flash_sector(buf,FCB[FCBsn].Entry_Storedin_Sector);
  i = FCB[FCBsn].Entry_Storedin_Sector_Offset + 28;
  FILESIZE = buf + buf[i+1] * 256 + buf[i+2] * 256 * 256+ buf[i+3]  * 256 * 256 *256;
  //检查文件大小是否已更新?
  if(FILESIZE != FCB[FCBsn].FileSize) 
  { //检查文件大小已更新,则更新File Directory entry的文件大小
FILESIZE = FCB[FCBsn].FileSize;
buf = (u8)(FILESIZE & 0xff);
buf[i+1] = (u8)((FILESIZE >> 8) & 0xff);
buf[i+2] = (u8)((FILESIZE >> 16) & 0xff);
buf[i+3] = (u8)((FILESIZE >> 24) & 0xff);
    write_flash_sector(buf,FCB[FCBsn].Entry_Storedin_Sector);
  }
  return(SUCC);
}
#endif 

/*
===============================================================================
函数
基于文件当前的位置,完成更新文件缓冲区
入口:u8 FCBsn
出口:SUCC,FAIL
===============================================================================
*/ 
#if EnableFileBuf
u8 Update_FCB_file_buffer(u8 FCBsn)

  u16 i;
  u16 ClusterQTY,BUFoffset;
  u32 FCBbufSize,sector,NEXTCluster,qty; 
  if(!(FileBUFSize * TotalFileBUFsQTYeachFCB))
     return(SUCC);
  if(((FCB[FCBsn].cur_position) >= FCB[FCBsn].CurBlockInBUF * FileBUFSize && 
     ((FCB[FCBsn].cur_position) <  (FCB[FCBsn].CurBlockInBUF + TotalFileBUFsQTYeachFCB) * FileBUFSize) ))
  {
  return(SUCC); 
  }
  if(FCB[FCBsn].Modified_Flag)//检查Modified_Flag,如果不为0,则需要回写FILE BUFFER
    if(Writeback_FCB_file_buffer(FCBsn) == FAIL)
  return(FAIL);
  //根据当前CurBlockInBUF计算需要移动CLUSTER数量
  FCB[FCBsn].CurBlockInBUF = FCB[FCBsn].cur_position / FileBUFSize;
  ClusterQTY = FCB[FCBsn].CurBlockInBUF / BPB.sector_per_cluster;
  NEXTCluster = FCB[FCBsn].FirstClusterOfFile; 
  qty = ClusterQTY;
  
  //计算需要移动CLUSTER数量  
  if(FCB[FCBsn].ClusterSNInBUF_for_read <= ClusterQTY)
  { 
    ClusterQTY -= FCB[FCBsn].ClusterSNInBUF_for_read;
    NEXTCluster = FCB[FCBsn].CurClusterInBUF_for_read;
  }
 else
 {
    NEXTCluster = FCB[FCBsn].FirstClusterOfFile; 
  } 

  //移动CLUSTER
  while(ClusterQTY)
  {
   if(NEXTCluster >= 0xfff4 && NEXTCluster <= 0xffff)
   return(SUCC);
   NEXTCluster =  Get_Next_Cluster_From_Current_Cluster(NEXTCluster);
   ClusterQTY--;
  } 
  FCB[FCBsn].CurClusterInBUF_for_read = NEXTCluster;
  FCB[FCBsn].ClusterSNInBUF_for_read = qty; 


  FCBbufSize = FileBUFSize * TotalFileBUFsQTYeachFCB; 
  BUFoffset = 0;
  i = FCB[FCBsn].CurBlockInBUF % BPB.sector_per_cluster;
    //获取首扇区
  sector = FirstSectorofCluster(NEXTCluster);
  do{  
   read_flash_sector(FCB[FCBsn].FileBUF + BUFoffset,sector + i); 
   BUFoffset += FileBUFSize;
   FCBbufSize -= FileBUFSize;
   if(FCBbufSize == 0)
    {
     return(SUCC); 
    }
   i++;
   if(i >= BPB.sector_per_cluster)
     {//超过簇边界, 转到下一簇继续读 
       NEXTCluster= Get_Next_Cluster_From_Current_Cluster(NEXTCluster);
       if(NEXTCluster >= 0xfff4 && NEXTCluster <= 0xffff)
   return(SUCC);
   sector = FirstSectorofCluster(NEXTCluster);
       i = 0;
      }    
  }while(1);
}
#endif 

/*
===============================================================================
函数
分配FCB
入口:无
出口:EAllocate_FCB-- Fail,other--SUCC with FCB sequential number
===============================================================================
*/ 
u8 Allocate_FCB(void)
{  
 u8 i;
 for (i = 0; i < MaximumFCB;i++)//找一个UnusedFlag的FCB,返回给调用者使用
  if (FCB.file_openned_flag == UnusedFlag)  
   {          
    FCB.file_openned_flag = UsedFlag;//设置为占用
FCB.Modified_Flag = 0;
    return(i);//返回FCB的编号
   }
 return(EAllocate_FCB);
}
/*
===============================================================================
函数
释放一个FCB
入口:FCB_sn
出口:EFree_FCB,SUCC
===============================================================================
*/     
u8 Free_FCB(u8 FCBsn)
{//检查FCB是否占用
 if(FCB[FCBsn].file_openned_flag == UsedFlag)
  {
    FCB[FCBsn].file_openned_flag = UnusedFlag;//设置为非占用
FCB[FCBsn].Modified_Flag = 0;
    return(SUCC);
  }
  else
   return(EFree_FCB);
}
/*
===============================================================================
函数
FAT初始化函数,一般由main()在使用文件系统之前调用
入口:无
出口:无
===============================================================================
*/ 
#if complie_FAT_filesystem_initialiation
u8 FAT_filesystem_initialiation(void)

  u8 root[] = "C:\\",i;
  CORE.PartitionID = 0xff;
  CORE.CurrentDirectoryType =  RootDirectory; 
  //初始化当前目录为'C:\'
  stringcpy(root,CORE.current_folder);
  //所有FCB设置为非占用
  for (i = 0; i < MaximumFCB;i++)
  {
   FCB.file_openned_flag = UnusedFlag; 
   FCB.Modified_Flag = 0;
  }
  //读取缺省的PBP和相关的信息
  return(Read_partition_PBP(0)); 

#endif


struct mbr MBR;

//write fat1/2
//    arameter: none      
//    Return:none
//
static void write_fat(u8 disk_)
{
 U8 buf[512];
 U32 i;//,begin_sector,counter_of_sector;
 for(i = 0;i<512;i++)
 buf = 0x0;

 for(i = 1;i<10000;i++)
  write_flash_sector(buf,i);
 //run block erase, clr root/fat1/2 region
 //while(block_erase(1,1+SDs_BlockNum-2)== FAIL);

 buf[0] = 0xf8;buf[1] = 0xff;buf[2] = 0xff;buf[3] = 0xff;
 write_flash_sector(buf,1); 
 write_flash_sector(buf,257); 

}
// fill mbr and write fat1/2, root
//    arameter: Tsectors-- total sector on the partition     
//    Return:none
//
static void fill_mbr_and_write_fat_root(U32 Tsectors,U8 disk_)
{U32 i;
 MBR.BS_jmpBoot[0] = 0XEB;
 MBR.BS_jmpBoot[1] = 0X3C;
 MBR.BS_jmpBoot[2] = 0X90;
 MBR.flag[0] = 0x55;
 MBR.flag[1] = 0xaa;
 MBR.BS_OEMName[0] = 'c';
 MBR.BS_OEMName[1] = 'e';
 MBR.BS_OEMName[2] = 'o';
 MBR.BS_OEMName[3] = ' ';
 MBR.BS_OEMName[4] = 's';
 MBR.BS_OEMName[5] = 'o';
 MBR.BS_OEMName[6] = 'f';
 MBR.BS_OEMName[7] = 't';
 /*write bpb*/

 /*BPB_BytsPerSec = 512*/
 MBR.BPB_BytsPerSec[0] = 0;
 MBR.BPB_BytsPerSec[1] = 2;
 /* BPB_SecPerClus*/  
 MBR.BPB_SecPerClus = 64;
 /* RESERVED SECTOR COUNTER = 1*/
 MBR.BPB_RsvdSecCnt[0] = 1;
 MBR.BPB_RsvdSecCnt[1] = 0;
 /*NUM of FATS*/
 MBR.BPB_NumFATs = 2;
 /* RootEntCnt = 1024*/
 MBR.BPB_RootEntCnt[0] = 0x00;
 MBR.BPB_RootEntCnt[1] = 0x4; 
 /* TotSec16[2] = 0*/
 MBR.BPB_TotSec16[0] = 0x0;
 MBR.BPB_TotSec16[1] = 0x0;
 /*0xF8 is the standard value for “fixed”*/
 MBR.BPB_Media = 0XF8;
 /* This field is the FAT12/FAT16 16-bit count of sectors occupied by
ONE FAT*/
 MBR.BPB_FATSz16[0] = 0;
 MBR.BPB_FATSz16[1] = 1;

/*BPB_TotSec32*/
 MBR.BPB_TotSec32[0] = (U8)(Tsectors & 0xff); 
 MBR.BPB_TotSec32[1] = (U8)((Tsectors >> 8) & 0xff);
 MBR.BPB_TotSec32[2] = (U8)((Tsectors >> 16) & 0xff);
 MBR.BPB_TotSec32[3] = (U8)((Tsectors >> 24) & 0xff);
 for(i = 0;i<448;i++)
 MBR.pad = ' ';
 MBR.BS_FilSysType[0] = 'F';
 MBR.BS_FilSysType[1] = 'A';
 MBR.BS_FilSysType[2] = 'T';
 MBR.BS_FilSysType[3] = '1';
 MBR.BS_FilSysType[4] = '6';
 MBR.BS_FilSysType[5] = ' ';
 MBR.BS_FilSysType[6] = ' ';
 MBR.BS_FilSysType[7] = ' ';
 for(i = 0;i<11;i++)
  MBR.BS_VolLab = ' ';
 MBR.BS_DrvNum = 0X0;
 MBR.BS_Reserved1 = 0;
 MBR.BS_BootSig = 0X29;
 MBR.BS_VolID[0] = 0XB9;
 MBR.BS_VolID[1] = 0XD2;
 MBR.BS_VolID[2] = 0X8F;
 MBR.BS_VolID[3] = 0XA8;
 write_flash_sector((U8 *)(&MBR),0);  
 //write_root();
 write_fat(disk_);
}
  
/*
===============================================================================
函数
自动格式化 FAT 文件系统
入口:disk_:盘符   filesystem_type:以FAT16,FAT32为格式化目标  disk_capacity:磁盘容量
出口:SUCC,FAIL
===============================================================================
*/ 
#if complie_FAT16_filesystem_autoformat
u8 FAT_filesystem_autoformat(u8 disk_,u8 filesystem_type,u32 disk_capacity)
{
 u8 buf[512];
 if( read_flash_sector(buf,0) == SUCC ) //read MBR
 {   
     if ( ! ( buf[510] == 0x55 && buf[511] == 0xaa))
  {  
  
 if(filesystem_type== FAT16)
       fill_mbr_and_write_fat_root(disk_capacity,disk_);
         else
 {

 }
  
  }
    }
 return(SUCC); 

#endif
   

/*
===============================================================================
函数 
打开文件
入口:u8 * filename:路径+文件名
出口:返回FCB_SN,FAIL
===============================================================================
*/   
#if complie_open_file 
u8 open_file(u8 * filename)

 u8 FCBsn;
 CORE.FullPathType = FilePath; 
 //检查文件是否存在?
 if(FullPathToSectorCluster(filename) == SUCC)
 {   //有这个文件,则执行FCB分配
     FCBsn = Allocate_FCB();
     if(FCBsn == EAllocate_FCB)
       return(FAIL);
     //初始化FCB的各个参数
 FCB[FCBsn].cur_position = 0;
 FCB[FCBsn].CurBlockInBUF = 0xffff;
 FCB[FCBsn].FirstClusterOfFile = CORE.ClusterOfDirectoryEntry;
     FCB[FCBsn].CurClusterInBUF = FCB[FCBsn].FirstClusterOfFile;
     FCB[FCBsn].ClusterSNInBUF = 0;

 FCB[FCBsn].CurClusterInBUF_for_read= FCB[FCBsn].FirstClusterOfFile;
     FCB[FCBsn].ClusterSNInBUF_for_read = 0;


     FCB[FCBsn].FileSize = CORE.FileSize;
     FCB[FCBsn].Entry_Storedin_Sector = CORE.PreEntrySectorNum ;  //Save sectorNUM of File Directory entry for current file
     FCB[FCBsn].Entry_Storedin_Sector_Offset = CORE.PreEntryoffset; //Save offset in sector of File Directory entry for current file
     FCB[FCBsn].Modified_Flag = 0;
 //检查文件是否已打开?
 if(Check_FileOpened_Status(CORE.ClusterOfDirectoryEntry,FCBsn) == FileAlreadyopenedByOtherHandle)
         FCB[FCBsn].Permission = ReadOnlyPermission;
 else
         FCB[FCBsn].Permission = FullPermission;
   //调用Update_FCB_file_buffer(),将文件读取到文件缓冲区
   #if EnableFileBuf
     Update_FCB_file_buffer(FCBsn);
   #endif 
     return(FCBsn); 
   }
  else
   return(FAIL);//文件不存在,文件打开失败
}
#endif 
/*
===============================================================================
函数 
关闭文件
入口:FCBsn
出口:SUCC,FAIL
===============================================================================
*/  
#if complie_close_file
u8 close_file(u8 FCBsn)
{  
  if(Free_FCB(FCBsn) == SUCC)//释放FCB
    return(SUCC);
  else
    return(FAIL);

#endif 
 
/*
===============================================================================
函数
Directory Entry offset+32 由建立文件/目录使用,遇末簇可自动分配空簇加入簇链
入口:buf--
出口:SUCC,FAIL
===============================================================================
*/             
static u8 CORE_offset_add_32_With_EMPTY_CLUSTER_ALLOCATION(u8 *buf)
{
  u32 temp;
  //位置+32
  CORE.offset += 32;
  if (CORE.offset >= 512)
  {//位置越过一个扇区
   CORE.SectorNum++;
  if (CORE.DirectoryType == RootDirectory)
  {     //针对根目录的处理
        if (CORE.SectorNum < ( CORE.RootDirSectors +  CORE.FirstRootDirSecNum))
         {
           
           CORE.offset = 0; 
           read_flash_sector(buf,CORE.SectorNum);
           return(SUCC);
         }
        else
           return(FAIL);
     }
    else  
     {//位置越过一个簇, 取下一簇,继续处理
        if( (CORE.SectorNum - FirstSectorofCluster(CORE.ClusterNum) + 1) > BPB.sector_per_cluster)
         {
   temp  = CORE.ClusterNum;
           CORE.ClusterNum = Get_Next_Cluster_From_Current_Cluster(CORE.ClusterNum);
           if( CORE.ClusterNum >= 2 && CORE.ClusterNum < 0xfff7)
            {
               CORE.SectorNum = FirstSectorofCluster(CORE.ClusterNum); 
               CORE.offset = 0;
               read_flash_sector(buf,CORE.SectorNum);
               return(SUCC);
            }
           else
   {   //遇末簇,分配空簇加入簇链 
   if(Allocate_EMPTY_CLUSTER_TO_CUR_CLUSTER_CHAIN(temp,&temp,buf) == FAIL)
   return(FAIL);
               CORE.ClusterNum = temp;
               CORE.SectorNum = FirstSectorofCluster(CORE.ClusterNum); 
               CORE.offset = 0;

               read_flash_sector(buf,CORE.SectorNum);
   return(SUCC);
   }
         }
        else
         {
            CORE.offset = 0;
            read_flash_sector(buf,CORE.SectorNum);
            return(SUCC);
         }
     }
  }
  return(SUCC);
}
/*
===============================================================================
函数 
计算长文件目录项的校验和
入口:*entry:longfilenameentry首地址
出口:checksum
===============================================================================
*/
static u8 calculate_checksum_longfilenameentry(u8 *entry)
{
 u8 sum,i;
 sum=0;
 i = 0;
 while (i < 11)
  {
   sum = (sum >> 1) | (sum << 7);
   sum += entry;
   i++;
  }
  return(sum);
}
/*
===============================================================================
函数 
在目录中寻找给定数量DIRECTORY ENTRY的空间
入口:Entry_Resuested_QTY-ENTRY的数量
出口:SUCC,FAIL
===============================================================================
*/
static u8 Seek_Space_to_Write_Directory_Entry(u16 Entry_Resuested_QTY,u8 *buf)
{
  u32 SectorNum_LOCAL,ClusterNum_LOCAL;
  u16 Offset_LOCAL;
  u8 Empty_Entry_Space_Count,found_flag;

  //根目录和非根目录的参数装载
  if(CORE.DirectoryType == RootDirectory)
  {
    CORE.SectorNum = CORE.FirstRootDirSecNum;
  }
  else
  { 
    CORE.ClusterNum = CORE.ClusterOfDirectoryEntry;
    CORE.SectorNum = FirstSectorofCluster(CORE.ClusterNum);
  } 
  CORE.offset = 0;
  read_flash_sector(buf,CORE.SectorNum);
  while(1)
  { 
    SectorNum_LOCAL = CORE.SectorNum; // 保存当前ENTRY的首位置
    ClusterNum_LOCAL = CORE.ClusterNum;
    Offset_LOCAL = CORE.offset;
found_flag = 0;
Empty_Entry_Space_Count = 0;
    do{
       if(buf[CORE.offset] == 0xe5 || buf[CORE.offset] == 0)//空ENTRY
   {
    Empty_Entry_Space_Count++;
//直到找到指定数量的空ENTRY
    if(Empty_Entry_Space_Count >= Entry_Resuested_QTY)
{
     found_flag = 1;
     break;
}
   }
   else
     break;
   if(CORE_offset_add_32_With_EMPTY_CLUSTER_ALLOCATION(buf) == FAIL)
return(FAIL);
}while(1);
    if(found_flag)//找到指定数量的空ENTRY

 CORE.SectorNum = SectorNum_LOCAL; //置空ENTRY的首位置
     CORE.ClusterNum = ClusterNum_LOCAL;
     CORE.offset = Offset_LOCAL;
     break;
}
else if(CORE_offset_add_32_With_EMPTY_CLUSTER_ALLOCATION(buf) == FAIL)
   return(FAIL);
  }   
 return(SUCC); 

}
/*
===============================================================================
函数 
填写一个LFN directory entry
入口:u8 * Directory_Entry_buf,u8 * Entry_Name,u8 LFN_record_FLAG
      u8 Entry_Name,u8 checksum
出口:SUCC,FAIL
===============================================================================
*/
static u8 Fill_LFN_Directory_Entry(u8 * Directory_Entry_buf,u8 * Entry_Name,u8 LFN_record_FLAG,u8 checksum)
{
  u8 i; 
  i = LengthofString(Entry_Name); 
  if(i < 12) 
  {
  do{          //填写空白空间
i++;
if(i >= 13)
break;
        Entry_Name = 0xff;
  }while(1);
  }
  Directory_Entry_buf[0] = LFN_record_FLAG;;
  //填写前5个字节
  for(i = 0;i < 5;i++)
  {
Directory_Entry_buf[1 + i * 2] = Entry_Name;
if(Entry_Name != 0xff)
  Directory_Entry_buf[2 + i * 2] = 0;
else 
      Directory_Entry_buf[2 + i * 2] = 0xff;
  }
  Directory_Entry_buf[11] = ATTR_LONG_NAME; //0x0F, impossible file attribute used as signature
  Directory_Entry_buf[12] = 0;    //Reserved (?). Set to 0x00
  Directory_Entry_buf[13] = checksum;//填写校验和
  //填写中间6个字节
  for(i = 0;i < 6;i++)
  {
Directory_Entry_buf[14 + i * 2] = Entry_Name[5 + i];
if(Entry_Name[5 + i] != 0xff)
  Directory_Entry_buf[15 + i * 2] = 0;
else
      Directory_Entry_buf[15 + i * 2] = 0xff;
  }
  Directory_Entry_buf[26] = 0;  //First cluster number (always 0x0000 for long filename records)
  Directory_Entry_buf[27] = 0;
  //填写2个字节
  for(i = 0;i < 2;i++)
  {
Directory_Entry_buf[28 + i * 2] = Entry_Name[11 + i];
if(Entry_Name[11 + i] != 0xff)
  Directory_Entry_buf[29 + i * 2] = 0;
else
      Directory_Entry_buf[29 + i * 2] = 0xff;
  }
  return(SUCC);
}
/*
===============================================================================
函数 
填写短文件directory entry
入口:u8 * Directory_Entry_buf,u8 * Entry_Name,u32 first_cluster,
      u32 FileSize,u8 attr
出口:SUCC,FAIL
===============================================================================
*/
static u8 Fill_SFN_Directory_Entry(u8 * Directory_Entry_buf,u8 * Entry_Name,u32 first_cluster,u32 FileSize,u8 attr)
{
 u8 i,flag,j;
 for(i = 0;i < 11;i++)
   Directory_Entry_buf = 0x20; 
  i = 0; 
  j = 0;
  flag = FILE_NAME;
  do{ //Directory_Entry分离取得Shortfile Entry name and file extension           
     if( ( * Entry_Name) != 0) 
       { 
        if( flag == FILE_NAME)
         {            
          if(*Entry_Name == '.')//遇到'.',转入填写File extension
             {
              flag  = FILE_EXTENSION;
  Entry_Name++;
             }  
          else
            {
             Directory_Entry_buf =  *Entry_Name;//填写Entry Name
             i++; 
             Entry_Name++;
 if( i > 8 )
               break;
  }
          }
        else if( flag  == FILE_EXTENSION)
         {
          if( j >= 3 )
            break;
           Directory_Entry_buf[8+j] =  *Entry_Name;//填写File extension
          j++;
          Entry_Name++;
         } 
      }
  else
 break;
 }while(1);
 Directory_Entry_buf[11] = attr;
 Directory_Entry_buf[12] = 0;
 Directory_Entry_buf[26] = (u8)(first_cluster & 0xff);  //填写首簇号
 Directory_Entry_buf[27] = (u8)((first_cluster >> 8) & 0xff);
 Directory_Entry_buf[28] = (u8)(FileSize & 0xff);////填写文件长度
 Directory_Entry_buf[29] = (u8)((FileSize >> 8) & 0xff);
 Directory_Entry_buf[30] = (u8)((FileSize >> 16) & 0xff);
 Directory_Entry_buf[31] = (u8)((FileSize >> 24) & 0xff);
 return(SUCC);
}
/*
===============================================================================
函数 
把Longfilename Directory Entry转换为short filename
入口:Directory_Entryirectory_Entry name,attr:attr of Directory_Entry
出口:SUCC,FAIL
===============================================================================
*/
static u8 LFN_convert_to_SFN(u8 * Directory_Entry,u8 * SFN_Directory_Entry_buf)
{
 u8 i,flag,j;
 for(i = 0;i < 11;i++)
   SFN_Directory_Entry_buf = 0x20; //初始化DIRECTORY ENTRY
  i = 0; 
  j = 0;
  flag = FILE_NAME;
  do{           
     if( ( * Directory_Entry) != 0) 
       { 
        if( flag == FILE_NAME)
         {            
          if(*Directory_Entry == '.')//遇到'.',转入填写File extension
             {
              flag  = FILE_EXTENSION;
  Directory_Entry++;
             }  
          else
            {
             SFN_Directory_Entry_buf =  *Directory_Entry;//填写Entry Name
             i++; 
 if(i >= 6)
 {
  SFN_Directory_Entry_buf = '~';
              SFN_Directory_Entry_buf[i+1] = '1';
              do{ 
      if(*Directory_Entry == '.' || ( * Directory_Entry) == 0 )   
  {
    flag  = FILE_EXTENSION;
    break;
  }
  else
                    Directory_Entry++;
  }while(1);
 }
             Directory_Entry++;
            }
          }
        else if( flag  == FILE_EXTENSION)
         {
          if( j >= 3 )
            return(FAIL);//填写File extension
          SFN_Directory_Entry_buf[8+j] =  *Directory_Entry;
          j++;
          Directory_Entry++;
         } 
      }
  else
  return(SUCC);
 }while(1);
}

/*
===============================================================================
函数 
将写Longfilename Directory Entry入磁盘
入口:Directory_Entryirectory_Entry name,attr:attr of Directory_Entry
出口:SUCC,FAIL
===============================================================================
*/
static u8 Write_LongFileName_Entry(u8 * Directory_Entry,u8 attr,u32 first_cluster,u8 * buf,u32 FileSize)
{
  u16 len;
  u8 i,checksum;
  u8 Directory_Entry_buf[32];
  u8 SN,LFN_record_FLAG;
  //计算需要的Directory_Entry空间,每个Directory_Entry空间为32个字节,计算结果放在len中
  len = LengthofString(Directory_Entry) / 13;
  if(LengthofString(Directory_Entry) % 13)
len++;
  SN = len; 
  //从long-filename directory entry处理得其对应的short-filename directory entry
  LFN_convert_to_SFN(Directory_Entry,Directory_Entry_buf);
  //计算short-filename directory entry校验和
  checksum = calculate_checksum_longfilenameentry(Directory_Entry_buf);
  //处理last long-filename directory entry for file
  read_flash_sector(buf,CORE.SectorNum);    
  LFN_record_FLAG = SN | (u8)Last_LFN_Record;
  Fill_LFN_Directory_Entry(buf + CORE.offset,Directory_Entry + (len - 1) * 13,LFN_record_FLAG,checksum);
  len--;
  write_flash_sector(buf,CORE.SectorNum);
  CORE_offset_add_32(buf);
  LFN_record_FLAG = SN;
  //处理其它LFN directory entry
  //do{
  while(len){
   SN--;
   Directory_Entry[len * 13] = 0;
   Fill_LFN_Directory_Entry(buf + CORE.offset,Directory_Entry + (len - 1) * 13,SN,checksum);
   len--;
   write_flash_sector(buf,CORE.SectorNum);
   CORE_offset_add_32(buf);
  }

  
  //处理LFN 相应的short-filename directory entry
  Directory_Entry_buf[11] = attr;
  Directory_Entry_buf[12] = 0;
  Directory_Entry_buf[26] = (u8)(first_cluster & 0xff);  //填写首簇号
  Directory_Entry_buf[27] = (u8)((first_cluster >> 8) & 0xff);
  Directory_Entry_buf[28] = (u8)(FileSize & 0xff);////填写文件长度
  Directory_Entry_buf[29] = (u8)((FileSize >> 8) & 0xff);
  Directory_Entry_buf[30] = (u8)((FileSize >> 16) & 0xff);
  Directory_Entry_buf[31] = (u8)((FileSize >> 24) & 0xff); 
  for(i = 0;i < 32;i++)
{
  buf[CORE.offset + i] = Directory_Entry_buf;
}
  write_flash_sector(buf,CORE.SectorNum);
  return(SUCC);
}
/*
===============================================================================
函数 
添加Directory_Entry至目录
入口:Directory_Entry-
出口:SUCC,FAIL
===============================================================================
*/
static u8 Add_A_Directory_Entry_(u8 * Directory_Entry,u8 attr,u32 first_cluster,u32 FileSize)
{
u16 len;
u8 buf[512];
u8 Directory_Entry_buf[32];
u8 temp,i;
    
if(attr & ATTR_DIRECTORY)
{//给新建的directory分配簇号再写入默认两个目录,“.”和“..”
  u32 sector_local;
  if( Allocate_An_Empty_cluster(&first_cluster,buf)== FAIL)
     return(FAIL);
  //初始化默认两个目录,目录名分别取名为“.”和“..”
  sector_local =  FirstSectorofCluster(first_cluster);
      for(i = 0;i < 11;i++)
 buf = 0x20; 
  buf[0] = '.';//填写目录名“.”
  buf[11] = attr;
  buf[12] = 0;
  buf[26] = (u8)(first_cluster & 0xff);  //填写当前目录簇号
  buf[27] = (u8)((first_cluster >> 8) & 0xff);
  buf[28] = 0;////填写文件长度
  buf[29] = 0;
  buf[30] = 0;
  buf[31] = 0;
      for(i = 0;i < 11;i++)
 buf[i + 32] = 0x20; 
  buf[32] = '.';   //填写目录名“..”
  buf[33] = '.';
  buf[32+11] = attr;
  buf[32+12] = 0;
  buf[32+26] = (u8)(CORE.ClusterNum & 0xff);  //填写当前目录父目录的首簇号
  buf[32+27] = (u8)((CORE.ClusterNum >> 8) & 0xff);
  buf[32+28] = 0;////填写文件长度
  buf[32+29] = 0;
  buf[32+30] = 0;
  buf[32+31] = 0;
  buf[64] = 0;
  write_flash_sector(buf,sector_local);
}
//计算Directory_Entry需要多少个空间,Directory_Entry每个空间为32个字节,计算结果放在len中
len = LengthofString(Directory_Entry) / 13;
if(LengthofString(Directory_Entry) % 13)
len++;
if(len > 1)
len++;
if(len == 1)
{  
   u8 count;
   count = 0;
   do{
   if(Directory_Entry[count] == 0 || Directory_Entry[count] == '.')
   break;
   count++;
   }while(1);
   if(count > 8)
   len = 2;

}
//寻找指定数量的空间
if(Seek_Space_to_Write_Directory_Entry(len,buf) == SUCC)

  if(len == 1)  //写短文件名
  {
UPCASE(Directory_Entry);
Fill_SFN_Directory_Entry(Directory_Entry_buf,Directory_Entry, first_cluster,FileSize,attr);
read_flash_sector(buf,CORE.SectorNum);
for(temp = 0;temp < 32;temp++)

  buf[CORE.offset + temp] = Directory_Entry_buf[temp];
}
write_flash_sector(buf,CORE.SectorNum);
return(SUCC);
  } 
  else//写长文件名
  { 
    return(Write_LongFileName_Entry(Directory_Entry,attr,first_cluster,buf,FileSize));
  }
}
else
 return(FAIL);
}

 /*
===============================================================================
函数 
建立文件
入口:无
出口:无
===============================================================================
*/  
#if complie_create_file
u8 create_file(u8 * filename)

 u16 len;
 u16 temp;
 u8 buf[260],status;
 stringcpy(filename,buf);
 CORE.FullPathType = FilePath;
 if(FullPathToSectorCluster(filename) != SUCC)  //检查文件是否已经存在
 {   //文件不存在,才可以建文件
     len = LengthofString(buf);
 //从文件名中分离路径
     temp = len - 1;
     do{ 
         if(buf[temp] =='\\')
  {
        buf[temp] = 0;
temp++;
        break;
  }
      if(!temp)
            break;
      temp--;
 }while(1);
     CORE.FullPathType = DirectoryPath; 
 if(!temp)
 {  //相对路径,当前目录下建文件
   if(FullPathToSectorCluster(CORE.current_folder) == FAIL)
  {
   return(FAIL);
  }
 } 
 else if(temp <= 3 && buf[1] == ':')
 {
  u8 TEMP[4];
  TEMP[0] = buf[0];
  TEMP[1] = buf[1];
  TEMP[2] = '\\';
  TEMP[3] = 0;
  //根目录下建文件
  if(FullPathToSectorCluster(TEMP) == FAIL)
  {
   return(FAIL);
  }   
 }
 else 
 {
   if(FullPathToSectorCluster(buf) == FAIL)
 return(FAIL);
 }
 //文件写入磁盘
 status = Add_A_Directory_Entry_(buf+temp,ATTR_ARCHIVE,0,0);
 return(status);
  }
  else
 return(FAIL);
}
#endif
/*
===============================================================================
函数
建立目录
入口:foldername--目录的路径
出口:无
===============================================================================
*/
#if complie_create_floder
u8 create_floder(u8 * foldername)
{  
 u16 len;
 u16 temp;
 u8 TEMP[4];
 u8 buf[260],status;
 stringcpy(foldername,buf);

 CORE.FullPathType = DirectoryPath; 
 if(FullPathToSectorCluster(buf) != SUCC)  //检查目录是否已经存在
  {//目录不存在,才可以建目录
     len = LengthofString(buf);
 //从目录名中分离路径
     temp = len - 1;
     do{
         if(buf[temp] =='\\')
  {
        buf[temp] = 0;
temp ++;
        break;
  }
      if(!temp)
            break;
      temp--;
 }while(1);
     CORE.FullPathType = DirectoryPath; 
 if( ! temp)
 { CORE.FullPathType = DirectoryPath; //相对路径,当前目录下建目录
   if(FullPathToSectorCluster(CORE.current_folder) == FAIL)
  {
   return(FAIL);
  }
 } 
 else if(buf[1] == ':' && temp <= 3)
 {
  TEMP[0] = buf[0];
  TEMP[1] = buf[1];
  TEMP[2] = '\\';
  TEMP[3] = 0;
  CORE.FullPathType = DirectoryPath; 
  //根目录下建目录
  if(FullPathToSectorCluster(TEMP) == FAIL)
    {
   return(FAIL);
  }
 }
 else if(FullPathToSectorCluster(buf) == FAIL)
 { 
   return(FAIL);  
  }
 //目录写入磁盘
 status = Add_A_Directory_Entry_(buf + temp,ATTR_DIRECTORY,0,0);
     return(status);
  }
  else
    return(FAIL);


}
#endif 

/*
===============================================================================
函数
当前操作位置设定函数
入口:无
出口:无
===============================================================================
*/ 
#if compile_fseek
u8 f_seek(u8 FCBsn, s32 offset, u8 origin)
{     
 if(FCB[FCBsn].file_openned_flag == UnusedFlag)
    return(FAIL);//FCB未占用,返回FAIL
 switch(origin)
  { 
   case SEEK_SET:  //相对于文件开始位置寻址 
    { 
      if(offset < 0 || (u32)offset >= FCB[FCBsn].FileSize)
        return(FAIL);
      FCB[FCBsn].cur_position = offset; 
    //根据文件的当前位置更新文件缓冲
    #if EnableFileBuf
      Update_FCB_file_buffer(FCBsn); 
    #endif
      break;
    }
   case SEEK_CUR: //相对于文件当前位置寻址 
    { 
      if(((FCB[FCBsn].cur_position + offset) < 0 )|| 
        ((FCB[FCBsn].cur_position + offset)  >= FCB[FCBsn].FileSize)) 
         return(FAIL); 
      FCB[FCBsn].cur_position += offset;
     //根据文件的当前位置更新文件缓冲
     #if EnableFileBuf
      Update_FCB_file_buffer(FCBsn);
     #endif
      break;
    }
   case SEEK_END: //相对于文件结束位置寻址 
    {
      if(offset > 0)
       return(FAIL);
       FCB[FCBsn].cur_position = FCB[FCBsn].FileSize + offset;
   //根据文件的当前位置更新文件缓冲
      #if EnableFileBuf
       Update_FCB_file_buffer(FCBsn);
      #endif
      break;
    }
   default:return(FAIL);
  }
 return(SUCC);
}
#endif 
/*
===============================================================================
函数
读文件
入口:u8 FCBsn,u8* buffer,u16 length
出口:读取的字节数
===============================================================================
*/ 
#if complie_read_file
u16 read_file(u8 FCBsn,u8* buffer,u16 length)
{  
 #if EnableFileBuf
  #if Read_File_Optimization_Selector
   u16 OffsetInbuf,temp;
   u32 readed_bytes;
   u8 * point;
   u32 i;
   if(FCB[FCBsn].file_openned_flag == UnusedFlag)
     return(0); //FCB未占用,返回FAIL
   readed_bytes = 0;//已读取的字节数置0
   if((FCB[FCBsn].cur_position + length) > FCB[FCBsn].FileSize)
   { //如果读取的位置已至尾,读取length个字符超过了可读取的字符数.
 //length置为当前可以读取的字符数
     length = FCB[FCBsn].FileSize - FCB[FCBsn].cur_position ;
 if(!length)
 return(readed_bytes);
   }  
   OffsetInbuf = (FCB[FCBsn].cur_position % (FileBUFSize * TotalFileBUFsQTYeachFCB));
   if(!OffsetInbuf)
   {//根据文件的当前位置更新文件缓冲
     Update_FCB_file_buffer(FCBsn);
   }
   temp = FileBUFSize * TotalFileBUFsQTYeachFCB - OffsetInbuf;
   point =  FCB[FCBsn].FileBUF + OffsetInbuf;
   if(temp >= length)
   { //length字节的数据可以直接从缓冲区中读数据
     for(i = 0;i < length ;i++)
       buffer = point;
     FCB[FCBsn].cur_position += length;
     return(i); //读取结束
   }
   else 
   { //直接从缓冲区中读数据
     for(i = 0;i < temp ;i++)
       buffer = point;
     FCB[FCBsn].cur_position += temp;
 readed_bytes += i;
 buffer += temp;
     length -= temp;
   }   
   do{
      Update_FCB_file_buffer(FCBsn);//根据文件的当前位置更新文件缓冲
      if(length <= FileBUFSize * TotalFileBUFsQTYeachFCB)
  {  //length字节的数据可以直接从缓冲区中读数据,读取结束
        for(i = 0;i < length ;i++)
          buffer = FCB[FCBsn].FileBUF;
        FCB[FCBsn].cur_position += length;
    readed_bytes += i; 
        return(readed_bytes); //读取结束  
  }  
  else
  { //直接从缓冲区中读数据
        for(i = 0;i < FileBUFSize * TotalFileBUFsQTYeachFCB ;i++)
          buffer = FCB[FCBsn].FileBUF;
        FCB[FCBsn].cur_position += FileBUFSize * TotalFileBUFsQTYeachFCB;
        length -= FileBUFSize * TotalFileBUFsQTYeachFCB;
    readed_bytes += FileBUFSize * TotalFileBUFsQTYeachFCB;
    buffer += FileBUFSize * TotalFileBUFsQTYeachFCB;
  }
   }while(1);
  #else
   u16 i,OffsetInbuf;
   if(FCB[FCBsn].file_openned_flag == UnusedFlag)
    return(0); //FCB未占用,返回FAIL
   for(i = 0;i < length ;i++)
   {                                   
  if(FCB[FCBsn].cur_position >= FCB[FCBsn].FileSize)
        return(i);
  OffsetInbuf = (u16)(FCB[FCBsn].cur_position % (FileBUFSize * TotalFileBUFsQTYeachFCB));
      if ( ! OffsetInbuf)
        Update_FCB_file_buffer(FCBsn);  //根据文件的当前位置更新文件缓冲
      buffer = FCB[FCBsn].FileBUF [OffsetInbuf];
      FCB[FCBsn].cur_position ++;
   }
  return(i); 
 #endif
#else
   //return(i);
#endif
}  
#endif
/*
===============================================================================
函数
写文件
入口:无
出口:无
===============================================================================
*/    
#if complie_write_file
u16 write_file(u8 FCBsn,u8* buffer, u16 length)
{  
  #if EnableFileBuf
   #if Write_File_Optimization_Selector
   u16 temp;
   u32 writed_bytes;
   u16 i,OffsetInbuf;
   u8 *point;     
   if(FCB[FCBsn].file_openned_flag == UnusedFlag)
     return(0);//FCB未占用,返回FAIL
   if(FCB[FCBsn].Permission == ReadOnlyPermission || length == 0)
 return(0); //如果文件为只读, 则返回
   writed_bytes = 0;
   OffsetInbuf = (FCB[FCBsn].cur_position % (FileBUFSize * TotalFileBUFsQTYeachFCB));
   if(!OffsetInbuf)
  {  
         if(Update_FCB_file_buffer(FCBsn) == FAIL) 
 return(0);//将file buffer回写磁盘,再更新FILE BUFFER
  } 
   temp = FileBUFSize * TotalFileBUFsQTYeachFCB - OffsetInbuf;
   if(temp >= length)
   { //直接向缓冲区中写数据,并回写磁盘
 point =  FCB[FCBsn].FileBUF + OffsetInbuf;
     for(i = 0;i < length ;i++)
       point = buffer;
     FCB[FCBsn].cur_position += length;
 FCB[FCBsn].Modified_Flag = 1;
 if(FCB[FCBsn].cur_position >= FCB[FCBsn].FileSize)
  FCB[FCBsn].FileSize = FCB[FCBsn].cur_position ;
     if(Writeback_FCB_file_buffer(FCBsn) == FAIL)  
    i = 0;//将file buffer回写磁盘,再更新FILE BUFFER
     return(i);
   }
   else
   { //直接向缓冲区中写数据,
 point =  FCB[FCBsn].FileBUF + OffsetInbuf;
     for(i = 0;i < temp ;i++)
       point = buffer;
 FCB[FCBsn].Modified_Flag = 1;
     FCB[FCBsn].cur_position += temp;
 writed_bytes += temp;
 buffer+= temp;
     length -= temp;
 if(FCB[FCBsn].cur_position >= FCB[FCBsn].FileSize)
  FCB[FCBsn].FileSize = FCB[FCBsn].cur_position; 
   }
   do{
     if(Update_FCB_file_buffer(FCBsn) == FAIL) 
    return(writed_bytes);// 将file buffer回写磁盘,再更新FILE BUFFER
     if(length <= FileBUFSize * TotalFileBUFsQTYeachFCB)
 {//将剩余的数据直接向缓冲区中写,并回写磁盘
      for(i = 0;i < length ;i++)
        FCB[FCBsn].FileBUF  = buffer;
      FCB[FCBsn].cur_position += length;
  FCB[FCBsn].Modified_Flag = 1; 
  if(FCB[FCBsn].cur_position >= FCB[FCBsn].FileSize)
  FCB[FCBsn].FileSize = FCB[FCBsn].cur_position ;
      if(Writeback_FCB_file_buffer(FCBsn) == FAIL) 
    i = 0;// 将file buffer回写磁盘,再更新FILE BUFFER
  writed_bytes += i; 
      return(writed_bytes);  
 }
 else
 {//直接向缓冲区中写数据,写满一个缓冲区
      for(i = 0;i < FileBUFSize * TotalFileBUFsQTYeachFCB ;i++)
        FCB[FCBsn].FileBUF  = buffer;
  FCB[FCBsn].Modified_Flag = 1;
      FCB[FCBsn].cur_position += FileBUFSize * TotalFileBUFsQTYeachFCB;
      length -= FileBUFSize * TotalFileBUFsQTYeachFCB;
  writed_bytes += FileBUFSize * TotalFileBUFsQTYeachFCB;
  buffer += FileBUFSize * TotalFileBUFsQTYeachFCB;
  if(FCB[FCBsn].cur_position >= FCB[FCBsn].FileSize)
  FCB[FCBsn].FileSize = FCB[FCBsn].cur_position ;
 }
   }while(1); 
   return(writed_bytes);
  #else 
   u16 i,OffsetInbuf;
   if(FCB[FCBsn].file_openned_flag == UnusedFlag)
     return(0);//FCB未占用,返回FAIL
   if(FCB[FCBsn].Permission == ReadOnlyPermission)
 return(0);//如果文件为只读, 则返回
   for(i = 0;i < length ;i++)
   {                                    
    OffsetInbuf = (u16)(FCB[FCBsn].cur_position % (FileBUFSize * TotalFileBUFsQTYeachFCB));
if(!OffsetInbuf)
  { 
         if(Update_FCB_file_buffer(FCBsn) == FAIL)
 return(0);// 将file buffer回写磁盘,再更新FILE BUFFER
  } 
      FCB[FCBsn].FileBUF [OffsetInbuf] = buffer;
  if(!FCB[FCBsn].Modified_Flag)
     FCB[FCBsn].Modified_Flag = 1 ;    
      if(FCB[FCBsn].cur_position >= FCB[FCBsn].FileSize)
  FCB[FCBsn].FileSize = FCB[FCBsn].cur_position + 1;
  FCB[FCBsn].cur_position ++;
   }
   if(Writeback_FCB_file_buffer(FCBsn) == FAIL)  
   i = 0;// 将file buffer回写磁盘,再更新FILE BUFFER
   return(i);
  #endif
 #else
  return(i);
 #endif
}   
 #endif
/*
===============================================================================
函数
改变当前目录
入口:foldername:目录名,
      mode: 0-- 进入目录; >0--返回上层目录
出口:SUCC,FAIL
===============================================================================
*/
#if compile_cd_folder
u8 cd_folder(u8 *foldername,u8 mode)

  u16 offset;
  if(mode)  //mode=1,返回上层目录
   {
    if (CORE.CurrentDirectoryType == RootDirectory)//如果当前目录为根目录,则返回上层目录失败
     return(0x55);
    else
    {
 CORE.FullPathType = DirectoryPath;
     if(FullPathToSectorCluster(CORE.current_folder) != SUCC)
   return(FAIL);
     //寻找目录分隔符'\',将当前目录减去一个目录
 offset = LengthofString(CORE.current_folder);
     offset --;
     do{
      if(CORE.current_folder[offset] != '\\')
  CORE.current_folder[offset] = 0;
      else
      {
   if(CORE.current_folder[offset-1] == ':')
 break;
       CORE.current_folder[offset] = 0;
       break;
      }
       offset--;
     }while(1);        

     if(LengthofString(CORE.current_folder) <= 3)
       CORE.CurrentDirectoryType = RootDirectory;
 else
       CORE.CurrentDirectoryType = NoneRootDirectory;
     return(SUCC);
    }
   }
   else  //进入子目录
   {
    CORE.FullPathType = DirectoryPath;      
    if(FullPathToSectorCluster(foldername) == SUCC)//检查目录是否存在?

  if((* foldername) >= 'C' && ( * foldername ) <= 'Z')
  {
       if(* (foldername + 1) == ':' &&  * (foldername + 2 ) == '\\')
  {//绝对路径,直接拷入CORE.current_folder
           stringcpy(foldername,CORE.current_folder);  
  }
  else
  { //相对路径,与CORE.current_folder连接后,拷贝进入CORE.current_folder
if(LengthofString(CORE.current_folder) != 3)
{
 CORE.current_folder[LengthofString(CORE.current_folder)] = '\\';
             CORE.current_folder[LengthofString(CORE.current_folder) + 1] = 0;
}
    concanenateString(CORE.current_folder,foldername);
  }
  }
  else if(*foldername == '\\')
  {
      stringcpy(foldername,CORE.current_folder + 1);
  }
//保存目录的相关参数
 if(LengthofString(CORE.current_folder) <= 3)
 {
      CORE.SectorNum = CORE.FirstRootDirSecNum; 
  CORE.CurrentDirectoryType = RootDirectory; 
 }
 else
 {
   CORE.CurrentDirectoryType = NoneRootDirectory;
       CORE.ClusterNum = CORE.ClusterOfDirectoryEntry;
   CORE.ClusterNOofCurrentFolder = CORE.ClusterOfDirectoryEntry;
       CORE.SectorNum =  FirstSectorofCluster(CORE.ClusterNum); 
 }
 CORE.offset = 0;
 return(SUCC);
}   
   }
   return(FAIL);
}
#endif 

/*
===============================================================================
函数
清除长文件名目录项
入口:buf
出口:SUCC,FAIL
===============================================================================
*/ 
static u8 Remove_LONGFILENAME(u8 *buf,u8 *folder_filename)
{
  u32 Cluster,Sector;
  u16 offset;//,length;
  u8 NextDirectoryEntryEMPTY; 
  u8 First_Entry_Deleted;
  Cluster = CORE.ClusterNum;
  Sector = CORE.SectorNum;
  offset = CORE.offset;
  First_Entry_Deleted = 0;
  read_flash_sector(buf,Sector);
  if(!buf[CORE.offset])//目录项之后的是空的吗?
   NextDirectoryEntryEMPTY = 1;
  else
   NextDirectoryEntryEMPTY = 0;  

  do{
  //位置转向前一个目录项
    if(offset == 0)
    { //遇到扇区边界--执行边界处理
      write_flash_sector(buf,Sector);
      Sector--; 
      offset = 512 - 32;
      if(CORE.DirectoryType == RootDirectory)
  { 
  if(Sector < CORE.FirstRootDirSecNum)
      return(SUCC); 
  }        
      else if (Sector  < FirstSectorofCluster(Cluster))
  { //遇到簇边界,--执行边界处理
         Cluster = Get_Previous_Cluster_From_Current_Cluster(Cluster);
         Sector = FirstSectorofCluster(Cluster) ;
 Sector += BPB.sector_per_cluster - 1;

       } 
      read_flash_sector(buf,Sector);     
    }
else
{
  offset -= 32;
}

    if(buf[offset + 11] == ATTR_LONG_NAME)
    {
  if(NextDirectoryEntryEMPTY)//将目录项置为删除
        buf[offset] = 0x0;
  else
        buf[offset] = 0xe5;
    }
    else
{
if(First_Entry_Deleted == 0)
{
      if(NextDirectoryEntryEMPTY)
           buf[offset] = 0x0;//将目录项置为删除
      else
           buf[offset] = 0xe5;
 First_Entry_Deleted = 1;
}
    else
{
 write_flash_sector(buf,Sector);
 return(SUCC);
}
}
  }while(1);
  return(SUCC);
}
/*
===============================================================================
函数
文件删除
入口:filename:文件路径
出口:SUCC,FAIL
===============================================================================
*/ 
#if complie_delete_file
u8 delete_file( u8 *filename)

 u8 buf[512];
 CORE.FullPathType = FilePath; 
 if(FullPathToSectorCluster(filename) == SUCC)//检查文件是否存在?
    {//检查文件是否被打开?
 if(Check_FileOpened_Status(CORE.ClusterOfDirectoryEntry,0xff) == FileAlreadyopenedByOtherHandle)
         return(FAIL);//文件打开中,删除失败
 //调用子函数,删除文件目录项
     if(Remove_LONGFILENAME(buf,filename) != SUCC)
         return(FAIL);
 if(CORE.ClusterOfDirectoryEntry)//删除文件占用的簇链
       FreeClusterChain(CORE.ClusterOfDirectoryEntry); 
     return(SUCC); 
   }
 else
     return(FAIL);
}
#endif
/*
===============================================================================
函数
目录删除
入口:char * foldername--路径+目录名
出口:SUCC,FAIL
===============================================================================
*/    
#if complie_delete_folder
u8 delete_folder(u8 * foldername)
{
 u8 buf[512];
 u32 sector;
 CORE.FullPathType = DirectoryPath; 
 if(FullPathToSectorCluster(foldername) == SUCC)//检查文件是否存在?
   {
     sector = FirstSectorofCluster(CORE.ClusterOfDirectoryEntry);
 read_flash_sector(buf,sector);
     if(buf[64] != 0)  //不允许删除非空目录
 {
  return(FAIL); 
 }
     //调用子函数,删除目录项
 Remove_LONGFILENAME(buf,foldername);
     //删除目录占用的簇链
     FreeClusterChain(CORE.ClusterOfDirectoryEntry);
     return(SUCC);
   }
  else
    return(FAIL);

     

#endif
/*
===============================================================================
函数    
重命名文件
入口:oldfilename:指向旧文件,newfilename:指向新文件(新文件名)
出口:SUCC,FAIL
===============================================================================
*/  
#if complie_rename_file
u8 rename_file(u8 * oldfilename1,u8 * newfilename1)
{  
 u16 len,temp; 
 u8 buf[512];
 u32 first_cluster;
 u32 FileSize;  
 u8 buff1[260],buff[260], *newfilename,temp2,position,*oldfilename;
 stringcpy(newfilename1,buff);
 stringcpy(oldfilename1,buff1);
 newfilename = buff;
 oldfilename = buff1;
 UPCASE(oldfilename);
 UPCASE(newfilename);

 CORE.FullPathType = FilePath; 
 if(FullPathToSectorCluster(oldfilename) == SUCC)//检查旧文件是否存在?
 {  //检查旧文件是否被打开?
if(Check_FileOpened_Status(CORE.ClusterOfDirectoryEntry,0xff) == FileAlreadyopenedByOtherHandle)
           return(FAIL);  //旧文件被打开中,不能删除
//首簇号,FileSize保存
FileSize = CORE.FileSize;
first_cluster = CORE.ClusterOfDirectoryEntry;
    len = LengthofString(newfilename);
    temp = len - 1;
//从新文件路径中分离出文件名
     do{
         if(newfilename[temp] =='\\')
  {
temp++;
        break;
  }
      if(!temp)
            break;
      temp--;
 }while(1);
 //从旧文件路径中分离出路径
temp2 = 0;
position = 0;
do{
    if(oldfilename[temp2] == 0)
{
temp2 = position;
    break;
}  
if(oldfilename[temp2] == '\\')
position = temp2;
 temp2++;
}while(1);


if(temp2 == 0)
{
  len = LengthofString(CORE.current_folder);
  stringcpy(CORE.current_folder,oldfilename);
  if(len > 3)
  {
     oldfilename[len] = '\\';  
 oldfilename[len+1] = 0;
  }
  /*  检查新文件可能有的重复情况,发现重复的情况则直接退出函数 */
      concanenateString(oldfilename,newfilename + temp);
      if(FullPathToSectorCluster(oldfilename) == SUCC)
      return(FAIL);
}
else
{
  oldfilename[temp2 + 1] = 0;
      concanenateString(oldfilename,newfilename + temp);
      /*  检查新文件可能有的重复情况,发现重复的情况则直接退出函数 */
  if(FullPathToSectorCluster(oldfilename) == SUCC)
      return(FAIL);

}

    stringcpy(oldfilename1,oldfilename);
CORE.FullPathType = FilePath; 
    FullPathToSectorCluster(oldfilename);
    Remove_LONGFILENAME(buf,oldfilename);//删除目录项,簇链不变化

    if(temp2 == 0)
{ //旧文件名为相对路径寻址
  CORE.FullPathType = DirectoryPath; 
      FullPathToSectorCluster(CORE.current_folder); 
}
else
{
if(temp2 < 3 && oldfilename[1] == ':')
oldfilename[temp2 + 1] = 0;
else
            oldfilename[temp2] = 0;
//旧文件句为绝对路径寻址
CORE.FullPathType = DirectoryPath;
        FullPathToSectorCluster(oldfilename);

}
//写入新文件目录项,完成改名
    Add_A_Directory_Entry_(newfilename + temp,ATTR_ARCHIVE,first_cluster,FileSize);
    return(SUCC);
  }
 else
   return(FAIL);
}   
#endif

/********************************************************************************************
函数
进入目录(由disk enumeration使用)
入口:无
出口:SUCC,FAIL
********************************************************************************************/
static u8 cd__folder_for_disk_enum()
{

     CORE.FullPathType = DirectoryPath;
 //检查目录是否存在?
     if(FullPathToSectorCluster(CORE.current_folder_for_disk_enum) != SUCC)
      return(FAIL);
 //保存目录参数
 if(LengthofString(CORE.current_folder_for_disk_enum) <= 3)
 {//保存根目录参数
      CORE.SectorNum = CORE.FirstRootDirSecNum; 
  CORE.CurrentDirectoryType = RootDirectory; 
 }
 else
 { //保存非根录参数
   CORE.CurrentDirectoryType = NoneRootDirectory;
       CORE.ClusterNum = CORE.ClusterOfDirectoryEntry;
   CORE.ClusterNOofCurrentFolder = CORE.ClusterOfDirectoryEntry;
       CORE.SectorNum =  FirstSectorofCluster(CORE.ClusterNum); 
 }
 CORE.offset = 0;
 return(SUCC);              
}

/********************************************************************************************
函数
退出目录(由disk enumeration使用)
入口:无
出口:SUCC,FAIL
********************************************************************************************/ 
static u8 cd__() 

  u16 offset;
  u8 entry[256],extension[20],folderSplit[256],i;
  i = 254;
  folderSplit = 0;
  i --;

     offset = LengthofString(CORE.current_folder_for_disk_enum);
     offset --;
 //从current_folder_for_disk_enum中分离出上一级目录
 //并保存分离丢弃的目录进入folderSplit[],以用于CD__后面的位置定位
     do{
      if(CORE.current_folder_for_disk_enum[offset] != '\\')
  {
  folderSplit = CORE.current_folder_for_disk_enum[offset];
  CORE.current_folder_for_disk_enum[offset] = 0;
  }
      else
      {
   if(CORE.current_folder_for_disk_enum[offset-1] == ':')
 break;
       CORE.current_folder_for_disk_enum[offset] = 0;
       break;
      }
       offset--;
   i--;
     }while(1);     
     //进入上一级目录
 cd__folder_for_disk_enum();
 
 do{ //CD__之后的位置定位到被丢弃目录之后
         //读取一个ENTRY 
 if(GetEntryFromDirectory(entry,extension,Get_All_Entries) == FAIL)
  {
     if(CORE.CurrentDirectoryType == RootDirectory)
 return(0x55);
  }

      //读取了非目录,继续读下一个ENTRY
          if(!(CORE.Entry_Attr & ATTR_DIRECTORY))
  continue;
          //读取的目录是否与被丢弃目录相同,相同退出
  if(stringcmp(entry,folderSplit+i+1) == SUCC)
  break;
 }while(1);

     if(LengthofString(CORE.current_folder_for_disk_enum) <= 3)
       CORE.CurrentDirectoryType = RootDirectory;
 else
       CORE.CurrentDirectoryType = NoneRootDirectory;
     return(SUCC);
}
/********************************************************************************************
函数
保存枚举的当前位置
入口:无
出口:无
********************************************************************************************/
save_enum_vars(u8 disk_or_folder)
{
   //保存ClusterNum,SectorNum,offset
   CORE.DIR_ENUM_ClusterNum[disk_or_folder] = CORE.ClusterNum;  
   CORE.DIR_ENUM_SectorNum[disk_or_folder] =CORE.SectorNum ;
   CORE.DIR_ENUM_offset[disk_or_folder] = CORE.offset;
   //保存ClusterNum,SectorNum,offset
   CORE.DIR_ENUM_ClusterOfDirectoryEntry[disk_or_folder] = CORE.ClusterOfDirectoryEntry;
   CORE.DIR_ENUM_DirectoryType[disk_or_folder] = CORE.DirectoryType; 
   CORE.DIR_ENUM_FullPathType[disk_or_folder] = CORE.FullPathType;
   CORE.DIR_ENUM_CurPathType[disk_or_folder] = CORE.CurPathType; 

}

/********************************************************************************************
函数
恢复枚举的当前位置
入口:无
出口:无
********************************************************************************************/
restore_enum_vars(u8 disk_or_folder)
{
   //恢复ClusterNum,SectorNum,offset
   CORE.ClusterNum = CORE.DIR_ENUM_ClusterNum[disk_or_folder];   
   CORE.SectorNum = CORE.DIR_ENUM_SectorNum[disk_or_folder];
   CORE.offset = CORE.DIR_ENUM_offset[disk_or_folder];
   //恢复ClusterNum,SectorNum,offset
   CORE.ClusterOfDirectoryEntry = CORE.DIR_ENUM_ClusterOfDirectoryEntry[disk_or_folder];  
   CORE.DirectoryType = CORE.DIR_ENUM_DirectoryType[disk_or_folder]; 
   CORE.FullPathType = CORE.DIR_ENUM_FullPathType[disk_or_folder];
   CORE.CurPathType = CORE.DIR_ENUM_CurPathType[disk_or_folder]; 

}
/********************************************************************************************
函数
列举当前目录下的所有文件和目录(子目录不列举)
入口:无
出口:无
********************************************************************************************/  
#if complie_folder_dir
u8 folder_enumeration(u8 *return_string,u8 mode,u8 *ATTR)

  u8  Extension[20];
  u16 temp;
  if(mode == 0x0)
  {//从新开始枚举
   CORE.FullPathType = DirectoryPath; 
   //进入当前目录
   if(cd_folder(CORE.current_folder,0) != SUCC)
   return(FAIL);
   CORE.offset = 0;
   //保存当前目录的参数
   if(CORE.CurrentDirectoryType ==  RootDirectory)
      CORE.SectorNum = CORE.FirstRootDirSecNum; 
   else
     {
       CORE.ClusterNum = CORE.ClusterNOofCurrentFolder;
       CORE.SectorNum = FirstSectorofCluster(CORE.ClusterNum); 
     }
     save_enum_vars(FOLDER_ENUM);//保存枚举的当前位置
  } 

  restore_enum_vars(FOLDER_ENUM);//恢复枚举的当前位置
do{
  stringcpy(CORE.current_folder,return_string);
  temp = LengthofString(return_string);
  if(return_string[temp-1] != '\\')
  {
   return_string[temp] = '\\';
   return_string[temp+1] = 0;
  }
  //从目录中读取一个ENTRY
  if(GetEntryFromDirectory(return_string+LengthofString
  (return_string), Extension,Get_All_Entries) == SUCC)
  {
   temp = LengthofString(return_string);
   *ATTR = CORE.Entry_Attr;
   //与FILE EXTENSION完成连接
   if(temp > 0 && (!((*ATTR) & ATTR_DIRECTORY)))
   {
    if(Extension[0] != 0)
{
     return_string[temp] = '.';
     return_string[temp+1] = 0;
 concanenateString(return_string,Extension);
}
   }

   //进滤"." ".."
  if(return_string[temp - 1] == '.' || (return_string[temp - 1] == '.'
  && return_string[temp - 2] == '.'))
  continue;
   save_enum_vars(FOLDER_ENUM);//保存枚举的当前位置
   return(SUCC);
  }
  else
   break;
 }while(1);
 return(FAIL);

#endif
/*******************************************************************************************
函数
列举disk中所有文件和目录   
入口:无
出口:无
********************************************************************************************/ 
u8 disk_enumeration(u8 *return_string,u8 mode,u8* ATTR)
{
 u16 temp; 
 u8 Extension[20];
 if( ! mode)
 {//从新开始枚举
   stringcpy("C:\\",CORE.current_folder_for_disk_enum);
   cd__folder_for_disk_enum();
   save_enum_vars(DISK_ENUM); //保存枚举的当前位置 
 }  
   restore_enum_vars(DISK_ENUM);//恢复枚举的当前位置
 do{
    stringcpy(CORE.current_folder_for_disk_enum,return_string);
    temp = LengthofString(return_string);

    if(return_string[temp-1] != '\\')
  {
         return_string[temp] = '\\';
         return_string[temp+1] = 0;
  }
//从目录中读取一个ENTRY
     if(GetEntryFromDirectory(return_string+LengthofString(return_string), 
      Extension,Get_All_Entries) == FAIL)
 {   
     //返回上一级目录
 if(cd__() == 0x55)
 {
     return(FAIL);
 }
         continue;

  }
 else{
       temp = LengthofString(return_string);
           *ATTR = CORE.Entry_Attr; 
        #if filter_hidden_entry
   if(*ATTR & ATTR_HIDDEN)
   continue;
        #endif
           //与FILE EXTENSION完成连接
           if(temp > 0 && (!((*ATTR) & ATTR_DIRECTORY)))
   {
              if(Extension[0] != 0)
  {
                  return_string[temp] = '.';
                  return_string[temp+1] = 0;
              concanenateString(return_string,Extension);
  }

   }
   else{  temp = LengthofString(return_string);
          //进滤"." ".."
          if(return_string[temp - 1] == '.' || (return_string[temp - 1] == '.'
  && return_string[temp - 2] == '.'))
  continue;
  stringcpy(return_string,CORE.current_folder_for_disk_enum);
                  //进入目录去枚举
  cd__folder_for_disk_enum();
   }

  }
   save_enum_vars(DISK_ENUM);//保存枚举的当前位置 
   return(SUCC);
 }while(1);
  
}
/********************************************************************************************
函数
文件查找函数
入口:1)mode = 0:在当前目录下查找;2)mode=1:在整个磁盘中查找
      filename-被查找文件,Return_string
出口:无
********************************************************************************************/
#if complie_find_file
u8 find_file(u8 * filename,u8 mode,u8* Return_string)
{   
u16 temp,POINTER;
u8 ATTR,disk_enum_mode;

    if(! mode)
{  //在当前目录下查找文件
      stringcpy(CORE.current_folder,Return_string);
      temp = LengthofString(Return_string);
  if(*(Return_string + temp - 1) != '\\')
  {
    Return_string[temp] = '\\';
Return_string[temp + 1] = 0;
  }
      concanenateString(Return_string,filename);
     CORE.FullPathType = FilePath;
 //直接用FullPathToSectorCluster()检查文件是否存在?
     if(FullPathToSectorCluster(Return_string) != SUCC)
      return(FAIL);//文件不存在,查找失败
 return(SUCC);//文件存在,查找成功

}
else
{//在磁盘中查找
     disk_enum_mode = 0;
 //用disk_enumeration()读取磁盘所有的ENTRY
     while(disk_enumeration(Return_string,disk_enum_mode,&ATTR) == SUCC)
 {  
    disk_enum_mode = 1;
temp = 0;
POINTER = 0;
if(ATTR & ATTR_DIRECTORY)
continue;
        do{
  if(Return_string[temp] == '\\')
  POINTER = temp;
  if(Return_string[temp] == 0)
  break;
  temp++;
}while(1);
        //检查文件名是相同?
if(stringcmp(Return_string + POINTER + 1,filename) == SUCC)
return(SUCC);
 } 
     return(FAIL);
}
}
#endif
/********************************************************************************************
函数
查询分区容量和剩余空间 --通过检查分区FAT表来实现
入口:partition_id(Supported ID:form 'C' to 'F'),u32 *volume_capacity, u32 *volume_free_space
出口:SUCC  (返回的分区容量和剩余空间以512 bytes扇区为单位)
**********************************************************************************************/  
#if complie_volume_inquiry 
u8 volume_inquiry(u8 partition_id,u32 *volume_capacity, u32 *volume_free_space)
{   
  u16 i,j,x;
  u8 buf[512];
  if(partition_id >= 'c' && partition_id <= 'f')
       partition_id -= 32;   
  if ( ! (partition_id >= 'C' && partition_id <= 'F'))
    return(FAIL); 
  //读取分区的BPB信息
  Read_partition_PBP((u8)(partition_id - 'C'));
   if (CORE.system_id == 0x6)
   {   
     *volume_free_space = 0;
 i = 0;
 x = 0;
 while(i < (CORE.CountofClusters) + 2){
 //从扇区CORE.FirstSectorofFAT1开始检查
      if(read_flash_sector(buf,CORE.FirstSectorofFAT1 + x) == SUCC) 
       {//检查一整个扇区
        for (j = 0;j < 512;j +=2)
         { 
          if(buf[j] == 0 && buf[j + 1] == 0)
             (*volume_free_space) ++;
  i++;
  if(i >= (CORE.CountofClusters + 2))
  break;
         }
 x++;//扇区号+1
        }
       else
        {
          *volume_capacity = 0;
          *volume_free_space = 0;
          return(FAIL);
         } 
 }
       *volume_free_space *=  BPB.sector_per_cluster;//函数完成,返回结果
       *volume_capacity =  CORE.total_sector;  
       return(SUCC);
   }
   else
   {
      *volume_capacity = 0;
      *volume_free_space = 0;
      return(FAIL);   
   }
}
#endif
/*
+FFTR--------------------------------------------------------------------
$Log: fat.c,v $


-FFTR--------------------------------------------------------------------
*/
回复 支持 反对

使用道具 举报

39

主题

597

帖子

2

精华

金牌会员

Rank: 6Rank: 6

积分
2124
金钱
2124
注册时间
2011-9-3
在线时间
124 小时
发表于 2011-11-18 16:19:59 | 显示全部楼层
帮顶,正想玩FAT文件系统,可是觉得代码太多,有点难度啊。。。
回复 支持 反对

使用道具 举报

46

主题

1579

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1970
金钱
1970
注册时间
2011-7-17
在线时间
4 小时
发表于 2011-11-18 17:55:10 | 显示全部楼层
回复【3楼】螃蟹爱虫:
---------------------------------
你之前公布的那个修正版的文件系统初始化函数刚测试发现不支持山寨2GTF卡。
Time?And?Relative?Dimension?In?Space.
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2011-11-18 18:30:12 | 显示全部楼层
楼主把源码打包上传吧。
最好附上一个STM32或者类似其他单片机上的工程实例,以便大家学习。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

12

主题

48

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2011-10-16
在线时间
5 小时
发表于 2011-11-18 19:27:59 | 显示全部楼层
回复【楼主位】figureyang:
---------------------------------
楼主辛苦了好人……能发到我邮箱吗?252473572@qq.com
谢啦
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2011-11-18 19:42:51 | 显示全部楼层
原来楼主是要收费的....
汗一个,学习下人家fatfs吧.日本人写的.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
77
金钱
77
注册时间
2011-11-18
在线时间
3 小时
 楼主| 发表于 2011-11-19 09:38:04 | 显示全部楼层
回复【7楼】正点原子:
---------------------------------
没说要收费啦,我不知道你是怎么理解的,我的意思提供免费的FAT16源代码
并不是说我的FAT32源代码收你的费啦
FAT32当初是为别的公司开发的,是当初的一个约定,不能公开啦!


当然,关于这个FAT32我要说的是,它是从FAT16的基础上开发出来的,它们俩保持了一致的API函数,
因此,也就是说,只要开发人员学会FAT16的使用,我们保证了开发人员同样就会使用FAT32,困为它们的API函数
是完全相同的,甚至你写好的FAT16上层代码不需要修改,就可以编译了,用在FAT32上,
我们的设计是从方便开发人员的角度来考虑的。
这个FAT32代码可以说是一个很方便使用的代码,对于这样的代码,我也想将它直接公布,让更多的人使用
让更多的开发人员从中受惠!如果你真的想得到这个FAT32代码用在项目上吧,我愿意征得委托开发公司的同意,给你源代码!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2011-11-19 09:58:45 | 显示全部楼层
回复【8楼】 figureyang :
---------------------------------
我是在这个帖子看到你说fat32要收费的:http://www.openedv.com/posts/list/2071.htm#10739
至于我理解错了么?
你这句话:
....FAT16为免费代码,您可以免费使用。
同时这个文件系统有与FAT32和FAT16双兼容的源代码(当然双兼容FAT32是收费的源代码)...
不就是说兼容FAT16和32的代码要收费才能使用/得到源码的嘛?

一个代码再好,如果没有一定的人群和条件来验证和使用,那么是不会得到推广的.

目前嵌入式文件系统已经有好几个不错的代码了(都是免费).我们开发板的暂且不提(不支持写),于振南的znFAT(仅支持fat32),日本人ELM老师的fatfs(支持fat12/16/32).建议你多给出一些你同这两者的区别优势等.为什么用你的就比别人的好?有什么数据?这些都是大家关心的.任何一个代码都不是一开始就完善的,需要大量的人员测试和实际使用者的测试,才能逐步提高和完

fatfs(已经更新到R0.09了)的官网:fatfs
znFAT的网址:znFAT

在TC最重要的是:软件不收费(纯商业软件/独一无二的除外)....
这点我相信你我,还有大家都很明白. .
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

6

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
77
金钱
77
注册时间
2011-11-18
在线时间
3 小时
 楼主| 发表于 2011-11-19 10:10:19 | 显示全部楼层

 我的工程文件贴出来了。当然是FAT16的工程代码!

这个是在VC下的一个工程,
它的运行原理是基于一个叫做磁盘IMG的文件!
工程里有一个基于这个磁盘IMG的文件的驱动,实现了所谓的虚拟磁盘!让文件系统在WINDOWS上跑!

调试过程如下:
1)编译生成文件系统的可执行文件fat_filesystem.exe(如果编译不通过,可查看《FAT16代码说明.doc》有说明)
2) 直接可以运行这个文件fat_filesystem.exe
3)运行文件后,自动生成一个磁盘IMG的文件,会自动格式化成FAT16格式,所以这个文件可以用winimg 5.0查看
3) 在IMG上建立一些文件和目录
4)写IMG里写文件readed.rar,直到IMG写满
5)把IMG时的所有文件和目录分离到当前目录下!(调用disk_enumeration()完成其功能,参考《嵌入式FAT16_32文件系统.doc》)

通过这个调试过程,可以完整测试文件系统的功能,代码完整性,代码稳定性,健壮性!

这个代码是一个最新的代码,如果你有发现BUG的话,可以告诉我,我有时间的时候会来解决,以达到尽善尽美!
我的联系方式:qq:292942278,e-mail:tony_yang123@sina.com.cn

FAT16.zip

1.05 MB, 下载次数: 3336

回复 支持 反对

使用道具 举报

2

主题

100

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
278
金钱
278
注册时间
2012-4-15
在线时间
0 小时
发表于 2012-7-7 20:26:10 | 显示全部楼层
留存,顶一下。
喜欢单片机,没什么道理,就像爱吃水煮鱼,对味而已。
回复 支持 反对

使用道具 举报

15

主题

46

帖子

0

精华

初级会员

Rank: 2

积分
126
金钱
126
注册时间
2014-10-13
在线时间
0 小时
发表于 2014-11-20 15:35:26 | 显示全部楼层
谢谢楼主分享,项目中正要使用文件系统,学习中。
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
21
金钱
21
注册时间
2014-12-8
在线时间
0 小时
发表于 2014-12-8 14:49:16 | 显示全部楼层
好人一生平安
回复 支持 反对

使用道具 举报

2

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2015-2-28
在线时间
8 小时
发表于 2015-3-22 16:10:57 | 显示全部楼层
顶.顶..顶...
回复 支持 反对

使用道具 举报

15

主题

143

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
243
金钱
243
注册时间
2014-10-31
在线时间
4 小时
发表于 2015-3-29 09:41:37 | 显示全部楼层
只能仰望啊  顶……
总有一天,要为自由而活
回复 支持 反对

使用道具 举报

7

主题

38

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2013-10-6
在线时间
15 小时
发表于 2015-5-2 09:57:52 | 显示全部楼层
厉害,分享万岁
回复 支持 反对

使用道具 举报

260

主题

810

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1899
金钱
1899
注册时间
2012-10-28
在线时间
358 小时
发表于 2015-10-20 14:55:24 | 显示全部楼层
厉害,分享万岁
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2017-4-12
在线时间
1 小时
发表于 2017-4-22 17:48:40 | 显示全部楼层
可以试下 http://ranfs.com  fat文件系统
功能更加完整和强大  
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-8-22 01:13

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表