FATFS文件系统剖析全.docx
《FATFS文件系统剖析全.docx》由会员分享,可在线阅读,更多相关《FATFS文件系统剖析全.docx(11页珍藏版)》请在冰豆网上搜索。
FATFS文件系统剖析全
FATFS文件系统剖析1:
FAT16:
数据按照其不同的特点和作用大致可分为5部分:
MBR区、DBR区、FAT区、DIR区和DATA区,相比fat12多了DBR区
Mainbootrecord:
MBR(0--1bdh) 磁盘参数存放
DPT(1beh--1fdh) 磁盘分区表
55,aa 分区结束标志
DBR(DosBootRecord)是操作系统引导记录区的意思
FAT区(有两个,一个备份):
对于fat16,每一个fat项16位,所以可寻址的簇项数为65535(2的16次方)。
而其每簇大小不超 过32k,所以其每个分区最大容量为2G。
fat32,每一个fat项32位,可寻址簇数目为2的32次方。
DIR区(根目录区):
紧接着第二FAT表(即备份的FAT表)之后,记录着根目录下每个文件(目录)的起始单元,文件的属性等。
定位文件位置时,操作系统根据DIR中的起始单元,结合FAT表就可以知道文件在硬盘中的具体位置和大小了。
DATA区:
实际文件内容存放区。
FAT32:
暂时放在这里,不讨论!
Fatfs:
嵌入式fat文件系统,支持fat16,fat32。
包含有ff.h,diskio.h,integer.h,ffconf.h四个头文件以及ff.c文件系统实现。
当然要实现具体的应用移植,自己要根据diskio.h实现其diskio。
c底层驱动。
diskio.h:
底层驱动头文件
ff.h :
文件系统实现头文件,定义有文件系统所需的数据结构
ff.c :
文件系统的具体实现
如下开始逐个文件加以分析:
integer.h:
仅实现数据类型重定义,增加系统的可移植性。
ffconf.h:
文件系统配置---逐个配置,先配置实现一个最小的fat文件系统,下面来分析各配置选项:
#define_FFCONF8255 //版本号
#define _FS_TINY 0 /*0:
Normalor1:
Tiny*/ //在这里与先前版本有些许变化,是通过配置头配置两种不同大小的文件系统,这里配置为0。
#define_FS_READONLY 1 //定义文件系统只读,也就不能写修改,在此定义为1,这样文件系统会大大缩小,简化学习理解过程。
#define_FS_MINIMIZE 3 /*0to3*/ 这个选项是用于过滤掉一些文件系统功能,为0时是全功能,3是功能实现最小
#define _USE_STRFUNC 0 /*0:
Disableor1/2:
Enable*/ 是否使用字符串文件接口,为0,不使用
#define _USE_MKFS 0/*0:
Disableor1:
Enable*/ 制作文件系统,这个功能实现是还要_FS_READONLY=0
#define _USE_FORWARD 0 /*0:
Disableor1:
Enable*/ f_forwardfunction 实现还需_FS_TINY =1
#define _USE_FASTSEEK 0 /*0:
Disableor1:
Enable*/ 快速查找功能
#define_CODE_PAGE 936 // 936 -SimplifiedChineseGBK(DBCS,OEM,Windows)
#define _USE_LFN 0 /*0to3*/ 0:
不使用长文件名
#define _MAX_LFN 255 /*MaximumLFNlengthtohandle(12to255)*/
#define _LFN_UNICODE 0 /*0:
ANSI/OEMor1:
Unicode*/
#define_FS_RPATH 0 /*0to2*/不使用相对路径
/*---------------------------------------------------------------------------/
/PhysicalDriveConfigurations
/----------------------------------------------------------------------------*/
#define_VOLUMES 1
/*Numberofvolumes(logicaldrives)tobeused.*/
#define _MAX_SS 512 /*512,1024,2048or4096*/ 512字节每扇区
#define _MULTI_PARTITION 0 /*0:
Singlepartitionor1:
Multiplepartition*/ 只有一个分区
#define _USE_ERASE 0 /*0:
Disableor1:
Enable*/
/*Toenablesectorerasefeature,set_USE_ERASEto1.*/
/*---------------------------------------------------------------------------/
/SystemConfigurations
/----------------------------------------------------------------------------*/
#define_WORD_ACCESS 0 /*0or1*/ 0:
Byte-by-byteaccess.
/*IncludeaheaderfileheretodefinesyncobjecttypesontheO/S*/
/*#include,,orohters.*/
#define_FS_REENTRANT 0 /*0:
Disableor1:
Enable*/ 同步选项
#define_FS_TIMEOUT 1000 /*Timeoutperiodinunitoftimeticks*/
#define _SYNC_t HANDLE /*O/Sdependenttypeofsyncobject.e.g.HANDLE,OS_EVENT*,IDandetc..*/
#define _FS_SHARE 0 /*0:
Disableor>=1:
Enable*/ 共享选项
如上已经配置成了一个最小的fat文件系统。
Diskio.h:
底层驱动头文件,就一些状态宏的定义和底层驱动函数的申明,看源码一目了然。
实现相应的diskio.c。
根据我的配置:
只需要根据不同的存储介质实现相应的disk_initialize,disk_status,disk_read三个函数就够了,
我在这里实现上s3c2440上的SD卡驱动:
DSTATUSdisk_initialize(BYTEnDisk)
{
return1;
}
DSTATUSdisk_status(BYTEnDisk)
{
return1;
}
DRESULTdisk_read(BYTEnDisk,BYTE*b,DWORDc,BYTEd)
{
return 0;
}
编译报错 get_fattime没实现:
DWORDget_fattime(void)
{
return0;
}
转自博客,供大家相互交流!
FATFS文件系统剖析2:
分析下ff.h和ff.c两个文件。
先来分析ff.h中定义的几个结构体:
typedefstruct{
BYTE fs_type; // 系统类型,为0时系统没有被挂载
BYTE drv; // 物理磁盘驱动号
BYTE csize; // 每簇的扇区数目, 簇是文件数据分配的基本单位
BYTE n_fats; // 文件分配表的数目,一般为两个(一个备份fat表)
//Fatfs文件系统应该是:
引导扇区,文件分配表2个,根目录区,和数据区
BYTE wflag; // 文件活动窗体是否改动标志,为1要回写
BYTE fsi_flag; // 文件信息回写标志
WORD id; // 文件系统加载id号
WORD n_rootdir; //根目录区目录项数目(针对FAT12/16,FAT32不使用)
#if_MAX_SS!
=512
WORD ssize; // 每扇区多少字节
#endif
#if_FS_REENTRANT
_SYNC_t sobj; //允许重入,则定义同步对象
#endif
#if!
_FS_READONLY
DWORD last_clust; //最新分配的簇
DWORD free_clust; //空闲簇
DWORD fsi_sector; //文件信息扇区(仅用于FAT32)
#endif
#if_FS_RPATH
DWORD cdir; //使用相对路径,文件系统的当前起始路径 0(root路径)
#endif
DWORD n_fatent; //文件分配表占用的扇区 n_fatent=数据簇数目+2
DWORD fsize; //每FAT表有多少个扇区
DWORD fatbase; //文件分配表开始扇区
DWORD dirbase; //如果是FAT32,根目录开始扇区需要首先得到
DWORD database; //数据起始扇区
DWORD winsect; //win中当前指定的扇区
BYTE win[_MAX_SS]; //扇区操作缓存
}FATFS;
typedefstruct{
FATFS* fs; //指向的文件系统
WORD id; //自身文件系统挂载id号 即fs->id
BYTE flag; //文件状态
BYTE pad1; //文件在簇里面扇区偏移 (0--fs->csize)
DWORD fptr; //文件当前读写指针位置,当文件打开时为0
DWORD fsize; //文件大小(按字节计算)
DWORD org_clust; //文件起始簇(0whenfsize==0)
DWORD curr_clust; // 文件当前操作簇
DWORD dsect; //文件当前操作扇区
#if!
_FS_READONLY
DWORD dir_sect; //包含路径入口的扇区号
BYTE* dir_ptr; //目录入口指针
#endif
#if_USE_FASTSEEK
DWORD* cltbl; //指向查找映射表的簇(nullonfileopen)
#endif
#if_FS_SHARE
UINT lockid; //文件锁ID号(indexoffilesemaphoretable)
#endif
#if!
_FS_TINY
BYTE buf[_MAX_SS]; //文件读写缓存
#endif
}FIL;
typedefstruct{
FATFS* fs; //对应的文件系统
WORD id; //自身文件系统挂载id号 即fs->id
WORD index; //目前读写索引号 /*Currentread/writeindexnumber*/
DWORD sclust; //目录表起始簇 (0:
Rootdir)
DWORD clust; //目前处理的簇
DWORD sect; //目前簇里对应的扇区
BYTE* dir; //指向当前在win[]中的短文件名入口项/*PointertothecurrentSFNentryinthewin[]
BYTE* fn; //指向短文件名 (in/out){file[8],ext[3],status[1]}
#if_USE_LFN
WCHAR* lfn; //指向长文件名缓冲 /*PointertotheLFNworkingbuffer*/
WORD lfn_idx; /*LastmatchedLFNindexnumber(0xFFFF:
NoLFN)*/
#endif
}DIR;
typedefstruct{ //文件目录表项 大小=4+2+2+1+13
DWORD fsize; /*Filesize*/
WORD fdate; /*Lastmodifieddate*/
WORD ftime; /*Lastmodifiedtime*/
BYTE fattrib; /*Attribute*///文件属性
TCHAR fname[13]; /*Shortfilename(8.3format)*/
#if_USE_LFN //长文件名支持
TCHAR* lfname; /*PointertotheLFNbuffer*/
UINT lfsize; /*SizeofLFNbufferinTCHAR*/
#endif
}FILINFO;
结构是搞清楚了,但其里面的具体联系怎么也还收理不清楚。
只有看ff.c来疏通了!
里面东西还是蛮多的,咋一看,3000多行类(太多,在这里就根据我的配置,进行逐个分析吧),从头到尾,一个一个来。
首先是三个内存操作和以个字符查找处理函数,不说不解释。
然后是:
static
FRESULTmove_window(
FATFS*fs, /*Filesystemobject*/
DWORDsector /*Sectornumbertomakeappearanceinthefs->win[]*/
) /*Movetozeroonlywritesbackdirtywindow*/
该函数就是把指定扇区sector中的数据读到fs->win[]里面
DWORDclust2sect( /*!
=0:
Sectornumber,0:
Failed-invalidcluster#*/
FATFS*fs, /*Filesystemobject*/
DWORDclst /*Cluster#tobeconverted*/
)
计算簇clst在对应文件系统fs里面的扇区号
DWORDget_fat( /*0xFFFFFFFF:
Diskerror,1:
Internalerror,Else:
Clusterstatus*/
FATFS*fs, /*Filesystemobject*/
DWORDclst /*Cluster#togetthelinkinformation*/
)
获取簇clst在文件系统fs中FAT表里面fat入口
static
FRESULTdir_sdi(
DIR*dj, /*Pointertodirectoryobject*/
WORDidx /*Directoryindexnumber*/
)
根据根目录索引号idx获取相应的目录信息存储到dj结构里面
static
FRESULTdir_next( /*FR_OK:
Succeeded,FR_NO_FILE:
Endoftable,FR_DENIED:
EOTandcouldnotstretch*/
DIR*dj, /*Pointertodirectoryobject*/
intstretch /*0:
Donotstretchtable,1:
Stretchtableifneeded*/
)
获取当前目录项的索引值+1,对应的目录项信息
static
FRESULTdir_find(
DIR*dj /*Pointertothedirectoryobjectlinkedtothefilename*/
)
在目录表中查找与dj->fn相同文件名的目录项
static
FRESULTcreate_name(
DIR*dj, /*Pointertothedirectoryobject*/
constTCHAR**path /*Pointertopointertothesegmentinthepathstring*/
)
创建一个文件名为path指向的dj目录项
static
FRESULTfollow_path( /*FR_OK(0):
successful,!
=0:
errorcode*/
DIR*dj, /*Directoryobjecttoreturnlastdirectoryandfoundobject*/
constTCHAR*path /*Full-pathstringtofindafileordirectory*/
)
获取文件路径path对应的目录项填入dj里面
static
BYTEcheck_fs( /*0:
TheFATBR,1:
ValidBRbutnotanFAT,2:
NotaBR,3:
Diskerror*/
FATFS*fs, /*Filesystemobject*/
DWORDsect /*Sector#(lba)tocheckifitisanFATbootrecordornot*/
)
读取文件系统fs的一号扇区,进行MBR检查,文件系统类型区分
static
FRESULTchk_mounted( /*FR_OK(0):
successful,!
=0:
anyerroroccurred*/
constTCHAR**path, /*Pointertopointertothepathname(drivenumber)*/
FATFS**rfs, /*Pointertopointertothefoundfilesystemobject*/
BYTEchk_wp /*!
=0:
Checkmediawriteprotectionforwriteaccess*/
)
测试文件系统是否已挂在,如没有,就进行挂载,文件系统结构初始化
static
FRESULTvalidate( /*FR_OK(0):
Theobjectisvalid,!
=0:
Invalid*/
FATFS*fs, /*Pointertothefilesystemobject*/
WORDid /*Memberidofthetargetobjecttobechecked*/
)
检测文件系统是否可用
如下是现配置好的文件系统引出的四个接口函数:
FRESULTf_mount( //挂在一个逻辑的文件系统
BYTEvol, /*Logicaldrivenumbertobemounted/unmounted*/
FATFS*fs /*Pointertonewfilesystemobject(NULLforunmount)*/
)
系统挂载
FRESULTf_open(
FIL*fp, /*Pointertotheblankfileobject*/
constTCHAR*path, /*Pointertothefilename*/
BYTEmode /*Accessmodeandfileopenmodeflags*/
)
文件打开,包括(真正的文件系统初始化,系统检测)
FRESULTf_read(
FIL*fp, /*Pointertothefileobject*/
void*buff, /*Pointertodatabuffer*/
UINTbtr, /*Numberofbytestoread*/
UINT*br /*Pointertonumberofbytesread*/
)
文件读
FRESULTf_close(
FIL