1 /**
2  * @file fat32.h
3  * @author fslongjin (longjin@RinGoTek.cn)
4  * @brief fat32文件系统
5  * @version 0.1
6  * @date 2022-04-19
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 
12 #pragma once
13 
14 #include <filesystem/MBR.h>
15 #include <filesystem/vfs/VFS.h>
16 
17 #define FAT32_MAX_PARTITION_NUM 128 // 系统支持的最大的fat32分区数量
18 
19 #define FAT32_DELETED_FLAG 0xe5 // 如果短目录项的name[0]为这个值,那么意味着这个短目录项是空闲的
20 
21 /**
22  * @brief fat32文件系统引导扇区结构体
23  *
24  */
25 struct fat32_BootSector_t
26 {
27     uint8_t BS_jmpBoot[3];    // 跳转指令
28     uint8_t BS_OEMName[8];    // 生产厂商名
29     uint16_t BPB_BytesPerSec; // 每扇区字节数
30     uint8_t BPB_SecPerClus;   // 每簇扇区数
31     uint16_t BPB_RsvdSecCnt;  // 保留扇区数
32     uint8_t BPB_NumFATs;      // FAT表数量
33     uint16_t BPB_RootEntCnt;  // 根目录文件数最大值
34     uint16_t BPB_TotSec16;    // 16位扇区总数
35     uint8_t BPB_Media;        // 介质描述符
36     uint16_t BPB_FATSz16;     // FAT12/16每FAT扇区数
37     uint16_t BPB_SecPerTrk;   // 每磁道扇区数
38     uint16_t BPB_NumHeads;    // 磁头数
39     uint32_t BPB_HiddSec;     // 隐藏扇区数
40     uint32_t BPB_TotSec32;    // 32位扇区总数
41 
42     uint32_t BPB_FATSz32;   // FAT32每FAT扇区数
43     uint16_t BPB_ExtFlags;  // 扩展标志
44     uint16_t BPB_FSVer;     // 文件系统版本号
45     uint32_t BPB_RootClus;  // 根目录起始簇号
46     uint16_t BPB_FSInfo;    // FS info结构体的扇区号
47     uint16_t BPB_BkBootSec; // 引导扇区的备份扇区号
48     uint8_t BPB_Reserved0[12];
49 
50     uint8_t BS_DrvNum; // int0x13的驱动器号
51     uint8_t BS_Reserved1;
52     uint8_t BS_BootSig;       // 扩展引导标记
53     uint32_t BS_VolID;        // 卷序列号
54     uint8_t BS_VolLab[11];    // 卷标
55     uint8_t BS_FilSysType[8]; // 文件系统类型
56 
57     uint8_t BootCode[420]; // 引导代码、数据
58 
59     uint16_t BS_TrailSig; // 结束标志0xAA55
60 } __attribute__((packed));
61 
62 /**
63  * @brief fat32文件系统的FSInfo扇区结构体
64  *
65  */
66 struct fat32_FSInfo_t
67 {
68     uint32_t FSI_LeadSig;       // FS info扇区标志符 数值为0x41615252
69     uint8_t FSI_Reserved1[480]; // 保留使用,全部置为0
70     uint32_t FSI_StrucSig;      // 另一个标志符,数值为0x61417272
71     uint32_t FSI_Free_Count;    // 上一次记录的空闲簇数量,这是一个参考值
72     uint32_t FSI_Nxt_Free;      // 空闲簇的起始搜索位置,这是为驱动程序提供的参考值
73     uint8_t FSI_Reserved2[12];  // 保留使用,全部置为0
74     uint32_t FSI_TrailSig;      // 结束标志,数值为0xaa550000
75 } __attribute__((packed));
76 
77 #define ATTR_READ_ONLY (1 << 0)
78 #define ATTR_HIDDEN (1 << 1)
79 #define ATTR_SYSTEM (1 << 2)
80 #define ATTR_VOLUME_ID (1 << 3)
81 #define ATTR_DIRECTORY (1 << 4)
82 #define ATTR_ARCHIVE (1 << 5)
83 #define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
84 
85 /**
86  * @brief fat32文件系统短目录项,大小为32bytes
87  *
88  */
89 struct fat32_Directory_t
90 {
91     unsigned char DIR_Name[11];
92     unsigned char DIR_Attr;         // 目录项属性
93     unsigned char DIR_NTRes;        // EXT|BASE => 8(BASE).3(EXT)
94                                     // BASE:LowerCase(8),UpperCase(0)
95                                     // EXT:LowerCase(16),UpperCase(0)
96     unsigned char DIR_CrtTimeTenth; // 文件创建的毫秒级时间戳
97     unsigned short DIR_CrtTime;     // 文件创建时间
98     unsigned short DIR_CrtDate;     // 文件创建日期
99     unsigned short DIR_LastAccDate; // 文件的最后访问日期
100     unsigned short DIR_FstClusHI;   // 起始簇号(高16bit)
101     unsigned short DIR_WrtTime;     // 最后写入时间
102     unsigned short DIR_WrtDate;     // 最后写入日期
103     unsigned short DIR_FstClusLO;   // 起始簇号(低16bit)
104     unsigned int DIR_FileSize;      // 文件大小
105 } __attribute__((packed));
106 
107 #define LOWERCASE_BASE (8)
108 #define LOWERCASE_EXT (16)
109 
110 /**
111  * @brief fat32文件系统长目录项,大小为32bytes
112  *
113  */
114 struct fat32_LongDirectory_t
115 {
116     unsigned char LDIR_Ord;        // 长目录项的序号
117     unsigned short LDIR_Name1[5];  // 长文件名的第1-5个字符,每个字符占2bytes
118     unsigned char LDIR_Attr;       // 目录项属性必须为ATTR_LONG_NAME
119     unsigned char LDIR_Type;       // 如果为0,则说明这是长目录项的子项
120     unsigned char LDIR_Chksum;     // 短文件名的校验和
121     unsigned short LDIR_Name2[6];  // 长文件名的第6-11个字符,每个字符占2bytes
122     unsigned short LDIR_FstClusLO; // 必须为0
123     unsigned short LDIR_Name3[2];  // 长文件名的12-13个字符,每个字符占2bytes
124 } __attribute__((packed));
125 
126 /**
127  * @brief fat32文件系统的超级块信息结构体
128  *
129  */
130 struct fat32_partition_info_t
131 {
132     uint16_t partition_id; // 全局fat32分区id
133     // todo: 增加mutex,使得对fat32文件系统的访问是互斥的
134 
135     struct fat32_BootSector_t bootsector;
136     struct fat32_FSInfo_t fsinfo;
137     uint64_t fsinfo_sector_addr_infat;
138     uint64_t bootsector_bak_sector_addr_infat;
139 
140     uint64_t starting_sector;
141     uint64_t sector_count;
142 
143     uint64_t sec_per_clus;   // 每簇扇区数
144     uint64_t bytes_per_sec;  // 每扇区字节数
145     uint64_t bytes_per_clus; // 每簇字节数
146 
147     uint64_t first_data_sector; // 数据区起始扇区号
148     uint64_t FAT1_base_sector;  // FAT1表的起始簇号
149     uint64_t FAT2_base_sector;  // FAT2表的起始簇号
150     uint64_t sec_per_FAT;       // 每FAT表扇区数
151     uint64_t NumFATs;           // FAT表数
152 };
153 
154 typedef struct fat32_partition_info_t fat32_sb_info_t;
155 
156 struct fat32_inode_info_t
157 {
158     uint32_t first_clus;                  // 文件的起始簇号
159     uint64_t dEntry_location_clus;        // fat entry的起始簇号 dEntry struct in cluster (0 is root, 1 is invalid)
160     uint64_t dEntry_location_clus_offset; // fat entry在起始簇中的偏移量(是第几个entry) dEntry struct offset in cluster
161 
162     uint16_t create_date;
163     uint16_t create_time;
164     uint16_t write_time;
165     uint16_t write_date;
166 };
167 
168 typedef struct fat32_inode_info_t fat32_inode_info_t;
169 
170 /**
171  * @brief FAT32目录项插槽信息
172  * 一个插槽指的是 一个长目录项/短目录项
173  */
174 struct fat32_slot_info
175 {
176     off_t i_pos;    // on-disk position of directory entry(扇区号)
177     off_t slot_off; // offset for slot or (de) start
178     int num_slots;  // number of slots +1(de) in filename
179     struct fat32_Directory_t * de;
180 
181     // todo: 加入block io层后,在这里引入buffer_head
182     void *buffer;   // 记得释放这个buffer!!!
183 };
184 
185 /**
186  * @brief 注册指定磁盘上的指定分区的fat32文件系统
187  *
188  * @param blk_dev 块设备结构体
189  * @param part_num 磁盘分区编号
190  *
191  * @return struct vfs_super_block_t * 文件系统的超级块
192  */
193 struct vfs_superblock_t *fat32_register_partition(struct block_device *blk_dev, uint8_t part_num);
194 
195 /**
196  * @brief 创建fat32文件系统的超级块
197  *
198  * @param blk 块设备结构体
199  * @return struct vfs_superblock_t* 创建好的超级块
200  */
201 struct vfs_superblock_t *fat32_read_superblock(struct block_device *blk);
202 
203 /**
204  * @brief 创建新的文件
205  * @param parent_inode 父目录的inode结构体
206  * @param dest_dEntry 新文件的dentry
207  * @param mode 创建模式
208  */
209 long fat32_create(struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dest_dEntry, int mode);
210 
211 void fat32_init();
212 
213 /**
214  * @brief 读取文件夹(在指定目录中找出有效目录项)
215  *
216  * @param file_ptr 文件结构体指针
217  * @param dirent 返回的dirent
218  * @param filler 填充dirent的函数
219  * @return int64_t
220  */
221 int64_t fat32_readdir(struct vfs_file_t *file_ptr, void *dirent, vfs_filldir_t filler);