luajitos

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

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 }