一、这是个什么玩意

它是一个文件系统,那文件系统是个什么玩意,直接从字面意思理解,它就是个管理文件的系统,所以叫文件系统,直白吧,也可以说是文件存储协议。但是继续追问的话会问,怎么来管理文件呢?好,基于怎么管理文件这个问题,就会产生不同的文件系统,不同的文件系统管理的策略都有不同(这里就不展开了说了,只说fatfs,有精力的话可以多了解几种通用的文件系统,yaffs,jffs等,或者对于嵌入式开发有限的资源可以自己编写文件系统)。下面说下fatfs。

fatfs是开源的。可以从官网下载源码。当前的fatfs文件系统有两个版本,一个是标准完整的fatfs,另一个是Tiny版本,适合ram比较小的设备,部分功能被禁止。不过两个版本都支持FAT12,FAT16和FAT32。通过宏_FS_TINY可以配置。从官网下载(http://elm-chan.org/fsw/ff/00index_e.html)下来解压会有两个文件夹,doc和src。doc里是关于FatFs的说明,包括特性,系统函数介绍,en是英语,ja是日语,res是资源文件夹,剩下官网主页。src里是文件系统实现源码。option文件夹是代码页表,可以不用管。剩下各个文件的功能可以参考00readme.txt。

00readme.txt   This file.
  00history.txt  Revision history.
  ff.c           FatFs module.
  ffconf.h       Configuration file of FatFs module.
  ff.h           Common include file for FatFs and application module.
  diskio.h       Common include file for FatFs and disk I/O module.
  diskio.c       An example of glue function to attach existing disk I/O module to FatFs.
  integer.h      Integer type definitions for FatFs.
  option         Optional external modules.

二、有毛用啊

文件系统在整个系统中的作用非常重要。对上(对用户或应用)可以方便的管理文件,上层可以随意管理文件(夹)。对下(各种设备)也可以合理的管理使用设备(硬盘,SD卡,Flash等)。对于硬盘还好点可以随意擦写,但是对于flash的话在写之前比如先擦,如果没有文件系统的话,上层直接访问操作的是物理空间,这就相当不方便了。

三、怎么用啊

所谓怎么用其实就是移植fatfs到你的系统,能够新建,打开,读,写,删出文件。fatfs的设计分层已经帮你设计好了,文件系统的实现已经和具体的硬件介质无关,只需要实现和介质相关的访问介质的各个接口(disk_initialize,disk_read,disk_write和disk_ioctl),除此之外就是修改配置文件,主要是两个,一个是interger.h文件,这个是文件系统所需的变量类型,和具体的处理器相关,可能会修改。另一个是ffconf.h文件,这个文件是具体配置文件系统的,根据自己的项目需求对文件系统进行裁剪。

在上面调试完成后,怎么使用fatfa就相对容易多了,主要是以下几个接口。format,mount,open,wirte,read,close。

下图是FAT32文件系统的结构:(FAT12、FAT16可能会有调整,这个得源码了,下面内容参考于https://www.cnblogs.com/amanlikethis/p/3793077.html#lab5 该部分讲的比较好,在此感谢)

  概念与分区功能简述:

MBR:

  保存了磁盘的分区信息(分区的起始地址、分区大小、分区结束地址)

DBR

  保存了当前分区的详细参数(比如FAT表的位置、FAT表的的大小、簇大小、扇区大小、根目录中最大目录项数等等)

FAT表

  以簇的形式对数据区重新划分空间,在FAT表中建立了簇的使用情况,哪些已经被占用,哪些没有被占用;簇链的结构,也即是簇与簇之间的连接关系。

目录

  在目录中,存在众多的目录项,目录项记录了文件名、大小、起始地址等等。

目录项

  目录中的存储单位,记录了每一个文件或者目录的信息。

数据区

  数据区中纯粹的文件数据

扇区

  SD卡最小的读写单位,512字节,也就是说一次最少读取或者写入的数据是512字节。

☆  说明

<1> 有些SD卡格式化后,并没有MBR部分,而且SD卡格式化后磁盘上只存在一个磁盘分区。也就是说,即使SD卡上有MBR部分,在MBR的DPT(硬盘分区表)中也只有一个分区记录。

<2> 位于数据区之前的可以称之为文件系统管理区,此区域是以物理扇区为单位进行管理的,数据区则是以簇为单位进行管理的。

笔者认为1:

  狭义上的文件专指普通文件,目录则是位于普通文件的上层,用于管理处在其中的文件或者目录栏。笔者认为广义上的文件包含”目录和普通文件”。这样说目录,表示目录实际上也是一个文件,只不过是一个管理文件信息的特殊文件。

  可以说文件与目录既有区别,又有联系。普通文件在文件管理的时候,给文件设计了一个管理变量—文件指针,用于指示文件当前读取或者写入的位置,它是以字节为单位进行计算的;而目录其实也有一个管理读取或者写入的位置的变量—目录指针,它则是以目录项(32字节)为单位进行计算的。

笔者认为2:

  文件 = 目录中的目录项、FAT表、文件对应的数据区内容

<1> 查看磁盘信息就是查看DBR和FAT表

<2> 读取文件就是查看目录项、FAT表和文件对应的数据区内容

<3> 写文件就是修改目录项、FAT表、文件对应的数据区内容

(参考结束,在此感谢)上述的内容如有理解不深入,直接撸代码。

本人用的是R0.12C版本,算是比较新的代码了,由于代码量还是不小,我只列部分,如有需要请邮件624801474@qq.com

1、首先来看ffconf.h文件

/*-----------------------------------------------------------------------------/
/ Function Configurations功能配置
/-----------------------------------------------------------------------------*/

#define _FS_READONLY         0      /* 0 to 1 */配置读写或只读,配成只读的话不支持一些接口如 f_write(), f_sync()等

#define _FS_MINIMIZE         0      /* 0 to 3 */函数功能支持,具体定义不同的值支持的函数也不同

#define _USE_STRFUNC         2      /* 0:Disable or 1-2:Enable */使能或禁止字符串函数

#define _USE_FIND            0      /* 0 to 1 */能或禁用在指定目录内搜索指定文件函数

#define _USE_MKFS            1    /* 0 to 1 */使能或禁用f_mkfs函数

#define _USE_FASTSEEK        1/* 0 to 1 */使能或禁用快速搜索功能

#define _USE_EXPAND   1    /* 0 to 1 */使能或禁用f_expand函数,该函数可以为文件分配连续数据区域

#define _USE_CHMOD  0  /* 0 to 1 */使能或禁用元数据控制函数:f_chmod和f_utime。

#define _USE_LABEL           0   /* 0 to 1 */使能或禁用卷标签API函数:f_getlabel和f_setlabel。

#define _USE_FORWARD         0    /* 0 to 1 */使能或禁用f_forward函数。

/*-----------------------------------------------------------------------------/
/ Locale and Namespace Configurations命名空间和本地环境配置
/-----------------------------------------------------------------------------*/

#define _CODE_PAGE         850     规定目标系统使用的OEM代码。如果该代码设置的不正确,可能会引起文件打开失败。如果没有根本没有使用扩展字符,则使用任何代码都没区别。
/   1   - ASCII (No extended character. Non-LFN cfg. only)
/   437 - U.S.
/   720 - Arabic
/   737 - Greek
/   771 - KBL
/   775 - Baltic
/   850 - Latin 1
/   852 - Latin 2
/   855 - Cyrillic
/   857 - Turkish
/   860 - Portuguese
/   861 - Icelandic
/   862 - Hebrew
/   863 - Canadian French
/   864 - Arabic
/   865 - Nordic
/   866 - Russian
/   869 - Greek 2
/   932 - Japanese (DBCS)
/   936 - Simplified Chinese (DBCS)
/   949 - Korean (DBCS)
/   950 - Traditional Chinese (DBCS)
*/

#define _USE_LFN     0    /* 0 to 3 */  使能或禁用长文件名(LFN)
#define _MAX_LFN     255  定义长文件名工作缓冲区大小,可以为12~255字节。当禁用长文件名时,此选项无效。

#define _LFN_UNICODE    0 /* 0:ANSI/OEM or 1:Unicode */使能或禁用Unicode

#define _STRF_ENCODE    3 /* 0 to 3 */  通过设置_LFN_UNICODE为1使能Unicode API函数时,这个选项定义通过字符串I/O函数读写的文件字符编码。

#define _FS_RPATH       0 /* 0 to 2 */配置相对路径函数。

/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations卷/驱动器配置
/----------------------------------------------------------------------------*/

#define _VOLUMES    2 配置可用卷的数目,可设置为1~10。

/* USER CODE BEGIN Volumes */ 
#define _STR_VOLUME_ID          0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */使能或禁用字符串卷标识
#define _VOLUME_STRS            "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"定义每一个逻辑驱动器ID。ID数目不能少于_VOLUMES。驱动器ID有效字符只能为A-Z和0-9。

#define _MULTI_PARTITION     0 /* 0:Single partition, 1:Multiple partition */使能或禁止多分区函数。
#define _MIN_SS    512  /* 512, 1024, 2048 or 4096 */
#define _MAX_SS    4096  /* 512, 1024, 2048 or 4096 */定义扇区大小,有效值为512、1024、2048、4096,需要根据硬件配置来定义。_MIN_SS定义最小扇区大小,_MAX_SS定义最大扇区大小。

#define _USE_TRIM      0 /* 0 to 1 */使能或禁用ATA-TRIM函数。

#define _FS_NOFSINFO    0 /* 0,1,2 or 3 */使能或禁用空闲簇计数和最后分配的簇计数。

/*---------------------------------------------------------------------------/
/ System Configurations系统配置
/----------------------------------------------------------------------------*/

#define _FS_TINY    1      /* 0:Normal or 1:Tiny */配置FatFs为正常模式或者微型(TINY)模式。

#define _FS_EXFAT 0     /* 0 to 1 */   使能或禁用exFAT文件系统。

#define _FS_NORTC 0  /* 0 to 1 */   使能或禁用时间戳函数。
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2018   如果系统没有RTC,这些宏用来定义固定时间戳。只读或者_FS_NORTC=0时,这些宏无意义。

#define _FS_LOCK    4     /* 0:Disable or >=1:Enable */使能或禁用文件锁功能。控制重复打开文件和非法打开文件对象。注意:文件锁功能不具有可重入性。只读模式下,这个宏必须为0。

#define _FS_REENTRANT    1/* 0:Disable or 1:Enable */使能或禁用FatFs模块的可重入特性。
#define _FS_TIMEOUT      1000 /* Timeout period in unit of time ticks */设置超时时间,单位为系统时钟滴答周期,当宏_FS_REENTRANT=0时,本设置无效。
#define _SYNC_t          osSemaphoreId 定义同步对象类型,取决于O/S。

2、integer.h文件忽略。

3、ff.h文件系统头文件,这个文件都是文件系统使用的各种宏定义、头文件和函数声明

/* Definitions of volume management */ 定义卷管理

#if _MULTI_PARTITION  /* Multiple partition configuration */
typedef struct {
 BYTE pd; /* Physical drive number */
 BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;分区表,定义了物理设备和逻辑分区的映射关系
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif

/* Type of path name strings on FatFs API */文件系统源码中暂时没什么用,先不用管

#if _LFN_UNICODE   /* Unicode (UTF-16) string */
#if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else      /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif

/* Type of file size variables */文件大小变量类型

#if _FS_EXFAT
#if _USE_LFN == 0
#error LFN must be enabled when enable exFAT
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif

/* File system object structure (FATFS) */文件系统结构体(重要之一)

typedef struct {
 BYTE fs_type;  /* File system type (0:N/A) */FAT文件系统的类型
 BYTE drv;   /* Physical drive number */物理驱动号
 BYTE n_fats;   /* Number of FATs (1 or 2) */FAT表数量
 BYTE wflag;   /* win[] flag (b0:dirty) */win是否回写标志
 BYTE fsi_flag;  /* FSINFO flags (b7:disabled, b0:dirty) */FSINFO脏标志
 WORD id;    /* File system mount ID */文件系统mountID
 WORD n_rootdir;  /* Number of root directory entries (FAT12/16) */根目录中的目录项项数
 WORD csize;   /* Cluster size [sectors] */簇数目
#if _MAX_SS != _MIN_SS
 WORD ssize;   /* Sector size (512, 1024, 2048 or 4096) */扇区大小
#endif
#if _USE_LFN != 0
 WCHAR* lfnbuf;   /* LFN working buffer */LFN工作缓冲
#endif
#if _FS_EXFAT
 BYTE* dirbuf;   /* Directory entry block scratchpad buffer */目录块暂存
#endif
#if _FS_REENTRANT
 _SYNC_t sobj;   /* Identifier of sync object */同步对象
#endif
#if !_FS_READONLY
 DWORD last_clst;  /* Last allocated cluster */最后分配的簇
 DWORD free_clst;  /* Number of free clusters */空闲簇的数量
#endif
#if _FS_RPATH != 0
 DWORD cdir;   /* Current directory start cluster (0:root) */当前目录的起始簇
#if _FS_EXFAT这三个不懂
 DWORD cdc_scl;  /* Containing directory start cluster (invalid when cdir is 0) */
 DWORD cdc_size;  /* b31-b8:Size of containing directory, b7-b0: Chain status */
 DWORD cdc_ofs;  /* Offset in the containing directory (invalid when cdir is 0) */
#endif
#endif
 DWORD n_fatent;  /* Number of FAT entries (number of clusters + 2) */
 DWORD fsize;   /* Size of an FAT [sectors] */FAT表的大小(扇区数)
 DWORD volbase;  /* Volume base sector */卷起始扇区
 DWORD fatbase;  /* FAT base sector */FAT起始扇区
 DWORD dirbase;  /* Root directory base sector/cluster */根目录起始扇区
 DWORD database;  /* Data base sector */数据起始扇区
 DWORD winsect;  /* Current sector appearing in the win[] */保存在win[]中的当前扇区地址
 BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */目录和FAT分配表的缓冲区
} FATFS;

/* Object ID and allocation information (_FDID) */该结构体是后来的版本才有的,个人理解是在FILE和DIR中抽象出来的共同体,分配信息对象

typedef struct {
 FATFS* fs;   /* Pointer to the owner file system object */
 WORD id;   /* Owner file system mount ID */
 BYTE attr;  /* Object attribute */
 BYTE stat;  /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */
 DWORD sclust;  /* Object start cluster (0:no cluster or root directory) */
 FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if _FS_EXFAT
 DWORD n_cont;  /* Size of first fragment, clusters - 1 (valid when stat == 3) */
 DWORD n_frag;  /* Size of last fragment needs to be written (valid when not zero) */
 DWORD c_scl;  /* Containing directory start cluster (valid when sclust != 0) */
 DWORD c_size;  /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
 DWORD c_ofs;  /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */
#endif
#if _FS_LOCK != 0
 UINT lockid;  /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
} _FDID;

/* File object structure (FIL) */

typedef struct {
 _FDID obj;   /* Object identifier (must be the 1st member to detect invalid object pointer) */
 BYTE flag;   /* File status flags */
 BYTE err;   /* Abort flag (error code) */
 FSIZE_t fptr;   /* File read/write pointer (Zeroed on file open) */
 DWORD clust;   /* Current cluster of fpter (invalid when fptr is 0) */
 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;

/* Directory object structure (DIR) */

typedef struct {
 _FDID obj;   /* Object identifier */
 DWORD dptr;   /* Current read/write offset */
 DWORD clust;   /* Current cluster */
 DWORD sect;   /* Current sector (0:Read operation has terminated) */
 BYTE* dir;   /* Pointer to the directory item in the win[] */
 BYTE fn[12];   /* SFN (in/out) {body[8],ext[3],status[1]} */
#if _USE_LFN != 0
 DWORD blk_ofs;  /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
#endif
#if _USE_FIND
 const TCHAR* pat;  /* Pointer to the name matching pattern */
#endif
} DIR;

/* File information structure (FILINFO) */

typedef struct {
 FSIZE_t fsize;   /* File size */
 WORD fdate;   /* Modified date */
 WORD ftime;   /* Modified time */
 BYTE fattrib;  /* File attribute */
#if _USE_LFN != 0
 TCHAR altname[13];   /* Alternative file name */
 TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
#else
 TCHAR fname[13];  /* File name */
#endif
} FILINFO;

/* File function return code (FRESULT) */

typedef enum {
 FR_OK = 0,    /* (0) Succeeded */
 FR_DISK_ERR,   /* (1) A hard error occurred in the low level disk I/O layer */
 FR_INT_ERR,    /* (2) Assertion failed */
 FR_NOT_READY,   /* (3) The physical drive cannot work */
 FR_NO_FILE,    /* (4) Could not find the file */
 FR_NO_PATH,    /* (5) Could not find the path */
 FR_INVALID_NAME,  /* (6) The path name format is invalid */
 FR_DENIED,    /* (7) Access denied due to prohibited access or directory full */
 FR_EXIST,    /* (8) Access denied due to prohibited access */
 FR_INVALID_OBJECT,  /* (9) The file/directory object is invalid */
 FR_WRITE_PROTECTED,  /* (10) The physical drive is write protected */
 FR_INVALID_DRIVE,  /* (11) The logical drive number is invalid */
 FR_NOT_ENABLED,   /* (12) The volume has no work area */
 FR_NO_FILESYSTEM,  /* (13) There is no valid FAT volume */
 FR_MKFS_ABORTED,  /* (14) The f_mkfs() aborted due to any problem */
 FR_TIMEOUT,    /* (15) Could not get a grant to access the volume within defined period */
 FR_LOCKED,    /* (16) The operation is rejected according to the file sharing policy */
 FR_NOT_ENOUGH_CORE,  /* (17) LFN working buffer could not be allocated */
 FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
 FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;

/*--------------------------------------------------------------*/
/* FatFs module application interface                           */

FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode);    /* Open or create a file */
FRESULT f_close (FIL* fp);           /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br);   /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs);        /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp);          /* Truncate the file */
FRESULT f_sync (FIL* fp);           /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path);      /* Open a directory */
FRESULT f_closedir (DIR* dp);          /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno);       /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno);       /* Find next file */
FRESULT f_mkdir (const TCHAR* path);        /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path);        /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno);     /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask);   /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno);   /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path);        /* Change current directory */
FRESULT f_chdrive (const TCHAR* path);        /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len);       /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label);       /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt);     /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt);   /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work);   /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp);          /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp);        /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...);      /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp);      /* Get a string from the file */

