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