fat16.c (30644B)
1 /* FAT16 Filesystem Driver for LuajitOS Boot Partition 2 * 3 * Simple FAT16 implementation for the unencrypted boot partition. 4 */ 5 6 #include "fat16.h" 7 #include "ata.h" 8 #include <string.h> 9 #include <stdlib.h> 10 #include <stdio.h> 11 12 /* External terminal function for debug output */ 13 extern void terminal_writestring(const char *str); 14 15 /* ============================================================================ 16 * Internal Helper Functions 17 * ========================================================================= */ 18 19 /* Read a sector from the partition */ 20 static int read_sector(fat16_context_t *ctx, uint32_t sector, void *buffer) { 21 uint32_t abs_sector = ctx->partition_start + sector; 22 return ata_read_sectors(ctx->bus, ctx->drive, abs_sector, 1, buffer); 23 } 24 25 /* Write a sector to the partition */ 26 static int write_sector(fat16_context_t *ctx, uint32_t sector, const void *buffer) { 27 uint32_t abs_sector = ctx->partition_start + sector; 28 return ata_write_sectors(ctx->bus, ctx->drive, abs_sector, 1, buffer); 29 } 30 31 /* Convert cluster number to sector number */ 32 static uint32_t cluster_to_sector(fat16_context_t *ctx, uint16_t cluster) { 33 return ctx->data_start + (cluster - 2) * ctx->sectors_per_cluster; 34 } 35 36 /* Read FAT entry for a cluster */ 37 static uint16_t read_fat_entry(fat16_context_t *ctx, uint16_t cluster) { 38 uint32_t fat_offset = cluster * 2; 39 uint32_t fat_sector = ctx->fat_start + (fat_offset / FAT16_SECTOR_SIZE); 40 uint32_t entry_offset = fat_offset % FAT16_SECTOR_SIZE; 41 42 uint8_t buffer[FAT16_SECTOR_SIZE]; 43 if (read_sector(ctx, fat_sector, buffer) != ATA_OK) { 44 return FAT16_CLUSTER_BAD; 45 } 46 47 return *(uint16_t *)(buffer + entry_offset); 48 } 49 50 /* Write FAT entry for a cluster */ 51 static int write_fat_entry(fat16_context_t *ctx, uint16_t cluster, uint16_t value) { 52 uint32_t fat_offset = cluster * 2; 53 uint32_t fat_sector = ctx->fat_start + (fat_offset / FAT16_SECTOR_SIZE); 54 uint32_t entry_offset = fat_offset % FAT16_SECTOR_SIZE; 55 56 uint8_t buffer[FAT16_SECTOR_SIZE]; 57 if (read_sector(ctx, fat_sector, buffer) != ATA_OK) { 58 return FAT16_ERR_IO; 59 } 60 61 *(uint16_t *)(buffer + entry_offset) = value; 62 63 /* Write to both FATs */ 64 if (write_sector(ctx, fat_sector, buffer) != ATA_OK) { 65 return FAT16_ERR_IO; 66 } 67 if (ctx->num_fats > 1) { 68 if (write_sector(ctx, fat_sector + ctx->fat_sectors, buffer) != ATA_OK) { 69 return FAT16_ERR_IO; 70 } 71 } 72 73 return FAT16_OK; 74 } 75 76 /* Allocate a free cluster */ 77 static uint16_t alloc_cluster(fat16_context_t *ctx) { 78 for (uint16_t cluster = 2; cluster < ctx->data_clusters + 2; cluster++) { 79 uint16_t entry = read_fat_entry(ctx, cluster); 80 if (entry == FAT16_CLUSTER_FREE) { 81 /* Mark as end of chain */ 82 write_fat_entry(ctx, cluster, FAT16_CLUSTER_END); 83 return cluster; 84 } 85 } 86 return 0; /* No free clusters */ 87 } 88 89 /* Free a cluster chain */ 90 static void free_cluster_chain(fat16_context_t *ctx, uint16_t start_cluster) { 91 uint16_t cluster = start_cluster; 92 while (cluster >= 2 && cluster < FAT16_CLUSTER_END_MIN) { 93 uint16_t next = read_fat_entry(ctx, cluster); 94 write_fat_entry(ctx, cluster, FAT16_CLUSTER_FREE); 95 cluster = next; 96 } 97 } 98 99 /* Convert filename to 8.3 format */ 100 static void name_to_83(const char *name, char *name83) { 101 memset(name83, ' ', 11); 102 103 int i = 0, j = 0; 104 105 /* Copy name part (up to 8 chars) */ 106 while (name[i] && name[i] != '.' && j < 8) { 107 char c = name[i++]; 108 if (c >= 'a' && c <= 'z') c -= 32; /* Uppercase */ 109 name83[j++] = c; 110 } 111 112 /* Skip to extension */ 113 while (name[i] && name[i] != '.') i++; 114 if (name[i] == '.') i++; 115 116 /* Copy extension (up to 3 chars) */ 117 j = 8; 118 while (name[i] && j < 11) { 119 char c = name[i++]; 120 if (c >= 'a' && c <= 'z') c -= 32; /* Uppercase */ 121 name83[j++] = c; 122 } 123 } 124 125 /* Compare 8.3 name */ 126 static int name83_equal(const char *a, const char *b) { 127 return memcmp(a, b, 11) == 0; 128 } 129 130 /* Parse path into components */ 131 static int parse_path(const char *path, char components[][12], int max_components) { 132 int count = 0; 133 const char *p = path; 134 135 /* Skip leading slash */ 136 if (*p == '/') p++; 137 138 while (*p && count < max_components) { 139 /* Extract component */ 140 char name[13] = {0}; 141 int len = 0; 142 while (*p && *p != '/' && len < 12) { 143 name[len++] = *p++; 144 } 145 if (len > 0) { 146 name_to_83(name, components[count]); 147 count++; 148 } 149 if (*p == '/') p++; 150 } 151 152 return count; 153 } 154 155 /* Find entry in directory */ 156 static int find_in_directory(fat16_context_t *ctx, uint32_t dir_sector, 157 uint32_t dir_entries, const char *name83, 158 fat16_dir_entry_t *out_entry, uint32_t *out_sector, 159 uint32_t *out_offset) { 160 uint8_t buffer[FAT16_SECTOR_SIZE]; 161 uint32_t entries_checked = 0; 162 163 for (uint32_t s = 0; entries_checked < dir_entries; s++) { 164 if (read_sector(ctx, dir_sector + s, buffer) != ATA_OK) { 165 return FAT16_ERR_IO; 166 } 167 168 for (int i = 0; i < FAT16_ENTRIES_PER_SECTOR && entries_checked < dir_entries; i++) { 169 fat16_dir_entry_t *entry = (fat16_dir_entry_t *)(buffer + i * FAT16_DIR_ENTRY_SIZE); 170 entries_checked++; 171 172 /* End of directory */ 173 if (entry->name[0] == 0x00) { 174 return FAT16_ERR_NOT_FOUND; 175 } 176 177 /* Deleted entry */ 178 if ((uint8_t)entry->name[0] == 0xE5) { 179 continue; 180 } 181 182 /* Volume label or long name entry */ 183 if (entry->attributes & FAT16_ATTR_VOLUME_ID) { 184 continue; 185 } 186 187 /* Compare name */ 188 if (name83_equal(entry->name, name83)) { 189 if (out_entry) *out_entry = *entry; 190 if (out_sector) *out_sector = dir_sector + s; 191 if (out_offset) *out_offset = i * FAT16_DIR_ENTRY_SIZE; 192 return FAT16_OK; 193 } 194 } 195 } 196 197 return FAT16_ERR_NOT_FOUND; 198 } 199 200 /* Find a free entry in directory */ 201 static int find_free_entry(fat16_context_t *ctx, uint32_t dir_sector, 202 uint32_t dir_entries, uint32_t *out_sector, 203 uint32_t *out_offset) { 204 uint8_t buffer[FAT16_SECTOR_SIZE]; 205 uint32_t entries_checked = 0; 206 207 for (uint32_t s = 0; entries_checked < dir_entries; s++) { 208 if (read_sector(ctx, dir_sector + s, buffer) != ATA_OK) { 209 return FAT16_ERR_IO; 210 } 211 212 for (int i = 0; i < FAT16_ENTRIES_PER_SECTOR && entries_checked < dir_entries; i++) { 213 fat16_dir_entry_t *entry = (fat16_dir_entry_t *)(buffer + i * FAT16_DIR_ENTRY_SIZE); 214 entries_checked++; 215 216 /* Free or deleted entry */ 217 if (entry->name[0] == 0x00 || (uint8_t)entry->name[0] == 0xE5) { 218 *out_sector = dir_sector + s; 219 *out_offset = i * FAT16_DIR_ENTRY_SIZE; 220 return FAT16_OK; 221 } 222 } 223 } 224 225 return FAT16_ERR_NO_SPACE; 226 } 227 228 /* Traverse path to find parent directory and final component */ 229 static int traverse_path(fat16_context_t *ctx, const char *path, 230 uint32_t *out_dir_sector, uint32_t *out_dir_entries, 231 uint16_t *out_dir_cluster, char *out_name83) { 232 char components[16][12]; 233 int num_components = parse_path(path, components, 16); 234 235 if (num_components == 0) { 236 return FAT16_ERR_INVALID; 237 } 238 239 /* Start at root directory */ 240 uint32_t dir_sector = ctx->root_start; 241 uint32_t dir_entries = ctx->root_entries; 242 uint16_t dir_cluster = 0; 243 244 /* Traverse to parent directory */ 245 for (int i = 0; i < num_components - 1; i++) { 246 fat16_dir_entry_t entry; 247 int result = find_in_directory(ctx, dir_sector, dir_entries, 248 components[i], &entry, NULL, NULL); 249 if (result != FAT16_OK) { 250 return result; 251 } 252 253 if (!(entry.attributes & FAT16_ATTR_DIRECTORY)) { 254 return FAT16_ERR_NOT_FOUND; 255 } 256 257 dir_cluster = entry.cluster_low; 258 dir_sector = cluster_to_sector(ctx, dir_cluster); 259 dir_entries = (ctx->sectors_per_cluster * FAT16_SECTOR_SIZE) / FAT16_DIR_ENTRY_SIZE; 260 } 261 262 *out_dir_sector = dir_sector; 263 *out_dir_entries = dir_entries; 264 *out_dir_cluster = dir_cluster; 265 memcpy(out_name83, components[num_components - 1], 11); 266 267 return FAT16_OK; 268 } 269 270 /* ============================================================================ 271 * Public API Implementation 272 * ========================================================================= */ 273 274 int fat16_format(uint8_t bus, uint8_t drive, 275 uint32_t part_start, uint32_t part_size, 276 const char *label) { 277 terminal_writestring("[FAT16] Formatting partition...\n"); 278 279 if (part_size < 4096) { /* Minimum ~2MB */ 280 return FAT16_ERR_INVALID; 281 } 282 283 /* Calculate filesystem parameters */ 284 uint16_t bytes_per_sector = 512; 285 uint8_t sectors_per_cluster; 286 287 /* Choose cluster size based on partition size */ 288 if (part_size < 32768) { /* < 16MB */ 289 sectors_per_cluster = 1; 290 } else if (part_size < 262144) { /* < 128MB */ 291 sectors_per_cluster = 4; 292 } else { 293 sectors_per_cluster = 8; 294 } 295 296 uint16_t reserved_sectors = 1; 297 uint8_t num_fats = 2; 298 uint16_t root_entries = 512; 299 uint32_t root_sectors = (root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector; 300 301 /* Calculate FAT size */ 302 uint32_t tmp_sectors = part_size - reserved_sectors - root_sectors; 303 uint32_t clusters = tmp_sectors / sectors_per_cluster; 304 uint16_t fat_sectors = (clusters * 2 + bytes_per_sector - 1) / bytes_per_sector; 305 306 /* Recalculate with actual FAT size */ 307 uint32_t data_start = reserved_sectors + (num_fats * fat_sectors) + root_sectors; 308 uint32_t data_sectors = part_size - data_start; 309 uint32_t data_clusters = data_sectors / sectors_per_cluster; 310 311 { 312 char dbg[128]; 313 snprintf(dbg, sizeof(dbg), "[FAT16] clusters=%d fat_sectors=%d data_start=%d\n", 314 (int)data_clusters, (int)fat_sectors, (int)data_start); 315 terminal_writestring(dbg); 316 } 317 318 /* Build boot sector */ 319 fat16_boot_sector_t boot; 320 memset(&boot, 0, sizeof(boot)); 321 322 boot.jump[0] = 0xEB; 323 boot.jump[1] = 0x3C; 324 boot.jump[2] = 0x90; 325 memcpy(boot.oem_name, "LUAJITOS", 8); 326 boot.bytes_per_sector = bytes_per_sector; 327 boot.sectors_per_cluster = sectors_per_cluster; 328 boot.reserved_sectors = reserved_sectors; 329 boot.num_fats = num_fats; 330 boot.root_entries = root_entries; 331 boot.total_sectors_16 = (part_size <= 65535) ? part_size : 0; 332 boot.media_type = 0xF8; /* Hard disk */ 333 boot.fat_sectors = fat_sectors; 334 boot.sectors_per_track = 63; 335 boot.num_heads = 255; 336 boot.hidden_sectors = part_start; 337 boot.total_sectors_32 = (part_size > 65535) ? part_size : 0; 338 boot.drive_number = 0x80; 339 boot.boot_signature = 0x29; 340 boot.volume_id = 0x12345678; /* TODO: use random */ 341 342 /* Volume label */ 343 memset(boot.volume_label, ' ', 11); 344 if (label) { 345 size_t len = strlen(label); 346 if (len > 11) len = 11; 347 memcpy(boot.volume_label, label, len); 348 } 349 memcpy(boot.fs_type, "FAT16 ", 8); 350 boot.signature = 0xAA55; 351 352 /* Write boot sector */ 353 if (ata_write_sectors(bus, drive, part_start, 1, &boot) != ATA_OK) { 354 return FAT16_ERR_IO; 355 } 356 357 /* Initialize FATs with zeros */ 358 uint8_t zero_sector[FAT16_SECTOR_SIZE]; 359 memset(zero_sector, 0, sizeof(zero_sector)); 360 361 uint32_t fat_start = part_start + reserved_sectors; 362 for (int f = 0; f < num_fats; f++) { 363 for (uint32_t s = 0; s < fat_sectors; s++) { 364 if (ata_write_sectors(bus, drive, fat_start + s, 1, zero_sector) != ATA_OK) { 365 return FAT16_ERR_IO; 366 } 367 } 368 fat_start += fat_sectors; 369 } 370 371 /* Set first two FAT entries (reserved) */ 372 uint8_t fat_buffer[FAT16_SECTOR_SIZE]; 373 memset(fat_buffer, 0, sizeof(fat_buffer)); 374 fat_buffer[0] = 0xF8; /* Media type */ 375 fat_buffer[1] = 0xFF; 376 fat_buffer[2] = 0xFF; /* End of chain marker */ 377 fat_buffer[3] = 0xFF; 378 379 fat_start = part_start + reserved_sectors; 380 if (ata_write_sectors(bus, drive, fat_start, 1, fat_buffer) != ATA_OK) { 381 return FAT16_ERR_IO; 382 } 383 if (num_fats > 1) { 384 if (ata_write_sectors(bus, drive, fat_start + fat_sectors, 1, fat_buffer) != ATA_OK) { 385 return FAT16_ERR_IO; 386 } 387 } 388 389 /* Initialize root directory with zeros */ 390 uint32_t root_start = part_start + reserved_sectors + (num_fats * fat_sectors); 391 for (uint32_t s = 0; s < root_sectors; s++) { 392 if (ata_write_sectors(bus, drive, root_start + s, 1, zero_sector) != ATA_OK) { 393 return FAT16_ERR_IO; 394 } 395 } 396 397 /* Create volume label entry in root directory */ 398 if (label && strlen(label) > 0) { 399 fat16_dir_entry_t vol_entry; 400 memset(&vol_entry, 0, sizeof(vol_entry)); 401 memset(vol_entry.name, ' ', 11); 402 size_t len = strlen(label); 403 if (len > 11) len = 11; 404 for (size_t i = 0; i < len; i++) { 405 char c = label[i]; 406 if (c >= 'a' && c <= 'z') c -= 32; 407 vol_entry.name[i] = c; 408 } 409 vol_entry.attributes = FAT16_ATTR_VOLUME_ID; 410 411 uint8_t root_buffer[FAT16_SECTOR_SIZE]; 412 memset(root_buffer, 0, sizeof(root_buffer)); 413 memcpy(root_buffer, &vol_entry, sizeof(vol_entry)); 414 if (ata_write_sectors(bus, drive, root_start, 1, root_buffer) != ATA_OK) { 415 return FAT16_ERR_IO; 416 } 417 } 418 419 terminal_writestring("[FAT16] Format complete\n"); 420 return FAT16_OK; 421 } 422 423 int fat16_mount(fat16_context_t *ctx, uint8_t bus, uint8_t drive, 424 uint32_t part_start) { 425 if (!ctx) return FAT16_ERR_INVALID; 426 427 memset(ctx, 0, sizeof(fat16_context_t)); 428 429 /* Read boot sector */ 430 fat16_boot_sector_t boot; 431 if (ata_read_sectors(bus, drive, part_start, 1, &boot) != ATA_OK) { 432 return FAT16_ERR_IO; 433 } 434 435 /* Verify signature */ 436 if (boot.signature != 0xAA55) { 437 return FAT16_ERR_NOT_FAT16; 438 } 439 440 /* Verify filesystem type */ 441 if (memcmp(boot.fs_type, "FAT16", 5) != 0 && 442 memcmp(boot.fs_type, "FAT12", 5) != 0) { 443 return FAT16_ERR_NOT_FAT16; 444 } 445 446 /* Initialize context */ 447 ctx->bus = bus; 448 ctx->drive = drive; 449 ctx->partition_start = part_start; 450 ctx->bytes_per_sector = boot.bytes_per_sector; 451 ctx->sectors_per_cluster = boot.sectors_per_cluster; 452 ctx->reserved_sectors = boot.reserved_sectors; 453 ctx->num_fats = boot.num_fats; 454 ctx->root_entries = boot.root_entries; 455 ctx->fat_sectors = boot.fat_sectors; 456 ctx->total_sectors = boot.total_sectors_16 ? boot.total_sectors_16 : boot.total_sectors_32; 457 458 ctx->fat_start = ctx->reserved_sectors; 459 uint32_t root_sectors = (ctx->root_entries * 32 + ctx->bytes_per_sector - 1) / ctx->bytes_per_sector; 460 ctx->root_start = ctx->fat_start + (ctx->num_fats * ctx->fat_sectors); 461 ctx->data_start = ctx->root_start + root_sectors; 462 ctx->data_clusters = (ctx->total_sectors - ctx->data_start) / ctx->sectors_per_cluster; 463 ctx->partition_size = ctx->total_sectors; 464 ctx->is_mounted = 1; 465 466 return FAT16_OK; 467 } 468 469 int fat16_unmount(fat16_context_t *ctx) { 470 if (!ctx) return FAT16_ERR_INVALID; 471 ctx->is_mounted = 0; 472 return FAT16_OK; 473 } 474 475 int fat16_create(fat16_context_t *ctx, const char *path, int is_dir) { 476 if (!ctx || !ctx->is_mounted || !path) return FAT16_ERR_INVALID; 477 478 uint32_t dir_sector, dir_entries; 479 uint16_t dir_cluster; 480 char name83[11]; 481 482 int result = traverse_path(ctx, path, &dir_sector, &dir_entries, 483 &dir_cluster, name83); 484 if (result != FAT16_OK) return result; 485 486 /* Check if already exists */ 487 fat16_dir_entry_t existing; 488 if (find_in_directory(ctx, dir_sector, dir_entries, name83, 489 &existing, NULL, NULL) == FAT16_OK) { 490 return FAT16_ERR_EXISTS; 491 } 492 493 /* Find free entry */ 494 uint32_t entry_sector, entry_offset; 495 result = find_free_entry(ctx, dir_sector, dir_entries, 496 &entry_sector, &entry_offset); 497 if (result != FAT16_OK) return result; 498 499 /* Create entry */ 500 fat16_dir_entry_t new_entry; 501 memset(&new_entry, 0, sizeof(new_entry)); 502 memcpy(new_entry.name, name83, 11); 503 new_entry.attributes = is_dir ? FAT16_ATTR_DIRECTORY : FAT16_ATTR_ARCHIVE; 504 new_entry.cluster_low = 0; 505 new_entry.file_size = 0; 506 507 /* If directory, allocate cluster for . and .. entries */ 508 if (is_dir) { 509 uint16_t cluster = alloc_cluster(ctx); 510 if (cluster == 0) return FAT16_ERR_NO_SPACE; 511 512 new_entry.cluster_low = cluster; 513 514 /* Initialize directory cluster */ 515 uint8_t dir_buffer[FAT16_SECTOR_SIZE]; 516 memset(dir_buffer, 0, sizeof(dir_buffer)); 517 518 /* . entry */ 519 fat16_dir_entry_t *dot = (fat16_dir_entry_t *)dir_buffer; 520 memset(dot->name, ' ', 11); 521 dot->name[0] = '.'; 522 dot->attributes = FAT16_ATTR_DIRECTORY; 523 dot->cluster_low = cluster; 524 525 /* .. entry */ 526 fat16_dir_entry_t *dotdot = (fat16_dir_entry_t *)(dir_buffer + 32); 527 memset(dotdot->name, ' ', 11); 528 dotdot->name[0] = '.'; 529 dotdot->name[1] = '.'; 530 dotdot->attributes = FAT16_ATTR_DIRECTORY; 531 dotdot->cluster_low = dir_cluster; 532 533 uint32_t new_dir_sector = cluster_to_sector(ctx, cluster); 534 for (uint32_t s = 0; s < ctx->sectors_per_cluster; s++) { 535 if (write_sector(ctx, new_dir_sector + s, 536 s == 0 ? dir_buffer : dir_buffer + FAT16_SECTOR_SIZE) != ATA_OK) { 537 return FAT16_ERR_IO; 538 } 539 } 540 } 541 542 /* Write entry to parent directory */ 543 uint8_t buffer[FAT16_SECTOR_SIZE]; 544 if (read_sector(ctx, entry_sector, buffer) != ATA_OK) { 545 return FAT16_ERR_IO; 546 } 547 memcpy(buffer + entry_offset, &new_entry, sizeof(new_entry)); 548 if (write_sector(ctx, entry_sector, buffer) != ATA_OK) { 549 return FAT16_ERR_IO; 550 } 551 552 return FAT16_OK; 553 } 554 555 int fat16_write_file(fat16_context_t *ctx, const char *path, 556 const void *data, uint32_t size) { 557 if (!ctx || !ctx->is_mounted || !path) return FAT16_ERR_INVALID; 558 559 uint32_t dir_sector, dir_entries; 560 uint16_t dir_cluster; 561 char name83[11]; 562 563 int result = traverse_path(ctx, path, &dir_sector, &dir_entries, 564 &dir_cluster, name83); 565 if (result != FAT16_OK) return result; 566 567 /* Find or create entry */ 568 fat16_dir_entry_t entry; 569 uint32_t entry_sector, entry_offset; 570 result = find_in_directory(ctx, dir_sector, dir_entries, name83, 571 &entry, &entry_sector, &entry_offset); 572 573 if (result == FAT16_ERR_NOT_FOUND) { 574 /* Create new file */ 575 result = find_free_entry(ctx, dir_sector, dir_entries, 576 &entry_sector, &entry_offset); 577 if (result != FAT16_OK) return result; 578 579 memset(&entry, 0, sizeof(entry)); 580 memcpy(entry.name, name83, 11); 581 entry.attributes = FAT16_ATTR_ARCHIVE; 582 } else if (result != FAT16_OK) { 583 return result; 584 } else { 585 /* Free existing cluster chain */ 586 if (entry.cluster_low >= 2) { 587 free_cluster_chain(ctx, entry.cluster_low); 588 } 589 } 590 591 /* Allocate clusters and write data */ 592 uint32_t bytes_per_cluster = ctx->sectors_per_cluster * FAT16_SECTOR_SIZE; 593 uint32_t clusters_needed = (size + bytes_per_cluster - 1) / bytes_per_cluster; 594 uint16_t first_cluster = 0; 595 uint16_t prev_cluster = 0; 596 const uint8_t *src = (const uint8_t *)data; 597 uint32_t bytes_remaining = size; 598 599 for (uint32_t i = 0; i < clusters_needed; i++) { 600 uint16_t cluster = alloc_cluster(ctx); 601 if (cluster == 0) { 602 if (first_cluster) free_cluster_chain(ctx, first_cluster); 603 return FAT16_ERR_NO_SPACE; 604 } 605 606 if (first_cluster == 0) { 607 first_cluster = cluster; 608 } else { 609 write_fat_entry(ctx, prev_cluster, cluster); 610 } 611 prev_cluster = cluster; 612 613 /* Write cluster data */ 614 uint32_t sector = cluster_to_sector(ctx, cluster); 615 uint8_t buffer[FAT16_SECTOR_SIZE]; 616 617 for (uint32_t s = 0; s < ctx->sectors_per_cluster && bytes_remaining > 0; s++) { 618 uint32_t to_write = bytes_remaining > FAT16_SECTOR_SIZE ? 619 FAT16_SECTOR_SIZE : bytes_remaining; 620 memset(buffer, 0, FAT16_SECTOR_SIZE); 621 memcpy(buffer, src, to_write); 622 623 if (write_sector(ctx, sector + s, buffer) != ATA_OK) { 624 free_cluster_chain(ctx, first_cluster); 625 return FAT16_ERR_IO; 626 } 627 628 src += to_write; 629 bytes_remaining -= to_write; 630 } 631 } 632 633 /* Update directory entry */ 634 entry.cluster_low = first_cluster; 635 entry.file_size = size; 636 637 uint8_t dir_buffer[FAT16_SECTOR_SIZE]; 638 if (read_sector(ctx, entry_sector, dir_buffer) != ATA_OK) { 639 return FAT16_ERR_IO; 640 } 641 memcpy(dir_buffer + entry_offset, &entry, sizeof(entry)); 642 if (write_sector(ctx, entry_sector, dir_buffer) != ATA_OK) { 643 return FAT16_ERR_IO; 644 } 645 646 return FAT16_OK; 647 } 648 649 int fat16_read_file(fat16_context_t *ctx, const char *path, 650 void *buffer, uint32_t max_size, uint32_t *bytes_read) { 651 if (!ctx || !ctx->is_mounted || !path || !buffer) return FAT16_ERR_INVALID; 652 653 uint32_t dir_sector, dir_entries; 654 uint16_t dir_cluster; 655 char name83[11]; 656 657 int result = traverse_path(ctx, path, &dir_sector, &dir_entries, 658 &dir_cluster, name83); 659 if (result != FAT16_OK) return result; 660 661 fat16_dir_entry_t entry; 662 result = find_in_directory(ctx, dir_sector, dir_entries, name83, 663 &entry, NULL, NULL); 664 if (result != FAT16_OK) return result; 665 666 if (entry.attributes & FAT16_ATTR_DIRECTORY) { 667 return FAT16_ERR_INVALID; 668 } 669 670 uint32_t to_read = entry.file_size < max_size ? entry.file_size : max_size; 671 uint8_t *dst = (uint8_t *)buffer; 672 uint32_t bytes_remaining = to_read; 673 uint16_t cluster = entry.cluster_low; 674 675 while (bytes_remaining > 0 && cluster >= 2 && cluster < FAT16_CLUSTER_END_MIN) { 676 uint32_t sector = cluster_to_sector(ctx, cluster); 677 uint8_t sector_buffer[FAT16_SECTOR_SIZE]; 678 679 for (uint32_t s = 0; s < ctx->sectors_per_cluster && bytes_remaining > 0; s++) { 680 if (read_sector(ctx, sector + s, sector_buffer) != ATA_OK) { 681 return FAT16_ERR_IO; 682 } 683 684 uint32_t copy_size = bytes_remaining > FAT16_SECTOR_SIZE ? 685 FAT16_SECTOR_SIZE : bytes_remaining; 686 memcpy(dst, sector_buffer, copy_size); 687 dst += copy_size; 688 bytes_remaining -= copy_size; 689 } 690 691 cluster = read_fat_entry(ctx, cluster); 692 } 693 694 if (bytes_read) *bytes_read = to_read - bytes_remaining; 695 return FAT16_OK; 696 } 697 698 int fat16_exists(fat16_context_t *ctx, const char *path) { 699 if (!ctx || !ctx->is_mounted || !path) return 0; 700 701 uint32_t dir_sector, dir_entries; 702 uint16_t dir_cluster; 703 char name83[11]; 704 705 if (traverse_path(ctx, path, &dir_sector, &dir_entries, 706 &dir_cluster, name83) != FAT16_OK) { 707 return 0; 708 } 709 710 return find_in_directory(ctx, dir_sector, dir_entries, name83, 711 NULL, NULL, NULL) == FAT16_OK; 712 } 713 714 int32_t fat16_file_size(fat16_context_t *ctx, const char *path) { 715 if (!ctx || !ctx->is_mounted || !path) return -1; 716 717 uint32_t dir_sector, dir_entries; 718 uint16_t dir_cluster; 719 char name83[11]; 720 721 if (traverse_path(ctx, path, &dir_sector, &dir_entries, 722 &dir_cluster, name83) != FAT16_OK) { 723 return -1; 724 } 725 726 fat16_dir_entry_t entry; 727 if (find_in_directory(ctx, dir_sector, dir_entries, name83, 728 &entry, NULL, NULL) != FAT16_OK) { 729 return -1; 730 } 731 732 return entry.file_size; 733 } 734 735 const char *fat16_error_string(int error) { 736 switch (error) { 737 case FAT16_OK: return "Success"; 738 case FAT16_ERR_IO: return "I/O error"; 739 case FAT16_ERR_NOT_FAT16: return "Not a FAT16 filesystem"; 740 case FAT16_ERR_NOT_FOUND: return "File not found"; 741 case FAT16_ERR_NO_SPACE: return "No space left"; 742 case FAT16_ERR_INVALID: return "Invalid parameter"; 743 case FAT16_ERR_EXISTS: return "File already exists"; 744 case FAT16_ERR_DIR_NOT_EMPTY: return "Directory not empty"; 745 default: return "Unknown error"; 746 } 747 } 748 749 /* ============================================================================ 750 * Lua Bindings 751 * ========================================================================= */ 752 753 #include "lua.h" 754 #include "lauxlib.h" 755 756 /* Global FAT16 context for mounted partition */ 757 static fat16_context_t g_fat16_ctx; 758 static int g_fat16_mounted = 0; 759 760 /* fat16.format(bus, drive, partStart, partSize, label) 761 * Returns: true on success, nil + error string on failure 762 */ 763 static int lua_fat16_format(lua_State *L) { 764 int bus = luaL_checkinteger(L, 1); 765 int drive = luaL_checkinteger(L, 2); 766 uint32_t part_start = (uint32_t)luaL_checkinteger(L, 3); 767 uint32_t part_size = (uint32_t)luaL_checkinteger(L, 4); 768 const char *label = luaL_optstring(L, 5, "BOOT"); 769 770 int result = fat16_format(bus, drive, part_start, part_size, label); 771 if (result != FAT16_OK) { 772 lua_pushnil(L); 773 lua_pushstring(L, fat16_error_string(result)); 774 return 2; 775 } 776 777 lua_pushboolean(L, 1); 778 return 1; 779 } 780 781 /* fat16.mount(bus, drive, partStart) 782 * Returns: true on success, nil + error string on failure 783 */ 784 static int lua_fat16_mount(lua_State *L) { 785 int bus = luaL_checkinteger(L, 1); 786 int drive = luaL_checkinteger(L, 2); 787 uint32_t part_start = (uint32_t)luaL_checkinteger(L, 3); 788 789 if (g_fat16_mounted) { 790 lua_pushnil(L); 791 lua_pushstring(L, "FAT16 filesystem already mounted"); 792 return 2; 793 } 794 795 int result = fat16_mount(&g_fat16_ctx, bus, drive, part_start); 796 if (result != FAT16_OK) { 797 lua_pushnil(L); 798 lua_pushstring(L, fat16_error_string(result)); 799 return 2; 800 } 801 802 g_fat16_mounted = 1; 803 lua_pushboolean(L, 1); 804 return 1; 805 } 806 807 /* fat16.unmount() 808 * Returns: true on success, nil + error string on failure 809 */ 810 static int lua_fat16_unmount(lua_State *L) { 811 if (!g_fat16_mounted) { 812 lua_pushnil(L); 813 lua_pushstring(L, "No FAT16 filesystem mounted"); 814 return 2; 815 } 816 817 fat16_unmount(&g_fat16_ctx); 818 g_fat16_mounted = 0; 819 lua_pushboolean(L, 1); 820 return 1; 821 } 822 823 /* fat16.mkdir(path) 824 * Returns: true on success, nil + error string on failure 825 */ 826 static int lua_fat16_mkdir(lua_State *L) { 827 const char *path = luaL_checkstring(L, 1); 828 829 if (!g_fat16_mounted) { 830 lua_pushnil(L); 831 lua_pushstring(L, "No FAT16 filesystem mounted"); 832 return 2; 833 } 834 835 int result = fat16_create(&g_fat16_ctx, path, 1); 836 if (result != FAT16_OK) { 837 lua_pushnil(L); 838 lua_pushstring(L, fat16_error_string(result)); 839 return 2; 840 } 841 842 lua_pushboolean(L, 1); 843 return 1; 844 } 845 846 /* fat16.writeFile(path, data) 847 * Returns: true on success, nil + error string on failure 848 */ 849 static int lua_fat16_write_file(lua_State *L) { 850 const char *path = luaL_checkstring(L, 1); 851 size_t data_len; 852 const char *data = luaL_checklstring(L, 2, &data_len); 853 854 if (!g_fat16_mounted) { 855 lua_pushnil(L); 856 lua_pushstring(L, "No FAT16 filesystem mounted"); 857 return 2; 858 } 859 860 int result = fat16_write_file(&g_fat16_ctx, path, data, (uint32_t)data_len); 861 if (result != FAT16_OK) { 862 lua_pushnil(L); 863 lua_pushstring(L, fat16_error_string(result)); 864 return 2; 865 } 866 867 lua_pushboolean(L, 1); 868 return 1; 869 } 870 871 /* fat16.readFile(path, maxSize) 872 * Returns: data string on success, nil + error string on failure 873 */ 874 static int lua_fat16_read_file(lua_State *L) { 875 const char *path = luaL_checkstring(L, 1); 876 uint32_t max_size = (uint32_t)luaL_optinteger(L, 2, 1024 * 1024); /* Default 1MB */ 877 878 if (!g_fat16_mounted) { 879 lua_pushnil(L); 880 lua_pushstring(L, "No FAT16 filesystem mounted"); 881 return 2; 882 } 883 884 /* Allocate buffer */ 885 char *buffer = malloc(max_size); 886 if (!buffer) { 887 lua_pushnil(L); 888 lua_pushstring(L, "Out of memory"); 889 return 2; 890 } 891 892 uint32_t bytes_read; 893 int result = fat16_read_file(&g_fat16_ctx, path, buffer, max_size, &bytes_read); 894 if (result != FAT16_OK) { 895 free(buffer); 896 lua_pushnil(L); 897 lua_pushstring(L, fat16_error_string(result)); 898 return 2; 899 } 900 901 lua_pushlstring(L, buffer, bytes_read); 902 free(buffer); 903 return 1; 904 } 905 906 /* fat16.exists(path) 907 * Returns: boolean 908 */ 909 static int lua_fat16_exists(lua_State *L) { 910 const char *path = luaL_checkstring(L, 1); 911 912 if (!g_fat16_mounted) { 913 lua_pushboolean(L, 0); 914 return 1; 915 } 916 917 lua_pushboolean(L, fat16_exists(&g_fat16_ctx, path)); 918 return 1; 919 } 920 921 /* fat16.fileSize(path) 922 * Returns: size in bytes, or nil + error string on failure 923 */ 924 static int lua_fat16_file_size(lua_State *L) { 925 const char *path = luaL_checkstring(L, 1); 926 927 if (!g_fat16_mounted) { 928 lua_pushnil(L); 929 lua_pushstring(L, "No FAT16 filesystem mounted"); 930 return 2; 931 } 932 933 int32_t size = fat16_file_size(&g_fat16_ctx, path); 934 if (size < 0) { 935 lua_pushnil(L); 936 lua_pushstring(L, "File not found"); 937 return 2; 938 } 939 940 lua_pushinteger(L, size); 941 return 1; 942 } 943 944 /* Module registration */ 945 static const luaL_Reg fat16_funcs[] = { 946 {"format", lua_fat16_format}, 947 {"mount", lua_fat16_mount}, 948 {"unmount", lua_fat16_unmount}, 949 {"mkdir", lua_fat16_mkdir}, 950 {"writeFile", lua_fat16_write_file}, 951 {"readFile", lua_fat16_read_file}, 952 {"exists", lua_fat16_exists}, 953 {"fileSize", lua_fat16_file_size}, 954 {NULL, NULL} 955 }; 956 957 int luaopen_fat16(lua_State *L) { 958 luaL_register(L, "fat16", fat16_funcs); 959 return 1; 960 }