#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->obj.objsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#define f_rmdir(path) f_unlink(path)

#ifndef EOF
#define EOF (-1)
#endif

/*--------------------------------------------------------------*/
/* Additional user defined functions                            */

/* RTC function */
#if !_FS_READONLY && !_FS_NORTC
DWORD get_fattime (void);
#endif

/* Unicode support functions */
#if _USE_LFN != 0      /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR chr);   /* Unicode upper-case conversion */
#if _USE_LFN == 3      /* Memory functions */
void* ff_memalloc (UINT msize);   /* Allocate memory block */
void ff_memfree (void* mblock);   /* Free memory block */
#endif
#endif

/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (_SYNC_t sobj);    /* Lock sync object */
void ff_rel_grant (_SYNC_t sobj);    /* Unlock sync object */
int ff_del_syncobj (_SYNC_t sobj);    /* Delete a sync object */
#endif

/*--------------------------------------------------------------*/
/* Flags and offset address                                     */

/* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ    0x01
#define FA_WRITE   0x02
#define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW  0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS  0x10
#define FA_OPEN_APPEND  0x30

/* Fast seek controls (2nd argument of f_lseek) */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)

/* Format options (2nd argument of f_mkfs) */
#define FM_FAT  0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY  0x07
#define FM_SFD  0x08

