Files
Espresso/drivers/fs/ramfs.c

349 lines
6.4 KiB
C
Raw Permalink Normal View History

2025-06-17 15:50:07 -05:00
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fs/ramfs.h>
static ramfs_file_header_t* ramfs_root = NULL;
static int32_t ramfs_num_files = 0;
static int32_t next_fd = 2;
bool ramfs_initialized = false;
void ramfs_init(void)
{
if (!ramfs_initialized)
{
/*printf("%i\n", (int32_t)sizeof(ramfs_file_header_t));*/
ramfs_initialized = true;
}
}
ramfs_file_header_t* ramfs_make_root(void)
{
ramfs_root = (ramfs_file_header_t*)malloc(sizeof(ramfs_file_header_t));
if (!ramfs_root)
{
printf("RAMFS: Error: malloc failed on attempt to malloc ramfs_root\n");
return NULL;
}
strcpy(ramfs_root->filename, "/");
ramfs_root->type = RAMFS_FILE_DIR;
ramfs_root->encryption = RAMFS_ENCR_NONE;
ramfs_root->content = NULL;
ramfs_root->parent = NULL;
ramfs_root->next = NULL;
ramfs_root->link_target = NULL;
ramfs_root->fd = 0;
return ramfs_root;
}
ramfs_file_header_t* ramfs_get_root(void)
{
if (!ramfs_root)
{
return NULL;
}
return ramfs_root;
}
int32_t ramfs_get_files(void)
{
return ramfs_num_files;
}
bool ramfs_get_initialized(void)
{
return ramfs_initialized;
}
ramfs_file_header_t* ramfs_create_file(char* name, char type, char encryption, ramfs_file_header_t* parent)
{
if (!parent)
{
return NULL;
}
if ((strlen(name) + 1) > RAMFS_FILENAME_LEN)
{
return NULL;
}
ramfs_file_header_t* _file = (ramfs_file_header_t*)malloc(sizeof(ramfs_file_header_t));
if (!_file)
{
printf("RAMFS: Error: malloc failed on attempt to malloc _file (in ramfs_create_file)\n");
return NULL;
}
strcpy(_file->filename, name);
_file->type = type;
_file->encryption = encryption;
_file->content = NULL;
_file->parent = parent;
_file->next = NULL;
_file->link_target = NULL;
_file->fd = (next_fd - 1);
_file->data_begin = (void*)0x0;
_file->data_end = (void*)0x0;
if (parent->content != NULL)
{
ramfs_file_header_t* current = parent->content;
/* Traverse to the end of the linked list */
while (current->next != NULL)
{
current = current->next;
}
/* Append the new file at the end */
current->next = _file;
}
else
{
/* If no content yet, this is the first child */
parent->content = _file;
}
ramfs_num_files++;
next_fd++;
return _file;
}
ramfs_file_header_t* ramfs_write_file(ramfs_file_header_t* file, void* data, size_t len)
{
if (!file || !data || !len || file->type == RAMFS_FILE_DIR)
{
return NULL;
}
/* Free existing data */
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 NULL;
}
memcpy(new_buf, data, len);
file->data_begin = new_buf;
file->data_end = (uint8_t*)new_buf + len;
return file;
}
int32_t ramfs_read_file(ramfs_file_header_t* file, void* buffer, size_t buffer_len)
{
if (!file)
{
return -1;
}
if (!buffer)
{
return -2;
}
if (file->type == RAMFS_FILE_DIR)
{
return -3;
}
if (!file->data_begin || !file->data_end)
{
return -4; /* No data to read */
}
size_t data_len = (size_t)((char*)file->data_end - (char*)file->data_begin);
if (buffer_len < data_len)
{
return -5; /* Buffer too small */
}
memcpy(buffer, file->data_begin, data_len);
return (int32_t)data_len; /* return number of bytes copied */
}
int32_t ramfs_delete_file(ramfs_file_header_t* file)
{
if (!file)
{
return -1;
}
if (!file->parent)
{
return -2; /* Don't delete the root or orphaned files */
}
ramfs_file_header_t* parent = file->parent;
ramfs_file_header_t* current = parent->content;
ramfs_file_header_t* prev = NULL;
/* Find the file in the linked list */
while (current && current != file)
{
prev = current;
current = current->next;
}
if (!current)
{
return -3; /* File not found in parent's content list */
}
/* Unlink the file from the list */
if (prev)
{
prev->next = current->next;
}
else
{
parent->content = current->next;
}
/* Recursively delete content if it's a directory */
if (file->type == RAMFS_FILE_DIR && file->content)
{
ramfs_file_header_t* child = file->content;
while (child)
{
ramfs_file_header_t* next_child = child->next;
ramfs_delete_file(child);
child = next_child;
}
}
/* Free file data if applicable */
if ((file->type == RAMFS_FILE_TEXT || file->type == RAMFS_FILE_BINARY) && file->data_begin)
{
free(file->data_begin);
}
/* Free the file header itself */
free(file);
next_fd--;
return 0;
}
ramfs_file_header_t* ramfs_resolve_path(const char* path)
{
if (!path || !ramfs_get_root())
{
return NULL;
}
ramfs_file_header_t* current;
/* Start from root if absolute path */
if (path[0] == '/')
{
current = ramfs_get_root();
path++;
}
else
{
/* TODO: make a ramfs_get_cwd and use it instead */
current = ramfs_get_root();
}
char* path_copy = strdup(path);
if (!path_copy)
{
return NULL;
}
char* token = strtok(path_copy, "/");
while (token && current)
{
if (strcmp(token, ".") == 0)
{
/* Stay in the same directory */
}
else if (strcmp(token, "..") == 0)
{
if (current->parent)
{
current = current->parent;
}
}
else
{
/* Traverse to matching child */
ramfs_file_header_t* child = current->content;
current = NULL;
while (child)
{
if (strcmp(child->filename, token) == 0)
{
current = child;
break;
}
child = child->next;
}
if (!current)
{
/* Not found */
break;
}
}
token = strtok(NULL, "/");
}
free(path_copy);
return current; /* NULL if not found or invalid path */
}
ramfs_file_header_t* ramfs_resolve_fd_dir(ramfs_file_header_t* current, int32_t fd)
{
if (!current)
{
return NULL;
}
if (current->fd == fd)
{
return current;
}
ramfs_file_header_t* found = ramfs_resolve_fd_dir(current->content, fd);
if (found)
{
return found;
}
return ramfs_resolve_fd_dir(current->next, fd);
}
ramfs_file_header_t* ramfs_resolve_fd(int32_t fd)
{
return ramfs_resolve_fd_dir(ramfs_root, fd);
}