Espresso 0.0.2c
This commit is contained in:
49
drivers/fs/ekfs.c
Normal file
49
drivers/fs/ekfs.c
Normal file
@ -0,0 +1,49 @@
|
||||
#include <types.h>
|
||||
#include <string.h>
|
||||
#include <drivers/ide.h>
|
||||
|
||||
#include <fs/ekfs.h>
|
||||
|
||||
/* work on this later */
|
||||
#if 0
|
||||
|
||||
/* note: __l being 0 is allowed, because that way read() can be used to tell if a file exists (with return value 0) */
|
||||
int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (!__f || !__b || (!__f->f_inode))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we assume drive 0 is already mounted */
|
||||
|
||||
char buffer[512];
|
||||
memset(buffer, 0, 512);
|
||||
|
||||
int num_sectors = __f->f_inode->i_len / 512;
|
||||
|
||||
if ((__l / 512) > num_sectors)
|
||||
{
|
||||
return EKFS_E_FILETOOSMALL;
|
||||
}
|
||||
|
||||
int read_sectors = num_sectors;
|
||||
|
||||
for (int i = 0; i < read_sectors; i++);
|
||||
{
|
||||
rv = read_sector(__f->f_inode->i_start, buffer);
|
||||
|
||||
if (rv != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
374
drivers/fs/fat16.c
Normal file
374
drivers/fs/fat16.c
Normal file
@ -0,0 +1,374 @@
|
||||
#include <string.h>
|
||||
#include <drivers/ide.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fs/fat16.h>
|
||||
|
||||
/*
|
||||
READ BELOW!!!
|
||||
Before any of you (or me,) use this code, please note that the functions below REQUIRE 8.3 formatted names.
|
||||
in fat16.h there is a helper function for convertion between normal filenames and 8.3 ones. ('filename_to_83', see static implementation in fat16.h)
|
||||
*/
|
||||
|
||||
static fat16_fs_t fs;
|
||||
static uint8_t boot_sector[SECTOR_SIZE];
|
||||
|
||||
int fat16_mount(uint8_t drive)
|
||||
{
|
||||
if (read_sector(0, boot_sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8);
|
||||
fs.sectors_per_cluster = boot_sector[13];
|
||||
fs.reserved_sector_count = boot_sector[14] | (boot_sector[15] << 8);
|
||||
fs.num_fats = boot_sector[16];
|
||||
fs.root_entry_count = boot_sector[17] | (boot_sector[18] << 8);
|
||||
fs.total_sectors_16 = boot_sector[19] | (boot_sector[20] << 8);
|
||||
fs.sectors_per_fat = boot_sector[22] | (boot_sector[23] << 8);
|
||||
fs.total_sectors = fs.total_sectors_16 != 0 ? fs.total_sectors_16 : boot_sector[32] | (boot_sector[33]<<8) | (boot_sector[34]<<16) | (boot_sector[35]<<24);
|
||||
fs.fat_start_lba = fs.reserved_sector_count;
|
||||
fs.root_dir_lba = fs.fat_start_lba + (fs.num_fats * fs.sectors_per_fat);
|
||||
fs.data_start_lba = fs.root_dir_lba + ((fs.root_entry_count * 32 + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t cluster_to_lba(uint16_t cluster)
|
||||
{
|
||||
return fs.data_start_lba + (cluster - 2) * fs.sectors_per_cluster;
|
||||
}
|
||||
|
||||
/* ----------------------- FAT helpers ------------------------- */
|
||||
static int read_fat_entry(uint16_t cluster, uint16_t* out_value)
|
||||
{
|
||||
uint32_t offset = (uint32_t)cluster * 2;
|
||||
uint32_t sector_index = offset / fs.bytes_per_sector;
|
||||
uint32_t idx = offset % fs.bytes_per_sector;
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
if (read_sector(fs.fat_start_lba + sector_index, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (idx == fs.bytes_per_sector - 1)
|
||||
{
|
||||
/* entry spans boundary -> read next sector */
|
||||
uint8_t next_sector[SECTOR_SIZE];
|
||||
|
||||
if (read_sector(fs.fat_start_lba + sector_index + 1, next_sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_value = sector[idx] | (next_sector[0] << 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
*out_value = sector[idx] | (sector[idx + 1] << 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int write_fat_entry(uint16_t cluster, uint16_t value)
|
||||
{
|
||||
uint32_t offset = cluster * 2;
|
||||
uint32_t sector_lba = fs.fat_start_lba + (offset / fs.bytes_per_sector);
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
if (read_sector(sector_lba, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sector[offset % fs.bytes_per_sector] = value & 0xFF;
|
||||
sector[(offset % fs.bytes_per_sector) + 1] = (value >> 8) & 0xFF;
|
||||
|
||||
/* write to all FAT copies */
|
||||
for (uint8_t f = 0; f < fs.num_fats; f++)
|
||||
{
|
||||
if (write_sector(fs.fat_start_lba + f * fs.sectors_per_fat + (offset / fs.bytes_per_sector), sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_free_cluster(uint16_t* out_cluster)
|
||||
{
|
||||
uint16_t total_clusters = (fs.total_sectors - fs.data_start_lba) / fs.sectors_per_cluster;
|
||||
uint16_t value;
|
||||
for (uint16_t c = 2; c < total_clusters; c++)
|
||||
{
|
||||
if (read_fat_entry(c, &value) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value == 0x0000)
|
||||
{
|
||||
*out_cluster = c;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1; /* no free cluster */
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Root directory ------------------------- */
|
||||
static int find_free_root_entry(uint32_t* out_sector, uint32_t* out_offset)
|
||||
{
|
||||
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < root_dir_sectors; i++)
|
||||
{
|
||||
if (read_sector(fs.root_dir_lba + i, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
|
||||
{
|
||||
if (sector[offset] == 0x00 || sector[offset] == 0xE5)
|
||||
{
|
||||
*out_sector = fs.root_dir_lba + i;
|
||||
*out_offset = offset;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -------------------- File operations ----------------------- */
|
||||
int fat16_find_file(const char* name, fat16_file_t* out_file)
|
||||
{
|
||||
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
for (uint32_t i = 0; i < root_dir_sectors; i++)
|
||||
{
|
||||
if (read_sector(fs.root_dir_lba + i, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32)
|
||||
{
|
||||
if (sector[offset] == 0x00)
|
||||
{
|
||||
return -1; /* no more entries */
|
||||
}
|
||||
else if (sector[offset] == 0xE5)
|
||||
{
|
||||
continue; /* deleted entry */
|
||||
}
|
||||
|
||||
if (memcmp(sector + offset, name, 11) == 0)
|
||||
{
|
||||
memcpy(out_file->name, sector + offset, 12);
|
||||
out_file->attr = sector[offset + 11];
|
||||
out_file->first_cluster = sector[offset + 26] | (sector[offset + 27] << 8);
|
||||
out_file->size = sector[offset + 28] | (sector[offset + 29] << 8) | (sector[offset + 30] << 16) | (sector[offset + 31] << 24);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fat16_create_file(const char* name, fat16_file_t* out_file)
|
||||
{
|
||||
uint16_t free_cluster;
|
||||
|
||||
if (find_free_cluster(&free_cluster) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t sector_lba, offset;
|
||||
|
||||
if (find_free_root_entry(§or_lba, &offset) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
|
||||
if (read_sector(sector_lba, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill root entry */
|
||||
memset(sector + offset, ' ', 11);
|
||||
memcpy(sector + offset, name, 11);
|
||||
sector[offset + 11] = 0x20; /* normal file */
|
||||
sector[offset + 26] = free_cluster & 0xFF;
|
||||
sector[offset + 27] = (free_cluster >> 8) & 0xFF;
|
||||
sector[offset + 28] = 0; sector[offset + 29] = 0;
|
||||
sector[offset + 30] = 0; sector[offset + 31] = 0;
|
||||
|
||||
if (write_sector(sector_lba, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* mark cluster as end-of-chain */
|
||||
if (write_fat_entry(free_cluster, 0xFFFF) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (out_file)
|
||||
{
|
||||
memset(out_file, 0, sizeof(fat16_file_t));
|
||||
strncpy(out_file->name, name, 11);
|
||||
out_file->first_cluster = free_cluster;
|
||||
out_file->size = 0;
|
||||
out_file->attr = 0x20;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fat16_write_file(fat16_file_t* file, const void* buffer, uint32_t size) {
|
||||
const uint8_t* buf = (const uint8_t*)buffer;
|
||||
uint32_t bytes_remaining = size;
|
||||
uint16_t cluster = file->first_cluster;
|
||||
|
||||
if (cluster == 0) return -1; /* safety: file must have a cluster */
|
||||
|
||||
while (bytes_remaining > 0) {
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
|
||||
for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++) {
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
memset(sector, 0, SECTOR_SIZE);
|
||||
uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE;
|
||||
memcpy(sector, buf, copy_bytes);
|
||||
if (write_sector(lba + i, sector) != 0) return -1;
|
||||
buf += copy_bytes;
|
||||
bytes_remaining -= copy_bytes;
|
||||
}
|
||||
|
||||
uint16_t next_cluster;
|
||||
if (bytes_remaining > 0) {
|
||||
if (find_free_cluster(&next_cluster) != 0) return -1;
|
||||
if (write_fat_entry(cluster, next_cluster) != 0) return -1;
|
||||
if (write_fat_entry(next_cluster, 0xFFFF) != 0) return -1;
|
||||
cluster = next_cluster;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update file size in root entry (your code already does this on disk) */
|
||||
/* Now update the in-memory struct so subsequent reads use the new size */
|
||||
file->size = size;
|
||||
|
||||
/* optionally: refresh metadata from disk:
|
||||
fat16_find_file(file->name, file); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int fat16_read_file(fat16_file_t* file, void* buffer)
|
||||
{
|
||||
uint8_t sector[SECTOR_SIZE];
|
||||
uint16_t cluster = file->first_cluster;
|
||||
uint32_t bytes_remaining = file->size;
|
||||
uint8_t* buf = (uint8_t*)buffer;
|
||||
|
||||
while (cluster >= 0x0002 && cluster < 0xFFF8)
|
||||
{
|
||||
uint32_t lba = cluster_to_lba(cluster);
|
||||
for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++)
|
||||
{
|
||||
if (read_sector(lba + i, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE;
|
||||
memcpy(buf, sector, copy_bytes);
|
||||
buf += copy_bytes;
|
||||
bytes_remaining -= copy_bytes;
|
||||
}
|
||||
|
||||
/* read next cluster from FAT */
|
||||
uint32_t fat_offset = cluster * 2; /* FAT16 */
|
||||
uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector);
|
||||
uint16_t fat_entry;
|
||||
if (read_sector(fat_sector, sector) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
fat_entry = sector[fat_offset % fs.bytes_per_sector] | (sector[(fat_offset % fs.bytes_per_sector) + 1] << 8);
|
||||
cluster = fat_entry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fat16_delete_file(const char* filename)
|
||||
{
|
||||
uint8_t sector[512];
|
||||
uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector;
|
||||
uint32_t root_dir_start = fs.root_dir_lba;
|
||||
|
||||
for (uint32_t s = 0; s < root_dir_sectors; s++)
|
||||
{
|
||||
if (read_sector(root_dir_start + s, sector) != 0)
|
||||
return -1;
|
||||
|
||||
for (int i = 0; i < fs.bytes_per_sector; i += 32)
|
||||
{
|
||||
uint8_t* entry = §or[i];
|
||||
|
||||
if (entry[0] == 0x00)
|
||||
return -1; // end of directory
|
||||
if (entry[0] == 0xE5)
|
||||
continue; // already deleted
|
||||
|
||||
if (memcmp(entry, filename, 11) == 0)
|
||||
{
|
||||
// Found the file — mark as deleted
|
||||
entry[0] = 0xE5;
|
||||
|
||||
if (write_sector(root_dir_start + s, sector) != 0)
|
||||
return -1;
|
||||
|
||||
// Free FAT chain
|
||||
uint16_t cluster = entry[26] | (entry[27] << 8);
|
||||
while (cluster >= 0x0002 && cluster < 0xFFF8)
|
||||
{
|
||||
uint32_t fat_offset = cluster * 2;
|
||||
uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector);
|
||||
uint32_t ent_offset = fat_offset % fs.bytes_per_sector;
|
||||
|
||||
if (read_sector(fat_sector, sector) != 0)
|
||||
break;
|
||||
|
||||
uint16_t next_cluster = sector[ent_offset] | (sector[ent_offset + 1] << 8);
|
||||
sector[ent_offset] = 0x00;
|
||||
sector[ent_offset + 1] = 0x00;
|
||||
|
||||
if (write_sector(fat_sector, sector) != 0)
|
||||
break;
|
||||
|
||||
cluster = next_cluster;
|
||||
}
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // file not found
|
||||
}
|
||||
|
||||
@ -1,24 +1,76 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tty.h>
|
||||
|
||||
#include <fs/vfs.h>
|
||||
|
||||
/* we use something similar to the Linux kernel in terms of a VFS system */
|
||||
|
||||
typedef struct vfs_file_header {
|
||||
char* filename; /* The filename, not the path. */
|
||||
|
||||
int32_t fd;
|
||||
|
||||
uint8_t type_info; /* Bits 0 - 3 -> File type, Bits 4 - 7 FS type */
|
||||
|
||||
uint16_t* fs_header;
|
||||
|
||||
struct vfs_file_header* next; /* Linked list */
|
||||
} vfs_file_header_t;
|
||||
#define MAX_FDS 64
|
||||
|
||||
struct inode {
|
||||
size_t size;
|
||||
int permissions;
|
||||
void *fs_data; /* FS-specific */
|
||||
};
|
||||
|
||||
struct file_ops {
|
||||
int (*read)(struct file*, char*, size_t);
|
||||
int (*write)(struct file*, const char*, size_t);
|
||||
};
|
||||
|
||||
struct file {
|
||||
struct inode* f_inode;
|
||||
size_t f_offset;
|
||||
size_t f_refcount;
|
||||
const struct file_ops f_ops;
|
||||
};
|
||||
|
||||
|
||||
vfs_file_header_t* root;
|
||||
|
||||
struct fdtable {
|
||||
struct file* fds[MAX_FDS];
|
||||
};
|
||||
|
||||
|
||||
|
||||
int vfs_handle_stdout(struct file* __f, const char* __s, size_t __l)
|
||||
{
|
||||
(void) __f;
|
||||
terminal_write(__s, __l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fdtable* vfs_init_kernel_fdtable(void)
|
||||
{
|
||||
#if 0
|
||||
struct fdtable* ft = malloc(sizeof(struct fdtable));
|
||||
struct file* _stdout = malloc(sizeof(struct file));
|
||||
struct file* _stdin = malloc(sizeof(struct file));
|
||||
|
||||
if (!ft || !_stdin || !_stdout)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_stdout->f_inode = NULL;
|
||||
_stdout->f_offset = 0;
|
||||
_stdout->f_refcount = 1;
|
||||
_stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout };
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int init_vfs(int argc, char** argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -28,5 +80,7 @@ vfs_file_header_t* root;
|
||||
wow.
|
||||
and now my CPU fan is going nuts.
|
||||
|
||||
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia drivers..
|
||||
--update: now it works. I had to go back to nouveau instead of the proprietary nVidia®©™ drivers..
|
||||
|
||||
--update: I wrote what months ago. now is 3/12/2026, I don't even remember what was going on well. wow.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user