1/* @title: FAT */
2#include <block/bcache.h>
3#include <block/block.h>
4#include <compiler/core.h>
5#include <math/align.h>
6#include <math/min_max.h>
7#include <stdint.h>
8
9// TODO: errno :boom:
10
11// fat32_ prefixed things are exclusively FAT32
12// fat_ prefixed things are usable in 12, 16, and 32
13// fat12_16_ prefixed things are exclusively FAT12/16
14// etc...
15
16#define FAT12_PARTITION_TYPE 0x01 // FAT12, CHS addressing
17#define FAT16_PARTITION_TYPE 0x04 // FAT16, CHS addressing (less than 32MB)
18#define FAT16_PARTITION_TYPE2 0x06 // FAT16, LBA addressing (greater than 32MB)
19#define FAT32_PARTITION_TYPE1 0x0B // FAT32, CHS addressing
20#define FAT32_PARTITION_TYPE2 0x0C // FAT32, LBA addressing
21
22#define FAT_DIR_CLUSTER_ROOT 0xFFFFFFFF
23
24enum fat_fstype : uint8_t {
25 FAT_12,
26 FAT_16,
27 FAT_32,
28};
29
30enum fat_fileattr : uint8_t {
31 FAT_RO = 0x01,
32 FAT_HIDDEN = 0x02,
33 FAT_SYSTEM = 0x04,
34 FAT_VOL_ID = 0x08,
35 FAT_DIR = 0x10,
36 FAT_ARCHIVE = 0x20,
37};
38
39static inline const char *get_fileattr_string(enum fat_fileattr f) {
40 switch (f) {
41 case FAT_RO: return "Read-Only";
42 case FAT_HIDDEN: return "Hidden";
43 case FAT_SYSTEM: return "System";
44 case FAT_VOL_ID: return "Volume ID";
45 case FAT_DIR: return "Directory";
46 case FAT_ARCHIVE: return "Archive";
47 }
48 return "Unknown";
49};
50
51struct fat12_16_ext_bpb {
52 uint8_t drive_number;
53 uint8_t reserved;
54 uint8_t boot_signature;
55 uint32_t volume_id;
56 uint8_t volume_label[11];
57 uint8_t fs_type[8];
58 uint8_t reserved1[448];
59} cc_packed;
60
61struct fat32_ext_bpb {
62 uint32_t fat_size_32;
63 uint16_t ext_flags;
64 uint16_t fs_version;
65 uint32_t root_cluster;
66 uint16_t fs_info;
67 uint16_t backup_boot_sector;
68 uint8_t reserved[12];
69 uint8_t drive_number;
70 uint8_t reserved1;
71 uint8_t boot_signature;
72 uint32_t volume_id;
73 uint8_t volume_label[11];
74 uint8_t fs_type[8];
75 uint8_t reserved2[420];
76} cc_packed;
77
78static_assert(sizeof(struct fat12_16_ext_bpb) == sizeof(struct fat32_ext_bpb));
79
80struct fat_bpb {
81 uint8_t jump_boot[3];
82 uint8_t oem_name[8];
83 uint16_t bytes_per_sector;
84 uint8_t sectors_per_cluster;
85 uint16_t reserved_sector_count;
86 uint8_t num_fats;
87 uint16_t root_entry_count;
88 uint16_t total_sectors_16;
89 uint8_t media;
90 uint16_t fat_size_16;
91 uint16_t sectors_per_track;
92 uint16_t num_heads;
93 uint32_t hidden_sectors;
94 uint32_t total_sectors_32;
95
96 union {
97 struct fat32_ext_bpb ext_32;
98 struct fat12_16_ext_bpb ext_12_16;
99 };
100} cc_packed;
101
102struct fat_date {
103 uint16_t day : 5;
104 uint16_t month : 4;
105 uint16_t year : 7;
106};
107
108struct fat_time {
109 uint16_t second : 5;
110 uint16_t minute : 6;
111 uint16_t hour : 5;
112};
113
114struct fat_dirent {
115 char name[11];
116 enum fat_fileattr attr; // attribute flags
117 uint8_t ntres; // reserved
118 uint8_t crttimetenth;
119 struct fat_time crttime;
120 struct fat_date crtdate;
121 struct fat_date lastaccess;
122 uint16_t high_cluster; // High 16 bits of cluster number
123 struct fat_time modtime;
124 struct fat_date moddate;
125 uint16_t low_cluster; // Low 16 bits of cluster number
126 uint32_t filesize;
127} cc_packed;
128static_assert(sizeof(struct fat_dirent) == 32);
129
130struct fat_fs {
131 enum fat_fstype type;
132 struct fat_bpb *bpb;
133 struct partition *partition;
134 struct block_device *disk;
135 uint32_t volume_base_lba;
136 uint32_t total_clusters;
137 uint32_t root_cluster;
138 uint32_t cluster_size;
139 uint32_t fsinfo_sector;
140 uint32_t free_clusters;
141 uint32_t last_alloc_cluster;
142 uint32_t entries_per_cluster;
143
144 // below is defined differently in 12/16 and 32
145 uint16_t fat_size;
146 uint8_t boot_signature;
147 uint8_t drive_number;
148 uint32_t volume_id;
149 uint8_t volume_label[11];
150 uint8_t fs_type[8];
151};
152
153typedef bool (*fat_walk_callback)(struct fat_dirent *, uint32_t, void *);
154
155// aside from BPB all pub funcs here should be 'fat_' - all FAT sizes
156
157//
158//
159// BPB Functions
160//
161//
162
163struct fat_bpb *fat32_read_bpb(struct partition *);
164void fat12_16_print_bpb(const struct fat_bpb *bpb);
165
166//
167//
168// Utility and miscellaneous
169//
170//
171
172uint32_t fat_eoc(struct fat_fs *fs);
173bool fat_is_eoc(struct fat_fs *fs, uint32_t cluster);
174uint32_t fat_get_dir_cluster(struct fat_dirent *d);
175void fat_format_filename_83(const char *name, char out[11]);
176
177uint32_t fat_first_data_sector(const struct fat_fs *fs);
178uint32_t fat_cluster_to_lba(const struct fat_fs *fs, uint32_t cluster);
179struct fat_date fat_get_current_date(void);
180struct fat_time fat_get_current_time(void);
181
182//
183//
184// Mount and print
185//
186//
187
188struct vfs_node *fat_g_mount(struct partition *p);
189
190void fat_g_print(struct partition *);
191void fat32_print_bpb(const struct fat_bpb *bpb);
192void fat_print_dirent(const struct fat_dirent *ent);
193void fat_list_root(struct fat_fs *fs);
194
195//
196//
197// Read/write of internal data
198//
199//
200
201bool fat_read_cluster(struct fat_fs *fs, uint32_t cluster, uint8_t *buffer);
202
203bool fat_write_cluster(struct fat_fs *fs, uint32_t cluster,
204 const uint8_t *buffer);
205
206bool fat_write_dirent(struct fat_fs *fs, uint32_t dir_cluster,
207 const struct fat_dirent *dirent_to_write,
208 uint32_t entry_index);
209
210bool fat_write_fat_entry(struct fat_fs *fs, uint32_t cluster, uint32_t value);
211uint32_t fat_read_fat_entry(struct fat_fs *fs, uint32_t cluster);
212
213uint32_t fat_alloc_cluster(struct fat_fs *fs);
214
215void fat_free_chain(struct fat_fs *fs, uint32_t start_cluster);
216void fat_write_fsinfo(struct fat_fs *fs);
217
218//
219//
220// Higher level file ops
221//
222//
223
224bool fat_create(struct fat_fs *fs, uint32_t dir_cluster, const char *filename,
225 struct fat_dirent *out_dirent, enum fat_fileattr attr,
226 uint32_t *out_cluster);
227
228bool fat_delete(struct fat_fs *fs, uint32_t dir_cluster, const char *filename);
229
230bool fat_rename(struct fat_fs *fs, uint32_t dir_cluster, const char *filename,
231 const char *new_filename);
232
233bool fat_read_file(struct fat_fs *fs, struct fat_dirent *ent, uint32_t offset,
234 uint32_t size, uint8_t *out_buf);
235
236bool fat_write_file(struct fat_fs *fs, struct fat_dirent *ent, uint32_t offset,
237 const uint8_t *data, uint32_t size);
238
239//
240//
241// Walk iterators/directories
242//
243//
244
245bool fat_walk_cluster(struct fat_fs *fs, uint32_t cluster, fat_walk_callback cb,
246 void *ctx);
247
248struct fat_dirent *fat_lookup(struct fat_fs *fs, uint32_t cluster,
249 const char *f, uint32_t *out_index);
250
251bool fat_contains(struct fat_fs *fs, uint32_t cluster, const char *f);
252
253bool fat_mkdir(struct fat_fs *fs, uint32_t parent_cluster, const char *name,
254 struct fat_dirent *out_dirent);
255
256#pragma once
257