/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4

/* File attribute bits for directory entry (FILINFO.fattrib) */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */

4、ff.c(部分内容)

f_mkfs函数,比较重要

/*-----------------------------------------------------------------------*/
/* Create an FAT/exFAT volume                                            */
/*-----------------------------------------------------------------------*/

FRESULT f_mkfs (
 const TCHAR* path, /* Logical drive number */
 BYTE opt,   /* Format option */
 DWORD au,   /* Size of allocation unit (cluster) [byte] */
 void* work,   /* Pointer to working buffer */
 UINT len   /* Size of working buffer */
)
{
 const UINT n_fats = 2;  /* Number of FATs for FAT12/16/32 volume (1 or 2) */
 const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */
 static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4Ks unit) */
 static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */
 BYTE fmt, sys, *buf, *pte, pdrv, part;
 WORD ss;
 DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n;
 DWORD b_vol, b_fat, b_data;    /* Base LBA for volume, fat, data */
 DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */
 UINT i;
 int vol;
 DSTATUS stat;
#if _USE_TRIM || _FS_EXFAT
 DWORD tbl[3];
#endif

/* Check mounted drive and clear work area */
 vol = get_ldnumber(&path);     /* Get target logical drive */
 if (vol < 0) return FR_INVALID_DRIVE;
 if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume */
 pdrv = LD2PD(vol); /* Physical drive */
 part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */

