]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
refactor: remove /disk/ VFS bypass from syscall.c — route through VFS mount + callbacks
authorTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 00:43:13 +0000 (21:43 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 02:44:55 +0000 (23:44 -0300)
- fs.h: add create/mkdir/unlink/rmdir/rename/truncate callbacks to fs_node_t
- fs.h: add vfs_lookup_parent, vfs_create, vfs_mkdir, vfs_unlink, vfs_rmdir,
  vfs_rename, vfs_truncate prototypes
- fs.c: implement vfs_lookup_parent (split path into parent dir + basename)
  and all VFS mutation wrappers that resolve mount points transparently
- diskfs.c: implement VFS callback wrappers (diskfs_vfs_create, diskfs_vfs_mkdir,
  diskfs_vfs_unlink, diskfs_vfs_rmdir, diskfs_vfs_rename, diskfs_vfs_truncate)
  using parent diskfs_node ino for correct hierarchy scoping
- diskfs.c: wire callbacks into root and subdirectory nodes via diskfs_set_dir_ops
- syscall.c: open/mkdir/unlink/rmdir/rename now use generic VFS functions
  instead of hardcoded path[0]==/ && path[1]==d... checks
- syscall.c: remove #include diskfs.h (only diskfs_link extern remains)

Any filesystem mounted via vfs_mount that implements these callbacks will
now transparently support file creation, directory operations, and rename
without requiring syscall.c modifications.

include/fs.h
src/kernel/diskfs.c
src/kernel/fs.c
src/kernel/syscall.c

index 96fe567ce6e490e8ab307a690e3f8315d73d956c..5f094c7a312fe5c121d84a9f0133d1e0c19f27c3 100644 (file)
@@ -29,6 +29,15 @@ typedef struct fs_node {
     int (*readdir)(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len);
     int (*ioctl)(struct fs_node* node, uint32_t cmd, void* arg);
     uintptr_t (*mmap)(struct fs_node* node, uintptr_t addr, uint32_t length, uint32_t prot, uint32_t offset);
+
+    // Directory mutation operations (called on the parent directory node)
+    int (*create)(struct fs_node* dir, const char* name, uint32_t flags, struct fs_node** out);
+    int (*mkdir)(struct fs_node* dir, const char* name);
+    int (*unlink)(struct fs_node* dir, const char* name);
+    int (*rmdir)(struct fs_node* dir, const char* name);
+    int (*rename)(struct fs_node* old_dir, const char* old_name,
+                  struct fs_node* new_dir, const char* new_name);
+    int (*truncate)(struct fs_node* node, uint32_t length);
 } fs_node_t;
 
 struct vfs_dirent {
@@ -46,6 +55,17 @@ void vfs_close(fs_node_t* node);
 
 fs_node_t* vfs_lookup(const char* path);
 
+// Resolve path to (parent_dir, basename).  Returns parent node or NULL.
+fs_node_t* vfs_lookup_parent(const char* path, char* name_out, size_t name_sz);
+
+// Directory mutation wrappers — route through mount points transparently
+int vfs_create(const char* path, uint32_t flags, fs_node_t** out);
+int vfs_mkdir(const char* path);
+int vfs_unlink(const char* path);
+int vfs_rmdir(const char* path);
+int vfs_rename(const char* old_path, const char* new_path);
+int vfs_truncate(const char* path, uint32_t length);
+
 int vfs_mount(const char* mountpoint, fs_node_t* root);
 
 // Global root of the filesystem
index 90ec0c2d368d29082b8f91f860d9e7add436dcd9..1921997c4ad5769f63d51052ec8fc58448edf0e8 100644 (file)
@@ -457,6 +457,9 @@ static int diskfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void
     return (int)(nents * (uint32_t)sizeof(struct vfs_dirent));
 }
 
+static void diskfs_set_dir_ops(fs_node_t* vfs);
+static int diskfs_vfs_truncate(struct fs_node* node, uint32_t length);
+
 static struct fs_node* diskfs_root_finddir(struct fs_node* node, const char* name) {
     struct diskfs_node* parent = (struct diskfs_node*)node;
     if (!g_ready) return 0;
@@ -491,11 +494,13 @@ static struct fs_node* diskfs_root_finddir(struct fs_node* node, const char* nam
         dn->vfs.write = 0;
         dn->vfs.finddir = &diskfs_root_finddir;
         dn->vfs.readdir = &diskfs_readdir_impl;
+        diskfs_set_dir_ops(&dn->vfs);
     } else {
         dn->vfs.flags = FS_FILE;
         dn->vfs.length = sb.inodes[cino].size_bytes;
         dn->vfs.read = &diskfs_read_impl;
         dn->vfs.write = &diskfs_write_impl;
+        dn->vfs.truncate = &diskfs_vfs_truncate;
         dn->vfs.finddir = 0;
     }
 
@@ -806,6 +811,205 @@ int diskfs_getdents(uint16_t dir_ino, uint32_t* inout_index, void* out, uint32_t
     return (int)(written * (uint32_t)sizeof(struct diskfs_kdirent));
 }
 
+/* ---- VFS callback wrappers ---- */
+
+static int diskfs_vfs_create(struct fs_node* dir, const char* name, uint32_t flags, struct fs_node** out) {
+    if (!dir || !name || !out) return -EINVAL;
+    *out = 0;
+    if (!g_ready) return -ENODEV;
+
+    struct diskfs_node* parent = (struct diskfs_node*)dir;
+    uint16_t parent_ino = parent->ino;
+
+    struct diskfs_super sb;
+    if (diskfs_super_load(&sb) < 0) return -EIO;
+    if (parent_ino >= DISKFS_MAX_INODES) return -EIO;
+    if (sb.inodes[parent_ino].type != DISKFS_INODE_DIR) return -ENOTDIR;
+
+    /* Check if it already exists */
+    int existing = diskfs_find_child(&sb, parent_ino, name);
+    if (existing >= 0) {
+        uint16_t ino = (uint16_t)existing;
+        if (sb.inodes[ino].type != DISKFS_INODE_FILE) return -EISDIR;
+
+        if ((flags & 0x200U) != 0U) { /* O_TRUNC */
+            sb.inodes[ino].size_bytes = 0;
+            if (diskfs_super_store(&sb) < 0) return -EIO;
+        }
+
+        struct diskfs_node* dn = (struct diskfs_node*)kmalloc(sizeof(*dn));
+        if (!dn) return -ENOMEM;
+        memset(dn, 0, sizeof(*dn));
+        diskfs_strlcpy(dn->vfs.name, name, sizeof(dn->vfs.name));
+        dn->vfs.flags = FS_FILE;
+        dn->vfs.inode = 100 + (uint32_t)ino;
+        dn->vfs.length = sb.inodes[ino].size_bytes;
+        dn->vfs.read = &diskfs_read_impl;
+        dn->vfs.write = &diskfs_write_impl;
+        dn->vfs.close = &diskfs_close_impl;
+        dn->ino = ino;
+        *out = &dn->vfs;
+        return 0;
+    }
+
+    /* Create new file */
+    if ((flags & 0x40U) == 0U) return -ENOENT; /* O_CREAT not set */
+
+    uint16_t new_ino = 0;
+    int rc = diskfs_alloc_inode_file(&sb, parent_ino, name, DISKFS_DEFAULT_CAP_SECTORS, &new_ino);
+    if (rc < 0) return rc;
+    if (diskfs_super_store(&sb) < 0) return -EIO;
+
+    struct diskfs_node* dn = (struct diskfs_node*)kmalloc(sizeof(*dn));
+    if (!dn) return -ENOMEM;
+    memset(dn, 0, sizeof(*dn));
+    diskfs_strlcpy(dn->vfs.name, name, sizeof(dn->vfs.name));
+    dn->vfs.flags = FS_FILE;
+    dn->vfs.inode = 100 + (uint32_t)new_ino;
+    dn->vfs.length = 0;
+    dn->vfs.read = &diskfs_read_impl;
+    dn->vfs.write = &diskfs_write_impl;
+    dn->vfs.close = &diskfs_close_impl;
+    dn->ino = new_ino;
+    *out = &dn->vfs;
+    return 0;
+}
+
+static int diskfs_vfs_mkdir(struct fs_node* dir, const char* name) {
+    if (!dir || !name || name[0] == 0) return -EINVAL;
+    if (!g_ready) return -ENODEV;
+
+    struct diskfs_node* parent = (struct diskfs_node*)dir;
+    uint16_t parent_ino = parent->ino;
+
+    struct diskfs_super sb;
+    if (diskfs_super_load(&sb) < 0) return -EIO;
+    if (parent_ino >= DISKFS_MAX_INODES) return -EIO;
+    if (sb.inodes[parent_ino].type != DISKFS_INODE_DIR) return -ENOTDIR;
+
+    if (diskfs_find_child(&sb, parent_ino, name) >= 0) return -EEXIST;
+
+    for (uint16_t i = 1; i < DISKFS_MAX_INODES; i++) {
+        if (sb.inodes[i].type != DISKFS_INODE_FREE) continue;
+        sb.inodes[i].type = DISKFS_INODE_DIR;
+        sb.inodes[i].parent = parent_ino;
+        memset(sb.inodes[i].name, 0, sizeof(sb.inodes[i].name));
+        diskfs_strlcpy(sb.inodes[i].name, name, sizeof(sb.inodes[i].name));
+        sb.inodes[i].start_lba = 0;
+        sb.inodes[i].size_bytes = 0;
+        sb.inodes[i].cap_sectors = 0;
+        return diskfs_super_store(&sb);
+    }
+
+    return -ENOSPC;
+}
+
+static int diskfs_vfs_unlink(struct fs_node* dir, const char* name) {
+    if (!dir || !name || name[0] == 0) return -EINVAL;
+    if (!g_ready) return -ENODEV;
+
+    struct diskfs_node* parent = (struct diskfs_node*)dir;
+    uint16_t parent_ino = parent->ino;
+
+    struct diskfs_super sb;
+    if (diskfs_super_load(&sb) < 0) return -EIO;
+
+    int child = diskfs_find_child(&sb, parent_ino, name);
+    if (child < 0) return -ENOENT;
+    uint16_t ino = (uint16_t)child;
+    if (ino == 0) return -EPERM;
+
+    if (sb.inodes[ino].type == DISKFS_INODE_DIR) return -EISDIR;
+    if (sb.inodes[ino].type != DISKFS_INODE_FILE) return -ENOENT;
+
+    memset(&sb.inodes[ino], 0, sizeof(sb.inodes[ino]));
+    return diskfs_super_store(&sb);
+}
+
+static int diskfs_vfs_rmdir(struct fs_node* dir, const char* name) {
+    if (!dir || !name || name[0] == 0) return -EINVAL;
+    if (!g_ready) return -ENODEV;
+
+    struct diskfs_node* parent = (struct diskfs_node*)dir;
+    uint16_t parent_ino = parent->ino;
+
+    struct diskfs_super sb;
+    if (diskfs_super_load(&sb) < 0) return -EIO;
+
+    int child = diskfs_find_child(&sb, parent_ino, name);
+    if (child < 0) return -ENOENT;
+    uint16_t ino = (uint16_t)child;
+    if (ino == 0) return -EPERM;
+    if (sb.inodes[ino].type != DISKFS_INODE_DIR) return -ENOTDIR;
+
+    /* Check directory is empty */
+    for (uint16_t i = 0; i < DISKFS_MAX_INODES; i++) {
+        if (sb.inodes[i].type == DISKFS_INODE_FREE) continue;
+        if (sb.inodes[i].parent == ino && i != ino) return -ENOTEMPTY;
+    }
+
+    memset(&sb.inodes[ino], 0, sizeof(sb.inodes[ino]));
+    return diskfs_super_store(&sb);
+}
+
+static int diskfs_vfs_rename(struct fs_node* old_dir, const char* old_name,
+                              struct fs_node* new_dir, const char* new_name) {
+    if (!old_dir || !old_name || !new_dir || !new_name) return -EINVAL;
+    if (!g_ready) return -ENODEV;
+
+    struct diskfs_node* odir = (struct diskfs_node*)old_dir;
+    struct diskfs_node* ndir = (struct diskfs_node*)new_dir;
+
+    struct diskfs_super sb;
+    if (diskfs_super_load(&sb) < 0) return -EIO;
+
+    int src = diskfs_find_child(&sb, odir->ino, old_name);
+    if (src < 0) return -ENOENT;
+    uint16_t src_ino = (uint16_t)src;
+    if (src_ino == 0) return -EPERM;
+
+    /* Check if destination exists */
+    int dst = diskfs_find_child(&sb, ndir->ino, new_name);
+    if (dst >= 0) {
+        uint16_t dst_ino = (uint16_t)dst;
+        if (sb.inodes[dst_ino].type != sb.inodes[src_ino].type) return -EINVAL;
+        if (dst_ino == src_ino) return 0;
+        memset(&sb.inodes[dst_ino], 0, sizeof(sb.inodes[dst_ino]));
+    }
+
+    sb.inodes[src_ino].parent = ndir->ino;
+    memset(sb.inodes[src_ino].name, 0, sizeof(sb.inodes[src_ino].name));
+    diskfs_strlcpy(sb.inodes[src_ino].name, new_name, sizeof(sb.inodes[src_ino].name));
+
+    return diskfs_super_store(&sb);
+}
+
+static int diskfs_vfs_truncate(struct fs_node* node, uint32_t length) {
+    if (!node) return -EINVAL;
+    if (!g_ready) return -ENODEV;
+
+    struct diskfs_node* dn = (struct diskfs_node*)node;
+    struct diskfs_super sb;
+    if (diskfs_super_load(&sb) < 0) return -EIO;
+    if (dn->ino >= DISKFS_MAX_INODES) return -EIO;
+    if (sb.inodes[dn->ino].type != DISKFS_INODE_FILE) return -EISDIR;
+
+    if (length < sb.inodes[dn->ino].size_bytes) {
+        sb.inodes[dn->ino].size_bytes = length;
+    }
+    node->length = sb.inodes[dn->ino].size_bytes;
+    return diskfs_super_store(&sb);
+}
+
+static void diskfs_set_dir_ops(fs_node_t* vfs) {
+    if (!vfs) return;
+    vfs->create = &diskfs_vfs_create;
+    vfs->mkdir = &diskfs_vfs_mkdir;
+    vfs->unlink = &diskfs_vfs_unlink;
+    vfs->rmdir = &diskfs_vfs_rmdir;
+    vfs->rename = &diskfs_vfs_rename;
+}
+
 fs_node_t* diskfs_create_root(void) {
     if (!g_ready) {
         if (ata_pio_init_primary_master() == 0) {
@@ -825,6 +1029,7 @@ fs_node_t* diskfs_create_root(void) {
         g_root.vfs.close = 0;
         g_root.vfs.finddir = &diskfs_root_finddir;
         g_root.vfs.readdir = &diskfs_readdir_impl;
+        diskfs_set_dir_ops(&g_root.vfs);
         g_root.ino = 0;
 
         if (g_ready) {
index b7ec4a9db30f3a62ea6116824702c7b92a4c469b..3ab06fb25f8b45ef9e6ea7cba48cb851a4dd706a 100644 (file)
@@ -153,3 +153,94 @@ static fs_node_t* vfs_lookup_depth(const char* path, int depth) {
 
     return cur;
 }
+
+/* Split path into dirname + basename.  Returns the parent directory node. */
+fs_node_t* vfs_lookup_parent(const char* path, char* name_out, size_t name_sz) {
+    if (!path || !name_out || name_sz == 0) return NULL;
+    name_out[0] = 0;
+
+    /* Find last '/' separator */
+    const char* last_slash = NULL;
+    for (const char* p = path; *p; p++) {
+        if (*p == '/') last_slash = p;
+    }
+
+    if (!last_slash) return NULL; /* no slash = relative, not supported */
+
+    /* Build parent path */
+    char parent_path[128];
+    size_t plen = (size_t)(last_slash - path);
+    if (plen == 0) plen = 1; /* root "/" */
+    if (plen >= sizeof(parent_path)) plen = sizeof(parent_path) - 1;
+    memcpy(parent_path, path, plen);
+    parent_path[plen] = 0;
+
+    /* Extract basename */
+    const char* base = last_slash + 1;
+    size_t blen = strlen(base);
+    if (blen == 0) return NULL; /* trailing slash, no basename */
+    if (blen >= name_sz) blen = name_sz - 1;
+    memcpy(name_out, base, blen);
+    name_out[blen] = 0;
+
+    return vfs_lookup(parent_path);
+}
+
+int vfs_create(const char* path, uint32_t flags, fs_node_t** out) {
+    if (!path || !out) return -EINVAL;
+    char name[128];
+    fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
+    if (!parent) return -ENOENT;
+    if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+    if (!parent->create) return -ENOSYS;
+    return parent->create(parent, name, flags, out);
+}
+
+int vfs_mkdir(const char* path) {
+    if (!path) return -EINVAL;
+    char name[128];
+    fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
+    if (!parent) return -ENOENT;
+    if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+    if (!parent->mkdir) return -ENOSYS;
+    return parent->mkdir(parent, name);
+}
+
+int vfs_unlink(const char* path) {
+    if (!path) return -EINVAL;
+    char name[128];
+    fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
+    if (!parent) return -ENOENT;
+    if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+    if (!parent->unlink) return -ENOSYS;
+    return parent->unlink(parent, name);
+}
+
+int vfs_rmdir(const char* path) {
+    if (!path) return -EINVAL;
+    char name[128];
+    fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
+    if (!parent) return -ENOENT;
+    if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+    if (!parent->rmdir) return -ENOSYS;
+    return parent->rmdir(parent, name);
+}
+
+int vfs_rename(const char* old_path, const char* new_path) {
+    if (!old_path || !new_path) return -EINVAL;
+    char old_name[128], new_name[128];
+    fs_node_t* old_parent = vfs_lookup_parent(old_path, old_name, sizeof(old_name));
+    fs_node_t* new_parent = vfs_lookup_parent(new_path, new_name, sizeof(new_name));
+    if (!old_parent || !new_parent) return -ENOENT;
+    if (!old_parent->rename) return -ENOSYS;
+    return old_parent->rename(old_parent, old_name, new_parent, new_name);
+}
+
+int vfs_truncate(const char* path, uint32_t length) {
+    if (!path) return -EINVAL;
+    fs_node_t* node = vfs_lookup(path);
+    if (!node) return -ENOENT;
+    if (node->flags != FS_FILE) return -EISDIR;
+    if (!node->truncate) return -ENOSYS;
+    return node->truncate(node, length);
+}
index a2aa41e1a306efc157f934955aafeaf3546f2d03..c7b613223f8a027996eea9f8983812fd43ae92e6 100644 (file)
@@ -10,7 +10,6 @@
 #include "heap.h"
 #include "tty.h"
 #include "pty.h"
-#include "diskfs.h"
 #include "tmpfs.h"
 
 #include "errno.h"
@@ -908,22 +907,19 @@ static int syscall_open_impl(const char* user_path, uint32_t flags) {
     int prc = path_resolve_user(user_path, path, sizeof(path));
     if (prc < 0) return prc;
 
-    fs_node_t* node = NULL;
-    if (path[0] == '/' && path[1] == 'd' && path[2] == 'i' && path[3] == 's' && path[4] == 'k' && path[5] == '/') {
-        // With hierarchical diskfs, /disk may contain directories.
-        // Use diskfs_open_file only when creation/truncation is requested.
-        if ((flags & 0x40U) != 0U || (flags & 0x200U) != 0U) {
-            const char* rel = path + 6;
-            if (rel[0] == 0) return -ENOENT;
-            int rc = diskfs_open_file(rel, flags, &node);
-            if (rc < 0) return rc;
-        } else {
-            node = vfs_lookup(path);
-            if (!node) return -ENOENT;
+    fs_node_t* node = vfs_lookup(path);
+    if (!node && (flags & 0x40U) != 0U) {
+        /* O_CREAT: create file through VFS */
+        int rc = vfs_create(path, flags, &node);
+        if (rc < 0) return rc;
+    } else if (!node) {
+        return -ENOENT;
+    } else if ((flags & 0x200U) != 0U && node->flags == FS_FILE) {
+        /* O_TRUNC on existing file */
+        if (node->truncate) {
+            node->truncate(node, 0);
+            node->length = 0;
         }
-    } else {
-        node = vfs_lookup(path);
-        if (!node) return -ENOENT;
     }
 
     /* Permission check based on open flags */
@@ -1142,13 +1138,7 @@ static int syscall_mkdir_impl(const char* user_path) {
     int prc = path_resolve_user(user_path, path, sizeof(path));
     if (prc < 0) return prc;
 
-    if (path[0] == '/' && path[1] == 'd' && path[2] == 'i' && path[3] == 's' && path[4] == 'k' && path[5] == '/') {
-        const char* rel = path + 6;
-        if (rel[0] == 0) return -EINVAL;
-        return diskfs_mkdir(rel);
-    }
-
-    return -ENOSYS;
+    return vfs_mkdir(path);
 }
 
 static int syscall_getdents_impl(int fd, void* user_buf, uint32_t len) {
@@ -1182,13 +1172,7 @@ static int syscall_unlink_impl(const char* user_path) {
     int prc = path_resolve_user(user_path, path, sizeof(path));
     if (prc < 0) return prc;
 
-    if (path[0] == '/' && path[1] == 'd' && path[2] == 'i' && path[3] == 's' && path[4] == 'k' && path[5] == '/') {
-        const char* rel = path + 6;
-        if (rel[0] == 0) return -EINVAL;
-        return diskfs_unlink(rel);
-    }
-
-    return -ENOSYS;
+    return vfs_unlink(path);
 }
 
 static int syscall_unlinkat_impl(int dirfd, const char* user_path, uint32_t flags) {
@@ -1204,13 +1188,7 @@ static int syscall_rmdir_impl(const char* user_path) {
     int prc = path_resolve_user(user_path, path, sizeof(path));
     if (prc < 0) return prc;
 
-    if (path[0] == '/' && path[1] == 'd' && path[2] == 'i' && path[3] == 's' && path[4] == 'k' && path[5] == '/') {
-        const char* rel = path + 6;
-        if (rel[0] == 0) return -EINVAL;
-        return diskfs_rmdir(rel);
-    }
-
-    return -ENOSYS;
+    return vfs_rmdir(path);
 }
 
 static int syscall_rename_impl(const char* user_old, const char* user_new) {
@@ -1223,16 +1201,7 @@ static int syscall_rename_impl(const char* user_old, const char* user_new) {
     rc = path_resolve_user(user_new, newp, sizeof(newp));
     if (rc < 0) return rc;
 
-    // Both must be under /disk/
-    if (oldp[0] == '/' && oldp[1] == 'd' && oldp[2] == 'i' && oldp[3] == 's' && oldp[4] == 'k' && oldp[5] == '/' &&
-        newp[0] == '/' && newp[1] == 'd' && newp[2] == 'i' && newp[3] == 's' && newp[4] == 'k' && newp[5] == '/') {
-        const char* old_rel = oldp + 6;
-        const char* new_rel = newp + 6;
-        if (old_rel[0] == 0 || new_rel[0] == 0) return -EINVAL;
-        return diskfs_rename(old_rel, new_rel);
-    }
-
-    return -ENOSYS;
+    return vfs_rename(oldp, newp);
 }
 
 static int syscall_read_impl(int fd, void* user_buf, uint32_t len) {