前序
前面分析了f_mkfs、f_mount函数,在格式化和挂载完成之后,当然是要创建文件的操作,本节分析f_open函数,分析一下创建和打开一个文件时,发生了什么。
分析假设
(1)假设一个磁盘就一个分区。
(2)只分析FAT32文件系统相关的代码。
(3)函数的大部分分析,都写入代码注释中。
(4)重要的注释都回加入很多星号以及数学标号。例如,
/****************** 1.把字符存入lfn的buffer中 *******************/
关键结构体
(1)FAT文件系统描述一个文件夹的结构体。虽然是一个文件夹结构体,但是再打开一个文件的开始,先创建这个结构体,然后先把文件的信息填充到这个结构体,最终使用这个结构体填充FIL结构图的一些重要信息。
typedef struct {
_FDID obj; /* 存放下一个目标的信息 */
DWORD dptr; /* 当前目录项的起始地址(单位:字节) */
DWORD clust; /* 当前簇 */
DWORD sect; /* 当前簇对应的扇区位置(通过目录项的位置确定) */
BYTE* dir; /* 指向当前扇区win[]中的偏移(单位:字节) */
BYTE fn[12]; /* 存放8.3文件名,最后1个字节存放标志:是否有长目录项 */
#if _USE_LFN != 0
DWORD blk_ofs; /* 指向第1个长目录项的起始位置(字节:单位) (0xFFFFFFFF:Invalid) */
#endif
#if _USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} DIR;
(2)FAT文件系统描述一个文件的结构图。
typedef struct {
_FDID obj; /* 存放下一个目标的信息 */
BYTE flag; /* 文件状态标志 */
BYTE err; /* 文件错误码 */
FSIZE_t fptr; /* 文件的读写指针位置 */
DWORD clust; /* fptr所在的当前簇 */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
#if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */
#endif
} FIL;
(3)_FDID结构体。
在(1)和(2)的结构体中,都有_FDID结构体,那么分析一下这个结构体的内容:
注:在FATFS中有个全局的指针数组FATFS[],在f_mount的时候可知,这个数组会被填充,填充的内容是MBR的内容,之后,我们把这个数组指针称作为**“超级快”**。
typedef struct {
FATFS* fs; /* 指向全局的在挂载的时候磁盘对应的超级块 */
WORD id; /* Owner file system mount ID */
BYTE attr; /* 目标属性,根据目录项中的属性进行填充 */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
DWORD sclust; /* 目标的起始簇号 */
FSIZE_t objsize; /* 文件或者文件夹的大小 */
#if _FS_LOCK != 0
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
} _FDID;
f_open函数分析
下面是f_open的源代码:
FRESULT f_open (
FIL* fp, /* 返回的文件描述符 */
const TCHAR* path, /* 打开文件的路径 */
BYTE mode /* 文件打开的模式 */
)
{
FRESULT res;
DIR dj; /* 分配一个DIR结构体 */
FATFS *fs;
#if !_FS_READONLY
DWORD dw, cl, bcs, clst, sc;
FSIZE_t ofs;
#endif
if (!fp) return FR_INVALID_OBJECT;
/* Get logical drive */
mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND;
res = find_volume(&path, &fs, mode);
if (res == FR_OK) {
dj.obj.fs = fs;
/* 根据不同的配置来分配fs->lfn,用于存放path指向的路径 */
INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */
#if !_FS_READONLY /* R/W configuration */
if (res == FR_OK) {
if (dj.fn[NSFLAG] & NS_NONAME) {
/* Origin directory itself? */
res = FR_INVALID_NAME;
}
#if _FS_LOCK != 0
else {
res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
}
#endif
}
/* Create or Open a file */
if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
if (res != FR_OK) {
/* 文件不存在 创建文件,省略不少代码 */
}
else {
/* 文件存在 但是不允许写入 */
if (dj.obj.attr & (AM_RDO | AM_DIR

本文深入解析f_open函数,探讨如何创建和打开文件,包括FAT32文件系统中关键结构体的使用,如DIR和FIL,以及f_open函数内部流程,如路径追踪和目录项匹配。
最低0.47元/天 解锁文章
3115