/* Check physical drive status */
 stat = disk_initialize(pdrv);
 if (stat & STA_NOINIT) return FR_NOT_READY;
 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
 if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */
#if _MAX_SS != _MIN_SS  /* Get sector size of the medium if variable sector size cfg. */
 if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR;
 if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR;
#else
 ss = _MAX_SS;
#endif
 if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */
 au /= ss; /* Cluster size in unit of sector */

/* Get working buffer */
 buf = (BYTE*)work;  /* Working buffer */
 sz_buf = len / ss;  /* Size of working buffer (sector) */
 szb_buf = sz_buf * ss; /* Size of working buffer (byte) */
 if (!szb_buf) return FR_MKFS_ABORTED;

/* Determine where the volume to be located (b_vol, sz_vol) */
 if (_MULTI_PARTITION && part != 0) {
  /* Get partition information from partition table in the MBR */
  if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */
  if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check if MBR is valid */
  pte = buf + (MBR_Table + (part - 1) * SZ_PTE);
  if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */
  b_vol = ld_dword(pte + PTE_StLba);  /* Get volume start sector */
  sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */
 } else {
  /* Create a single-partition in this function */
  if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR;
  b_vol = (opt & FM_SFD) ? 0 : 63;  /* Volume start sector */
  if (sz_vol < b_vol) return FR_MKFS_ABORTED;
  sz_vol -= b_vol;      /* Volume size */
 }
 if (sz_vol < 128) return FR_MKFS_ABORTED; /* Check if volume size is >=128s */

/* Pre-determine the FAT type */
 do {
  if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */
   if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */
    fmt = FS_EXFAT; break;
   }
  }
  if (au > 128) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */
  if (opt & FM_FAT32) { /* FAT32 possible? */
   if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */
    fmt = FS_FAT32; break;
   }
  }
  if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */
  fmt = FS_FAT16;
 } while (0);

