Espresso 0.0.1b

This commit is contained in:
2025-06-27 14:48:06 -05:00
parent fca025a9bf
commit c336584114
39 changed files with 2676 additions and 936 deletions

View File

@ -1,93 +1,806 @@
#include <string.h>
#include <stdlib.h>
#include <drivers/ide.h>
#include <fs/duckfs.h>
#define DFS_MAGIC 0xDF1984CC
static duckfs_superblock_t super;
#define DFS_BLOCK_SIZE 512
extern int32_t disk_write(uint64_t lba, const void* buffer, uint32_t count);
extern int32_t disk_read(uint64_t lba, void* buffer, uint32_t count);
#define DFS_VERSION_0 "DuckFS, wheresDax?"
#define DFS_VERSION_1 "DuckFS, Terminator"
#define DFS_VERSION_2 "DuckFS-Terminator2"
#define DFS_VERSION_3 "DuckFS,StarWarsEIV"
#define DFS_VERSION_4 "DuckFS QUACK,QUACK"
#define DFS_FILE_ERROR -8
#define DFS_FILE_UNUSED -1
#define DFS_FILE_USED 0
#define DFS_FILE_TEXT 0
#define DFS_FILE_BINARY 1
#define DFS_FILE_DIRECTORY 2
/* encryption algorithms */
#define DFS_CAESAR_5 88
#define DFS_CAESAR_8 84
#define DFS_CAESAR_2 09
#define DFS_QUACK_32 99
#define DFS_MAX_FILENAME_LEN 64
#define DFS_MAX_FILES 256
typedef struct duckfs_file_header {
char filename[DFS_MAX_FILENAME_LEN + 1]; /* + 1 for the \0 */
char permissions[3]; /* Same thing here */
/*
512 Bytes per sector, meaning a 2 sector file is 1024 bytes, or 1 KiB.
Only valid if this file is not a directory.
*/
int32_t num_sectors;
int16_t type; /* Indicates the file type. -1 for null file, 0 for a text file, 1 for a binary file, and 2 for a directory. */
uint16_t _reserved0; /* (align to 4) */
struct duckfs_file_header* next; /* Next file in the directory this file is in. */
struct duckfs_file_header* contents; /* contains the first file in the directory. only valid if this file is a directory. */
struct duckfs_file_header* parent; /* The directory this file is in. */
uint64_t next_lba; /* The LBA of the next file's file header on the disk. */
uint64_t contents_lba;
uint64_t parent_lba;
uint64_t lba_start; /* only is valid if this file is not a directory. */
uint64_t lba_end; /* only is valid if this file is not a directory. */
uint8_t _reserved1[126]; /* padding to 256 bytes total */
} duckfs_file_header_t;
typedef struct duckfs_superblock {
int32_t duckfs_magic; /* must be DFS_MAGIC. */
char duckfs_version_string[19];
char volume_label[19]; /* 18 characters and a null zero. */
int16_t encryption;
uint64_t duckfs_root; /* LBA of the root directory's file header */
uint32_t _padding[115]; /* padding to 512 bytes total */
} duckfs_superblock_t;
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 };
void duckfs_init(void)
int32_t duckfs_mount(void)
{
printf("\t%i\n", (sizeof(duckfs_file_header_t)));
printf("\t\t%i\n", (sizeof(duckfs_superblock_t)));
/* int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer) */
/* int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer) */
/*uint8_t superblock_sector[512] = { 0 };
ide_read*/
if (disk_read(8, &super, 1) != 0)
{
return -1;
}
if (memcmp(super.magic, DUCKFS_MAGIC, 7) != 0)
{
return -2;
}
return 0;
}
static int32_t read_header(uint64_t lba, duckfs_file_header_t* hdr)
{
uint8_t sector[512];
if (disk_read(lba, sector, 1) != 0)
{
return -1;
}
memcpy(hdr, sector, sizeof(duckfs_file_header_t));
return 0;
}
static const char* next_token(const char* path, char* token)
{
while (*path == '/')
{
path++;
}
if (*path == 0)
{
return NULL;
}
size_t len = 0;
while (*path && *path != '/')
{
token[len++] = *path++;
}
token[len] = 0;
return path;
}
static int32_t duckfs_alloc_block(uint64_t* out_lba)
{
if (super.free_list_lba == 0)
{
return -1;
}
*out_lba = super.free_list_lba;
uint64_t next;
if (disk_read(*out_lba, &next, 1) != 0)
{
return -2;
}
super.free_list_lba = next;
/* Persist the updated superblock */
if (disk_write(8, &super, 1) != 0)
{
return -3;
}
return 0;
}
static int32_t duckfs_alloc_file_data(const void* content, size_t size, uint64_t* first_lba)
{
const uint8_t* src = (const uint8_t*)content;
size_t remaining = size;
uint64_t prev_lba = 0;
uint64_t head_lba = 0;
while (remaining > 0)
{
uint64_t block_lba;
if (duckfs_alloc_block(&block_lba) != 0)
{
return -1;
}
/* Write next block LBA at start (for linking) */
uint64_t next = 0;
if (remaining > super.block_size - sizeof(uint64_t))
{
if (duckfs_alloc_block(&next) != 0)
{
return -2;
}
}
uint8_t buffer[512] = {0};
memcpy(buffer, &next, sizeof(uint64_t));
size_t copy_len = super.block_size - sizeof(uint64_t);
if (copy_len > remaining)
{
copy_len = remaining;
}
memcpy(buffer + sizeof(uint64_t), src, copy_len);
if (disk_write(block_lba, buffer, 1) != 0)
{
return -3;
}
if (prev_lba != 0) {
if (disk_write(prev_lba, &block_lba, 1) != 0)
{
return -4;
}
}
else
{
head_lba = block_lba;
}
prev_lba = block_lba;
src += copy_len;
remaining -= copy_len;
}
*first_lba = head_lba;
return 0;
}
int32_t duckfs_find(const char* path, duckfs_file_header_t* out)
{
char token[DUCKFS_NAME_LEN];
duckfs_file_header_t current;
if (read_header(super.root_header_lba, &current) != 0)
{
return -1;
}
const char* p = path;
while ((p = next_token(p, token)))
{
if (current.type != DUCKFS_TYPE_DIR)
{
return -2;
}
uint64_t child = current.child_lba;
int32_t found = 0;
while (child != 0)
{
duckfs_file_header_t entry;
if (read_header(child, &entry) != 0)
{
return -3;
}
if (strncmp(entry.name, token, DUCKFS_NAME_LEN) == 0)
{
current = entry;
found = 1;
break;
}
child = entry.next_file_lba;
}
if (!found)
{
return -4;
}
}
*out = current;
return 0;
}
int32_t duckfs_create_file(const char* name, const void* content, size_t size, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
/* Check for existing file */
duckfs_file_header_t child;
uint64_t current = parent_dir->child_lba;
uint64_t prev_lba = 0;
while (current != 0)
{
if (disk_read(current, &child, 1) != 0)
{
return -2;
}
if (strncmp(child.name, name, DUCKFS_NAME_LEN) == 0)
{
/* Overwrite content */
uint64_t data_lba;
if (duckfs_alloc_file_data(content, size, &data_lba) != 0)
{
return -3;
}
child.first_block_lba = data_lba;
child.size = size;
child.modified = 0; /* TODO: timestamp */
return disk_write(current, &child, 1);
}
prev_lba = current;
current = child.next_file_lba;
}
/* Allocate header */
uint64_t file_hdr_lba;
if (duckfs_alloc_block(&file_hdr_lba) != 0)
{
return -4;
}
/* Write content */
uint64_t data_lba;
if (duckfs_alloc_file_data(content, size, &data_lba) != 0)
{
return -5;
}
duckfs_file_header_t new_file = {0};
strncpy(new_file.name, name, DUCKFS_NAME_LEN);
new_file.type = DUCKFS_TYPE_FILE;
new_file.permissions = perms;
new_file.uid = uid;
new_file.gid = gid;
new_file.size = size;
new_file.first_block_lba = data_lba;
new_file.modified = 0;
/* Add to dir */
if (prev_lba == 0)
{
parent_dir->child_lba = file_hdr_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -6;
}
}
else
{
child.next_file_lba = file_hdr_lba;
if (disk_write(prev_lba, &child, 1) != 0)
{
return -7;
}
}
return disk_write(file_hdr_lba, &new_file, 1);
}
int32_t duckfs_create_dir(const char* name, uint16_t uid, uint16_t gid, uint8_t perms, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
/* Allocate header */
uint64_t hdr_lba;
if (duckfs_alloc_block(&hdr_lba) != 0)
{
return -2;
}
duckfs_file_header_t new_dir = {0};
strncpy(new_dir.name, name, DUCKFS_NAME_LEN);
new_dir.type = DUCKFS_TYPE_DIR;
new_dir.permissions = perms;
new_dir.uid = uid;
new_dir.gid = gid;
new_dir.modified = 0;
new_dir.size = 0;
/* Write header */
if (disk_write(hdr_lba, &new_dir, 1) != 0)
{
return -3;
}
/* Add to parent */
duckfs_file_header_t sibling;
uint64_t current = parent_dir->child_lba;
uint64_t prev = 0;
while (current != 0)
{
if (disk_read(current, &sibling, 1) != 0)
{
return -4;
}
prev = current;
current = sibling.next_file_lba;
}
if (prev == 0)
{
parent_dir->child_lba = hdr_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -5;
}
}
else
{
sibling.next_file_lba = hdr_lba;
if (disk_write(prev, &sibling, 1) != 0)
{
return -6;
}
}
return 0;
}
int32_t duckfs_read_file(const duckfs_file_header_t* file, void* buffer, size_t size)
{
if (file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t to_read = size;
if (to_read > file->size)
{
to_read = file->size;
}
uint64_t blocks = (to_read + super.block_size - 1) / super.block_size;
return disk_read(file->first_block_lba, buffer, blocks);
}
int32_t duckfs_write_data(duckfs_file_header_t* file, const void* data, size_t offset, size_t length)
{
if (!file || file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t final_size = offset + length;
if (final_size > file->size)
{
/* Grow */
if (duckfs_append_data(file, ((const uint8_t*)data) + (file->size - offset), final_size - file->size) != 0)
{
return -2;
}
}
size_t block_size = super.block_size;
size_t remaining = length;
const uint8_t* src = (const uint8_t*)data;
uint64_t current_lba = file->first_block_lba;
uint64_t block_offset = 0;
/* Traverse to block containing `offset` */
size_t logical = 0;
while (logical + (block_size - 8) <= offset)
{
uint64_t next;
if (disk_read(current_lba, &next, 1) != 0)
{
return -3;
}
current_lba = next;
if (current_lba == 0)
{
return -4; /* ran out */
}
logical += block_size - 8;
}
/* Start writing */
while (remaining > 0)
{
uint8_t buffer[512];
if (disk_read(current_lba, buffer, 1) != 0)
{
return -5;
}
uint64_t next_lba;
memcpy(&next_lba, buffer, sizeof(uint64_t));
size_t block_start = (offset > logical) ? (offset - logical) : 0;
size_t to_copy = block_size - 8 - block_start;
if (to_copy > remaining) to_copy = remaining;
memcpy(buffer + 8 + block_start, src, to_copy);
if (disk_write(current_lba, buffer, 1) != 0)
{
return -6;
}
src += to_copy;
remaining -= to_copy;
offset += to_copy;
logical += block_size - 8;
current_lba = next_lba;
}
return 0;
}
int32_t duckfs_append_data(duckfs_file_header_t* file, const void* data, size_t length)
{
if (!file || file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t block_size = super.block_size;
size_t data_per_block = block_size - sizeof(uint64_t);
uint64_t last_lba = file->first_block_lba;
if (last_lba == 0)
{
/* Allocate first block */
if (duckfs_alloc_block(&last_lba) != 0)
{
return -2;
}
file->first_block_lba = last_lba;
}
else
{
/* Traverse to last block */
uint64_t next;
while (1)
{
if (disk_read(last_lba, &next, 1) != 0)
{
return -3;
}
memcpy(&next, &next, sizeof(uint64_t));
if (next == 0)
{
break;
}
last_lba = next;
}
}
size_t offset_in_block = file->size % data_per_block;
size_t remaining = length;
const uint8_t* src = (const uint8_t*)data;
/* Write to the partially filled last block */
if (offset_in_block != 0)
{
uint8_t buffer[512];
if (disk_read(last_lba, buffer, 1) != 0)
{
return -4;
}
size_t to_copy = data_per_block - offset_in_block;
if (to_copy > remaining)
{
to_copy = remaining;
}
memcpy(buffer + sizeof(uint64_t) + offset_in_block, src, to_copy);
if (disk_write(last_lba, buffer, 1) != 0)
{
return -5;
}
file->size += to_copy;
remaining -= to_copy;
src += to_copy;
}
/* Write remaining data to new blocks */
while (remaining > 0)
{
uint64_t new_lba;
if (duckfs_alloc_block(&new_lba) != 0)
{
return -6;
}
/* Link previous block to this one */
if (disk_write(last_lba, &new_lba, 1) != 0)
{
return -7;
}
uint8_t buffer[512] = {0};
uint64_t next = 0;
memcpy(buffer, &next, sizeof(uint64_t));
size_t to_copy = (remaining > data_per_block) ? data_per_block : remaining;
memcpy(buffer + sizeof(uint64_t), src, to_copy);
if (disk_write(new_lba, buffer, 1) != 0)
{
return -8;
}
last_lba = new_lba;
src += to_copy;
remaining -= to_copy;
file->size += to_copy;
}
return 0;
}
int32_t duckfs_truncate(duckfs_file_header_t* file, size_t new_size)
{
if (!file || file->type != DUCKFS_TYPE_FILE)
{
return -1;
}
size_t block_size = super.block_size;
size_t data_per_block = block_size - sizeof(uint64_t);
size_t needed_blocks = (new_size + data_per_block - 1) / data_per_block;
uint64_t current = file->first_block_lba;
uint64_t prev = 0;
for (size_t i = 0; i < needed_blocks; i++)
{
if (current == 0)
{
break;
}
uint64_t next;
if (disk_read(current, &next, 1) != 0)
{
return -2;
}
memcpy(&next, &next, sizeof(uint64_t));
prev = current;
current = next;
}
/* `current` is now first block to free */
while (current != 0)
{
uint64_t next;
if (disk_read(current, &next, 1) != 0)
{
return -3;
}
memcpy(&next, &next, sizeof(uint64_t));
/* Write freelist entry */
if (disk_write(current, &super.free_list_lba, 1) != 0)
{
return -4;
}
super.free_list_lba = current;
current = next;
}
/* Finalize */
if (disk_write(8, &super, 1) != 0)
{
return -5;
}
/* Cut block chain */
if (prev != 0)
{
uint64_t zero = 0;
if (disk_write(prev, &zero, 1) != 0)
{
return -6;
}
}
file->size = new_size;
return 0;
}
int32_t duckfs_delete_file(const char* name, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
duckfs_file_header_t child;
uint64_t prev_lba = 0;
uint64_t current_lba = parent_dir->child_lba;
/* Search for file by name */
while (current_lba != 0)
{
if (disk_read(current_lba, &child, 1) != 0)
{
return -2;
}
if (strncmp(child.name, name, DUCKFS_NAME_LEN) == 0)
{
break;
}
prev_lba = current_lba;
current_lba = child.next_file_lba;
}
if (current_lba == 0)
{
return -3; /* not found */
}
/* Remove from parent's linked list */
if (prev_lba == 0)
{
/* It's the first child */
parent_dir->child_lba = child.next_file_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -4;
}
}
else
{
duckfs_file_header_t prev;
if (disk_read(prev_lba, &prev, 1) != 0)
{
return -5;
}
prev.next_file_lba = child.next_file_lba;
if (disk_write(prev_lba, &prev, 1) != 0)
{
return -6;
}
}
/* Free file data blocks */
uint64_t current = child.first_block_lba;
while (current != 0)
{
uint64_t next;
if (disk_read(current, &next, 1) != 0)
{
return -7;
}
/* Insert this block into the freelist */
if (disk_write(current, &super.free_list_lba, 1) != 0)
{
return -8;
}
super.free_list_lba = current;
current = next;
}
/* Free file header block */
if (disk_write(current_lba, &super.free_list_lba, 1) != 0)
{
return -9;
}
super.free_list_lba = current_lba;
/* Save updated superblock */
if (disk_write(8, &super, 1) != 0)
{
return -10;
}
return 0;
}
int32_t duckfs_delete_dir(const char* name, duckfs_file_header_t* parent_dir)
{
if (!parent_dir || parent_dir->type != DUCKFS_TYPE_DIR)
{
return -1;
}
duckfs_file_header_t dir;
uint64_t prev_lba = 0;
uint64_t current_lba = parent_dir->child_lba;
/* Find directory */
while (current_lba != 0)
{
if (disk_read(current_lba, &dir, 1) != 0)
{
return -2;
}
if (strncmp(dir.name, name, DUCKFS_NAME_LEN) == 0 && dir.type == DUCKFS_TYPE_DIR)
{
break;
}
prev_lba = current_lba;
current_lba = dir.next_file_lba;
}
if (current_lba == 0)
{
return -3; /* not found */
}
/* Delete contents recursively */
uint64_t child_lba = dir.child_lba;
while (child_lba != 0)
{
duckfs_file_header_t child;
if (disk_read(child_lba, &child, 1) != 0)
{
return -4;
}
uint64_t next_lba = child.next_file_lba;
if (child.type == DUCKFS_TYPE_FILE)
{
if (duckfs_delete_file(child.name, &dir) != 0)
{
return -5;
}
}
else if (child.type == DUCKFS_TYPE_DIR)
{
if (duckfs_delete_dir(child.name, &dir) != 0)
{
return -6;
}
}
child_lba = next_lba;
}
/* Remove dir from parent */
if (prev_lba == 0)
{
parent_dir->child_lba = dir.next_file_lba;
if (disk_write(parent_dir->first_block_lba, parent_dir, 1) != 0)
{
return -7;
}
}
else
{
duckfs_file_header_t prev;
if (disk_read(prev_lba, &prev, 1) != 0)
{
return -8;
}
prev.next_file_lba = dir.next_file_lba;
if (disk_write(prev_lba, &prev, 1) != 0)
{
return -9;
}
}
/* Free directory header block */
if (disk_write(current_lba, &super.free_list_lba, 1) != 0)
{
return -10;
}
super.free_list_lba = current_lba;
/* Save updated superblock */
return disk_write(8, &super, 1);
}

View File

@ -0,0 +1,50 @@
#include <fs/duckfs.h>
#include <string.h>
#include <stdio.h>
extern int32_t ide_read48(uint8_t drive, uint64_t lba, uint8_t sector_count, void* buffer);
extern int32_t ide_write48(uint8_t drive, uint64_t lba, uint8_t sector_count, const void* buffer);
static uint8_t duckfs_drive = 0;
void duckfs_set_drive(uint8_t drive)
{
duckfs_drive = drive;
}
int32_t disk_read(uint64_t lba, void* buffer, uint32_t count)
{
/* IDE spec only allows up to 256 sectors in one call */
while (count > 0)
{
uint8_t sectors = (count > 256) ? 256 : count;
int32_t result = ide_read48(duckfs_drive, lba, sectors, buffer);
if (result < 0)
{
return -1;
}
lba += sectors;
count -= sectors;
buffer = (void*)((uintptr_t)buffer + 512 * sectors);
}
return 0;
}
int32_t disk_write(uint64_t lba, const void* buffer, uint32_t count)
{
while (count > 0)
{
uint8_t sectors = (count > 256) ? 256 : count;
int32_t result = ide_write48(duckfs_drive, lba, sectors, buffer);
if (result < 0)
{
return -1;
}
lba += sectors;
count -= sectors;
buffer = (const void*)((uintptr_t)buffer + 512 * sectors);
}
return 0;
}

248
drivers/fs/fat16.c Normal file
View File

@ -0,0 +1,248 @@
#include <drivers/ide.h>
#include <string.h>
#include <stdio.h>
#include <fs/fat16.h>
static fat16_t fat;
#pragma pack(push, 1)
typedef struct {
uint8_t jmp[3];
char oem[8];
uint16_t bytes_per_sector;
uint8_t sectors_per_cluster;
uint16_t reserved_sectors;
uint8_t fat_count;
uint16_t root_entries;
uint16_t total_sectors_short;
uint8_t media_desc;
uint16_t fat_size_sectors;
uint16_t sectors_per_track;
uint16_t heads;
uint32_t hidden_sectors;
uint32_t total_sectors_long;
// Extended Boot Record...
} fat16_bpb_t;
typedef struct {
char name[8];
char ext[3];
uint8_t attr;
uint8_t reserved;
uint8_t create_time_tenth;
uint16_t create_time;
uint16_t create_date;
uint16_t access_date;
uint16_t first_cluster_hi;
uint16_t write_time;
uint16_t write_date;
uint16_t first_cluster_lo;
uint32_t size;
} fat16_direntry_raw_t;
#pragma pack(pop)
static uint8_t sector_buffer[512];
uint32_t cluster_to_lba(uint16_t cluster)
{
return fat.data_start + ((cluster - 2) * fat.sectors_per_cluster);
}
int32_t fat16_init(uint8_t drive)
{
if (ide_read48(drive, 0, 1, sector_buffer) < 0)
{
return -1;
}
fat16_bpb_t* bpb = (fat16_bpb_t*)sector_buffer;
fat.drive = drive;
fat.bytes_per_sector = bpb->bytes_per_sector;
fat.sectors_per_cluster = bpb->sectors_per_cluster;
fat.root_entry_count = bpb->root_entries;
fat.fat_start = bpb->reserved_sectors;
fat.root_dir_start = fat.fat_start + bpb->fat_count * bpb->fat_size_sectors;
fat.data_start = fat.root_dir_start + ((bpb->root_entries * 32 + fat.bytes_per_sector - 1) / fat.bytes_per_sector);
fat.current_dir_cluster = 0;
return 0;
}
uint16_t fat16_get_fat_entry(uint16_t cluster)
{
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0)
{
return 0xFFFF;
}
return *(uint16_t*)&sector_buffer[ent_offset];
}
uint16_t fat16_alloc_cluster(void)
{
for (uint16_t cluster = 2; cluster < 0xFFF0; ++cluster) {
uint16_t entry = fat16_get_fat_entry(cluster);
if (entry == 0x0000) {
// Mark as end of chain
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0) return 0;
*(uint16_t*)&sector_buffer[ent_offset] = 0xFFFF;
if (ide_write48(fat.drive, fat_sector, 1, sector_buffer) < 0) return 0;
return cluster;
}
}
return 0;
}
int32_t fat16_list_dir(fat16_dir_entry_t* entries, size_t max_entries)
{
size_t count = 0;
if (fat.current_dir_cluster == 0)
{
uint16_t root_sectors = ((fat.root_entry_count * 32) + (fat.bytes_per_sector - 1)) / fat.bytes_per_sector;
for (uint32_t i = 0; i < root_sectors && count < max_entries; ++i)
{
if (ide_read48(fat.drive, fat.root_dir_start + i, 1, sector_buffer) < 0)
{
return -1;
}
fat16_direntry_raw_t* de = (fat16_direntry_raw_t*)sector_buffer;
for (int32_t j = 0; j < 512 / 32 && count < max_entries; ++j, ++de)
{
if (de->name[0] == 0x00 || de->name[0] == 0xE5)
{
continue;
}
memcpy(entries[count].name, de->name, 8);
entries[count].name[8] = '\0';
entries[count].attr = de->attr;
entries[count].cluster = de->first_cluster_lo;
entries[count].size = de->size;
count++;
}
}
}
/* TODO: Add support for listing subdirectories if current_dir_cluster != 0 */
return count;
}
int32_t fat16_read_file(const char* filename, void* buffer, size_t max_size) {
fat16_dir_entry_t entries[64];
int32_t n = fat16_list_dir(entries, 64);
for (int32_t i = 0; i < n; ++i) {
if (!(entries[i].attr & FAT16_ATTR_DIRECTORY) &&
strncmp(entries[i].name, filename, FAT16_MAX_FILENAME) == 0) {
uint16_t cluster = entries[i].cluster;
uint8_t* out = (uint8_t*)buffer;
size_t remaining = entries[i].size < max_size ? entries[i].size : max_size;
while (cluster >= 0x0002 && cluster < 0xFFF8 && remaining > 0) {
uint32_t lba = cluster_to_lba(cluster);
size_t to_read = fat.bytes_per_sector * fat.sectors_per_cluster;
if (ide_read48(fat.drive, lba, fat.sectors_per_cluster, sector_buffer) < 0)
return -1;
size_t copy_size = (remaining < to_read) ? remaining : to_read;
memcpy(out, sector_buffer, copy_size);
out += copy_size;
remaining -= copy_size;
cluster = fat16_get_fat_entry(cluster);
}
return (int32_t)(out - (uint8_t*)buffer);
}
}
return -1;
}
int32_t fat16_write_file(const char* filename, const void* data, size_t size) {
fat16_dir_entry_t entries[64];
int32_t n = fat16_list_dir(entries, 64);
for (int32_t i = 0; i < n; ++i) {
if (strncmp(entries[i].name, filename, FAT16_MAX_FILENAME) == 0) {
uint16_t cluster = entries[i].cluster;
const uint8_t* src = (const uint8_t*)data;
size_t remaining = size;
while (remaining > 0) {
uint32_t lba = cluster_to_lba(cluster);
size_t cluster_bytes = fat.sectors_per_cluster * fat.bytes_per_sector;
size_t to_write = remaining < cluster_bytes ? remaining : cluster_bytes;
memset(sector_buffer, 0, cluster_bytes); // Clear old data
memcpy(sector_buffer, src, to_write);
if (ide_write48(fat.drive, lba, fat.sectors_per_cluster, sector_buffer) < 0)
return -1;
src += to_write;
remaining -= to_write;
// Last chunk?
if (remaining == 0)
break;
// Check next cluster
uint16_t next = fat16_get_fat_entry(cluster);
if (next >= 0xFFF8 || next == 0x0000) {
// Need to allocate a new cluster
uint16_t new_cluster = fat16_alloc_cluster();
if (new_cluster == 0) return -1;
// Update FAT to point to new cluster
uint32_t fat_offset = cluster * 2;
uint32_t fat_sector = fat.fat_start + (fat_offset / fat.bytes_per_sector);
uint32_t ent_offset = fat_offset % fat.bytes_per_sector;
if (ide_read48(fat.drive, fat_sector, 1, sector_buffer) < 0) return -1;
*(uint16_t*)&sector_buffer[ent_offset] = new_cluster;
if (ide_write48(fat.drive, fat_sector, 1, sector_buffer) < 0) return -1;
next = new_cluster;
}
cluster = next;
}
return (int32_t)size;
}
}
return -1;
}
int32_t fat16_change_dir(const char* dirname)
{
fat16_dir_entry_t entries[64];
int32_t n = fat16_list_dir(entries, 64);
for (int32_t i = 0; i < n; ++i)
{
if ((entries[i].attr & FAT16_ATTR_DIRECTORY) && strncmp(entries[i].name, dirname, FAT16_MAX_FILENAME) == 0)
{
fat.current_dir_cluster = entries[i].cluster;
return 0;
}
}
return -1;
}

