Upload files to "drivers/fs"

This commit is contained in:
2025-05-20 20:38:50 -05:00
parent 34ec10138b
commit c4740c78fc
2 changed files with 648 additions and 0 deletions

220
drivers/fs/duckfs.c Normal file
View File

@ -0,0 +1,220 @@
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <drivers/ide.h>
#include <fs/duckfs.h>
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)
{
}

428
drivers/fs/fat32.c Normal file
View File

@ -0,0 +1,428 @@
#include <string.h>
#include <stdio.h>
#include <drivers/ide.h>
#include <fs/fat32.h>
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 *)&sector[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("<DIR> %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 *)&sector[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 *)&sector[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 = &sector[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 *)&sector[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 *)&sector[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;
}