#if _FS_EXFAT
 if (fmt == FS_EXFAT) { /* Create an exFAT volume */
  DWORD szb_bit, szb_case, sum, nb, cl;
  WCHAR ch, si;
  UINT j, st;
  BYTE b;

if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */
#if _USE_TRIM
  tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */
  disk_ioctl(pdrv, CTRL_TRIM, tbl);
#endif
  /* Determine FAT location, data location and number of clusters */
  if (!au) { /* au auto-selection */
   au = 8;
   if (sz_vol >= 0x80000) au = 64;  /* >= 512Ks */
   if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */
  }
  b_fat = b_vol + 32;          /* FAT start at offset 32 */
  sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss;   /* Number of FAT sectors */
  b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
  if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED;  /* Too small volume? */
  n_clst = (sz_vol - (b_data - b_vol)) / au;    /* Number of clusters */
  if (n_clst <16) return FR_MKFS_ABORTED;     /* Too few clusters? */
  if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED;   /* Too many clusters? */

szb_bit = (n_clst + 7) / 8;      /* Size of allocation bitmap */
  tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */

/* Create a compressed up-case table */
  sect = b_data + au * tbl[0]; /* Table start sector */
  sum = 0;      /* Table checksum to be stored in the 82 entry */
  st = si = i = j = szb_case = 0;
  do {
   switch (st) {
   case 0:
    ch = ff_wtoupper(si); /* Get an up-case char */
    if (ch != si) {
     si++; break;  /* Store the up-case char if exist */
    }
    for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */
    if (j >= 128) {
     ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */
    }
    st = 1;   /* Do not compress short run */
    /* go to next case */
   case 1:
    ch = si++;  /* Fill the short run */
    if (--j == 0) st = 0;
    break;

default:
    ch = (WCHAR)j; si += j; /* Number of chars to skip */
    st = 0;
   }
   sum = xsum32(buf[i + 0] = (BYTE)ch, sum);  /* Put it into the write buffer */
   sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum);
   i += 2; szb_case += 2;
   if (!si || i == szb_buf) {  /* Write buffered data when buffer full or end of process */
    n = (i + ss - 1) / ss;
    if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
    sect += n; i = 0;
   }
  } while (si);
  tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */
  tbl[2] = 1;          /* Number of root dir clusters */

/* Initialize the allocation bitmap */
  sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */
  nb = tbl[0] + tbl[1] + tbl[2];     /* Number of clusters in-use by system */
  do {
   mem_set(buf, 0, szb_buf);
   for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ;
   for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ;
   n = (nsect > sz_buf) ? sz_buf : nsect;  /* Write the buffered data */
   if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
   sect += n; nsect -= n;
  } while (nsect);

/* Initialize the FAT */
  sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */
  j = nb = cl = 0;
  do {
   mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */
   if (cl == 0) { /* Set entry 0 and 1 */
    st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++;
    st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++;
   }
   do {   /* Create chains of bitmap, up-case and root dir */
    while (nb && i < szb_buf) {   /* Create a chain */
     st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF);
     i += 4; cl++; nb--;
    }
    if (!nb && j < 3) nb = tbl[j++]; /* Next chain */
   } while (nb && i < szb_buf);
   n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */
   if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
   sect += n; nsect -= n;
  } while (nsect);

/* Initialize the root directory */
  mem_set(buf, 0, szb_buf);
  buf[SZDIRE * 0 + 0] = 0x83;  /* 83 entry (volume label) */
  buf[SZDIRE * 1 + 0] = 0x81;  /* 81 entry (allocation bitmap) */
  st_dword(buf + SZDIRE * 1 + 20, 2);
  st_dword(buf + SZDIRE * 1 + 24, szb_bit);
  buf[SZDIRE * 2 + 0] = 0x82;  /* 82 entry (up-case table) */
  st_dword(buf + SZDIRE * 2 + 4, sum);
  st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]);
  st_dword(buf + SZDIRE * 2 + 24, szb_case);
  sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */
  do { /* Fill root directory sectors */
   n = (nsect > sz_buf) ? sz_buf : nsect;
   if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
   mem_set(buf, 0, ss);
   sect += n; nsect -= n;
  } while (nsect);

/* Create two set of the exFAT VBR blocks */
  sect = b_vol;
  for (n = 0; n < 2; n++) {
   /* Main record (+0) */
   mem_set(buf, 0, ss);
   mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT   ", 11); /* Boot jump code (x86), OEM name */
   st_dword(buf + BPB_VolOfsEx, b_vol);     /* Volume offset in the physical drive [sector] */
   st_dword(buf + BPB_TotSecEx, sz_vol);     /* Volume size [sector] */
   st_dword(buf + BPB_FatOfsEx, b_fat - b_vol);   /* FAT offset [sector] */
   st_dword(buf + BPB_FatSzEx, sz_fat);     /* FAT size [sector] */
   st_dword(buf + BPB_DataOfsEx, b_data - b_vol);   /* Data offset [sector] */
   st_dword(buf + BPB_NumClusEx, n_clst);     /* Number of clusters */
   st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */
   st_dword(buf + BPB_VolIDEx, GET_FATTIME());    /* VSN */
   st_word(buf + BPB_FSVerEx, 0x100);      /* File system version (1.00) */
   for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */
   for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */
   buf[BPB_NumFATsEx] = 1;     /* Number of FATs */
   buf[BPB_DrvNumEx] = 0x80;    /* Drive number (for int13) */
   st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */
   st_word(buf + BS_55AA, 0xAA55);   /* Signature (placed here regardless of sector size) */
   for (i = sum = 0; i < ss; i++) {  /* VBR checksum */
    if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum);
   }
   if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
   /* Extended bootstrap record (+1..+8) */
   mem_set(buf, 0, ss);
   st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */
   for (j = 1; j < 9; j++) {
    for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */
    if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
   }
   /* OEM/Reserved record (+9..+10) */
   mem_set(buf, 0, ss);
   for ( ; j < 11; j++) {
    for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */
    if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
   }
   /* Sum record (+11) */
   for (i = 0; i < ss; i += 4) st_dword(buf + i, sum);  /* Fill with checksum value */
   if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
  }

} else
#endif /* _FS_EXFAT */
 { /* Create an FAT12/16/32 volume */
  do {
   pau = au;
   /* Pre-determine number of clusters and FAT sub-type */
   if (fmt == FS_FAT32) { /* FAT32 volume */
    if (!pau) { /* au auto-selection */
     n = sz_vol / 0x20000; /* Volume size in unit of 128KS */
     for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */
    }
    n_clst = sz_vol / pau; /* Number of clusters */
    sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */
    sz_rsv = 32; /* Number of reserved sectors */
    sz_dir = 0;  /* No static directory */
    if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED;
   } else {    /* FAT12/16 volume */
    if (!pau) { /* au auto-selection */
     n = sz_vol / 0x1000; /* Volume size in unit of 4KS */
     for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */
    }
    n_clst = sz_vol / pau;
    if (n_clst > MAX_FAT12) {
     n = n_clst * 2 + 4;  /* FAT size [byte] */
    } else {
     fmt = FS_FAT12;
     n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */
    }
    sz_fat = (n + ss - 1) / ss;  /* FAT size [sector] */
    sz_rsv = 1;      /* Number of reserved sectors */
    sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */
   }
   b_fat = b_vol + sz_rsv;      /* FAT base */
   b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */

/* Align data base to erase block boundary (for flash memory media) */
   n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */
   if (fmt == FS_FAT32) {  /* FAT32: Move FAT base */
    sz_rsv += n; b_fat += n;
   } else {     /* FAT12/16: Expand FAT size */
    sz_fat += n / n_fats;
   }

/* Determine number of clusters and final check of validity of the FAT sub-type */
   if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */
   n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;
   if (fmt == FS_FAT32) {
    if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */
     if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */
     return FR_MKFS_ABORTED;
    }
   }
   if (fmt == FS_FAT16) {
    if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */
     if (!au && (pau * 2) <= 64) {
      au = pau * 2; continue;  /* Adjust cluster size and retry */
     }
     if ((opt & FM_FAT32)) {
      fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */
     }
     if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
     return FR_MKFS_ABORTED;
    }
    if  (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */
     if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
     return FR_MKFS_ABORTED;
    }
   }
   if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */

