349 lines
6.4 KiB
C
349 lines
6.4 KiB
C
#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);
|
|
}
|