| 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 | |
| 17 | bool 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 | |
| 27 | static bool fat12_write_fat_entry(struct fat_fs *fs, uint32_t, uint32_t value); |
| 28 | static bool fat16_write_fat_entry(struct fat_fs *fs, uint32_t, uint32_t value); |
| 29 | static bool fat32_write_fat_entry(struct fat_fs *fs, uint32_t, uint32_t value); |
| 30 | |
| 31 | bool 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 | |
| 40 | static 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 |
| 108 | static 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 | |
| 143 | static 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 | |
| 187 | bool 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 | |
| 195 | static uint32_t fat12_read_fat_entry(struct fat_fs *fs, uint32_t cluster); |
| 196 | static uint32_t fat16_read_fat_entry(struct fat_fs *fs, uint32_t cluster); |
| 197 | static uint32_t fat32_read_fat_entry(struct fat_fs *fs, uint32_t cluster); |
| 198 | |
| 199 | uint32_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 | |
| 208 | static 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 | |
| 241 | done: |
| 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 | |
| 250 | static 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 | |
| 271 | static 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 | |
| 292 | bool 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 | |