/* Ok, it is the valid cluster configuration */
   break;
  } while (1);

#if _USE_TRIM
  tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */
  disk_ioctl(pdrv, CTRL_TRIM, tbl);
#endif
  /* Create FAT VBR */
  mem_set(buf, 0, ss);
  mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */
  st_word(buf + BPB_BytsPerSec, ss);    /* Sector size [byte] */
  buf[BPB_SecPerClus] = (BYTE)pau;    /* Cluster size [sector] */
  st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */
  buf[BPB_NumFATs] = (BYTE)n_fats;    /* Number of FATs */
  st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */
  if (sz_vol < 0x10000) {
   st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */
  } else {
   st_dword(buf + BPB_TotSec32, sz_vol);  /* Volume size in 32-bit LBA */
  }
  buf[BPB_Media] = 0xF8;       /* Media descriptor byte */
  st_word(buf + BPB_SecPerTrk, 63);    /* Number of sectors per track (for int13) */
  st_word(buf + BPB_NumHeads, 255);    /* Number of heads (for int13) */
  st_dword(buf + BPB_HiddSec, b_vol);    /* Volume offset in the physical drive [sector] */
  if (fmt == FS_FAT32) {
   st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */
   st_dword(buf + BPB_FATSz32, sz_fat);  /* FAT size [sector] */
   st_dword(buf + BPB_RootClus32, 2);   /* Root directory cluster # (2) */
   st_word(buf + BPB_FSInfo32, 1);    /* Offset of FSINFO sector (VBR + 1) */
   st_word(buf + BPB_BkBootSec32, 6);   /* Offset of backup VBR (VBR + 6) */
   buf[BS_DrvNum32] = 0x80;     /* Drive number (for int13) */
   buf[BS_BootSig32] = 0x29;     /* Extended boot signature */
   mem_cpy(buf + BS_VolLab32, "NO NAME    " "FAT32   ", 19); /* Volume label, FAT signature */
  } else {
   st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */
   st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */
   buf[BS_DrvNum] = 0x80;      /* Drive number (for int13) */
   buf[BS_BootSig] = 0x29;      /* Extended boot signature */
   mem_cpy(buf + BS_VolLab, "NO NAME    " "FAT     ", 19); /* Volume label, FAT signature */
  }
  st_word(buf + BS_55AA, 0xAA55);     /* Signature (offset is fixed here regardless of sector size) */
  if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */

/* Create FSINFO record if needed */
  if (fmt == FS_FAT32) {
   disk_write(pdrv, buf, b_vol + 6, 1);  /* Write backup VBR (VBR + 6) */
   mem_set(buf, 0, ss);
   st_dword(buf + FSI_LeadSig, 0x41615252);
   st_dword(buf + FSI_StrucSig, 0x61417272);
   st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */
   st_dword(buf + FSI_Nxt_Free, 2);   /* Last allocated cluster# */
   st_word(buf + BS_55AA, 0xAA55);
   disk_write(pdrv, buf, b_vol + 7, 1);  /* Write backup FSINFO (VBR + 7) */
   disk_write(pdrv, buf, b_vol + 1, 1);  /* Write original FSINFO (VBR + 1) */
  }

/* Initialize FAT area */
  mem_set(buf, 0, (UINT)szb_buf);
  sect = b_fat;  /* FAT start sector */
  for (i = 0; i < n_fats; i++) {   /* Initialize FATs each */
   if (fmt == FS_FAT32) {
    st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */
    st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */
    st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */
   } else {
    st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */
   }
   nsect = sz_fat;  /* Number of FAT sectors */
   do { /* Fill FAT sectors */
    n = (nsect > sz_buf) ? sz_buf : nsect;
    if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;
    mem_set(buf, 0, ss);
    sect += n; nsect -= n;
   } while (nsect);
  }

/* Initialize root directory (fill with zero) */
  nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */
  do {
   n = (nsect > sz_buf) ? sz_buf : nsect;
   if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;
   sect += n; nsect -= n;
  } while (nsect);
 }

/* Determine system ID in the partition table */
 if (_FS_EXFAT && fmt == FS_EXFAT) {
  sys = 0x07;   /* HPFS/NTFS/exFAT */
 } else {
  if (fmt == FS_FAT32) {
   sys = 0x0C;  /* FAT32X */
  } else {
   if (sz_vol >= 0x10000) {
    sys = 0x06; /* FAT12/16 (>=64KS) */
   } else {
    sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */
   }
  }
 }

