From: Tulio A M Mendes Date: Sat, 7 Feb 2026 22:31:58 +0000 (-0300) Subject: fs: add mounts and basic tmpfs X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=761f873ab708ae8967f5bfbdef75297badce26f9;p=AdrOS.git fs: add mounts and basic tmpfs --- diff --git a/include/fs.h b/include/fs.h index b9c43e0..d03e54d 100644 --- a/include/fs.h +++ b/include/fs.h @@ -31,6 +31,8 @@ void vfs_close(fs_node_t* node); fs_node_t* vfs_lookup(const char* path); +int vfs_mount(const char* mountpoint, fs_node_t* root); + // Global root of the filesystem extern fs_node_t* fs_root; diff --git a/include/tmpfs.h b/include/tmpfs.h new file mode 100644 index 0000000..8a57ec2 --- /dev/null +++ b/include/tmpfs.h @@ -0,0 +1,10 @@ +#ifndef TMPFS_H +#define TMPFS_H + +#include "fs.h" +#include + +fs_node_t* tmpfs_create_root(void); +int tmpfs_add_file(fs_node_t* root_dir, const char* name, const uint8_t* data, uint32_t len); + +#endif diff --git a/src/kernel/fs.c b/src/kernel/fs.c index d3a5fed..7c162b1 100644 --- a/src/kernel/fs.c +++ b/src/kernel/fs.c @@ -4,6 +4,70 @@ fs_node_t* fs_root = NULL; +struct vfs_mount { + char mountpoint[128]; + fs_node_t* root; +}; + +static struct vfs_mount g_mounts[8]; +static int g_mount_count = 0; + +static int path_is_mountpoint_prefix(const char* mp, const char* path) { + size_t mpl = strlen(mp); + if (mpl == 0) return 0; + if (strcmp(mp, "/") == 0) return 1; + + if (strncmp(path, mp, mpl) != 0) return 0; + if (path[mpl] == 0) return 1; + if (path[mpl] == '/') return 1; + return 0; +} + +static void normalize_mountpoint(const char* in, char* out, size_t out_sz) { + if (!out || out_sz == 0) return; + out[0] = 0; + if (!in || in[0] == 0) { + strcpy(out, "/"); + return; + } + + size_t i = 0; + if (in[0] != '/') { + out[i++] = '/'; + } + + for (size_t j = 0; in[j] != 0 && i + 1 < out_sz; j++) { + out[i++] = in[j]; + } + out[i] = 0; + + size_t l = strlen(out); + while (l > 1 && out[l - 1] == '/') { + out[l - 1] = 0; + l--; + } +} + +int vfs_mount(const char* mountpoint, fs_node_t* root) { + if (!root) return -1; + if (g_mount_count >= (int)(sizeof(g_mounts) / sizeof(g_mounts[0]))) return -1; + + char mp[128]; + normalize_mountpoint(mountpoint, mp, sizeof(mp)); + + for (int i = 0; i < g_mount_count; i++) { + if (strcmp(g_mounts[i].mountpoint, mp) == 0) { + g_mounts[i].root = root; + return 0; + } + } + + strcpy(g_mounts[g_mount_count].mountpoint, mp); + g_mounts[g_mount_count].root = root; + g_mount_count++; + return 0; +} + uint32_t vfs_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { if (node->read) return node->read(node, offset, size, buffer); @@ -31,11 +95,33 @@ fs_node_t* vfs_lookup(const char* path) { if (strcmp(path, "/") == 0) return fs_root; - const char* p = path; - while (*p == '/') p++; - if (*p == 0) return fs_root; + const char* start_path = path; + while (*start_path == '/') start_path++; + if (*start_path == 0) return fs_root; + + fs_node_t* base = fs_root; + const char* rel = path; + size_t best_len = 0; + + for (int i = 0; i < g_mount_count; i++) { + const char* mp = g_mounts[i].mountpoint; + if (!mp[0] || !g_mounts[i].root) continue; + + if (path_is_mountpoint_prefix(mp, path)) { + size_t mpl = strlen(mp); + if (mpl >= best_len) { + best_len = mpl; + base = g_mounts[i].root; + rel = path + mpl; + } + } + } + + while (*rel == '/') rel++; + if (*rel == 0) return base; - fs_node_t* cur = fs_root; + const char* p = rel; + fs_node_t* cur = base; char part[128]; while (*p != 0) { diff --git a/src/kernel/init.c b/src/kernel/init.c index 8047268..8b96d85 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -4,6 +4,7 @@ #include "fs.h" #include "initrd.h" +#include "tmpfs.h" #include "tty.h" #include "uart_console.h" @@ -42,6 +43,13 @@ int init_start(const struct boot_info* bi) { } } + fs_node_t* tmp = tmpfs_create_root(); + if (tmp) { + static const uint8_t hello[] = "hello from tmpfs\n"; + (void)tmpfs_add_file(tmp, "hello.txt", hello, (uint32_t)(sizeof(hello) - 1)); + (void)vfs_mount("/tmp", tmp); + } + tty_init(); int user_ret = arch_platform_start_userspace(bi); diff --git a/src/kernel/tmpfs.c b/src/kernel/tmpfs.c new file mode 100644 index 0000000..c1219fb --- /dev/null +++ b/src/kernel/tmpfs.c @@ -0,0 +1,147 @@ +#include "tmpfs.h" + +#include "heap.h" +#include "utils.h" + +struct tmpfs_node { + fs_node_t vfs; + struct tmpfs_node* parent; + struct tmpfs_node* first_child; + struct tmpfs_node* next_sibling; + + uint8_t* data; + uint32_t cap; +}; + +static uint32_t g_tmpfs_next_inode = 1; + +static struct tmpfs_node* tmpfs_node_alloc(const char* name, uint32_t flags) { + struct tmpfs_node* n = (struct tmpfs_node*)kmalloc(sizeof(*n)); + if (!n) return NULL; + memset(n, 0, sizeof(*n)); + + if (name) { + strcpy(n->vfs.name, name); + } else { + n->vfs.name[0] = 0; + } + + n->vfs.flags = flags; + n->vfs.inode = g_tmpfs_next_inode++; + n->vfs.length = 0; + + return n; +} + +static struct tmpfs_node* tmpfs_child_find(struct tmpfs_node* dir, const char* name) { + if (!dir || !name) return NULL; + struct tmpfs_node* c = dir->first_child; + while (c) { + if (strcmp(c->vfs.name, name) == 0) return c; + c = c->next_sibling; + } + return NULL; +} + +static void tmpfs_child_add(struct tmpfs_node* dir, struct tmpfs_node* child) { + child->parent = dir; + child->next_sibling = dir->first_child; + dir->first_child = child; +} + +static uint32_t tmpfs_read_impl(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + if (!node || !buffer) return 0; + if (node->flags != FS_FILE) return 0; + + struct tmpfs_node* tn = (struct tmpfs_node*)node; + if (offset > tn->vfs.length) return 0; + if (offset + size > tn->vfs.length) size = tn->vfs.length - offset; + + if (size == 0) return 0; + memcpy(buffer, tn->data + offset, size); + return size; +} + +static uint32_t tmpfs_write_impl(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + if (!node || !buffer) return 0; + if (node->flags != FS_FILE) return 0; + + struct tmpfs_node* tn = (struct tmpfs_node*)node; + uint64_t end = (uint64_t)offset + (uint64_t)size; + if (end > 0xFFFFFFFFULL) return 0; + + if ((uint32_t)end > tn->cap) { + uint32_t new_cap = tn->cap ? tn->cap : 64; + while (new_cap < (uint32_t)end) { + new_cap *= 2; + } + + uint8_t* new_data = (uint8_t*)kmalloc(new_cap); + if (!new_data) return 0; + memset(new_data, 0, new_cap); + if (tn->data && tn->vfs.length) { + memcpy(new_data, tn->data, tn->vfs.length); + } + if (tn->data) kfree(tn->data); + tn->data = new_data; + tn->cap = new_cap; + } + + memcpy(tn->data + offset, buffer, size); + if ((uint32_t)end > tn->vfs.length) tn->vfs.length = (uint32_t)end; + return size; +} + +static struct fs_node* tmpfs_finddir_impl(struct fs_node* node, char* name) { + if (!node || !name) return 0; + if (node->flags != FS_DIRECTORY) return 0; + + struct tmpfs_node* dir = (struct tmpfs_node*)node; + struct tmpfs_node* child = tmpfs_child_find(dir, name); + if (!child) return 0; + return &child->vfs; +} + +fs_node_t* tmpfs_create_root(void) { + struct tmpfs_node* root = tmpfs_node_alloc("", FS_DIRECTORY); + if (!root) return NULL; + + root->vfs.read = 0; + root->vfs.write = 0; + root->vfs.open = 0; + root->vfs.close = 0; + root->vfs.finddir = &tmpfs_finddir_impl; + + return &root->vfs; +} + +int tmpfs_add_file(fs_node_t* root_dir, const char* name, const uint8_t* data, uint32_t len) { + if (!root_dir || root_dir->flags != FS_DIRECTORY) return -1; + if (!name || name[0] == 0) return -1; + + struct tmpfs_node* dir = (struct tmpfs_node*)root_dir; + if (tmpfs_child_find(dir, name)) return -1; + + struct tmpfs_node* f = tmpfs_node_alloc(name, FS_FILE); + if (!f) return -1; + + f->vfs.read = &tmpfs_read_impl; + f->vfs.write = &tmpfs_write_impl; + f->vfs.open = 0; + f->vfs.close = 0; + f->vfs.finddir = 0; + + if (len) { + f->data = (uint8_t*)kmalloc(len); + if (!f->data) { + kfree(f); + return -1; + } + memcpy(f->data, data, len); + f->cap = len; + f->vfs.length = len; + } + + tmpfs_child_add(dir, f); + return 0; +}