1、简介
由于最近开发录像存储功能,因此需要对文件系统进行了解,这一节先介绍一下磁盘的的基础知识。
2、机械硬盘
2.1 机械硬盘物理结构
机械硬盘主要由盘片,磁头,盘片转轴及控制电机,磁头控制器,数据转换器,接口,缓存等几个部分组成。如下图所示:
2.2 机械硬盘的逻辑结构
机械硬盘会有多个盘片组成,每个盘片包含两个面,每个盘面都对应地有一个读/写磁头。机械硬盘逻辑上将空间分为扇区、磁道、柱面进行管理。具体示意图如下:
- 扇区:硬盘的内部圆形金属盘片被磁道划分成若干个扇形区域,用以存储数据,硬盘的读写以扇区为基本单位。
- 块/簇:磁盘块/簇(虚拟出来的)。 块是操作系统中最小的逻辑存储单位。操作系统与磁盘打交道的最小单位是磁盘块。
存储容量 = 磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数;
下面的命令查看的是SD的信息
# fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 31.9 GB, 31927042048 bytes
4 heads, 16 sectors/track, 974336 cylinders
Units = cylinders of 64 * 512 = 32768 bytes
Device Boot Start End Blocks Id System
/dev/mmcblk0p1 1 974336 31178744 c Win95 FAT32 (LBA)
3、FAT32文件系统
3.1 FAT32简介
-
文件系统:操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构,即在存储设备上组织文件的方法。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。
-
FAT32文件系统: FAT32指的是文件分配表是采用32位二进制数记录管理的磁盘文件管理方式,因FAT类文件系统的核心是文件分配表,命名由此得来。FAT32是从FAT和FAT16发展而来的,优点是稳定性和兼容性好,能充分兼容Win 9X及以前版本,且维护方便。缺点是安全性差,且最大只能支持2T分区,单个文件也只能支持最大4GB。
3.2 FAT32 存储器数据分布结构详解
FAT32文件系统存储器数据分布结构如下所示:
- MBR扇区;
- 保留扇区;
- DBR扇区即文件系统0扇区;
- FSINFO扇区,文件系统1扇区;
- 保留扇区;
- FAT表;
- 根目录;
- 数据区;
其具体示意图如下:
下面对上述内容分别介绍:
- MBR扇区:
硬盘第一个扇区,前446字节为硬盘主引导记录(即Master Boot Record,MBR),其后64字节为分区表,最后2个字节为结束码(固定为55 AA)。下图是分区表的示意图:
分区表,每16字节为一个分区表项,64字节总共可以存放4个分区表项,分区表数据结构如下所示。
其数据结构如下所示:
struct partition {
uint8_t boot_ind;
uint8_t head;
uint8_t sector;
uint8_t cyl;
uint8_t sys_ind;
uint8_t end_head;
uint8_t end_sector;
uint8_t end_cyl;
uint8_t start[4];
uint8_t size[4];
}__attribute__ ((__packed__));
- DBR扇区:
DBR扇区详细结构如下图所示: - 0x00~0x02:3字节,跳转指令。
- 0x03~0x0A:8字节,文件系统标志和版本号,这里为MSDOS5.0。
- 0x0B~0x0C:2字节,每扇区字节数,0x0200=512
- 0x0D~0x0D:1字节,每簇扇区数,0x08。
- 0x0E~0x0F:2字节,保留扇区数,0x0C22=3106
- 0x10~0x10:1字节,FAT表个数,0x02。
- 0x11~0x12:2字节,FAT32必须等于0,FAT12/FAT16为根目录中目录的个数;
- 0x13~0x14:2字节,FAT32必须等于0,FAT12/FAT16为扇区总数。
- 0x15~0x15:1字节,哪种存储介质,0xF8标准值,可移动存储介质。
- 0x16~0x17:2字节,FAT32必须为0,FAT12/FAT16为一个FAT 表所占的扇区数。
- 0x18~0x19:2字节,每磁道扇区数,只对于“特殊形状”(由磁头和柱面分割为若干磁道)的存储介质有效,0x003F=63。
- 0x1A~0x1B:2字节,磁头数,只对特殊的介质才有效,0x00FF=255。
- 0x1C~0x1F:4字节,EBR分区之前所隐藏的扇区数,0x0004A800=305152又出现了呢,与MBR中地址0x1C6开始的4个字节数值相等。
- 0x20~0x23:4字节,文件系统总扇区数,0x00E83800=15218688
- 0x24~0x27:4字节,每个FAT表占用扇区数,0x000039EF=14831
- 0x28~0x29:2字节,标记,此域FAT32 特有。
- 0x2A~0x2B:2字节,FAT32版本号0.0,FAT32特有。
- 0x2C~0x2F:4字节,根目录所在第一个簇的簇号,0x02。(虽然在FAT32文件系统下,根目录可以存放在数据区的任何位置,但是通常情况下还是起始于2号簇)
- 0x30~0x31:2字节,FSINFO(文件系统信息扇区)扇区号0x01,该扇区为操作系统提供关于空簇总数及下一可用簇的信息。
- 0x32~0x33:2字节,备份引导扇区的位置。备份引导扇区总是位于文件系统的6号扇区。
- 0x34~0x3F:12字节,用于以后FAT 扩展使用。
- 0x40~0x40:1字节,与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已。
- 0x41~0x41:1字节,与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已 。
- 0x42~0x42:1字节,扩展引导标志,0x29。与FAT12/16 的定义相同,只不过两者位于启动扇区不同的位置而已
- 0x43~0x46:4字节,卷序列号。通常为一个随机值。
- 0x47~0x51:11字节,卷标(ASCII码),如果建立文件系统的时候指定了卷标,会保存在此。
- 0x52~0x59:8字节,文件系统格式的ASCII码,FAT32。
- 0x5A~0x1FD:共420字节,引导代码。
- 0x1FE~0x1FF:签名标志“55 AA”。
其数据结构如下所示:
struct msdos_boot_sector
{
uint8_t boot_jump[3];
uint8_t system_id[8];
uint8_t sector_size[3];
uint8_t cluster_size;
uint16_t res;
uint8_t fats;
uint8_t dir_entries[2];
uint8_t sectors[2];
uint8_t media;
uint16_t fat_lenght;
uint16_t secs_track;
uint16_t heads;
uint32_t hidden;
uint32_t total_sect;
union
{
struct
{
struct msdos_volume_info vi;
uint8_t boot_code[BOOTCODE_SIZE];
}__attribute__ ((packed)) _oldfat;
struct
{
uint32_t fat32_lenght;
uint16_t flags;
uint8_t ver[2];
uint32_t root_cluster;
uint16_t info_sector;
uint16_t backup_root;
uint16_t res[2];
}__attribute__ ((packed)) _fat32;
}__attribute__ ((packed)) fstype;
uint16_t boot_sign;
}
- FSINFO扇区:
FSINFO扇区如下如所示:
其具体数据结构如下图所示:
struct fat32_fsinfo {
uint32_t res;
uint32_t signature;
uint32_t free_clusters;
uint32_t next_cluster;
uint32_t res[4];
}
- FAT表:
文件系统分配磁盘空间按簇来分配。对于大文件,需要分配多个簇。同一个文件的数据并不一定完整地存放在磁盘中一个连续地区域内,而往往会分若干段,像链子一样存放。这种存储方式称为文件的链式存储。为了实现文件的链式存储,文件系统必须准确地记录哪些簇已经被文件占用,还必须为每个已经占用的簇指明存储后继的下一个簇的簇号,对于文件的最后一簇,则要指明本簇无后继簇。这些都是由FAT表来保存的,FAT 表对应表项中记录着它所代表的簇的有关信息:诸如是空,是不是坏簇,是否是已经是某个文件的尾簇等。
每个簇的簇地址是有32bit(4个字节),FAT表中的所有字节位置以4字节为单位进行划分。
- 特殊:0x0FFFFFF8
- 结束:0x0FFFFFFF
- 坏簇:0x0FFFFFF7
其中FAT表0、1固定为 0x0FFFFFF8、 0x0FFFFFFF ,2号簇为根目录;
- 目录项:
目录所在的扇区,都是以32 Bytes划分为一个单位,每个单位称为一个目录项,即每个目录项的长度都是32 Bytes 。根目录由若干个目录项组成,一个目录项占用32个字节,可以是长目录项、短目录项、“.”目录项和“…”目录项等。每个文件都对应于一个目录项。 - 短目录项:
其数据结构:
typedef struct {
uint8_t name[8];
uint8_t ext[3];
uint8_t lcase;
uint8_t ctime_ms;
uint16_t ctime;
uint16_t cdate;
uint16_t adate;
uint16_t starthi;
uint16_t time;
uint16_t date;
uint16_t start;
uint32_t size;
} msdos_dir_entry;
- 长目录项:
其数据结构:
typedef struct
{
uint8_t id;
uint8_t name0_4[10];
uint8_t attr;
uint8_t res;
uint8_t alias_checksum;
uint8_t name5_10[12];
uint16_t start;
uint8_t name11_12[4];
} msdos_dir_slot;
3.3 FAT32 文件系统格式化流程
FAT32格式化主要分为5部分:
- 设置分区表;
- FAT32的DBR扇区;
- FSINFO扇区;
- FAT表;
- 根目录初始化;
-
设置分区表:
–prepare_for_createfile
----getTotalSectors获取SD卡总扇区
----usrFdiskPartCreate根据SD卡大小进行分区
------add_partition_auto填写分区表
--------set_partition设置每个分区表
----------set_start_sect填写分区起始扇区
----------set_nr_sects填写分区总扇区数
------write_part_table_flag写结束码(0xAA55)
------write_sector将内存数据写入到SD卡 -
FAT32的DBR扇区初始化:
prepare_for_createfile格式化总接口
–dosFsCreate格式化分区,可传入扇区大小、簇大小等参数
----mkfs_main格式化主函数
------getopt解析参数,目前不带入参数
------count_blocks统计设备分区总块数
------open打开分区文件,所有的格式化都是对这个分区文件进行读写
------establish_params创建参数
--------media设置媒体介质0XF8
--------cluster_size设置簇大小,fs size >= 16G: 16k clusters
--------setup_tables设置表参数
--------system_id文件系统标志和版本号,mkdosfs
--------volume_id卷序列号,格式化时间
--------volume_label卷标,11个空格
--------boot_jump跳转指令
--------fat32.boot_code引导码,420字节
--------boot_sign结束码,0xAA55
--------reserved保留扇区个数
--------fats,FAT表个数,2个
--------hidden隐藏扇区数,未使用
--------fat32.fat32_length,FAT表大小
--------fat32.flags 标志,0
--------fat32.version版本号,0
--------fat32.root_cluster根目录簇号,簇号2
--------fat32.info_sector,FSINFO扇区号,扇区1
--------fat32.backup_boot,DBR扇区备份扇区号,扇区6
--------total_sect文件系统总扇区数
--------ext_boot_sign扩展引导标志,0x29 -
根目录初始化:
prepare_for_createfile
–dosFsCreate格式化分区,可传入扇区大小、簇大小等参数
----mkfs_main格式化主函数
------setup_tables设置表参数
--------de->name文件名
--------de-> ext扩展名
--------de->attr 文件属性 ATTR_VOLUME卷标
--------de->time时间
--------de->date日期
--------de->starthi文件起始簇号高2位
--------de->start文件起始簇号低2位
--------de->size文件大小 -
FAT表初始化:
prepare_for_createfile
–dosFsCreate格式化分区,可传入扇区大小、簇大小等参数
----mkfs_main格式化主函数
------setup_tables设置表参数
--------mark_FAT_cluster (0, 0xffffffff)设置第一个FAT表项0x0FFFFFF8
--------mark_FAT_cluster (1, 0xffffffff)设置第一个FAT表项0x0FFFFFFF
--------mark_FAT_cluster (2, FAT_EOF)设置根目录簇号FAT表项 -
FSINFO扇区:
prepare_for_createfile
–dosFsCreate格式化分区,可传入扇区大小、簇大小等参数
----mkfs_main格式化主函数
------setup_tables设置表参数
--------扩展引导标志 4字节,字符串“RRaA”
--------未使用区域,420字节,置零
--------info->signature 4字节,签名0x72724161
--------info->free_clusters 4字节,文件系统空簇数
--------info->next_cluster 4字节 下一可用簇号,2号
-------info->next_cluster 4字节 下一可用簇号,2号 -
写入到SD卡:
prepare_for_createfile
–dosFsCreate格式化分区,可传入扇区大小、簇大小等参数
----mkfs_main格式化主函数
------write_tables将初始化在内存的数据写到SD卡
--------seekto定位到偏移地址
--------writebuf写入数据
参考资料:
https://baike.baidu.com/item/FAT32/827339?fr=aladdin
https://blog.csdn.net/li_wen01/article/details/79929730/
https://blog.csdn.net/z1026544682/article/details/99759500