/* Update partition information */
 if (_MULTI_PARTITION && part != 0) { /* Created in the existing partition */
  /* Update system ID in the partition table */
  if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */
  buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys;  /* Set system ID */
  if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */
 } else {        /* Created as a new single partition */
  if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */
   mem_set(buf, 0, ss);
   st_word(buf + BS_55AA, 0xAA55);  /* MBR signature */
   pte = buf + MBR_Table;    /* Create partition table for single partition in the drive */
   pte[PTE_Boot] = 0;     /* Boot indicator */
   pte[PTE_StHead] = 1;    /* Start head */
   pte[PTE_StSec] = 1;     /* Start sector */
   pte[PTE_StCyl] = 0;     /* Start cylinder */
   pte[PTE_System] = sys;    /* System type */
   n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */
   pte[PTE_EdHead] = 254;    /* End head */
   pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */
   pte[PTE_EdCyl] = (BYTE)n;   /* End cylinder */
   st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */
   st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */
   if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */
  }
 }

if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR;

return FR_OK;
}

f_mount函数

/*---------------------------------------------------------------------------

Public Functions (FatFs API)

----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------*/
/* Mount/Unmount a Logical Drive                                         */
/*-----------------------------------------------------------------------*/

FRESULT f_mount (
 FATFS* fs,   /* Pointer to the file system object (NULL:unmount)*/
 const TCHAR* path, /* Logical drive number to be mounted/unmounted */
 BYTE opt   /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */
)
{
 FATFS *cfs;
 int vol;
 FRESULT res;
 const TCHAR *rp = path;

/* Get logical drive number */
 vol = get_ldnumber(&rp);
 if (vol < 0) return FR_INVALID_DRIVE;
 cfs = FatFs[vol];     /* Pointer to fs object */

if (cfs) {
#if _FS_LOCK != 0
  clear_lock(cfs);
#endif
#if _FS_REENTRANT      /* Discard sync object of the current volume */
  if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;
#endif
  cfs->fs_type = 0;    /* Clear old fs object */
 }

if (fs) {
  fs->fs_type = 0;    /* Clear new fs object */
#if _FS_REENTRANT      /* Create sync object for the new volume */
  if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
#endif
 }
 FatFs[vol] = fs;     /* Register new fs object */

if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */

res = find_volume(&path, &fs, 0); /* Force mounted the volume */
 LEAVE_FF(fs, res);
}
这里面最重要的find_volume函数就不粘贴了,太多了……

5、diskio.h

#define _USE_WRITE 1 /* 1: Enable disk_write function */
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl function */

#include "integer.h"

/* Status of Disk Functions */
typedef BYTE DSTATUS;

/* Results of Disk Functions */
typedef enum {
 RES_OK = 0,  /* 0: Successful */
 RES_ERROR,  /* 1: R/W Error */
 RES_WRPRT,  /* 2: Write Protected */
 RES_NOTRDY,  /* 3: Not Ready */
 RES_PARERR  /* 4: Invalid Parameter */
} DRESULT;

/*---------------------------------------*/
/* Prototypes for disk control functions */

DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
DWORD get_fattime (void);

/* Disk Status Bits (DSTATUS) */

#define STA_NOINIT  0x01 /* Drive not initialized */
#define STA_NODISK  0x02 /* No medium in the drive */
#define STA_PROTECT  0x04 /* Write protected */

/* Command code for disk_ioctrl fucntion */

/* Generic command (Used by FatFs) */
#define CTRL_SYNC  0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE  2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE  3 /* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM  4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */

/* Generic command (Not used by FatFs) */
#define CTRL_POWER   5 /* Get/Set power status */
#define CTRL_LOCK   6 /* Lock/Unlock media removal */
#define CTRL_EJECT   7 /* Eject media */
#define CTRL_FORMAT   8 /* Create physical format on the media */

/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE  10 /* Get card type */
#define MMC_GET_CSD   11 /* Get CSD */
#define MMC_GET_CID   12 /* Get CID */
#define MMC_GET_OCR   13 /* Get OCR */
#define MMC_GET_SDSTAT  14 /* Get SD status */

/* ATA/CF specific ioctl command */
#define ATA_GET_REV   20 /* Get F/W revision */
#define ATA_GET_MODEL  21 /* Get model name */
#define ATA_GET_SN   22 /* Get serial number */

6、diskio.c文件

DSTATUS disk_status (
 BYTE pdrv  /* Physical drive number to identify the drive */
)
{
  DSTATUS stat;

stat = disk.drv[pdrv]->disk_status(disk.lun[pdrv]);
  return stat;
}

/**
  * @brief  Initializes a Drive
  * @param  pdrv: Physical drive number (0..)
  * @retval DSTATUS: Operation status
  */
DSTATUS disk_initialize (
 BYTE pdrv    /* Physical drive nmuber to identify the drive */
)
{
  DSTATUS stat = RES_OK;

if(disk.is_initialized[pdrv] == 0)
  {
    disk.is_initialized[pdrv] = 1;
    stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);
  }
  return stat;
}

/**
  * @brief  Reads Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT disk_read (
 BYTE pdrv,  /* Physical drive nmuber to identify the drive */
 BYTE *buff,  /* Data buffer to store read data */
 DWORD sector,         /* Sector address in LBA */
 UINT count  /* Number of sectors to read */
)
{
  DRESULT res;

res = disk.drv[pdrv]->disk_read(disk.lun[pdrv], buff, sector, count);
  return res;
}

/**
  * @brief  Writes Sector(s)
  * @param  pdrv: Physical drive number (0..)
  * @param  *buff: Data to be written
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to write (1..128)
  * @retval DRESULT: Operation result
  */
#if _USE_WRITE == 1
DRESULT disk_write (
 BYTE pdrv,  /* Physical drive nmuber to identify the drive */
 const BYTE *buff, /* Data to be written */
 DWORD sector,  /* Sector address in LBA */
 UINT count         /* Number of sectors to write */
)
{
  DRESULT res;

res = disk.drv[pdrv]->disk_write(disk.lun[pdrv], buff, sector, count);
  return res;
}
#endif /* _USE_WRITE == 1 */

