From c4740c78fc7a794e7fa05064e2aa4c85ca2828bd Mon Sep 17 00:00:00 2001 From: david-on-debian Date: Tue, 20 May 2025 20:38:50 -0500 Subject: [PATCH] Upload files to "drivers/fs" --- drivers/fs/duckfs.c | 220 +++++++++++++++++++++++ drivers/fs/fat32.c | 428 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 648 insertions(+) create mode 100644 drivers/fs/duckfs.c create mode 100644 drivers/fs/fat32.c diff --git a/drivers/fs/duckfs.c b/drivers/fs/duckfs.c new file mode 100644 index 0000000..b201580 --- /dev/null +++ b/drivers/fs/duckfs.c @@ -0,0 +1,220 @@ +#include + +#include +#include +#include + +#include + + +static uint16_t duckfs_initialized = 0; + +static duckfs_file_header_t duckfs_root; + +const char* duckfs_versions[18] = { DFS_VERSION_0, DFS_VERSION_1, DFS_VERSION_2, DFS_VERSION_3, DFS_VERSION_4 }; + +int32_t duckfs_init(int16_t drive) +{ + char duckfs_header_block[512]; + if (ide_read48(drive, 0xA, 1, duckfs_header_block) != 0) + { + printf("[ DEBUG ] Disk read error on drive #%i\n", drive); + return -1; + } + + duckfs_superblock_t* superblock = (duckfs_superblock_t*)duckfs_header_block; + /* + if (superblock->duckfs_magic != (int32_t) DFS_MAGIC) + { + return -2; + } + + bool compliant = false; + for (int16_t i = 0; i < 5; ++i) + { + if (strcmp(superblock->duckfs_version_string, duckfs_versions[i]) == 0) + { + compliant = true; + } + } + + if (compliant == false) + { + return -3; + }*/ + + memset(&duckfs_root, 0, sizeof(duckfs_root)); + + strncpy(duckfs_root.filename, "/", DFS_MAX_FILENAME_LEN); + strncpy(duckfs_root.permissions, "RW", sizeof(duckfs_root.permissions)); + + duckfs_root.num_sectors = -1; + duckfs_root.type = DFS_FILE_DIRECTORY; + duckfs_root.next = NULL; + duckfs_root.prev = NULL; + duckfs_root.contents = NULL; + duckfs_root.lba_start = 0; + duckfs_root.lba_end = 0; + + duckfs_root.contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES); + if (!duckfs_root.contents) { + printf("Memory allocation failed for duckfs_root.contents\n"); + return -4; + } + + for (int32_t i = 0; i < DFS_MAX_FILES; i++) { + duckfs_root.contents[i].type = DFS_FILE_UNUSED; + } + + + duckfs_initialized = 1; + return 0; +} + + +void duckfs_format(int16_t drive) +{ + /* Nothing to do, DuckFS does not require formatting. */ +} + +int32_t duckfs_makedir(const char* filename, const char* perms) +{ + duckfs_file_header_t* dir = malloc(sizeof(duckfs_file_header_t)); + if (!dir) + { + return -1; + } + + if (strlen(perms) < 3) + { + return -2; + } + + char p[3] = { "." }; + p[0] = perms[0]; + p[1] = perms[1]; + p[2] = perms[2]; + + char filen[DFS_MAX_FILENAME_LEN + 1]; + char perma[3]; + + strcpy(filen, filename); + + + strcpy(perma, perms); + + strncpy(dir->filename, filen, sizeof(dir->filename) - 1); + dir->filename[sizeof(dir->filename) - 1] = '\0'; + + strncpy(dir->permissions, p, sizeof(dir->permissions)); + + dir->type = DFS_FILE_DIRECTORY; + dir->contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES); + + if (!dir->contents) { + free(dir); + return -1; + } + + for (int i = 0; i < DFS_MAX_FILES; i++) { + dir->contents[i].type = DFS_FILE_UNUSED; + } + + return 0; +} + +void duckfs_free_directory(duckfs_file_header_t* dir) +{ + if (!dir || dir->type != DFS_FILE_DIRECTORY || !dir->contents) + { + return; + } + + for (int i = 0; i < DFS_MAX_FILES; i++) { + duckfs_file_header_t* entry = &dir->contents[i]; + + if (entry->type == DFS_FILE_UNUSED) + { + continue; + } + + if (entry->type == DFS_FILE_DIRECTORY) { + duckfs_free_directory(entry); + } + } + + free(dir->contents); + dir->contents = NULL; +} + + +bool duckfs_add_entry(duckfs_file_header_t* dir, duckfs_file_header_t* entry) +{ + if (dir->type != DFS_FILE_DIRECTORY || !dir->contents) + { + return false; + } + + for (int i = 0; i < DFS_MAX_FILES; i++) { + if (dir->contents[i].type == DFS_FILE_UNUSED) { + dir->contents[i] = *entry; + return true; + } + } + return false; /* Directory full */ +} + +duckfs_file_header_t duckfs_create_entry(const char* name, const char* perms, const char* type) +{ + duckfs_file_header_t entry = {0}; + + strncpy(entry.filename, name, DFS_MAX_FILENAME_LEN); + strncpy(entry.permissions, perms, sizeof(entry.permissions) - 1); + + int16_t itype = DFS_FILE_UNUSED; + + if (strcmp(type, "text") == 0) + { + itype = DFS_FILE_TEXT; + } + else if (strcmp(type, "bin") == 0) + { + itype = DFS_FILE_BINARY; + } + else if (strcmp(type, "dir") == 0) + { + itype = DFS_FILE_BINARY; + } + else + { + duckfs_file_header_t vvvv = { .type = DFS_FILE_ERROR }; + return vvvv; + } + + entry.num_sectors = 0; + entry.type = itype; + entry.next = NULL; + entry.prev = NULL; + entry.contents = NULL; + entry.lba_start = 0; + entry.lba_end = 0; + + if (itype == DFS_FILE_DIRECTORY) + { + entry.contents = malloc(sizeof(duckfs_file_header_t) * DFS_MAX_FILES); + if (entry.contents) + { + for (int i = 0; i < DFS_MAX_FILES; i++) + { + entry.contents[i].type = DFS_FILE_UNUSED; + } + } + } + + return entry; +} + +duckfs_file_header_t duckfs_makefile(const char* filename, const char* perms, duckfs_file_header_t parent) +{ + +} diff --git a/drivers/fs/fat32.c b/drivers/fs/fat32.c new file mode 100644 index 0000000..ffa17aa --- /dev/null +++ b/drivers/fs/fat32.c @@ -0,0 +1,428 @@ +#include +#include +#include + +#include + +struct __attribute__((packed)) fat32_bpb { + uint8_t jmp[3]; + uint8_t oem[8]; + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sector_count; + uint8_t num_fats; + uint16_t root_entry_count; + uint16_t total_sectors_16; + uint8_t media; + uint16_t fat_size_16; + uint16_t sectors_per_track; + uint16_t num_heads; + uint32_t hidden_sectors; + uint32_t total_sectors_32; + uint32_t fat_size_32; + uint16_t ext_flags; + uint16_t fs_version; + uint32_t root_cluster; +}; + +static int32_t fat32_drive = 0; +static struct fat32_bpb bpb; +static uint32_t fat_start_lba; +static uint32_t cluster_heap_lba; +static uint32_t current_directory_cluster; + +static uint8_t sector[512]; + +int32_t fat32_init(int32_t drive) +{ + fat32_drive = drive; + int err = ide_read48(drive, 0, 1, sector); + if (err != 0) { + printf("ide_read48 failed on sector 0 (err = %d)\n", err); + return -1; + } + + memcpy(&bpb, sector, sizeof(bpb)); + + + fat_start_lba = bpb.reserved_sector_count; + cluster_heap_lba = fat_start_lba + bpb.num_fats * bpb.fat_size_32; + current_directory_cluster = bpb.root_cluster; + printf("Bytes per sector: %u\n", bpb.bytes_per_sector); + printf("Sectors per cluster: %u\n", bpb.sectors_per_cluster); + printf("Reserved sectors: %u\n", bpb.reserved_sector_count); + printf("Number of FATs: %u\n", bpb.num_fats); + printf("FAT size (32): %u\n", bpb.fat_size_32); + printf("Root cluster: %u\n", bpb.root_cluster); + + return 0; +} + +static uint32_t cluster_to_lba(uint32_t cluster) +{ + return cluster_heap_lba + (cluster - 2) * bpb.sectors_per_cluster; +} + +static void format_83_name(const char *input, char out[11]) { + memset(out, ' ', 11); + int i = 0, j = 0; + + // Copy name part (up to 8 chars) + while (input[i] && input[i] != '.' && j < 8) { + out[j++] = toupper((unsigned char)input[i++]); + } + + // Skip dot + if (input[i] == '.') i++; + + // Copy extension (up to 3 chars) + int k = 8; + while (input[i] && j < 11) { + out[k++] = toupper((unsigned char)input[i++]); + j++; + } +} + +static uint32_t find_free_cluster() { + // Read FAT sectors one by one + for (uint32_t cluster = 2; cluster < bpb.total_sectors_32; cluster++) { + uint32_t fat_sector = fat_start_lba + (cluster * 4) / 512; + uint32_t fat_offset = (cluster * 4) % 512; + + if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0) + return 0; + + uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF; + if (entry == 0x00000000) { + return cluster; + } + } + return 0; // No free cluster found +} + + + +int32_t fat32_list_root(void) +{ + uint32_t lba = cluster_to_lba(current_directory_cluster); + if (ide_read48(fat32_drive, lba, 1, sector) != 0) + { + return -1; + } + + for (int i = 0; i < 512; i += 32) + { + char *entry = (char *)§or[i]; + if ((uint8_t)entry[0] == 0x00) + { + break; + } + + if ((uint8_t)entry[0] == 0xE5) + { + continue; + } + + char name[12]; + memcpy(name, entry, 11); + name[11] = 0; + for (int j = 0; j < 11; j++) + { + if (name[j] == ' ') + { + name[j] = 0; + } + } + + uint8_t attr = entry[11]; + if (attr & FAT32_ATTR_DIRECTORY) + { + printf(" %s\n", name); + } + else + { + printf(" %s\n", name); + } + } + return 0; +} + +int32_t fat32_read_file(const char *name, uint8_t *buffer, uint32_t max_len) +{ + uint32_t lba = cluster_to_lba(current_directory_cluster); + if (ide_read48(fat32_drive, lba, 1, sector) != 0) + { + return -1; + } + + for (int32_t i = 0; i < 512; i += 32) + { + char *entry = (char *)§or[i]; + if ((uint8_t)entry[0] == 0x00) + { + break; + } + if ((uint8_t)entry[0] == 0xE5) + { + continue; + } + + char entry_name[12]; + memcpy(entry_name, entry, 11); + entry_name[11] = 0; + for (int32_t j = 0; j < 11; j++) + { + if (entry_name[j] == ' ') + { + entry_name[j] = 0; + } + } + + if (strncmp(entry_name, name, 11) != 0) + { + continue; + } + + uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16); + uint32_t size = *(uint32_t *)(entry + 28); + uint32_t bytes_read = 0; + + while (cluster < 0x0FFFFFF8 && bytes_read < max_len && bytes_read < size) + { + uint32_t lba = cluster_to_lba(cluster); + if (ide_read48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_read) != 0) + { + return -1; + } + + bytes_read += bpb.sectors_per_cluster * 512; + + uint32_t fat_sector = cluster * 4 / 512; + uint32_t fat_offset = cluster * 4 % 512; + if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0) + { + return -1; + } + + cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF; + } + + return bytes_read; + } + return -2; +} + +int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len) +{ + uint32_t lba = cluster_to_lba(current_directory_cluster); + if (ide_read48(fat32_drive, lba, 1, sector) != 0) + { + return -1; + } + + for (int32_t i = 0; i < 512; i += 32) + { + char *entry = (char *)§or[i]; + if ((uint8_t)entry[0] == 0x00) break; + if ((uint8_t)entry[0] == 0xE5) continue; + + char entry_name[12]; + memcpy(entry_name, entry, 11); + entry_name[11] = 0; + for (int j = 0; j < 11; j++) + { + if (entry_name[j] == ' ') + { + entry_name[j] = 0; + } + } + + if (strncmp(entry_name, name, 11) != 0) + { + continue; + } + + uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16); + uint32_t bytes_written = 0; + + while (cluster < 0x0FFFFFF8 && bytes_written < len) + { + uint32_t lba = cluster_to_lba(cluster); + if (ide_write48(fat32_drive, lba, bpb.sectors_per_cluster, buffer + bytes_written) != 0) + { + return -1; + } + + bytes_written += bpb.sectors_per_cluster * 512; + + if (bytes_written < len) + { + uint32_t fat_sector = cluster * 4 / 512; + uint32_t fat_offset = cluster * 4 % 512; + + if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0) + { + return -1; + } + + uint32_t next_cluster = find_free_cluster(); + if (next_cluster == 0) + { + return -3; + } + + *(uint32_t *)(sector + fat_offset) = next_cluster & 0x0FFFFFFF; + + if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0) + { + return -1; + } + + cluster = next_cluster; + } + else + { + uint32_t fat_sector = cluster * 4 / 512; + uint32_t fat_offset = cluster * 4 % 512; + + if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0) + { + return -1; + } + + *(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF; + + if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0) + { + return -1; + } + + break; + } + } + + *(uint32_t *)(entry + 28) = len; + if (ide_write48(fat32_drive, lba, 1, sector) != 0) + { + return -1; + } + + return bytes_written; + } + return -2; +} + +int32_t fat32_create_file(const char *name) { + uint32_t root_lba = cluster_to_lba(bpb.root_cluster); + + // Read root directory cluster sector (assuming 1 sector here for simplicity) + if (ide_read48(fat32_drive, root_lba, 1, sector) != 0) + return -1; + + char formatted_name[11]; + format_83_name(name, formatted_name); + + for (int32_t i = 0; i < 512; i += 32) { + uint8_t *entry = §or[i]; + if (entry[0] == 0x00 || entry[0] == 0xE5) { + // Found free directory entry, clear it + memset(entry, 0, 32); + + // Copy formatted filename + memcpy(entry, formatted_name, 11); + + // Set attributes to Archive (normal file) + entry[11] = 0x20; + + // Allocate first cluster for the file + uint32_t free_cluster = find_free_cluster(); + if (free_cluster == 0) { + return -2; // No free cluster + } + + // Mark cluster as end-of-chain in FAT + uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512; + uint32_t fat_offset = (free_cluster * 4) % 512; + if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0) + return -1; + + *(uint32_t *)(sector + fat_offset) = 0x0FFFFFFF; // end of cluster chain + if (ide_write48(fat32_drive, fat_sector, 1, sector) != 0) + return -1; + + // Set first cluster in directory entry (split high and low 16 bits) + entry[20] = (free_cluster >> 16) & 0xFF; + entry[21] = (free_cluster >> 24) & 0xFF; + entry[26] = free_cluster & 0xFF; + entry[27] = (free_cluster >> 8) & 0xFF; + + // Set file size = 0 + entry[28] = 0; + entry[29] = 0; + entry[30] = 0; + entry[31] = 0; + + // Write back directory sector + if (ide_write48(fat32_drive, root_lba, 1, sector) != 0) + return -1; + + return 0; // Success + } + } + + return -3; // No free directory entry found +} + +int32_t fat32_create_directory(const char *name) { + uint32_t lba = cluster_to_lba(current_directory_cluster); + if (ide_read48(fat32_drive, lba, 1, sector) != 0) + return -1; + + for (int32_t i = 0; i < 512; i += 32) { + char *entry = (char *)§or[i]; + if ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5) { + memset(entry, 0, 32); + memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name)); + entry[11] = FAT32_ATTR_DIRECTORY; + + uint32_t cluster = 6; + *(uint16_t *)(entry + 26) = cluster & 0xFFFF; + *(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF; + *(uint32_t *)(entry + 28) = 0; + + if (ide_write48(fat32_drive, lba, 1, sector) != 0) + return -1; + + return 0; + } + } + return -2; +} + +int32_t fat32_change_directory(const char *name) { + uint32_t lba = cluster_to_lba(current_directory_cluster); + if (ide_read48(fat32_drive, lba, 1, sector) != 0) + return -1; + + for (int32_t i = 0; i < 512; i += 32) { + char *entry = (char *)§or[i]; + if ((uint8_t)entry[0] == 0x00) break; + if ((uint8_t)entry[0] == 0xE5) continue; + + char entry_name[12]; + memcpy(entry_name, entry, 11); + entry_name[11] = 0; + for (int32_t j = 0; j < 11; j++) + if (entry_name[j] == ' ') entry_name[j] = 0; + + if (strncmp(entry_name, name, 11) != 0) continue; + + if (!(entry[11] & FAT32_ATTR_DIRECTORY)) + return -2; + + current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16); + return 0; + } + return -3; +} +