1#include <fs/fat.h>
2#include <mem/alloc.h>
3#include <stdbool.h>
4#include <stdint.h>
5#include <string.h>
6
7// TODO: errno :boom:
8
9//
10//
11//
12// ---------- WRITING CLUSTERS AND FAT ENTRIES ----------
13//
14//
15//
16
17bool fat_write_cluster(struct fat_fs *fs, uint32_t cluster,
18 const uint8_t *buffer) {
19 const struct fat_bpb *bpb = fs->bpb;
20
21 uint32_t lba = fat_cluster_to_lba(fs, cluster);
22
23 return fs->disk->write_sector(fs->disk, lba, buffer,
24 bpb->sectors_per_cluster);
25}
26
27static bool fat12_write_fat_entry(struct fat_fs *fs, uint32_t, uint32_t value);
28static bool fat16_write_fat_entry(struct fat_fs *fs, uint32_t, uint32_t value);
29static bool fat32_write_fat_entry(struct fat_fs *fs, uint32_t, uint32_t value);
30
31bool fat_write_fat_entry(struct fat_fs *fs, uint32_t cluster, uint32_t value) {
32 switch (fs->type) {
33 case FAT_12: return fat12_write_fat_entry(fs, cluster, value);
34 case FAT_16: return fat16_write_fat_entry(fs, cluster, value);
35 case FAT_32: return fat32_write_fat_entry(fs, cluster, value);
36 }
37 return false;
38}
39
40static bool fat12_write_fat_entry(struct fat_fs *fs, uint32_t cluster,
41 uint32_t value) {
42 struct block_device *disk = fs->disk;
43 uint32_t fat_offset = cluster + (cluster / 2);
44 uint16_t offset = fat_offset % fs->bpb->bytes_per_sector;
45 uint32_t fat_size = fs->fat_size;
46 bool result = true;
47
48 uint8_t *buf1 = valloc(disk->sector_size);
49 uint8_t *buf2 = valloc(disk->sector_size);
50 if (!buf1 || !buf2) {
51 vfree(buf1);
52 vfree(buf2);
53 return false;
54 }
55
56 for (uint32_t fat_index = 0; fat_index < fs->bpb->num_fats; fat_index++) {
57 uint32_t base = fs->bpb->reserved_sector_count + fat_index * fat_size;
58 uint32_t sector = base + (fat_offset / fs->bpb->bytes_per_sector);
59 sector += fs->volume_base_lba;
60
61 if (!disk->read_sector(disk, sector, buf1, 1)) {
62 result = false;
63 continue;
64 }
65
66 if (offset == fs->bpb->bytes_per_sector - 1) {
67 // Entry crosses a sector boundary
68 if (!disk->read_sector(disk, sector + 1, buf2, 1)) {
69 result = false;
70 continue;
71 }
72
73 uint16_t combined = buf1[offset] | (buf2[0] << 8);
74 if (cluster & 1)
75 combined = (combined & 0x000F) | ((value & 0x0FFF) << 4);
76 else
77 combined = (combined & 0xF000) | (value & 0x0FFF);
78
79 buf1[offset] = combined & 0xFF;
80 buf2[0] = (combined >> 8) & 0xFF;
81
82 if (!disk->write_sector(disk, sector, buf1, 1) ||
83 !disk->write_sector(disk, sector + 1, buf2, 1)) {
84 result = false;
85 }
86 } else {
87 // Entry fits within a single sector
88 uint16_t old = buf1[offset] | (buf1[offset + 1] << 8);
89 uint16_t new_val;
90
91 if (cluster & 1)
92 new_val = (old & 0x000F) | ((value & 0x0FFF) << 4);
93 else
94 new_val = (old & 0xF000) | (value & 0x0FFF);
95
96 buf1[offset] = new_val & 0xFF;
97 buf1[offset + 1] = (new_val >> 8) & 0xFF;
98
99 if (!disk->write_sector(disk, sector, buf1, 1)) {
100 result = false;
101 }
102 }
103 }
104
105 vfree(buf1);
106 vfree(buf2);
107 return result;
108}
109
110// TODO: we can combine these with fat32 too
111static bool fat16_write_fat_entry(struct fat_fs *fs, uint32_t cluster,
112 uint32_t value) {
113 struct block_device *disk = fs->disk;
114 uint32_t fat_offset = cluster * 2;
115 uint32_t offset = fat_offset % fs->bpb->bytes_per_sector;
116 uint32_t fat_size = fs->bpb->fat_size_16;
117 uint8_t *buf = valloc(disk->sector_size);
118 if (!buf)
119 return false;
120
121 bool result = true;
122
123 for (uint32_t fat_index = 0; fat_index < fs->bpb->num_fats; fat_index++) {
124 uint32_t sector = fs->bpb->reserved_sector_count +
125 fat_index * fat_size +
126 (fat_offset / fs->bpb->bytes_per_sector);
127
128 sector += fs->volume_base_lba;
129
130 if (!disk->read_sector(disk, sector, buf, 1)) {
131 result = false;
132 continue;
133 }
134
135 *(uint16_t *) &buf[offset] = value & 0xFFFF;
136
137 if (!disk->write_sector(disk, sector, buf, 1)) {
138 result = false;
139 }
140 }
141
142 vfree(buf);
143 return result;
144}
145
146static bool fat32_write_fat_entry(struct fat_fs *fs, uint32_t cluster,
147 uint32_t value) {
148 struct block_device *disk = fs->disk;
149 uint32_t fat_offset = cluster * 4;
150 uint32_t offset = fat_offset % fs->bpb->bytes_per_sector;
151 uint32_t fat_size = fs->fat_size;
152 uint8_t *buf = valloc(disk->sector_size);
153 if (!buf)
154 return false;
155
156 bool result = true;
157
158 for (uint32_t fat_index = 0; fat_index < fs->bpb->num_fats; fat_index++) {
159 uint32_t sector = fs->bpb->reserved_sector_count +
160 fat_index * fat_size +
161 (fat_offset / fs->bpb->bytes_per_sector);
162
163 sector += fs->volume_base_lba;
164
165 if (!disk->read_sector(disk, sector, buf, 1)) {
166 result = false;
167 continue;
168 }
169
170 uint32_t *entry = (uint32_t *) &buf[offset];
171 *entry = (*entry & 0xF0000000) | (value & 0x0FFFFFFF);
172
173 if (!disk->write_sector(disk, sector, buf, 1)) {
174 result = false;
175 }
176 }
177
178 vfree(buf);
179 return result;
180}
181
182//
183//
184//
185// ---------- READING CLUSTERS AND FAT ENTRIES ----------
186//
187//
188//
189
190bool fat_read_cluster(struct fat_fs *fs, uint32_t cluster, uint8_t *buffer) {
191 const struct fat_bpb *bpb = fs->bpb;
192
193 uint32_t lba = fat_cluster_to_lba(fs, cluster);
194 return fs->disk->read_sector(fs->disk, lba, buffer,
195 bpb->sectors_per_cluster);
196}
197
198static uint32_t fat12_read_fat_entry(struct fat_fs *fs, uint32_t cluster);
199static uint32_t fat16_read_fat_entry(struct fat_fs *fs, uint32_t cluster);
200static uint32_t fat32_read_fat_entry(struct fat_fs *fs, uint32_t cluster);
201
202uint32_t fat_read_fat_entry(struct fat_fs *fs, uint32_t cluster) {
203 switch (fs->type) {
204 case FAT_12: return fat12_read_fat_entry(fs, cluster);
205 case FAT_16: return fat16_read_fat_entry(fs, cluster);
206 case FAT_32: return fat32_read_fat_entry(fs, cluster);
207 }
208 return 0xFFFFFFFF;
209}
210
211static uint32_t fat12_read_fat_entry(struct fat_fs *fs, uint32_t cluster) {
212 struct block_device *disk = fs->disk;
213 uint32_t fat_offset = cluster + (cluster / 2);
214 uint16_t offset = fat_offset % fs->bpb->bytes_per_sector;
215 uint32_t sector = fs->bpb->reserved_sector_count +
216 (fat_offset / fs->bpb->bytes_per_sector);
217
218 sector += fs->volume_base_lba;
219
220 uint8_t *buf = valloc(disk->sector_size);
221 uint8_t *buf2 = NULL;
222 uint32_t result = 0xFFFFFFFF;
223
224 if (!buf)
225 return result;
226
227 if (!disk->read_sector(disk, sector, buf, 1))
228 goto done;
229
230 if (offset == fs->bpb->bytes_per_sector - 1) {
231 buf2 = valloc(disk->sector_size);
232 if (!buf2)
233 return result;
234
235 if (!disk->read_sector(disk, sector + 1, buf2, 1))
236 goto done;
237 uint16_t val = buf[offset] | (buf2[0] << 8);
238 result = (cluster & 1) ? (val >> 4) & 0x0FFF : val & 0x0FFF;
239 } else {
240 uint16_t val = buf[offset] | (buf[offset + 1] << 8);
241 result = (cluster & 1) ? (val >> 4) & 0x0FFF : val & 0x0FFF;
242 }
243
244done:
245 vfree(buf);
246 if (buf2)
247 vfree(buf2);
248 return result;
249}
250
251// TODO: These are kinda same-y, can combine into one function
252
253static uint32_t fat16_read_fat_entry(struct fat_fs *fs, uint32_t cluster) {
254 struct block_device *disk = fs->disk;
255 uint32_t fat_offset = cluster * 2;
256 uint32_t offset = fat_offset % fs->bpb->bytes_per_sector;
257 uint32_t sector = fs->bpb->reserved_sector_count +
258 (fat_offset / fs->bpb->bytes_per_sector);
259
260 sector += fs->volume_base_lba;
261
262 uint8_t *buf = valloc(disk->sector_size);
263 uint32_t result = 0xFFFFFFFF;
264 if (!buf)
265 return result;
266
267 if (disk->read_sector(disk, sector, buf, 1))
268 result = *(uint16_t *) &buf[offset];
269
270 vfree(buf);
271 return result;
272}
273
274static uint32_t fat32_read_fat_entry(struct fat_fs *fs, uint32_t cluster) {
275 struct block_device *disk = fs->disk;
276 uint32_t fat_offset = cluster * 4;
277 uint32_t offset = fat_offset % fs->bpb->bytes_per_sector;
278 uint32_t sector = fs->bpb->reserved_sector_count +
279 (fat_offset / fs->bpb->bytes_per_sector);
280
281 sector += fs->volume_base_lba;
282
283 uint8_t *buf = valloc(disk->sector_size);
284 uint32_t result = 0xFFFFFFFF;
285 if (!buf)
286 return result;
287
288 if (disk->read_sector(disk, sector, buf, 1))
289 result = *(uint32_t *) &buf[offset] & 0x0FFFFFFF;
290
291 vfree(buf);
292 return result;
293}
294
295bool fat_write_dirent(struct fat_fs *fs, uint32_t dir_cluster,
296 const struct fat_dirent *dirent_to_write,
297 uint32_t entry_index) {
298
299 uint32_t index_in_cluster = entry_index % fs->entries_per_cluster;
300
301 uint32_t current_cluster = dir_cluster;
302
303 if (dir_cluster == FAT_DIR_CLUSTER_ROOT) {
304 uint32_t bytes_per_sector = fs->bpb->bytes_per_sector;
305 uint32_t root_dir_size =
306 fs->bpb->root_entry_count * sizeof(struct fat_dirent);
307
308 uint32_t root_dir_sectors =
309 DIV_ROUND_UP(root_dir_size, bytes_per_sector);
310 uint32_t dirent_size = sizeof(struct fat_dirent);
311
312 uint32_t entry_offset_bytes = entry_index * dirent_size;
313 uint32_t sector_offset = entry_offset_bytes / bytes_per_sector;
314 uint32_t offset_in_sector = entry_offset_bytes % bytes_per_sector;
315
316 if (sector_offset >= root_dir_sectors) {
317 return false;
318 }
319
320 uint32_t lba =
321 fat_cluster_to_lba(fs, FAT_DIR_CLUSTER_ROOT) + sector_offset;
322
323 uint8_t *sector_buf = valloc(bytes_per_sector);
324 if (!sector_buf)
325 return false;
326
327 if (!fs->disk->read_sector(fs->disk, lba, sector_buf, 1)) {
328 vfree(sector_buf);
329 return false;
330 }
331
332 memcpy(sector_buf + offset_in_sector, dirent_to_write, dirent_size);
333
334 bool success = fs->disk->write_sector(fs->disk, lba, sector_buf, 1);
335 vfree(sector_buf);
336 return success;
337 }
338
339 uint8_t *cluster_buf = valloc(fs->cluster_size);
340 if (!cluster_buf)
341 return false;
342
343 if (!fat_read_cluster(fs, cluster: current_cluster, buffer: cluster_buf)) {
344 vfree(cluster_buf);
345 return false;
346 }
347
348 memcpy(cluster_buf + index_in_cluster * sizeof(struct fat_dirent),
349 dirent_to_write, sizeof(struct fat_dirent));
350
351 bool success = fat_write_cluster(fs, cluster: current_cluster, buffer: cluster_buf);
352
353 vfree(cluster_buf);
354 return success;
355}
356