/**
  * @brief  I/O control operation
  * @param  pdrv: Physical drive number (0..)
  * @param  cmd: Control code
  * @param  *buff: Buffer to send/receive control data
  * @retval DRESULT: Operation result
  */
#if _USE_IOCTL == 1
DRESULT disk_ioctl (
 BYTE pdrv,  /* Physical drive nmuber (0..) */
 BYTE cmd,  /* Control code */
 void *buff  /* Buffer to send/receive control data */
)
{
  DRESULT res;

res = disk.drv[pdrv]->disk_ioctl(disk.lun[pdrv], cmd, buff);
  return res;
}
#endif /* _USE_IOCTL == 1 */

/**
  * @brief  Gets Time from RTC
  * @param  None
  * @retval Time in DWORD
  */
__weak DWORD get_fattime (void)
{
  return 0;
}

上面就是整个文件系统我的理解添加的注释

1. FatFs中有两个重要的缓冲区:win[]和buffer。win[]在FATFS结构体中,buffer在FIL结构体中。

win[]:系统缓冲区。当操作MBR,DBR,FAT表,根目录区时,使用该缓冲区;

buffer:文件缓冲区。当对文件的内容进行操作时,如读、写、修改时,才使用该缓冲区。

2. 在对文件的f_read和f_write过程中(不考虑f_lseek的情况),只有需要读写的最后一个扇区(内容小于512字节)才会被暂存到buffer中,而前面的扇区内容是直接通过磁盘驱动disk_read/disk_write在用户缓冲区和物理磁盘之间进行交互的。



【原创】【FS】FATFS文件系统介绍(未完待续........2018.4.1)相关推荐

  1. 【转载】【FS】FATFS文件系统介绍(未完待续........2018.4.1)

    一.这是个什么玩意 它是一个文件系统,那文件系统是个什么玩意,直接从字面意思理解,它就是个管理文件的系统,所以叫文件系统,直白吧,也可以说是文件存储协议.但是继续追问的话会问,怎么来管理文件呢?好,基 ...

  2. mega raid linux,在lsi megaraid sas 8204elp 装linux系统(未完待续)

    在lsi megaraid sas 8204elp 装linux系统(未完待续) (2009-05-06 13:24:00) 标签: 杂谈 在目前最新的linux内核中,没有8204elp的raid驱 ...

  3. CentOS8搭建SonarQube9+SonarScanner+Postgresql+bitbucket+cppcheck 扫描C语言。(未完待续)

    前提条件 带有您首选发行版的新安装的 Linux 服务器. 一.添加新用户sonar 1.添加一个新的用户帐户 使用命令创建一个新的用户帐户sonar. # adduser sonar 使用 为新用户 ...

  4. linux引数列项目过长,Linux 命令个人总结====== 未完待续 个人认为比较重要

    Linux 命令个人总结====== 未完待续 man [功能说明]: 查看帮助 [语法格式]: man [123456789]命令.文件. [选项参数]: 数字"1"表示用户命令 ...

  5. javascript有用小功能总结(未完待续)

    1)javascript让页面标题滚动效果 代码如下: <title>您好,欢迎访问我的博客</title> <script type="text/javasc ...

  6. Ubuntu1804和2004高版本,右键无法创建TXT文档的解决办法【未完待续】

    Ubuntu1804和2004高版本,右键无法创建TXT文档的解决办法[未完待续] 问题: Ubuntu1804和2004高版本,右键无法创建TXT文档 解决办法1:[常用] 1.打开终端 2.输入: ...

  7. 《图解 HTTP》读书笔记(未完待续)

    ARP 协议(Address Resolution Protocol)一种以解析地址的协议,根据通信双方的 IP 地址就可以查出对应的 MAC 地址. MAC( Media Access Contro ...

  8. pythonb超分辨成像_Papers | 超分辨 + 深度学习(未完待续)

    1. SRCNN 1.1. Contribution end-to-end深度学习应用在超分辨领域的开山之作(非 end-to-end 见 Story.3 ). 指出了超分辨方向上传统方法( spar ...

  9. WindowsMobile应该如何发展?(未完待续)

    MEDC2007已经过去两周了,作为WindowsMobile软件应用及开发界的一次盛会,本次大会后留给我的不仅仅是绚丽的UI,强大的功能.新的开发工具.而是更多的关于WindowsMobile在中国 ...

最新文章

  1. 架构师技术文档:Redis+Nginx+Spring全家桶+Dubbo精选
  2. 【C/C++】运算结果出现1.#Q0问题分析
  3. 号称迄今为止最快,.NET6带来了什么?
  4. 浅拷贝+引用计数--写时拷贝---模拟实现string容器
  5. The .NET Core runtime can be found at:(Windows)
  6. adb工具 手工操作android模拟器上的数据库
  7. 故障常见原因归类分析及预防和应对措施
  8. 查看文件md5_了解 | Mongodb 文件存储之 GridFs
  9. 京东联盟高级API接口-批量查询推广位-京东联盟接口详情
  10. u-boot编译构成之 MLO(1)
  11. 自知、自胜、知足、强行,不失其所
  12. [data engineering] (一)数据工程师的工作内容以及需要的软硬实力
  13. 自动驾驶下的伦理困境
  14. java ews appointment_EWS-JAVA-API的使用
  15. Leetcode分类练习-查找(2)对撞指针
  16. Seq2Seq Attention模型
  17. matlab中for循环,while循环的基本使用。
  18. DaVinci DM6437 中文教程
  19. C语言实现的超详细的冒泡排序(附有详细代码)
  20. 如何在Excel/WPS表格中使用百度翻译公式?

热门文章

  1. C# 从入门到入土(自学笔记)--Day3
  2. 简单的c语言三角形程序,剖析C语言是如何画出这样的三角形的
  3. Spring Bean的三种配置方式
  4. Java实验一——习题册+登陆界面 源代码
  5. pycharm debug加参数
  6. “世界超级船厂项目”选用霍尼韦尔互联控制、安全和安防系统
  7. 双路高速 AD 实验
  8. python 将语音转为吉他谱
  9. NER 原理及 TENER 模型搭建
  10. 使用SpaCy构建自定义 NER 模型