diskfs.c (47686B)
1 /* DiskFS - Simple Filesystem for ATA drives in LuajitOS */ 2 3 #include "diskfs.h" 4 #include "ata.h" 5 #include "fde.h" 6 #include <string.h> 7 #include <stdlib.h> 8 #include <lua.h> 9 #include <lauxlib.h> 10 11 /* External FDE contexts from fde.c */ 12 extern fde_context_t fde_contexts[4]; 13 14 /* Check if FDE is active for a drive */ 15 static int fde_is_active(uint8_t bus, uint8_t drive) { 16 int idx = bus * 2 + drive; 17 if (idx < 0 || idx >= 4) return 0; 18 return fde_contexts[idx].is_open; 19 } 20 21 /* Get FDE context for a drive */ 22 static fde_context_t* get_fde_context(uint8_t bus, uint8_t drive) { 23 int idx = bus * 2 + drive; 24 if (idx < 0 || idx >= 4) return NULL; 25 return &fde_contexts[idx]; 26 } 27 28 /* External terminal function */ 29 extern void terminal_writestring(const char* str); 30 31 /* strdup implementation for bare metal */ 32 static char* diskfs_strdup(const char* s) { 33 if (!s) return NULL; 34 size_t len = strlen(s) + 1; 35 char* dup = malloc(len); 36 if (dup) { 37 memcpy(dup, s, len); 38 } 39 return dup; 40 } 41 42 /* Mount table */ 43 static diskfs_mount_t mounts[DISKFS_MAX_MOUNTS]; 44 45 /* Sector buffer for I/O */ 46 static uint8_t sector_buffer[DISKFS_SECTOR_SIZE]; 47 48 /* Get mount index from bus/drive */ 49 static int get_mount_index(uint8_t bus, uint8_t drive) { 50 return (bus * 2) + drive; 51 } 52 53 /* Read a sector - routes through FDE if encryption is active */ 54 static int read_sector(uint8_t bus, uint8_t drive, uint32_t sector, void* buffer) { 55 if (fde_is_active(bus, drive)) { 56 fde_context_t* ctx = get_fde_context(bus, drive); 57 int result = fde_read_sector(ctx, sector, buffer); 58 if (sector < 5) { 59 char dbg[80]; 60 snprintf(dbg, sizeof(dbg), "[DISKFS] read_sector FDE: sector=%d result=%d\n", (int)sector, result); 61 terminal_writestring(dbg); 62 } 63 return (result == FDE_OK) ? ATA_OK : ATA_ERR_IO; 64 } 65 return ata_read_sectors(bus, drive, sector, 1, buffer); 66 } 67 68 /* Write a sector - routes through FDE if encryption is active */ 69 static int write_sector(uint8_t bus, uint8_t drive, uint32_t sector, const void* buffer) { 70 if (fde_is_active(bus, drive)) { 71 fde_context_t* ctx = get_fde_context(bus, drive); 72 if (sector < 5) { 73 char dbg[80]; 74 snprintf(dbg, sizeof(dbg), "[DISKFS] write_sector FDE: sector=%d\n", (int)sector); 75 terminal_writestring(dbg); 76 } 77 int result = fde_write_sector(ctx, sector, buffer); 78 if (result != FDE_OK) { 79 char dbg[80]; 80 snprintf(dbg, sizeof(dbg), "[DISKFS] write_sector FDE FAILED: sector=%d result=%d\n", (int)sector, result); 81 terminal_writestring(dbg); 82 } 83 return (result == FDE_OK) ? ATA_OK : ATA_ERR_IO; 84 } 85 return ata_write_sectors(bus, drive, sector, 1, buffer); 86 } 87 88 /* Allocate a free sector */ 89 static int alloc_sector(uint8_t bus, uint8_t drive, uint32_t* sector_out) { 90 diskfs_superblock_t sb; 91 92 if (read_sector(bus, drive, DISKFS_SUPERBLOCK_SECTOR, &sb) != ATA_OK) { 93 return DISKFS_ERR_IO; 94 } 95 96 if (sb.free_list_head == 0 || sb.free_sectors == 0) { 97 return DISKFS_ERR_FULL; 98 } 99 100 *sector_out = sb.free_list_head; 101 102 /* Read the free sector to get next in free list */ 103 uint8_t temp[DISKFS_SECTOR_SIZE]; 104 if (read_sector(bus, drive, sb.free_list_head, temp) != ATA_OK) { 105 return DISKFS_ERR_IO; 106 } 107 108 /* Next free sector is stored at end of sector */ 109 uint32_t next_free = *(uint32_t*)(temp + DISKFS_SECTOR_SIZE - 4); 110 111 /* Update superblock */ 112 sb.free_list_head = next_free; 113 sb.free_sectors--; 114 115 if (write_sector(bus, drive, DISKFS_SUPERBLOCK_SECTOR, &sb) != ATA_OK) { 116 return DISKFS_ERR_IO; 117 } 118 119 /* Clear the allocated sector */ 120 memset(temp, 0, DISKFS_SECTOR_SIZE); 121 if (write_sector(bus, drive, *sector_out, temp) != ATA_OK) { 122 return DISKFS_ERR_IO; 123 } 124 125 return DISKFS_OK; 126 } 127 128 /* Free a sector back to free list */ 129 static int free_sector(uint8_t bus, uint8_t drive, uint32_t sector) { 130 diskfs_superblock_t sb; 131 132 if (read_sector(bus, drive, DISKFS_SUPERBLOCK_SECTOR, &sb) != ATA_OK) { 133 return DISKFS_ERR_IO; 134 } 135 136 /* Read sector and set its next pointer to current free list head */ 137 uint8_t temp[DISKFS_SECTOR_SIZE]; 138 memset(temp, 0, DISKFS_SECTOR_SIZE); 139 *(uint32_t*)(temp + DISKFS_SECTOR_SIZE - 4) = sb.free_list_head; 140 141 if (write_sector(bus, drive, sector, temp) != ATA_OK) { 142 return DISKFS_ERR_IO; 143 } 144 145 /* Update superblock */ 146 sb.free_list_head = sector; 147 sb.free_sectors++; 148 149 if (write_sector(bus, drive, DISKFS_SUPERBLOCK_SECTOR, &sb) != ATA_OK) { 150 return DISKFS_ERR_IO; 151 } 152 153 return DISKFS_OK; 154 } 155 156 /* Find entry in directory by name */ 157 static int find_entry_in_dir(uint8_t bus, uint8_t drive, uint32_t dir_sector, 158 const char* name, uint32_t* entry_sector, uint32_t* entry_index) { 159 uint32_t current = dir_sector; 160 161 while (current != 0) { 162 if (read_sector(bus, drive, current, sector_buffer) != ATA_OK) { 163 return DISKFS_ERR_IO; 164 } 165 166 diskfs_entry_t* entries = (diskfs_entry_t*)sector_buffer; 167 for (int i = 0; i < DISKFS_ENTRIES_PER_SECTOR; i++) { 168 if (entries[i].type != DISKFS_TYPE_FREE) { 169 if (strcmp(entries[i].name, name) == 0) { 170 *entry_sector = current; 171 *entry_index = i; 172 return DISKFS_OK; 173 } 174 } 175 } 176 177 /* Check for continuation sector (stored at end) */ 178 current = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 179 } 180 181 return DISKFS_ERR_NOT_FOUND; 182 } 183 184 /* Find a free entry slot in directory */ 185 static int find_free_entry(uint8_t bus, uint8_t drive, uint32_t dir_sector, 186 uint32_t* entry_sector, uint32_t* entry_index) { 187 uint32_t current = dir_sector; 188 uint32_t last = dir_sector; 189 190 while (current != 0) { 191 if (read_sector(bus, drive, current, sector_buffer) != ATA_OK) { 192 return DISKFS_ERR_IO; 193 } 194 195 diskfs_entry_t* entries = (diskfs_entry_t*)sector_buffer; 196 for (int i = 0; i < DISKFS_ENTRIES_PER_SECTOR; i++) { 197 if (entries[i].type == DISKFS_TYPE_FREE) { 198 *entry_sector = current; 199 *entry_index = i; 200 return DISKFS_OK; 201 } 202 } 203 204 last = current; 205 current = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 206 } 207 208 /* No free entry found, allocate new directory sector */ 209 uint32_t new_sector; 210 int result = alloc_sector(bus, drive, &new_sector); 211 if (result != DISKFS_OK) { 212 return result; 213 } 214 215 /* Link new sector to last sector */ 216 if (read_sector(bus, drive, last, sector_buffer) != ATA_OK) { 217 return DISKFS_ERR_IO; 218 } 219 *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4) = new_sector; 220 if (write_sector(bus, drive, last, sector_buffer) != ATA_OK) { 221 return DISKFS_ERR_IO; 222 } 223 224 *entry_sector = new_sector; 225 *entry_index = 0; 226 return DISKFS_OK; 227 } 228 229 /* Resolve path to directory entry */ 230 static int resolve_path(uint8_t bus, uint8_t drive, const char* path, 231 uint32_t* entry_sector, uint32_t* entry_index, 232 uint32_t* parent_sector) { 233 if (!path || path[0] == '\0' || (path[0] == '/' && path[1] == '\0')) { 234 /* Root directory - return special values */ 235 *entry_sector = DISKFS_ROOT_DIR_SECTOR; 236 *entry_index = 0xFFFFFFFF; /* Special marker for root */ 237 if (parent_sector) *parent_sector = 0; 238 return DISKFS_OK; 239 } 240 241 /* Skip leading slash */ 242 if (path[0] == '/') path++; 243 244 uint32_t current_dir = DISKFS_ROOT_DIR_SECTOR; 245 char component[DISKFS_NAME_MAX + 1]; 246 247 while (*path) { 248 /* Extract next path component */ 249 const char* slash = strchr(path, '/'); 250 size_t len; 251 if (slash) { 252 len = slash - path; 253 } else { 254 len = strlen(path); 255 } 256 257 if (len > DISKFS_NAME_MAX) { 258 return DISKFS_ERR_NAME_TOO_LONG; 259 } 260 261 memcpy(component, path, len); 262 component[len] = '\0'; 263 264 /* Find entry in current directory */ 265 uint32_t found_sector, found_index; 266 int result = find_entry_in_dir(bus, drive, current_dir, component, &found_sector, &found_index); 267 if (result != DISKFS_OK) { 268 return result; 269 } 270 271 /* Read the entry */ 272 if (read_sector(bus, drive, found_sector, sector_buffer) != ATA_OK) { 273 return DISKFS_ERR_IO; 274 } 275 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[found_index]; 276 277 /* Move to next component or return */ 278 path += len; 279 if (*path == '/') path++; 280 281 if (*path == '\0') { 282 /* This is the final component */ 283 *entry_sector = found_sector; 284 *entry_index = found_index; 285 if (parent_sector) *parent_sector = current_dir; 286 return DISKFS_OK; 287 } 288 289 /* Must be a directory to continue */ 290 if (entry->type != DISKFS_TYPE_DIR) { 291 return DISKFS_ERR_NOT_DIR; 292 } 293 294 current_dir = entry->first_sector; 295 } 296 297 return DISKFS_ERR_NOT_FOUND; 298 } 299 300 /* Get parent directory path */ 301 static void get_parent_path(const char* path, char* parent, const char** basename) { 302 const char* last_slash = strrchr(path, '/'); 303 if (!last_slash || last_slash == path) { 304 strcpy(parent, "/"); 305 *basename = (last_slash == path) ? path + 1 : path; 306 } else { 307 size_t len = last_slash - path; 308 memcpy(parent, path, len); 309 parent[len] = '\0'; 310 *basename = last_slash + 1; 311 } 312 } 313 314 /* ============================================================================ 315 * Public API 316 * ========================================================================= */ 317 318 void diskfs_init(void) { 319 memset(mounts, 0, sizeof(mounts)); 320 321 /* Try to mount any formatted drives */ 322 for (int bus = 0; bus < 2; bus++) { 323 for (int drive = 0; drive < 2; drive++) { 324 ata_drive_info_t* info = ata_get_drive_info(bus, drive); 325 if (info && info->present && info->is_ata) { 326 diskfs_mount(bus, drive); 327 } 328 } 329 } 330 } 331 332 int diskfs_format(uint8_t bus, uint8_t drive, const char* volume_name) { 333 uint32_t total_sectors; 334 335 /* Check if FDE is active - use FDE's virtual sector count */ 336 if (fde_is_active(bus, drive)) { 337 fde_context_t* ctx = get_fde_context(bus, drive); 338 total_sectors = ctx->total_sectors; 339 terminal_writestring("[DISKFS] Format: FDE active, sectors="); 340 char buf[20]; 341 snprintf(buf, sizeof(buf), "%d\n", (int)total_sectors); 342 terminal_writestring(buf); 343 } else { 344 ata_drive_info_t* info = ata_get_drive_info(bus, drive); 345 if (!info || !info->present || !info->is_ata) { 346 return DISKFS_ERR_INVALID; 347 } 348 total_sectors = info->sectors; 349 terminal_writestring("[DISKFS] Format: No FDE, using ATA directly\n"); 350 } 351 352 if (total_sectors < 16) { 353 terminal_writestring("[DISKFS] Format: Too few sectors\n"); 354 return DISKFS_ERR_INVALID; /* Too small */ 355 } 356 357 /* Create superblock */ 358 diskfs_superblock_t sb; 359 memset(&sb, 0, sizeof(sb)); 360 sb.magic = DISKFS_MAGIC; 361 sb.version = DISKFS_VERSION; 362 sb.total_sectors = total_sectors; 363 sb.free_sectors = total_sectors - 2; /* Minus superblock and root dir */ 364 sb.root_dir_sector = DISKFS_ROOT_DIR_SECTOR; 365 sb.free_list_head = 2; /* First free sector after root dir */ 366 367 if (volume_name) { 368 strncpy((char*)sb.volume_name, volume_name, 31); 369 sb.volume_name[31] = '\0'; 370 } 371 372 /* Write superblock */ 373 terminal_writestring("[DISKFS] Writing superblock...\n"); 374 if (write_sector(bus, drive, DISKFS_SUPERBLOCK_SECTOR, &sb) != ATA_OK) { 375 terminal_writestring("[DISKFS] Superblock write failed!\n"); 376 return DISKFS_ERR_IO; 377 } 378 379 /* Initialize root directory (empty) */ 380 terminal_writestring("[DISKFS] Writing root directory...\n"); 381 memset(sector_buffer, 0, DISKFS_SECTOR_SIZE); 382 if (write_sector(bus, drive, DISKFS_ROOT_DIR_SECTOR, sector_buffer) != ATA_OK) { 383 terminal_writestring("[DISKFS] Root directory write failed!\n"); 384 return DISKFS_ERR_IO; 385 } 386 387 /* Quick format: initialize enough free list sectors for basic usage 388 * Full format would take too long with encryption (246K+ writes). 389 * Initialize first 100 sectors of free list for immediate use. 390 */ 391 terminal_writestring("[DISKFS] Quick format - initializing first 100 free sectors\n"); 392 uint32_t init_sectors = (total_sectors > 102) ? 100 : (total_sectors - 2); 393 for (uint32_t i = 2; i < 2 + init_sectors; i++) { 394 memset(sector_buffer, 0, DISKFS_SECTOR_SIZE); 395 /* Next pointer at end of sector */ 396 uint32_t next = (i + 1 < total_sectors) ? (i + 1) : 0; 397 /* For sectors beyond our init range, point to 0 (end of list) */ 398 if (i + 1 >= 2 + init_sectors) { 399 next = 0; 400 } 401 *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4) = next; 402 if (write_sector(bus, drive, i, sector_buffer) != ATA_OK) { 403 char dbg[60]; 404 snprintf(dbg, sizeof(dbg), "[DISKFS] Free list init failed at sector %d\n", (int)i); 405 terminal_writestring(dbg); 406 return DISKFS_ERR_IO; 407 } 408 } 409 terminal_writestring("[DISKFS] Free list initialized\n"); 410 411 /* Update superblock with correct free count */ 412 sb.free_sectors = init_sectors; 413 sb.free_list_head = 2; 414 if (write_sector(bus, drive, DISKFS_SUPERBLOCK_SECTOR, &sb) != ATA_OK) { 415 terminal_writestring("[DISKFS] Failed to update superblock\n"); 416 return DISKFS_ERR_IO; 417 } 418 419 /* Flush cache */ 420 ata_flush(bus, drive); 421 422 /* Mount the newly formatted drive */ 423 return diskfs_mount(bus, drive); 424 } 425 426 int diskfs_mount(uint8_t bus, uint8_t drive) { 427 int idx = get_mount_index(bus, drive); 428 if (idx >= DISKFS_MAX_MOUNTS) { 429 return DISKFS_ERR_INVALID; 430 } 431 432 /* Check drive exists - either via FDE or ATA directly */ 433 if (!fde_is_active(bus, drive)) { 434 ata_drive_info_t* info = ata_get_drive_info(bus, drive); 435 if (!info || !info->present || !info->is_ata) { 436 return DISKFS_ERR_INVALID; 437 } 438 } 439 440 /* Read superblock (routes through FDE if active) */ 441 diskfs_superblock_t sb; 442 if (read_sector(bus, drive, DISKFS_SUPERBLOCK_SECTOR, &sb) != ATA_OK) { 443 return DISKFS_ERR_IO; 444 } 445 446 /* Check magic */ 447 if (sb.magic != DISKFS_MAGIC) { 448 mounts[idx].mounted = 0; 449 mounts[idx].formatted = 0; 450 return DISKFS_ERR_NOT_FORMATTED; 451 } 452 453 /* Populate mount info */ 454 mounts[idx].bus = bus; 455 mounts[idx].drive = drive; 456 mounts[idx].mounted = 1; 457 mounts[idx].formatted = 1; 458 mounts[idx].total_sectors = sb.total_sectors; 459 mounts[idx].free_sectors = sb.free_sectors; 460 strncpy(mounts[idx].volume_name, (char*)sb.volume_name, 31); 461 mounts[idx].volume_name[31] = '\0'; 462 463 return DISKFS_OK; 464 } 465 466 int diskfs_is_diskfs_path(const char* path, uint8_t* bus, uint8_t* drive, const char** subpath) { 467 if (!path || strncmp(path, "/mnt/hd", 7) != 0) { 468 return 0; 469 } 470 471 /* Parse /mnt/hdX or /mnt/hdXY */ 472 const char* p = path + 7; 473 if (*p < '0' || *p > '3') { 474 return 0; 475 } 476 477 int drive_num = *p - '0'; 478 *bus = drive_num / 2; 479 *drive = drive_num % 2; 480 481 p++; 482 if (*p == '\0') { 483 *subpath = "/"; 484 } else if (*p == '/') { 485 *subpath = p; 486 } else { 487 return 0; 488 } 489 490 return 1; 491 } 492 493 int diskfs_exists(uint8_t bus, uint8_t drive, const char* path) { 494 uint32_t entry_sector, entry_index; 495 return resolve_path(bus, drive, path, &entry_sector, &entry_index, NULL) == DISKFS_OK; 496 } 497 498 int diskfs_is_dir(uint8_t bus, uint8_t drive, const char* path) { 499 uint32_t entry_sector, entry_index; 500 if (resolve_path(bus, drive, path, &entry_sector, &entry_index, NULL) != DISKFS_OK) { 501 return 0; 502 } 503 504 /* Root is always a directory */ 505 if (entry_index == 0xFFFFFFFF) { 506 return 1; 507 } 508 509 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 510 return 0; 511 } 512 513 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 514 return entry->type == DISKFS_TYPE_DIR; 515 } 516 517 int diskfs_is_file(uint8_t bus, uint8_t drive, const char* path) { 518 uint32_t entry_sector, entry_index; 519 if (resolve_path(bus, drive, path, &entry_sector, &entry_index, NULL) != DISKFS_OK) { 520 return 0; 521 } 522 523 /* Root is not a file */ 524 if (entry_index == 0xFFFFFFFF) { 525 return 0; 526 } 527 528 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 529 return 0; 530 } 531 532 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 533 return entry->type == DISKFS_TYPE_FILE; 534 } 535 536 int diskfs_mkdir(uint8_t bus, uint8_t drive, const char* path) { 537 /* Check if already exists */ 538 if (diskfs_exists(bus, drive, path)) { 539 return DISKFS_ERR_EXISTS; 540 } 541 542 /* Get parent directory */ 543 char parent_path[256]; 544 const char* name; 545 get_parent_path(path, parent_path, &name); 546 547 if (strlen(name) > DISKFS_NAME_MAX) { 548 return DISKFS_ERR_NAME_TOO_LONG; 549 } 550 551 /* Find parent directory */ 552 uint32_t parent_entry_sector, parent_entry_index; 553 int result = resolve_path(bus, drive, parent_path, &parent_entry_sector, &parent_entry_index, NULL); 554 if (result != DISKFS_OK) { 555 return result; 556 } 557 558 /* Get parent's content sector */ 559 uint32_t parent_content; 560 if (parent_entry_index == 0xFFFFFFFF) { 561 parent_content = DISKFS_ROOT_DIR_SECTOR; 562 } else { 563 if (read_sector(bus, drive, parent_entry_sector, sector_buffer) != ATA_OK) { 564 return DISKFS_ERR_IO; 565 } 566 diskfs_entry_t* parent = &((diskfs_entry_t*)sector_buffer)[parent_entry_index]; 567 if (parent->type != DISKFS_TYPE_DIR) { 568 return DISKFS_ERR_NOT_DIR; 569 } 570 parent_content = parent->first_sector; 571 } 572 573 /* Allocate sector for new directory content */ 574 uint32_t dir_sector; 575 result = alloc_sector(bus, drive, &dir_sector); 576 if (result != DISKFS_OK) { 577 return result; 578 } 579 580 /* Find free entry in parent */ 581 uint32_t entry_sector, entry_index; 582 result = find_free_entry(bus, drive, parent_content, &entry_sector, &entry_index); 583 if (result != DISKFS_OK) { 584 free_sector(bus, drive, dir_sector); 585 return result; 586 } 587 588 /* Create the directory entry */ 589 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 590 free_sector(bus, drive, dir_sector); 591 return DISKFS_ERR_IO; 592 } 593 594 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 595 memset(entry, 0, sizeof(*entry)); 596 strncpy(entry->name, name, DISKFS_NAME_MAX); 597 entry->type = DISKFS_TYPE_DIR; 598 entry->size = 0; 599 entry->first_sector = dir_sector; 600 entry->parent_sector = parent_content; 601 602 if (write_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 603 free_sector(bus, drive, dir_sector); 604 return DISKFS_ERR_IO; 605 } 606 607 return DISKFS_OK; 608 } 609 610 diskfs_handle_t* diskfs_open(uint8_t bus, uint8_t drive, const char* path, const char* mode) { 611 { 612 char dbg[120]; 613 snprintf(dbg, sizeof(dbg), "[DISKFS] open: path=%s mode=%s\n", path ? path : "(null)", mode ? mode : "(null)"); 614 terminal_writestring(dbg); 615 } 616 617 if (!mode || (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a')) { 618 terminal_writestring("[DISKFS] open: invalid mode\n"); 619 return NULL; 620 } 621 622 diskfs_handle_t* handle = malloc(sizeof(diskfs_handle_t)); 623 if (!handle) { 624 terminal_writestring("[DISKFS] open: malloc failed\n"); 625 return NULL; 626 } 627 628 memset(handle, 0, sizeof(*handle)); 629 handle->bus = bus; 630 handle->drive = drive; 631 handle->mode = mode[0]; 632 633 uint32_t entry_sector, entry_index, parent_sector; 634 int result = resolve_path(bus, drive, path, &entry_sector, &entry_index, &parent_sector); 635 636 if (mode[0] == 'r') { 637 /* Read mode - file must exist */ 638 if (result != DISKFS_OK || entry_index == 0xFFFFFFFF) { 639 free(handle); 640 return NULL; 641 } 642 643 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 644 free(handle); 645 return NULL; 646 } 647 648 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 649 if (entry->type != DISKFS_TYPE_FILE) { 650 free(handle); 651 return NULL; 652 } 653 654 handle->entry_sector = entry_sector; 655 handle->entry_index = entry_index; 656 handle->size = entry->size; 657 handle->first_sector = entry->first_sector; 658 handle->current_sector = entry->first_sector; 659 handle->position = 0; 660 handle->sector_offset = 0; 661 handle->is_open = 1; 662 663 } else { 664 /* Write or append mode */ 665 if (result == DISKFS_OK && entry_index != 0xFFFFFFFF) { 666 /* File exists */ 667 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 668 free(handle); 669 return NULL; 670 } 671 672 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 673 if (entry->type != DISKFS_TYPE_FILE) { 674 free(handle); 675 return NULL; 676 } 677 678 handle->entry_sector = entry_sector; 679 handle->entry_index = entry_index; 680 handle->size = entry->size; 681 handle->first_sector = entry->first_sector; 682 683 if (mode[0] == 'w') { 684 /* Truncate - free all data sectors */ 685 uint32_t sector = entry->first_sector; 686 while (sector != 0) { 687 if (read_sector(bus, drive, sector, sector_buffer) != ATA_OK) break; 688 uint32_t next = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 689 free_sector(bus, drive, sector); 690 sector = next; 691 } 692 693 /* Update entry */ 694 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 695 free(handle); 696 return NULL; 697 } 698 entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 699 entry->size = 0; 700 entry->first_sector = 0; 701 if (write_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 702 free(handle); 703 return NULL; 704 } 705 706 handle->size = 0; 707 handle->first_sector = 0; 708 handle->current_sector = 0; 709 handle->position = 0; 710 } else { 711 /* Append - seek to end */ 712 handle->position = handle->size; 713 /* Find last sector */ 714 uint32_t sector = handle->first_sector; 715 uint32_t prev = 0; 716 while (sector != 0) { 717 if (read_sector(bus, drive, sector, sector_buffer) != ATA_OK) break; 718 prev = sector; 719 sector = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 720 } 721 handle->current_sector = prev; 722 handle->sector_offset = handle->size % DISKFS_DATA_PER_SECTOR; 723 } 724 handle->is_open = 1; 725 726 } else { 727 /* Create new file */ 728 char parent_path[256]; 729 const char* name; 730 get_parent_path(path, parent_path, &name); 731 732 if (strlen(name) > DISKFS_NAME_MAX) { 733 free(handle); 734 return NULL; 735 } 736 737 /* Find parent */ 738 result = resolve_path(bus, drive, parent_path, &entry_sector, &entry_index, NULL); 739 if (result != DISKFS_OK) { 740 free(handle); 741 return NULL; 742 } 743 744 uint32_t parent_content; 745 if (entry_index == 0xFFFFFFFF) { 746 parent_content = DISKFS_ROOT_DIR_SECTOR; 747 } else { 748 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 749 free(handle); 750 return NULL; 751 } 752 diskfs_entry_t* parent = &((diskfs_entry_t*)sector_buffer)[entry_index]; 753 if (parent->type != DISKFS_TYPE_DIR) { 754 free(handle); 755 return NULL; 756 } 757 parent_content = parent->first_sector; 758 } 759 760 /* Find free entry */ 761 uint32_t new_entry_sector, new_entry_index; 762 result = find_free_entry(bus, drive, parent_content, &new_entry_sector, &new_entry_index); 763 if (result != DISKFS_OK) { 764 free(handle); 765 return NULL; 766 } 767 768 /* Create entry */ 769 if (read_sector(bus, drive, new_entry_sector, sector_buffer) != ATA_OK) { 770 free(handle); 771 return NULL; 772 } 773 774 diskfs_entry_t* new_entry = &((diskfs_entry_t*)sector_buffer)[new_entry_index]; 775 memset(new_entry, 0, sizeof(*new_entry)); 776 strncpy(new_entry->name, name, DISKFS_NAME_MAX); 777 new_entry->type = DISKFS_TYPE_FILE; 778 new_entry->size = 0; 779 new_entry->first_sector = 0; 780 new_entry->parent_sector = parent_content; 781 782 if (write_sector(bus, drive, new_entry_sector, sector_buffer) != ATA_OK) { 783 free(handle); 784 return NULL; 785 } 786 787 handle->entry_sector = new_entry_sector; 788 handle->entry_index = new_entry_index; 789 handle->size = 0; 790 handle->first_sector = 0; 791 handle->current_sector = 0; 792 handle->position = 0; 793 handle->sector_offset = 0; 794 handle->is_open = 1; 795 } 796 } 797 798 return handle; 799 } 800 801 int diskfs_read(diskfs_handle_t* handle, void* buffer, uint32_t size, uint32_t* bytes_read) { 802 if (!handle || !handle->is_open || handle->mode != 'r') { 803 return DISKFS_ERR_INVALID; 804 } 805 806 *bytes_read = 0; 807 uint8_t* out = (uint8_t*)buffer; 808 809 while (size > 0 && handle->position < handle->size) { 810 if (handle->current_sector == 0) { 811 break; 812 } 813 814 /* Read current sector */ 815 if (read_sector(handle->bus, handle->drive, handle->current_sector, sector_buffer) != ATA_OK) { 816 return DISKFS_ERR_IO; 817 } 818 819 /* How much can we read from this sector? */ 820 uint32_t available = DISKFS_DATA_PER_SECTOR - handle->sector_offset; 821 uint32_t remaining_in_file = handle->size - handle->position; 822 uint32_t to_read = size; 823 if (to_read > available) to_read = available; 824 if (to_read > remaining_in_file) to_read = remaining_in_file; 825 826 memcpy(out, sector_buffer + handle->sector_offset, to_read); 827 828 out += to_read; 829 *bytes_read += to_read; 830 handle->position += to_read; 831 handle->sector_offset += to_read; 832 size -= to_read; 833 834 /* Move to next sector if needed */ 835 if (handle->sector_offset >= DISKFS_DATA_PER_SECTOR) { 836 handle->current_sector = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 837 handle->sector_offset = 0; 838 } 839 } 840 841 return DISKFS_OK; 842 } 843 844 int diskfs_write(diskfs_handle_t* handle, const void* data, uint32_t size) { 845 { 846 char dbg[80]; 847 snprintf(dbg, sizeof(dbg), "[DISKFS] write: size=%d\n", (int)size); 848 terminal_writestring(dbg); 849 } 850 851 if (!handle || !handle->is_open || handle->mode == 'r') { 852 terminal_writestring("[DISKFS] write: invalid handle/mode\n"); 853 return DISKFS_ERR_INVALID; 854 } 855 856 const uint8_t* in = (const uint8_t*)data; 857 858 while (size > 0) { 859 /* Allocate sector if needed */ 860 if (handle->current_sector == 0) { 861 uint32_t new_sector; 862 int result = alloc_sector(handle->bus, handle->drive, &new_sector); 863 if (result != DISKFS_OK) { 864 return result; 865 } 866 867 if (handle->first_sector == 0) { 868 handle->first_sector = new_sector; 869 870 /* Update entry */ 871 if (read_sector(handle->bus, handle->drive, handle->entry_sector, sector_buffer) != ATA_OK) { 872 return DISKFS_ERR_IO; 873 } 874 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[handle->entry_index]; 875 entry->first_sector = new_sector; 876 if (write_sector(handle->bus, handle->drive, handle->entry_sector, sector_buffer) != ATA_OK) { 877 return DISKFS_ERR_IO; 878 } 879 } 880 881 handle->current_sector = new_sector; 882 handle->sector_offset = 0; 883 } 884 885 /* Read current sector */ 886 if (read_sector(handle->bus, handle->drive, handle->current_sector, sector_buffer) != ATA_OK) { 887 return DISKFS_ERR_IO; 888 } 889 890 /* How much can we write to this sector? */ 891 uint32_t available = DISKFS_DATA_PER_SECTOR - handle->sector_offset; 892 uint32_t to_write = (size < available) ? size : available; 893 894 memcpy(sector_buffer + handle->sector_offset, in, to_write); 895 896 /* Check if we need to link to a new sector */ 897 if (handle->sector_offset + to_write >= DISKFS_DATA_PER_SECTOR) { 898 uint32_t next = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 899 if (next == 0 && size > to_write) { 900 /* Need to allocate next sector */ 901 int result = alloc_sector(handle->bus, handle->drive, &next); 902 if (result != DISKFS_OK) { 903 return result; 904 } 905 *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4) = next; 906 } 907 } 908 909 if (write_sector(handle->bus, handle->drive, handle->current_sector, sector_buffer) != ATA_OK) { 910 return DISKFS_ERR_IO; 911 } 912 913 in += to_write; 914 handle->position += to_write; 915 handle->sector_offset += to_write; 916 size -= to_write; 917 918 if (handle->position > handle->size) { 919 handle->size = handle->position; 920 } 921 922 /* Move to next sector if needed */ 923 if (handle->sector_offset >= DISKFS_DATA_PER_SECTOR) { 924 handle->current_sector = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 925 handle->sector_offset = 0; 926 } 927 } 928 929 /* Update file size in directory entry */ 930 if (read_sector(handle->bus, handle->drive, handle->entry_sector, sector_buffer) != ATA_OK) { 931 return DISKFS_ERR_IO; 932 } 933 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[handle->entry_index]; 934 entry->size = handle->size; 935 if (write_sector(handle->bus, handle->drive, handle->entry_sector, sector_buffer) != ATA_OK) { 936 return DISKFS_ERR_IO; 937 } 938 939 return DISKFS_OK; 940 } 941 942 void diskfs_close(diskfs_handle_t* handle) { 943 if (handle) { 944 if (handle->is_open && handle->mode != 'r') { 945 ata_flush(handle->bus, handle->drive); 946 } 947 free(handle); 948 } 949 } 950 951 int diskfs_remove(uint8_t bus, uint8_t drive, const char* path) { 952 uint32_t entry_sector, entry_index, parent_sector; 953 int result = resolve_path(bus, drive, path, &entry_sector, &entry_index, &parent_sector); 954 if (result != DISKFS_OK) { 955 return result; 956 } 957 958 if (entry_index == 0xFFFFFFFF) { 959 return DISKFS_ERR_INVALID; /* Can't remove root */ 960 } 961 962 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 963 return DISKFS_ERR_IO; 964 } 965 966 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 967 968 if (entry->type == DISKFS_TYPE_DIR) { 969 /* Check if directory is empty */ 970 uint32_t dir_sector = entry->first_sector; 971 if (dir_sector != 0) { 972 uint8_t temp[DISKFS_SECTOR_SIZE]; 973 if (read_sector(bus, drive, dir_sector, temp) != ATA_OK) { 974 return DISKFS_ERR_IO; 975 } 976 diskfs_entry_t* entries = (diskfs_entry_t*)temp; 977 for (int i = 0; i < DISKFS_ENTRIES_PER_SECTOR; i++) { 978 if (entries[i].type != DISKFS_TYPE_FREE) { 979 return DISKFS_ERR_NOT_EMPTY; 980 } 981 } 982 /* Free directory sector */ 983 free_sector(bus, drive, dir_sector); 984 } 985 } else if (entry->type == DISKFS_TYPE_FILE) { 986 /* Free all data sectors */ 987 uint32_t sector = entry->first_sector; 988 while (sector != 0) { 989 uint8_t temp[DISKFS_SECTOR_SIZE]; 990 if (read_sector(bus, drive, sector, temp) != ATA_OK) break; 991 uint32_t next = *(uint32_t*)(temp + DISKFS_SECTOR_SIZE - 4); 992 free_sector(bus, drive, sector); 993 sector = next; 994 } 995 } 996 997 /* Clear the entry */ 998 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 999 return DISKFS_ERR_IO; 1000 } 1001 entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 1002 memset(entry, 0, sizeof(*entry)); 1003 if (write_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 1004 return DISKFS_ERR_IO; 1005 } 1006 1007 return DISKFS_OK; 1008 } 1009 1010 int diskfs_list(uint8_t bus, uint8_t drive, const char* path, 1011 char*** names, uint32_t** types, uint32_t* count) { 1012 { 1013 char dbg[100]; 1014 snprintf(dbg, sizeof(dbg), "[DISKFS] list: bus=%d drive=%d path=%s\n", bus, drive, path ? path : "(null)"); 1015 terminal_writestring(dbg); 1016 } 1017 1018 uint32_t entry_sector, entry_index; 1019 int result = resolve_path(bus, drive, path, &entry_sector, &entry_index, NULL); 1020 if (result != DISKFS_OK) { 1021 char dbg[60]; 1022 snprintf(dbg, sizeof(dbg), "[DISKFS] list: resolve_path failed=%d\n", result); 1023 terminal_writestring(dbg); 1024 return result; 1025 } 1026 1027 uint32_t dir_sector; 1028 if (entry_index == 0xFFFFFFFF) { 1029 dir_sector = DISKFS_ROOT_DIR_SECTOR; 1030 terminal_writestring("[DISKFS] list: using root dir sector\n"); 1031 } else { 1032 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 1033 return DISKFS_ERR_IO; 1034 } 1035 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 1036 if (entry->type != DISKFS_TYPE_DIR) { 1037 return DISKFS_ERR_NOT_DIR; 1038 } 1039 dir_sector = entry->first_sector; 1040 } 1041 1042 { 1043 char dbg[60]; 1044 snprintf(dbg, sizeof(dbg), "[DISKFS] list: dir_sector=%d\n", (int)dir_sector); 1045 terminal_writestring(dbg); 1046 } 1047 1048 /* Count entries first */ 1049 uint32_t total = 0; 1050 uint32_t current = dir_sector; 1051 while (current != 0) { 1052 if (read_sector(bus, drive, current, sector_buffer) != ATA_OK) { 1053 terminal_writestring("[DISKFS] list: read_sector failed during count\n"); 1054 return DISKFS_ERR_IO; 1055 } 1056 diskfs_entry_t* entries = (diskfs_entry_t*)sector_buffer; 1057 for (int i = 0; i < DISKFS_ENTRIES_PER_SECTOR; i++) { 1058 if (entries[i].type != DISKFS_TYPE_FREE) { 1059 total++; 1060 } 1061 } 1062 current = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 1063 } 1064 1065 { 1066 char dbg[60]; 1067 snprintf(dbg, sizeof(dbg), "[DISKFS] list: total entries=%d\n", (int)total); 1068 terminal_writestring(dbg); 1069 } 1070 1071 *count = total; 1072 if (total == 0) { 1073 *names = NULL; 1074 *types = NULL; 1075 return DISKFS_OK; 1076 } 1077 1078 *names = malloc(total * sizeof(char*)); 1079 *types = malloc(total * sizeof(uint32_t)); 1080 if (!*names || !*types) { 1081 free(*names); 1082 free(*types); 1083 return DISKFS_ERR_IO; 1084 } 1085 1086 /* Collect entries */ 1087 uint32_t idx = 0; 1088 current = dir_sector; 1089 while (current != 0 && idx < total) { 1090 if (read_sector(bus, drive, current, sector_buffer) != ATA_OK) { 1091 break; 1092 } 1093 diskfs_entry_t* entries = (diskfs_entry_t*)sector_buffer; 1094 for (int i = 0; i < DISKFS_ENTRIES_PER_SECTOR && idx < total; i++) { 1095 if (entries[i].type != DISKFS_TYPE_FREE) { 1096 (*names)[idx] = diskfs_strdup(entries[i].name); 1097 (*types)[idx] = entries[i].type; 1098 idx++; 1099 } 1100 } 1101 current = *(uint32_t*)(sector_buffer + DISKFS_SECTOR_SIZE - 4); 1102 } 1103 1104 return DISKFS_OK; 1105 } 1106 1107 void diskfs_free_list(char** names, uint32_t* types, uint32_t count) { 1108 if (names) { 1109 for (uint32_t i = 0; i < count; i++) { 1110 free(names[i]); 1111 } 1112 free(names); 1113 } 1114 free(types); 1115 } 1116 1117 int diskfs_get_size(uint8_t bus, uint8_t drive, const char* path, uint32_t* size) { 1118 uint32_t entry_sector, entry_index; 1119 int result = resolve_path(bus, drive, path, &entry_sector, &entry_index, NULL); 1120 if (result != DISKFS_OK) { 1121 return result; 1122 } 1123 1124 if (entry_index == 0xFFFFFFFF) { 1125 *size = 0; /* Root directory */ 1126 return DISKFS_OK; 1127 } 1128 1129 if (read_sector(bus, drive, entry_sector, sector_buffer) != ATA_OK) { 1130 return DISKFS_ERR_IO; 1131 } 1132 1133 diskfs_entry_t* entry = &((diskfs_entry_t*)sector_buffer)[entry_index]; 1134 *size = entry->size; 1135 return DISKFS_OK; 1136 } 1137 1138 diskfs_mount_t* diskfs_get_mount(uint8_t bus, uint8_t drive) { 1139 int idx = get_mount_index(bus, drive); 1140 if (idx >= DISKFS_MAX_MOUNTS) return NULL; 1141 return &mounts[idx]; 1142 } 1143 1144 const char* diskfs_error_string(int error) { 1145 switch (error) { 1146 case DISKFS_OK: return "Success"; 1147 case DISKFS_ERR_NOT_FORMATTED: return "Disk not formatted"; 1148 case DISKFS_ERR_IO: return "I/O error"; 1149 case DISKFS_ERR_NOT_FOUND: return "Not found"; 1150 case DISKFS_ERR_EXISTS: return "Already exists"; 1151 case DISKFS_ERR_FULL: return "Disk full"; 1152 case DISKFS_ERR_NOT_DIR: return "Not a directory"; 1153 case DISKFS_ERR_NOT_FILE: return "Not a file"; 1154 case DISKFS_ERR_INVALID: return "Invalid parameter"; 1155 case DISKFS_ERR_NOT_EMPTY: return "Directory not empty"; 1156 case DISKFS_ERR_NAME_TOO_LONG: return "Name too long"; 1157 default: return "Unknown error"; 1158 } 1159 } 1160 1161 /* ============================================================================ 1162 * Lua Bindings 1163 * ========================================================================= */ 1164 1165 /* diskfs.format(bus, drive, volume_name) */ 1166 static int lua_diskfs_format(lua_State* L) { 1167 int bus = luaL_checkinteger(L, 1); 1168 int drive = luaL_checkinteger(L, 2); 1169 const char* name = luaL_optstring(L, 3, "DISK"); 1170 1171 int result = diskfs_format(bus, drive, name); 1172 if (result != DISKFS_OK) { 1173 lua_pushnil(L); 1174 lua_pushstring(L, diskfs_error_string(result)); 1175 return 2; 1176 } 1177 1178 lua_pushboolean(L, 1); 1179 return 1; 1180 } 1181 1182 /* diskfs.exists(path) - path like "/mnt/hd0/dir/file.txt" */ 1183 static int lua_diskfs_exists(lua_State* L) { 1184 const char* path = luaL_checkstring(L, 1); 1185 1186 uint8_t bus, drive; 1187 const char* subpath; 1188 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1189 lua_pushboolean(L, 0); 1190 return 1; 1191 } 1192 1193 lua_pushboolean(L, diskfs_exists(bus, drive, subpath)); 1194 return 1; 1195 } 1196 1197 /* diskfs.isdir(path) */ 1198 static int lua_diskfs_isdir(lua_State* L) { 1199 const char* path = luaL_checkstring(L, 1); 1200 1201 uint8_t bus, drive; 1202 const char* subpath; 1203 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1204 lua_pushboolean(L, 0); 1205 return 1; 1206 } 1207 1208 lua_pushboolean(L, diskfs_is_dir(bus, drive, subpath)); 1209 return 1; 1210 } 1211 1212 /* diskfs.isfile(path) */ 1213 static int lua_diskfs_isfile(lua_State* L) { 1214 const char* path = luaL_checkstring(L, 1); 1215 1216 uint8_t bus, drive; 1217 const char* subpath; 1218 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1219 lua_pushboolean(L, 0); 1220 return 1; 1221 } 1222 1223 lua_pushboolean(L, diskfs_is_file(bus, drive, subpath)); 1224 return 1; 1225 } 1226 1227 /* diskfs.mkdir(path) */ 1228 static int lua_diskfs_mkdir(lua_State* L) { 1229 const char* path = luaL_checkstring(L, 1); 1230 1231 uint8_t bus, drive; 1232 const char* subpath; 1233 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1234 lua_pushnil(L); 1235 lua_pushstring(L, "Invalid path"); 1236 return 2; 1237 } 1238 1239 int result = diskfs_mkdir(bus, drive, subpath); 1240 if (result != DISKFS_OK) { 1241 lua_pushnil(L); 1242 lua_pushstring(L, diskfs_error_string(result)); 1243 return 2; 1244 } 1245 1246 lua_pushboolean(L, 1); 1247 return 1; 1248 } 1249 1250 /* diskfs.open(path, mode) -> handle */ 1251 static int lua_diskfs_open(lua_State* L) { 1252 const char* path = luaL_checkstring(L, 1); 1253 const char* mode = luaL_optstring(L, 2, "r"); 1254 1255 uint8_t bus, drive; 1256 const char* subpath; 1257 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1258 lua_pushnil(L); 1259 lua_pushstring(L, "Invalid path"); 1260 return 2; 1261 } 1262 1263 diskfs_handle_t* handle = diskfs_open(bus, drive, subpath, mode); 1264 if (!handle) { 1265 lua_pushnil(L); 1266 lua_pushstring(L, "Failed to open file"); 1267 return 2; 1268 } 1269 1270 lua_pushlightuserdata(L, handle); 1271 return 1; 1272 } 1273 1274 /* diskfs.read(handle) -> data */ 1275 static int lua_diskfs_read(lua_State* L) { 1276 diskfs_handle_t* handle = lua_touserdata(L, 1); 1277 if (!handle || !handle->is_open) { 1278 lua_pushnil(L); 1279 return 1; 1280 } 1281 1282 /* Read entire file */ 1283 uint32_t size = handle->size; 1284 if (size == 0) { 1285 lua_pushstring(L, ""); 1286 return 1; 1287 } 1288 1289 char* buffer = malloc(size); 1290 if (!buffer) { 1291 lua_pushnil(L); 1292 return 1; 1293 } 1294 1295 uint32_t bytes_read; 1296 int result = diskfs_read(handle, buffer, size, &bytes_read); 1297 if (result != DISKFS_OK) { 1298 free(buffer); 1299 lua_pushnil(L); 1300 return 1; 1301 } 1302 1303 lua_pushlstring(L, buffer, bytes_read); 1304 free(buffer); 1305 return 1; 1306 } 1307 1308 /* diskfs.write(handle, data) */ 1309 static int lua_diskfs_write(lua_State* L) { 1310 diskfs_handle_t* handle = lua_touserdata(L, 1); 1311 size_t len; 1312 const char* data = luaL_checklstring(L, 2, &len); 1313 1314 if (!handle || !handle->is_open) { 1315 lua_pushnil(L); 1316 lua_pushstring(L, "Invalid handle"); 1317 return 2; 1318 } 1319 1320 int result = diskfs_write(handle, data, len); 1321 if (result != DISKFS_OK) { 1322 lua_pushnil(L); 1323 lua_pushstring(L, diskfs_error_string(result)); 1324 return 2; 1325 } 1326 1327 lua_pushboolean(L, 1); 1328 return 1; 1329 } 1330 1331 /* diskfs.close(handle) */ 1332 static int lua_diskfs_close(lua_State* L) { 1333 diskfs_handle_t* handle = lua_touserdata(L, 1); 1334 diskfs_close(handle); 1335 return 0; 1336 } 1337 1338 /* diskfs.remove(path) */ 1339 static int lua_diskfs_remove(lua_State* L) { 1340 const char* path = luaL_checkstring(L, 1); 1341 1342 uint8_t bus, drive; 1343 const char* subpath; 1344 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1345 lua_pushnil(L); 1346 lua_pushstring(L, "Invalid path"); 1347 return 2; 1348 } 1349 1350 int result = diskfs_remove(bus, drive, subpath); 1351 if (result != DISKFS_OK) { 1352 lua_pushnil(L); 1353 lua_pushstring(L, diskfs_error_string(result)); 1354 return 2; 1355 } 1356 1357 lua_pushboolean(L, 1); 1358 return 1; 1359 } 1360 1361 /* diskfs.list(path) -> {items} */ 1362 static int lua_diskfs_list(lua_State* L) { 1363 const char* path = luaL_checkstring(L, 1); 1364 1365 uint8_t bus, drive; 1366 const char* subpath; 1367 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1368 lua_pushnil(L); 1369 lua_pushstring(L, "Invalid path"); 1370 return 2; 1371 } 1372 1373 char** names; 1374 uint32_t* types; 1375 uint32_t count; 1376 1377 int result = diskfs_list(bus, drive, subpath, &names, &types, &count); 1378 if (result != DISKFS_OK) { 1379 lua_pushnil(L); 1380 lua_pushstring(L, diskfs_error_string(result)); 1381 return 2; 1382 } 1383 1384 lua_newtable(L); 1385 for (uint32_t i = 0; i < count; i++) { 1386 lua_newtable(L); 1387 lua_pushstring(L, names[i]); 1388 lua_setfield(L, -2, "name"); 1389 lua_pushstring(L, types[i] == DISKFS_TYPE_DIR ? "dir" : "file"); 1390 lua_setfield(L, -2, "type"); 1391 lua_rawseti(L, -2, i + 1); 1392 } 1393 1394 diskfs_free_list(names, types, count); 1395 return 1; 1396 } 1397 1398 /* diskfs.getinfo(path) -> {size, type} */ 1399 static int lua_diskfs_getinfo(lua_State* L) { 1400 const char* path = luaL_checkstring(L, 1); 1401 1402 uint8_t bus, drive; 1403 const char* subpath; 1404 if (!diskfs_is_diskfs_path(path, &bus, &drive, &subpath)) { 1405 lua_pushnil(L); 1406 return 1; 1407 } 1408 1409 if (!diskfs_exists(bus, drive, subpath)) { 1410 lua_pushnil(L); 1411 return 1; 1412 } 1413 1414 lua_newtable(L); 1415 1416 if (diskfs_is_dir(bus, drive, subpath)) { 1417 lua_pushstring(L, "dir"); 1418 } else { 1419 lua_pushstring(L, "file"); 1420 } 1421 lua_setfield(L, -2, "type"); 1422 1423 uint32_t size; 1424 if (diskfs_get_size(bus, drive, subpath, &size) == DISKFS_OK) { 1425 lua_pushinteger(L, size); 1426 lua_setfield(L, -2, "size"); 1427 } 1428 1429 return 1; 1430 } 1431 1432 /* diskfs.getMounts() -> {{bus, drive, mounted, formatted, volume_name}, ...} */ 1433 static int lua_diskfs_getmounts(lua_State* L) { 1434 lua_newtable(L); 1435 int idx = 1; 1436 1437 for (int bus = 0; bus < 2; bus++) { 1438 for (int drive = 0; drive < 2; drive++) { 1439 ata_drive_info_t* info = ata_get_drive_info(bus, drive); 1440 if (info && info->present && info->is_ata) { 1441 diskfs_mount_t* mount = diskfs_get_mount(bus, drive); 1442 1443 lua_newtable(L); 1444 lua_pushinteger(L, bus); 1445 lua_setfield(L, -2, "bus"); 1446 lua_pushinteger(L, drive); 1447 lua_setfield(L, -2, "drive"); 1448 lua_pushstring(L, info->model); 1449 lua_setfield(L, -2, "model"); 1450 lua_pushinteger(L, info->sectors); 1451 lua_setfield(L, -2, "sectors"); 1452 lua_pushboolean(L, mount && mount->formatted); 1453 lua_setfield(L, -2, "formatted"); 1454 if (mount && mount->formatted) { 1455 lua_pushstring(L, mount->volume_name); 1456 lua_setfield(L, -2, "volume_name"); 1457 lua_pushinteger(L, mount->free_sectors); 1458 lua_setfield(L, -2, "free_sectors"); 1459 } 1460 1461 /* Add FDE encryption info */ 1462 lua_pushboolean(L, fde_is_active(bus, drive)); 1463 lua_setfield(L, -2, "encrypted"); 1464 if (fde_is_active(bus, drive)) { 1465 fde_context_t* ctx = get_fde_context(bus, drive); 1466 lua_pushstring(L, fde_cipher_name(ctx->cipher_mode)); 1467 lua_setfield(L, -2, "cipher"); 1468 lua_pushinteger(L, ctx->total_sectors); 1469 lua_setfield(L, -2, "encrypted_sectors"); 1470 } 1471 1472 lua_rawseti(L, -2, idx++); 1473 } 1474 } 1475 } 1476 1477 return 1; 1478 } 1479 1480 int luaopen_diskfs(lua_State* L) { 1481 static const luaL_Reg funcs[] = { 1482 {"format", lua_diskfs_format}, 1483 {"exists", lua_diskfs_exists}, 1484 {"isdir", lua_diskfs_isdir}, 1485 {"isfile", lua_diskfs_isfile}, 1486 {"mkdir", lua_diskfs_mkdir}, 1487 {"open", lua_diskfs_open}, 1488 {"read", lua_diskfs_read}, 1489 {"write", lua_diskfs_write}, 1490 {"close", lua_diskfs_close}, 1491 {"remove", lua_diskfs_remove}, 1492 {"list", lua_diskfs_list}, 1493 {"getinfo", lua_diskfs_getinfo}, 1494 {"getMounts", lua_diskfs_getmounts}, 1495 {NULL, NULL} 1496 }; 1497 1498 luaL_newlib(L, funcs); 1499 return 1; 1500 }