View File

@ -5,24 +5,24 @@
#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;
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;
@ -37,9 +37,10 @@ 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;
if (err != 0)
{
printf("ide_read48 failed on sector 0 (err = %d)\n", err);
return -1;
}
memcpy(&bpb, sector, sizeof(bpb));
@ -47,56 +48,79 @@ int32_t fat32_init(int32_t drive)
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("========= Start FAT info =========\n");
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);
printf("========= End FAT info =========\n");
return 0;
}
void print_83(const char *s) {
for (int i = 0; i < 11; i++) {
char c = s[i];
if (c >= 32 && c <= 126) {
printf("%c", c); // or your kernel's character output function
} else {
printf("\\x%02X", (unsigned char)c); // hex-escape non-printables
}
}
printf("\n");
}
static uint32_t cluster_to_lba(uint32_t cluster)
{
printf("cluster_heap_lba: %u\n", cluster_heap_lba);
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;
void format_83_name(const char* input, char* output)
{
printf("Input name: %s, Input length: %i\n", input, strlen(input));
// Copy name part (up to 8 chars)
while (input[i] && input[i] != '.' && j < 8) {
out[j++] = toupper((unsigned char)input[i++]);
memset(output, ' ', 11);
int32_t i = 0, j = 0;
while (input[i] && j < 11)
{
if (input[i] == '.')
{
j = 8;
i++;
continue;
}
// 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++;
if (j < 11)
{
output[j++] = toupper((unsigned char)input[i++]);
}
}
}
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;
static uint32_t find_free_cluster(void)
{
/* 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;
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
if (entry == 0x00000000) {
return cluster;
}
if (ide_read48(fat32_drive, fat_sector, 1, sector) != 0)
{
return 0;
}
return 0; // No free cluster found
uint32_t entry = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
if (entry == 0x00000000)
{
return cluster;
}
}
return 0; // No free cluster found
}
@ -148,70 +172,336 @@ int32_t fat32_list_root(void)
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)
char formatted[11];
memset(formatted, 0xAB, sizeof(formatted));
format_83_name(name, formatted);
uint32_t dir_cluster = current_directory_cluster;
while (dir_cluster < 0x0FFFFFF8)
{
uint32_t lba = cluster_to_lba(dir_cluster);
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
{
if (ide_read48(fat32_drive, lba + sector_idx, 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 || (uint8_t)entry[11] == 0x0F)
{
continue;
}
printf("here\n");
char entry_name[12] = { '\0' };
memcpy((void*)entry_name, (void*)entry, 11);
int32_t err = memcmp(entry_name, formatted, (size_t)11);
if (err != 0)
{
printf("memcmp: %i\n", err);
continue;
}
/* File found */
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 file_lba = cluster_to_lba(cluster);
if (ide_read48(fat32_drive, file_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;
}
}
/* Next directory cluster */
uint32_t fat_sector = dir_cluster * 4 / 512;
uint32_t fat_offset = dir_cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
}
return -2; /* File not found */
}
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
{
uint8_t fat_sector_buf[512];
char formatted[11];
memset(formatted, 0xAB, sizeof(formatted));
format_83_name(name, formatted);
uint32_t dir_cluster = current_directory_cluster;
while (dir_cluster < 0x0FFFFFF8)
{
uint32_t lba = cluster_to_lba(dir_cluster);
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
{
// Read directory sector
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
// Find matching entry offset inside this sector
int32_t entry_offset = -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 || (uint8_t)entry[11] == 0x0F)
{
continue;
}
char entry_name[12] = {0};
memcpy(entry_name, entry, 11);
if (memcmp(entry_name, formatted, 11) == 0)
{
entry_offset = i;
break;
}
}
if (entry_offset == -1)
{
// Not found in this sector, continue to next
continue;
}
// Entry found, write file data clusters
uint8_t *entry = &sector[entry_offset];
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 file_lba = cluster_to_lba(cluster);
if (ide_write48(fat32_drive, file_lba, bpb.sectors_per_cluster, buffer + bytes_written) != 0)
{
return -1;
}
bytes_written += bpb.sectors_per_cluster * 512;
if (bytes_written < len)
{
// Read FAT sector for current cluster
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, fat_sector_buf) != 0)
{
return -1;
}
uint32_t next_cluster = find_free_cluster();
if (next_cluster == 0)
{
return -3; // No free cluster
}
*(uint32_t *)(fat_sector_buf + fat_offset) = next_cluster & 0x0FFFFFFF;
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
cluster = next_cluster;
}
else
{
// Mark end of cluster chain
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, fat_sector_buf) != 0)
{
return -1;
}
*(uint32_t *)(fat_sector_buf + fat_offset) = 0x0FFFFFFF;
if (ide_write48(fat32_drive, fat_start_lba + fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
break;
}
}
// **Re-read the directory sector before updating file size**
if (ide_read48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
// Update file size in directory entry again after re-read
entry = &sector[entry_offset];
*(uint32_t *)(entry + 28) = len;
// Write back updated directory sector
if (ide_write48(fat32_drive, lba + sector_idx, 1, sector) != 0)
{
return -1;
}
// Debug print updated directory entry
printf("Directory entry after write (offset %d):\n", entry_offset);
for (int j = 0; j < 32; j++) {
uint8_t b = (uint8_t)entry[j];
printf("%02X ", b);
if ((j + 1) % 16 == 0) printf(" ");
}
printf("\n");
for (int j = 0; j < 32; j++) {
char c = entry[j];
printf("%c", (c >= 32 && c <= 126) ? c : '.');
}
printf("\n");
return bytes_written;
}
// Move to next cluster of the directory
uint32_t fat_sector = dir_cluster * 4 / 512;
uint32_t fat_offset = dir_cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
{
return -1;
}
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
}
return -2; // File not found
}
int32_t fat32_create_file(const char *name)
{
uint8_t dir_sector[512];
uint8_t fat_sector_buf[512];
uint32_t root_lba = cluster_to_lba(current_directory_cluster);
if (ide_read48(fat32_drive, root_lba, 1, dir_sector) != 0)
{
return -1;
}
char formatted_name[11];
format_83_name(name, formatted_name);
for (int32_t i = 0; i < 512; i += 32)
{
char *entry = (char *)&sector[i];
if ((uint8_t)entry[0] == 0x00)
uint8_t *entry = &dir_sector[i];
if (entry[0] == 0x00 || entry[0] == 0xE5)
{
break;
}
if ((uint8_t)entry[0] == 0xE5)
{
continue;
}
printf("Writing entry at offset %d\n", i);
memset(entry, 0, 32);
memcpy(entry, formatted_name, 11);
entry[11] = 0x20;
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] == ' ')
uint32_t free_cluster = find_free_cluster();
if (free_cluster == 0)
{
entry_name[j] = 0;
return -2;
}
}
if (strncmp(entry_name, name, 11) != 0)
{
continue;
}
uint32_t fat_sector = fat_start_lba + (free_cluster * 4) / 512;
uint32_t fat_offset = (free_cluster * 4) % 512;
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)
if (ide_read48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
bytes_read += bpb.sectors_per_cluster * 512;
*(uint32_t *)(fat_sector_buf + fat_offset) = 0x0FFFFFFF;
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)
if (ide_write48(fat32_drive, fat_sector, 1, fat_sector_buf) != 0)
{
return -1;
}
cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
/* Set first cluster */
entry[20] = (free_cluster >> 16) & 0xFF;
entry[21] = (free_cluster >> 24) & 0xFF;
entry[26] = free_cluster & 0xFF;
entry[27] = (free_cluster >> 8) & 0xFF;
/* File size = 0 */
memset(entry + 28, 0, 4);
if (ide_write48(fat32_drive, root_lba, 1, dir_sector) != 0)
{
return -1;
}
uint8_t temp[512];
ide_read48(fat32_drive, cluster_to_lba(bpb.root_cluster), 1, temp);
printf("Root directory cluster 2 dump (first 64 bytes):\n");
for (int i = 0; i < 64; i++) {
printf("%02X ", temp[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
return 0;
}
return bytes_read;
}
return -2;
return -8;
}
int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
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)
@ -222,206 +512,90 @@ int32_t fat32_write_file(const char *name, const uint8_t *buffer, uint32_t len)
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 ((uint8_t)entry[0] == 0x00 || (uint8_t)entry[0] == 0xE5)
{
if (entry_name[j] == ' ')
{
entry_name[j] = 0;
}
}
if (strncmp(entry_name, name, 11) != 0)
{
continue;
}
memset(entry, 0, 32);
memcpy(entry, name, strlen(name) > 11 ? 11 : strlen(name));
entry[11] = FAT32_ATTR_DIRECTORY;
uint32_t cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
uint32_t bytes_written = 0;
uint32_t cluster = 6;
*(uint16_t *)(entry + 26) = cluster & 0xFFFF;
*(uint16_t *)(entry + 20) = (cluster >> 16) & 0xFFFF;
*(uint32_t *)(entry + 28) = 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)
if (ide_write48(fat32_drive, lba, 1, sector) != 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;
}
return 0;
}
*(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);
int32_t fat32_change_directory(const char *name)
{
uint32_t dir_cluster = current_directory_cluster;
// Read root directory cluster sector (assuming 1 sector here for simplicity)
if (ide_read48(fat32_drive, root_lba, 1, sector) != 0)
while (dir_cluster < 0x0FFFFFF8)
{
uint32_t lba = cluster_to_lba(dir_cluster);
for (uint8_t sector_idx = 0; sector_idx < bpb.sectors_per_cluster; sector_idx++)
{
if (ide_read48(fat32_drive, lba + sector_idx, 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) {
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;
if ((uint8_t)entry[0] == 0x00)
{
break;
}
if ((uint8_t)entry[0] == 0xE5)
{
continue;
}
}
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;
for (int 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;
{
return -2;
}
current_directory_cluster = (*(uint16_t *)(entry + 26)) | ((*(uint16_t *)(entry + 20)) << 16);
return 0;
}
}
return -3;
uint32_t fat_sector = dir_cluster * 4 / 512;
uint32_t fat_offset = dir_cluster * 4 % 512;
if (ide_read48(fat32_drive, fat_start_lba + fat_sector, 1, sector) != 0)
return -1;
dir_cluster = *(uint32_t *)(sector + fat_offset) & 0x0FFFFFFF;
}
return -3;
}

View File

@ -1,8 +1,8 @@
#include <fs/ramfs.h>
/*#include <fs/fat16.h>
#include <stdlib.h>
#include <string.h>
#include <fs/vfs.h>
#include <fs/vfs.h>*/
/*
@ -11,7 +11,7 @@
-33 means stdout (which can be read)
*/
bool vfs_initialized = false;
/*bool vfs_initialized = false;
ramfs_file_header_t* vfs_current_dir = NULL;
void vfs_init(void)
@ -27,204 +27,4 @@ void vfs_init(void)
}
}
/* ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent); */
FILE create_file(char* filename, char type, char encryption, FILE parent)
{
if (!filename)
{
return -1;
}
if (parent == -128)
{
parent = vfs_current_dir->fd;
}
ramfs_file_header_t* file = ramfs_create_file(filename, type, encryption, ramfs_resolve_fd(parent));
if (!file)
{
return -4; /* error code for failed creation */
}
return file->fd;
}
int32_t delete_file(FILE file)
{
/*
XXX WARNING: ANY AND ALL PROCESSES CAN DELETE A FILE VIA THIS INTERFACE!!! XXX
XXX THIS MUST BE PACHED SOON!!! OR AT LEAST ADD PERMISSION CHECKING IN THE SYSCALL INTERFACE XXX
XXX OR IN THE C LIBRARIES!!! XXX
*/
if (file < 1)
{
return -4;
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
return ramfs_delete_file(_file);
}
/*
Open a file based on a string.
Return a file descriptor on success, a negative value on failure.
return values:
(positive non-zero value) - File descriptor
-1 - Insufficient permissions to open file
-2 - File does not exist ( or at least, File not found. )
-3 - No filesystem is initialized
-4 - Internal error, perhaps try again
*/
FILE open_file(char* filename)
{
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_path(filename);
if (!_file)
{
return (FILE)-2;
}
return (FILE)_file->fd;
}
return (FILE)-3;
}
FILE write_file(FILE file, void* data, size_t len)
{
if (file < 1 || !data || len == 0)
{
return file;
}
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file)
{
return -4;
}
if (_file->type == RAMFS_FILE_DIR)
{
return -1;
}
if (_file->data_begin)
{
free(_file->data_begin);
_file->data_begin = NULL;
_file->data_end = NULL;
}
void* new_buf = malloc(len);
if (!new_buf)
{
return -2;
}
memcpy(new_buf, data, len);
_file->data_begin = new_buf;
_file->data_end = (void*)((uint8_t*)new_buf + len);
return file;
}
return -3;
}
int32_t read_file(FILE file, void* buf, size_t buflen)
{
if (file < 1 || !buf || buflen == 0)
{
return -1; /* Invalid arguments */
}
if (ramfs_get_initialized() && vfs_initialized)
{
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file || _file->type == RAMFS_FILE_DIR)
{
return -2; /* Not a file or trying to read a directory */
}
if (!_file->data_begin || !_file->data_end)
{
return 0; /* Empty file */
}
size_t total_len = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
if (_file->read_offset >= (int32_t)total_len)
{
return 0; /* End of file */
}
size_t available = total_len - _file->read_offset;
size_t to_copy = (buflen < available) ? buflen : available;
memcpy(buf, (uint8_t*)_file->data_begin + _file->read_offset, to_copy);
_file->read_offset += to_copy;
return (int32_t)to_copy;
}
return -3; /* FS not initialized */
}
int32_t reset_read_offset(FILE file)
{
if (file < 1)
{
return -1;
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file)
{
return -2;
}
_file->read_offset = 0;
return 0;
}
int32_t seek_file(FILE file, int32_t offset)
{
if (file < 0 && file != -32 && file != -33)
{
return -1; /* Invalid file descriptor */
}
ramfs_file_header_t* _file = ramfs_resolve_fd_dir(vfs_current_dir, file);
if (!_file || _file->type == RAMFS_FILE_DIR)
return -2; // Invalid file or directory
if (!_file->data_begin || !_file->data_end)
return -3; // Empty file
size_t file_size = (size_t)((uint8_t*)_file->data_end - (uint8_t*)_file->data_begin);
if (offset < 0 || (size_t)offset > file_size)
return -4; // Offset out of bounds
_file->read_offset = offset;
return 0; // Success
}