From b82be7d8a1fa332f05000aa03881709c3956fd9a Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Thu, 12 Feb 2026 21:43:13 -0300 Subject: [PATCH] =?utf8?q?refactor:=20remove=20/disk/=20VFS=20bypass=20fro?= =?utf8?q?m=20syscall.c=20=E2=80=94=20route=20through=20VFS=20mount=20+=20?= =?utf8?q?callbacks?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - 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 | 20 +++++ src/kernel/diskfs.c | 205 +++++++++++++++++++++++++++++++++++++++++++ src/kernel/fs.c | 91 +++++++++++++++++++ src/kernel/syscall.c | 63 ++++--------- 4 files changed, 332 insertions(+), 47 deletions(-) diff --git a/include/fs.h b/include/fs.h index 96fe567..5f094c7 100644 --- a/include/fs.h +++ b/include/fs.h @@ -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 diff --git a/src/kernel/diskfs.c b/src/kernel/diskfs.c index 90ec0c2..1921997 100644 --- a/src/kernel/diskfs.c +++ b/src/kernel/diskfs.c @@ -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) { diff --git a/src/kernel/fs.c b/src/kernel/fs.c index b7ec4a9..3ab06fb 100644 --- a/src/kernel/fs.c +++ b/src/kernel/fs.c @@ -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); +} diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index a2aa41e..c7b6132 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -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) { -- 2.43.0