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