]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fs: add mounts and basic tmpfs
authorTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 22:31:58 +0000 (19:31 -0300)
committerTulio A M Mendes <[email protected]>
Sat, 7 Feb 2026 22:31:58 +0000 (19:31 -0300)
include/fs.h
include/tmpfs.h [new file with mode: 0644]
src/kernel/fs.c
src/kernel/init.c
src/kernel/tmpfs.c [new file with mode: 0644]

index b9c43e003f65b694c05261e820625c50acb23aab..d03e54d400647cd57e39c28456f44e605d12d391 100644 (file)
@@ -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 (file)
index 0000000..8a57ec2
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef TMPFS_H
+#define TMPFS_H
+
+#include "fs.h"
+#include <stdint.h>
+
+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
index d3a5fedab68fbc6a66239557e6ed7f89b7b76310..7c162b1cb37f0a7931c9cb2a0213b128649adcd6 100644 (file)
@@ -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) {
index 8047268ec6b55e7a4c0c298ac18c7822e36c5984..8b96d8588fa8fdda96f43aeee6f31638ca54796d 100644 (file)
@@ -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 (file)
index 0000000..c1219fb
--- /dev/null
@@ -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;
+}