关于FAT文件系统的基本理论,可以参考作者ZC·Shou的博客:
FatFs 之一 R0.13c版源码目录文件、函数、全配置项详解及移植说明
FatFs 之二 路径规则、字符编码、编码页、卷管理详解[添加链接描述]
FatFs 之三 FAT文件系统基础、FAT 数据格式、引导、编码
接下来对文件类型FAT12进行解析,其他相关配置默认不开启。
f_mkfs() FAT12格式化包含如下几个部分:
区域名称 作用 位置 大小
MBR(主引导记录) 磁盘分区表,定义分区信息 磁盘的第一个扇区 1 扇区
VRB 包含引导扇区、文件系统元数据 分区的起始扇区 由 BPB_ResvdSecCnt 定义
FAT 表 记录簇的分配状态和簇链 保留区之后 由 BPB_FATSz 定义(每个FAT表大小)
根目录 存储根目录下的文件和子目录条目(仅 FAT12/16) FAT 表之后 固定大小(FAT32 无固定根目录)
数据区 存储文件和目录的实际数据 根目录或 FAT 表之后 剩余所有扇区
f_mkfs()源码
FRESULT f_mkfs (
const TCHAR* path, /* Logical drive number */
const MKFS_PARM* opt, /* Format options */
void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */
UINT len /* Size of working buffer [byte] */
)
{
static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4K sector unit)FAT卷的簇大小边界(4K扇区单位) */
static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128K sector unit)FAT32 卷的簇大小边界(128K 扇区单位) */
static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */
BYTE fsopt, fsty, sys, pdrv, ipart;
BYTE *buf;
BYTE *pte;
WORD ss; /* Sector size */
DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn;
LBA_t sz_vol, b_vol, b_fat, b_data; /* Volume size, base LBA of volume, base LBA of FAT and base LBA of data */
LBA_t sect, lba[2];
DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved area, FAT area, directry area, data area and cluster */
UINT n_fat, n_root, i; /* Number of FATs, number of roor directory entries and some index */
int vol;
DSTATUS ds;
FRESULT res;
/* Check mounted drive and clear work area */
/*获取逻辑驱动卷ID,数字:0~9。并获取卷ID后面的段'\'*/
vol = get_ldnumber(&path); /* Get target logical drive 获取卷ID*/
if (vol < 0) return FR_INVALID_DRIVE;
if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted 已挂载过,清除文件类型*/
pdrv = LD2PD(vol); /* Hosting physical drive 获取逻辑驱动号*/
ipart = LD2PT(vol); /* Hosting partition (0:create as new, 1..:existing partition) 默认0自动分区创建*/
/* Initialize the hosting physical drive */
ds = disk_initialize(pdrv);/*初始化物理磁盘*/
if (ds & STA_NOINIT) return FR_NOT_READY;
if (ds & STA_PROTECT) return FR_WRITE_PROTECTED;/*处于写保护时,不可操作*/
/* Get physical drive parameters (sz_drv, sz_blk and ss) */
/* 如配置:获取磁盘的一些参数设置:簇、目录数目、文件类型、fat表个数、块大小 */
if (!opt) opt = &defopt; /* 使用默认配置Use default parameter if it is not given */
sz_blk = opt->align;
if (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the parameter or lower layer */
if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Use default if the block size is invalid 参数检测包括:如果不是2的倍数(或者0),写入默认值 */
#if FF_MAX_SS != FF_MIN_SS
if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR;
if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR;
#else
ss = FF_MAX_SS;/*每个扇区大小 BYTE*/
#endif
/* Options for FAT sub-type and FAT parameters FAT 子类型和 FAT 参数的选项*/
fsopt = opt->fmt & (FM_ANY | FM_SFD);
n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1;/*1~2 fat表个数最多为2(fat+fat备份)*/
n_root = (opt->n_root >= 1 && opt->n_root <= 32768 && (opt->n_root % (ss / SZDIRE)) == 0) ? opt->n_root : 512;/* 根目录条目数,每个目录32字节*/
sz_au = (opt->au_size <= 0x1000000 && (opt->au_size & (opt->au_size - 1)) == 0) ? opt->au_size : 0;/*簇大小 byte */
sz_au /= ss; /* Byte --> Sector 每簇包含多少扇区*/
/* Get working buffer */
sz_buf = len / ss; /* Size of working buffer [sector]工作缓冲区 */
if (sz_buf == 0) return FR_NOT_ENOUGH_CORE;
buf = (BYTE*)work; /* Working buffer 检测buff是否为空指针*/
#if FF_USE_LFN == 3
if (!buf) buf = ff_memalloc(sz_buf * ss); /* Use heap memory for working buffer */
#endif
if (!buf) return FR_NOT_ENOUGH_CORE;
/* Determine where the volume to be located (b_vol, sz_vol) 确定卷的位置(b_vol,sz_vol) */
b_vol = sz_vol = 0;
if (FF_MULTI_PARTITION && ipart != 0) { /* Is the volume associated with any specific partition? 多分区*/
/* Get partition location from the existing partition table */
if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */
if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */
#if FF_LBA64
if (buf[MBR_Table + PTE_System] == 0xEE) { /* GPT protective MBR? */
DWORD n_ent, ofs;
QWORD pt_lba;
/* Get the partition location from GPT */
if (disk_read(pdrv, buf, 1, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load GPT header sector (next to MBR) */
if (!test_gpt_header(buf)) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if GPT header is valid */
n_ent = ld_dword(buf + GPTH_PtNum); /* Number of entries */
pt_lba = ld_qword(buf + GPTH_PtOfs); /* Table start sector */
ofs = i = 0;
while (n_ent) { /* Find MS Basic partition with order of ipart */
if (ofs == 0 && disk_read(pdrv, buf, pt_lba++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Get PT sector */
if (!memcmp(buf + ofs + GPTE_PtGuid, GUID_MS_Basic, 16) && ++i == ipart) { /* MS basic data partition? */
b_vol = ld_qword(buf + ofs + GPTE_FstLba);
sz_vol = ld_qword(buf + ofs + GPTE_LstLba) - b_vol + 1;
break;
}
n_ent--; ofs = (ofs + SZ_GPTE) % ss; /* Next entry */
}
if (n_ent == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* Partition not found */
fsopt |= 0x80; /* Partitioning is in GPT */
} else
#endif
{ /* Get the partition location from MBR partition table */
pte = buf + (MBR_Table + (ipart - 1) * SZ_PTE);
if (ipart > 4 || pte[PTE_System] == 0) LEAVE_MKFS(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 { /* The volume is associated with a physical drive 物理设备:扇区数目*/
if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
if (!(fsopt & FM_SFD)) { /* To be partitioned? 是否需要分区*/
/* Create a single-partition on the drive in this function 在驱动器上创建一个单一分区*/
#if FF_LBA64
if (sz_vol >= FF_MIN_GPT) { /* Which partition type to create, MBR or GPT? */
fsopt |= 0x80; /* Partitioning is in GPT */
b_vol = GPT_ALIGN / ss; sz_vol -= b_vol + GPT_ITEMS * SZ_GPTE / ss + 1; /* Estimated partition offset and size */
} else
#endif
{ /* Partitioning is in MBR MBR(主引导记录,存储分区表,定义分区信息)扇区0 */
if (sz_vol > N_SEC_TRACK) {
b_vol = N_SEC_TRACK; sz_vol -= b_vol; /* Estimated partition offset and size 预计的分区偏移量和大小*/
}
}
}
}
if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128 sectors */
/* Now start to create an FAT volume at b_vol and sz_vol 开启创建FAT表 */
do { /* Pre-determine the FAT type 预先确定FAT类型*/
if (FF_FS_EXFAT && (fsopt & FM_EXFAT)) { /* exFAT possible? 是否是扩展FAT */
if ((fsopt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || sz_au > 128) { /* exFAT only, vol >= 64M sectors or sz_au > 128 sectors ? */
fsty = FS_EXFAT; break;
}
}
#if FF_LBA64
if (sz_vol >= 0x100000000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too large volume for FAT/FAT32 */
#endif
if (sz_au > 128) sz_au = 128; /* Invalid AU for FAT/FAT32? 簇数不能超过128 即簇数(n)*/
if (fsopt & FM_FAT32) { /* FAT32 possible? */
if (!(fsopt & FM_FAT)) { /* no-FAT? */
fsty = FS_FAT32; break;
}
}
if (!(fsopt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */
fsty = FS_FAT16;/*不是FAT32,默认FAT16,后面根据磁盘大小确定是FAT12 or FAT16*/
} while (0);
vsn = (DWORD)sz_vol + GET_FATTIME(); /* VSN(卷序列号) generated from current time and partition size */
#if FF_FS_EXFAT
if (fsty == FS_EXFAT) { /* Create an exFAT volume */
DWORD szb_bit, szb_case, sum, nbit, clu, clen[3];
WCHAR ch, si;
UINT j, st;
if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume for exFAT? */
#if FF_USE_TRIM
lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */
disk_ioctl(pdrv, CTRL_TRIM, lba);
#endif
/* Determine FAT location, data location and number of clusters */
if (sz_au == 0) { /* AU auto-selection */
sz_au = 8;
if (sz_vol >= 0x80000) sz_au = 64; /* >= 512Ks */
if (sz_vol >= 0x4000000) sz_au = 256; /* >= 64Ms */
}
b_fat = b_vol + 32; /* FAT start at offset 32 */
sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */
b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */
if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
n_clst = (DWORD)((sz_vol - (b_data - b_vol)) / sz_au); /* Number of clusters */
if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */
if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */
szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */
clen[0] = (szb_bit + sz_au * ss - 1) / (sz_au * ss); /* Number of allocation bitmap clusters */
/* Create a compressed up-case table */
sect = b_data + sz_au * clen[0]; /* Table start sector */
sum = 0; /* Table checksum to be stored in the 82 entry */
st = 0; si = 0; i = 0; j = 0; szb_case = 0;
do {
switch (st) {
case 0:
ch = (WCHAR)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 chars */
}
st = 1; /* Do not compress short run */
/* FALLTHROUGH */
case 1:
ch = si++; /* Fill the short run */
if (--j == 0) st = 0;
break;
default:
ch = (WCHAR)j; si += (WCHAR)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 == 0 || i == sz_buf * ss) { /* Write buffered data when buffer full or end of process */
n = (i + ss - 1) / ss;
if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
sect += n; i = 0;
}
} while (si);
clen[1] = (szb_case + sz_au * ss - 1) / (sz_au * ss); /* Number of up-case table clusters */
clen[2] = 1; /* Number of root directory clusters */
/* Initialize the allocation bitmap */
sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of bitmap sectors */
nbit = clen[0] + clen[1] + clen[2]; /* Number of clusters in-use by system (bitmap, up-case and root-dir) */
do {
memset(buf, 0, sz_buf * ss); /* Initialize bitmap buffer */
for (i = 0; nbit != 0 && i / 8 < sz_buf * ss; buf[i / 8] |= 1 << (i % 8), i++, nbit--) ; /* Mark used clusters */
n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */
if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(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 = nbit = clu = 0;
do {
memset(buf, 0, sz_buf * ss); i = 0; /* Clear work area and reset write offset */
if (clu == 0) { /* Initialize FAT [0] and FAT[1] */
st_dword(buf + i, 0xFFFFFFF8); i += 4; clu++;
st_dword(buf + i, 0xFFFFFFFF); i += 4; clu++;
}
do { /* Create chains of bitmap, up-case and root directory */
while (nbit != 0 && i < sz_buf * ss) { /* Create a chain */
st_dword(buf + i, (nbit > 1) ? clu + 1 : 0xFFFFFFFF);
i += 4; clu++; nbit--;
}
if (nbit == 0 && j < 3) nbit = clen[j++]; /* Get next chain length */
} while (nbit != 0 && i < sz_buf * ss);
n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */
if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
sect += n; nsect -= n;
} while (nsect);
/* Initialize the root directory */
memset(buf, 0, sz_buf * ss);
buf[SZDIRE * 0 + 0] = ET_VLABEL; /* Volume label entry (no label) */
buf[SZDIRE * 1 + 0] = ET_BITMAP; /* Bitmap entry */
st_dword(buf + SZDIRE * 1 + 20, 2); /* cluster */
st_dword(buf + SZDIRE * 1 + 24, szb_bit); /* size */
buf[SZDIRE * 2 + 0] = ET_UPCASE; /* Up-case table entry */
st_dword(buf + SZDIRE * 2 + 4, sum); /* sum */
st_dword(buf + SZDIRE * 2 + 20, 2 + clen[0]); /* cluster */
st_dword(buf + SZDIRE * 2 + 24, szb_case); /* size */
sect = b_data + sz_au * (clen[0] + clen[1]); nsect = sz_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) LEAVE_MKFS(FR_DISK_ERR);
memset(buf, 0, ss); /* Rest of entries are filled with zero */
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) */
memset(buf, 0, ss);
memcpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */
st_qword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */
st_qword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */
st_dword(buf + BPB_FatOfsEx, (DWORD)(b_fat - b_vol)); /* FAT offset [sector] */
st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */
st_dword(buf + BPB_DataOfsEx, (DWORD)(b_data - b_vol)); /* Data offset [sector] */
st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */
st_dword(buf + BPB_RootClusEx, 2 + clen[0] + clen[1]); /* Root directory cluster number */
st_dword(buf + BPB_VolIDEx, vsn); /* VSN */
st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem 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 = sz_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) LEAVE_MKFS(FR_DISK_ERR);
/* Extended bootstrap record (+1..+8) */
memset(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) LEAVE_MKFS(FR_DISK_ERR);
}
/* OEM/Reserved record (+9..+10) */
memset(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) LEAVE_MKFS(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) LEAVE_MKFS(FR_DISK_ERR);
}
} else
#endif /* FF_FS_EXFAT */
{ /* Create an FAT/FAT32 volume 此处开始创建一个FAT卷 */
do {
pau = sz_au;/* 簇大小:扇区数*/
/* Pre-determine number of clusters and FAT sub-type 预先确定簇的数量和 FAT 子类型 前面默认定义fsty */
if (fsty == FS_FAT32) { /* FAT32 volume */
if (pau == 0) { /* AU auto-selection */
n = (DWORD)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 = (DWORD)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) LEAVE_MKFS(FR_MKFS_ABORTED);
} else { /* FAT volume */
if (pau == 0) { /* au auto-selection 如果未定义簇,则自动簇数*/
n = (DWORD)sz_vol / 0x1000; /* Volume size in unit of 4KS sz_vol为去掉63扇区大小,卷尺寸以4k为单位*/
for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */
}
n_clst = (DWORD)sz_vol / pau;/*计算出剩余扇区,也就是分区的总簇数 */
if (n_clst > MAX_FAT12) {
n = n_clst * 2 + 4; /* FAT size [byte] */
} else {
fsty = FS_FAT12;
n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] 每簇1.5byte 总簇数在FAT表上总字节数=(n_clst +2)×1.5 向上取整*/
}
sz_fat = (n + ss - 1) / ss; /* FAT size [sector] 根据簇数字节数,计算出FAT表大小(占用扇区数)*/
sz_rsv = 1; /* Number of reserved sectors 1个保留扇区*/
sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root directory size [sector] 根目录大小(占用扇区数) 32字节一个目录 */
}
b_fat = b_vol + sz_rsv; /* FAT base FAT表起始扇区*/
b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base 数据区起始扇区*/
/* Align data area to erase block boundary (for flash memory media) 将数据区域对齐到擦除块边界(适用于闪存介质)*/
n = (DWORD)(((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data); /* Sectors to next nearest from current data base 从当前数据块到下一个最近扇区的扇区数*/
if (fsty == FS_FAT32) { /* FAT32: Move FAT */
sz_rsv += n; b_fat += n;
} else { /* FAT: Expand FAT */
if (n % n_fat) { /* Adjust fractional error if needed */
n--; sz_rsv++; b_fat++;
}
sz_fat += n / n_fat;
}
/* Determine number of clusters and final check of validity of the FAT sub-type 确定簇的数量并最终检查 FAT 子类型的有效性*/
if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */
n_clst = ((DWORD)sz_vol - sz_rsv - sz_fat * n_fat - sz_dir) / pau;/*数据区占用的簇数*/
if (fsty == FS_FAT32) {
if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32? */
if (sz_au == 0 && (sz_au = pau / 2) != 0) continue; /* Adjust cluster size and retry */
LEAVE_MKFS(FR_MKFS_ABORTED);
}
}
/* 根据数据区占用的簇数,计算出当前卷的文件类型*/
if (fsty == FS_FAT16) {
if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */
if (sz_au == 0 && (pau * 2) <= 64) {
sz_au = pau * 2; continue; /* Adjust cluster size and retry */
}
if ((fsopt & FM_FAT32)) {
fsty = FS_FAT32; continue; /* Switch type to FAT32 and retry */
}
if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
LEAVE_MKFS(FR_MKFS_ABORTED);
}
if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */
if (sz_au == 0 && (sz_au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
LEAVE_MKFS(FR_MKFS_ABORTED);
}
}
if (fsty == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */
/* Ok, it is the valid cluster configuration */
break;
} while (1);
#if FF_USE_TRIM
lba[0] = b_vol; lba[1] = b_vol + sz_vol - 1; /* Inform storage device that the volume area may be erased */
disk_ioctl(pdrv, CTRL_TRIM, lba);
#endif
/* Create FAT VBR 分区起始的扇区VBR,记录分区信息 */
memset(buf, 0, ss);
memcpy(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_fat; /* Number of FATs FAT表个数 */
st_word(buf + BPB_RootEntCnt, (WORD)((fsty == FS_FAT32) ? 0 : n_root)); /* Number of root directory entries 根目录个数 */
if (sz_vol < 0x10000) {
st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* FAT卷有效扇区总数Volume size in 16-bit LBA */
} else {
st_dword(buf + BPB_TotSec32, (DWORD)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, (DWORD)b_vol); /* 分区位置在卷上的偏移Volume offset in the physical drive [sector] */
if (fsty == FS_FAT32) {
st_dword(buf + BS_VolID32, vsn); /* 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 */
memcpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
} else {
st_dword(buf + BS_VolID, vsn); /* 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 */
memcpy(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) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */
/* Create FSINFO record if needed */
if (fsty == FS_FAT32) {
disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */
memset(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 初始化FAT表 */
memset(buf, 0, sz_buf * ss);
sect = b_fat; /* FAT start sector FAT起始扇区位置*/
for (i = 0; i < n_fat; i++) { /* Initialize FATs each */
if (fsty == FS_FAT32) {
st_dword(buf + 0, 0xFFFFFFF8); /* FAT[0] */
st_dword(buf + 4, 0xFFFFFFFF); /* FAT[1] */
st_dword(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory at cluster# 2) */
} else {
st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] fat表的扇区头:2个簇号大小*/
}
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) LEAVE_MKFS(FR_DISK_ERR);
memset(buf, 0, ss); /* Rest of FAT area is initially zero */
sect += n; nsect -= n;
} while (nsect);
}
/* Initialize root directory (fill with zero) 把根目录所在的扇区全部清0 */
nsect = (fsty == 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) LEAVE_MKFS(FR_DISK_ERR);
sect += n; nsect -= n;
} while (nsect);
}
/* A FAT volume has been created here */
/* Determine system ID in the MBR partition table MBR:第0号扇区写入 */
if (FF_FS_EXFAT && fsty == FS_EXFAT) {
sys = 0x07; /* exFAT */
} else if (fsty == FS_FAT32) {
sys = 0x0C; /* FAT32X */
} else if (sz_vol >= 0x10000) {
sys = 0x06; /* FAT12/16 (large) */
} else if (fsty == FS_FAT16) {
sys = 0x04; /* FAT16 */
} else {
sys = 0x01; /* FAT12 */
}
/* Update partition information */
if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */
if (!FF_LBA64 || !(fsopt & 0x80)) { /* Is the partition in MBR? */
/* Update system ID in the partition table */
if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */
buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */
if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */
}
} else { /* Volume as a new single partition */
if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD format 如果不是SFD格式,则创建分区表。*/
lba[0] = sz_vol; lba[1] = 0;
res = create_partition(pdrv, lba, sys, buf);/*创建MBR*/
if (res != FR_OK) LEAVE_MKFS(res);
}
}
if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
LEAVE_MKFS(FR_OK);
}
接下来对源码执行步骤释义:
1.首先get_ldnumber(&path)获取当前逻辑驱动器的卷ID,可以是数字、字符或者字符和数字混合,例如:数字型:“0:/test.txt”,ID就是0。
/*-----------------------------------------------------------------------*/
/* Get logical drive number from path name */
/*-----------------------------------------------------------------------*/
static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */
const TCHAR** path /* Pointer to pointer to the path name */
)
{
const TCHAR *tp;
const TCHAR *tt;
TCHAR chr;
int i;
#if FF_STR_VOLUME_ID /* Find string volume ID */
const char *vsp;
char vchr;
#endif
tt = tp = *path;
if (!tp) return -1; /* Invalid path name? */
do { /* Find a colon in the path */
chr = *tt++;
} while (!IsTerminator(chr) && chr != ':');
if (chr == ':') { /* Is there a DOS/Windows style volume ID? */
i = FF_VOLUMES;
if (IsDigit(*tp) && tp + 2 == tt) { /* Is it a numeric volume ID + colon? */
i = (int)*tp - '0'; /* Get the logical drive number */
}
#if FF_STR_VOLUME_ID == 1 /* Arbitrary string volume ID is enabled 字符串卷ID*/
else {
i = 0; /* Find volume ID string in the preconfigured table 在预配置表中查找卷 ID 字符串*/
do {
vsp = VolumeStr[i]; tp = *path; /* Preconfigured string and path name to test */
do { /* Compare the volume ID with path name in case-insensitive */
vchr = *vsp++; chr = *tp++;
if (IsLower(vchr)) vchr -= 0x20;/*转换为大写 (小写-32)*/
if (IsLower(chr)) chr -= 0x20;
} while (vchr && (TCHAR)vchr == chr);
} while ((vchr || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match 遍历卷ID*/
}
#endif
if (i >= FF_VOLUMES) return -1; /* Not found or invalid volume ID */
*path = tt; /* Snip the drive prefix off 去掉驱动器前缀 :之前数据*/
return i; /* Return the found drive number */
}
#if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */
if (*tp == '/') { /* Is there a volume ID? */
while (*(tp + 1) == '/') tp++; /* Skip duplicated separator */
i = 0;
do {
vsp = VolumeStr[i]; tt = tp; /* Preconfigured string and path name to test */
do { /* Compare the volume ID with path name in case-insensitive */
vchr = *vsp++; chr = *(++tt);
if (IsLower(vchr)) vchr -= 0x20;
if (IsLower(chr)) chr -= 0x20;
} while (vchr && (TCHAR)vchr == chr);
} while ((vchr || (chr != '/' && !IsTerminator(chr))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */
if (i >= FF_VOLUMES) return -1; /* Not found (invalid volume ID) */
*path = tt; /* Snip the node name off */
return i; /* Return the found drive number */
}
#endif
/* No drive prefix */
#if FF_FS_RPATH != 0
return (int)CurrVol; /* Default drive is current drive */
#else
return 0; /* Default drive is 0 */
#endif
}
2.物理设备初始化
/* Initialize the hosting physical drive */
ds = disk_initialize(pdrv);/*初始化物理磁盘*/
3.structure (MKFS_PARM) 相关参数的检测。
typedef struct {
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
BYTE n_fat; /* Number of FATs */
UINT align; /* Data area alignment (sector) */
UINT n_root; /* Number of root directory entries */
DWORD au_size; /* Cluster size (byte) */
} MKFS_PARM;
如未定义则使用默认值
static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */
其中簇是的单位是byte ,每簇包含的扇区数:除以FF_MAX_SS。
/* Options for FAT sub-type and FAT parameters 文件系统fat类型*/
fsopt = opt->fmt & (FM_ANY | FM_SFD);
n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1;/*1~2 fat表个数*/
n_root = (opt->n_root >= 1 && opt->n_root <= 32768 && (opt->n_root % (ss / SZDIRE)) == 0) ? opt->n_root : 512;/* 根目录条目数*/
sz_au = (opt->au_size <= 0x1000000 && (opt->au_size & (opt->au_size - 1)) == 0) ? opt->au_size : 0;/*簇大小 byte */
sz_au /= ss; /* Byte --> Sector 簇占用的扇区数*/
4. FAT表、目录、数据区扇区偏移。
if (pau == 0) { /* au auto-selection 自动簇数*/
n = (DWORD)sz_vol / 0x1000; /* Volume size in unit of 4KS 默认扇区4k为一簇*/
for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */
}
n_clst = (DWORD)sz_vol / pau;/*总簇数 */
if (n_clst > MAX_FAT12) {
n = n_clst * 2 + 4;
} else {
fsty = FS_FAT12;
n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] 每簇1.5byte 总字节数=(n_clst +2)×1.5 向上取整*/
}
sz_fat = (n + ss - 1) / ss; /* FAT size [sector] fat扇区数*/
sz_rsv = 1; /* Number of reserved sectors 保留扇区*/
sz_dir = (DWORD)n_root * SZDIRE / ss; /* Root directory size [sector] 根目录大小 扇区数 */
}
b_fat = b_vol + sz_rsv; /* FAT base FAT表 扇区偏移数 63+sz_rsv*/
b_data = b_fat + sz_fat * n_fat + sz_dir; /* Data base 数据区位置 偏移扇区数 */
/* Align data area to erase block boundary (for flash memory media) 将数据区域对齐到擦除块边界(适用于闪存介质)*/
n = (DWORD)(((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data); /* Sectors to next nearest from current data base 从当前数据块到下一个最近扇区的扇区数*/
if (fsty == FS_FAT32) { /* FAT32: Move FAT */
sz_rsv += n; b_fat += n;
} else { /* FAT: Expand FAT */
if (n % n_fat) { /* Adjust fractional error if needed */
n--; sz_rsv++; b_fat++;
}
sz_fat += n / n_fat;
}
5.创建VBR :分区起始的扇区位置,包含当前分区的信息。
/* Create FAT VBR 分区起始的扇区VBR,记录分区信息 */
memset(buf, 0, ss);
memcpy(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_fat; /* Number of FATs FAT表个数 */
st_word(buf + BPB_RootEntCnt, (WORD)((fsty == FS_FAT32) ? 0 : n_root)); /* Number of root directory entries 根目录个数 */
if (sz_vol < 0x10000) {
st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* FAT卷有效扇区总数Volume size in 16-bit LBA */
} else {
st_dword(buf + BPB_TotSec32, (DWORD)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, (DWORD)b_vol); /* 分区位置在卷上的偏移Volume offset in the physical drive [sector] */
if (fsty == FS_FAT32) {
st_dword(buf + BS_VolID32, vsn); /* 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 */
memcpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
} else {
st_dword(buf + BS_VolID, vsn); /* 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 */
memcpy(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) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */
/* Create FSINFO record if needed */
if (fsty == FS_FAT32) {
disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */
memset(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) */
}
6. 初始化FAT表:每个fat表扇区头写入2个簇号大小的默认值,如FAT12,每个簇号1.5字节,所以写入3个字节0xFFFFF8。
/* Initialize FAT area 初始化FAT表 */
memset(buf, 0, sz_buf * ss);
sect = b_fat; /* FAT start sector */
for (i = 0; i < n_fat; i++) { /* Initialize FATs each */
if (fsty == FS_FAT32) {
st_dword(buf + 0, 0xFFFFFFF8); /* FAT[0] */
st_dword(buf + 4, 0xFFFFFFFF); /* FAT[1] */
st_dword(buf + 8, 0x0FFFFFFF); /* FAT[2] (root directory at cluster# 2) */
} else {
st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[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) LEAVE_MKFS(FR_DISK_ERR);
memset(buf, 0, ss); /* Rest of FAT area is initially zero */
sect += n; nsect -= n;
} while (nsect);
7.初始化目录表:根目录所在的扇区全部清0
/* Initialize root directory (fill with zero) */
nsect = (fsty == 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) LEAVE_MKFS(FR_DISK_ERR);
sect += n; nsect -= n;
} while (nsect);
8.创建MBR:主引导记录。最多4个分区。
主要关注这两个信息:分区起始扇区和分区大小。
st_dword(pte + PTE_StLba, nxt_alloc32); /* Partition start LBA sector /
st_dword(pte + PTE_SizLba, sz_part32); / Size of partition [sector]
static FRESULT create_partition (
BYTE drv, /* Physical drive number */
const LBA_t plst[], /* Partition list */
BYTE sys, /* System ID for each partition (for only MBR) */
BYTE *buf /* Working buffer for a sector */
)
{
UINT i, cy;
LBA_t sz_drv;
DWORD sz_drv32, nxt_alloc32, sz_part32;
BYTE *pte;
BYTE hd, n_hd, sc, n_sc;
/* Get physical drive size */
if (disk_ioctl(drv, GET_SECTOR_COUNT, &sz_drv) != RES_OK) return FR_DISK_ERR;
{ /* Create partitions in MBR format */
sz_drv32 = (DWORD)sz_drv;
n_sc = N_SEC_TRACK; /* Determine drive CHS without any consideration of the drive geometry 在不考虑驱动器几何结构的情况下确定驱动器的CHS*/
for (n_hd = 8; n_hd != 0 && sz_drv32 / n_hd / n_sc > 1024; n_hd *= 2) ;
if (n_hd == 0) n_hd = 255; /* Number of heads needs to be <256 */
memset(buf, 0, FF_MAX_SS); /* Clear MBR */
pte = buf + MBR_Table; /* Partition table in the MBR */
for (i = 0, nxt_alloc32 = n_sc; i < 4 && nxt_alloc32 != 0 && nxt_alloc32 < sz_drv32; i++, nxt_alloc32 += sz_part32) {
sz_part32 = (DWORD)plst[i]; /* Get partition size */
if (sz_part32 <= 100) sz_part32 = (sz_part32 == 100) ? sz_drv32 : sz_drv32 / 100 * sz_part32; /* Size in percentage? */
if (nxt_alloc32 + sz_part32 > sz_drv32 || nxt_alloc32 + sz_part32 < nxt_alloc32) sz_part32 = sz_drv32 - nxt_alloc32; /* Clip at drive size */
if (sz_part32 == 0) break; /* End of table or no sector to allocate? */
st_dword(pte + PTE_StLba, nxt_alloc32); /* Partition start LBA sector */
st_dword(pte + PTE_SizLba, sz_part32); /* Size of partition [sector] */
pte[PTE_System] = sys; /* System type */
cy = (UINT)(nxt_alloc32 / n_sc / n_hd); /* Partitio start CHS cylinder */
hd = (BYTE)(nxt_alloc32 / n_sc % n_hd); /* Partition start CHS head */
sc = (BYTE)(nxt_alloc32 % n_sc + 1); /* Partition start CHS sector */
pte[PTE_StHead] = hd;
pte[PTE_StSec] = (BYTE)((cy >> 2 & 0xC0) | sc);
pte[PTE_StCyl] = (BYTE)cy;
cy = (UINT)((nxt_alloc32 + sz_part32 - 1) / n_sc / n_hd); /* Partition end CHS cylinder */
hd = (BYTE)((nxt_alloc32 + sz_part32 - 1) / n_sc % n_hd); /* Partition end CHS head */
sc = (BYTE)((nxt_alloc32 + sz_part32 - 1) % n_sc + 1); /* Partition end CHS sector */
pte[PTE_EdHead] = hd;
pte[PTE_EdSec] = (BYTE)((cy >> 2 & 0xC0) | sc);
pte[PTE_EdCyl] = (BYTE)cy;
pte += SZ_PTE; /* Next entry */
}
st_word(buf + BS_55AA, 0xAA55); /* MBR signature */
if (disk_write(drv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */
}
return FR_OK;
}