]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
refactor: route link() through VFS callback — remove last diskfs bypass from syscall.c
authorTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 00:58:05 +0000 (21:58 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 02:44:55 +0000 (23:44 -0300)
- fs.h: add link callback to fs_node_t (dir, name, target_node)
- fs.c: implement vfs_link() wrapper — resolves old_path to node,
  new_path to parent+basename, calls parent->link()
- diskfs.c: implement diskfs_vfs_link() using parent ino + target ino,
  wire into diskfs_set_dir_ops()
- syscall.c: syscall_link_impl now calls vfs_link() instead of
  extern diskfs_link() with /disk/ prefix stripping

syscall.c no longer references any diskfs symbol.

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

index 5f094c7a312fe5c121d84a9f0133d1e0c19f27c3..afb959533f7b4c4d52a9cc9287380d16acbadb72 100644 (file)
@@ -38,6 +38,7 @@ typedef struct fs_node {
     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);
+    int (*link)(struct fs_node* dir, const char* name, struct fs_node* target);
 } fs_node_t;
 
 struct vfs_dirent {
@@ -65,6 +66,7 @@ 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_link(const char* old_path, const char* new_path);
 
 int vfs_mount(const char* mountpoint, fs_node_t* root);
 
index 1921997c4ad5769f63d51052ec8fc58448edf0e8..4727d9d7480a88664978b7b783f7aee294f0eba5 100644 (file)
@@ -1001,6 +1001,47 @@ static int diskfs_vfs_truncate(struct fs_node* node, uint32_t length) {
     return diskfs_super_store(&sb);
 }
 
+static int diskfs_vfs_link(struct fs_node* dir, const char* name, struct fs_node* target) {
+    if (!dir || !name || name[0] == 0 || !target) return -EINVAL;
+    if (!g_ready) return -ENODEV;
+
+    struct diskfs_node* parent = (struct diskfs_node*)dir;
+    struct diskfs_node* src = (struct diskfs_node*)target;
+
+    struct diskfs_super sb;
+    if (diskfs_super_load(&sb) < 0) return -EIO;
+
+    uint16_t src_ino = src->ino;
+    if (src_ino >= DISKFS_MAX_INODES) return -EIO;
+    if (sb.inodes[src_ino].type != DISKFS_INODE_FILE) return -EPERM;
+
+    /* Check new name doesn't already exist */
+    if (diskfs_find_child(&sb, parent->ino, name) >= 0) return -EEXIST;
+
+    /* Find a free inode slot */
+    uint16_t new_ino = 0;
+    for (uint16_t i = 1; i < DISKFS_MAX_INODES; i++) {
+        if (sb.inodes[i].type == DISKFS_INODE_FREE) { new_ino = i; break; }
+    }
+    if (new_ino == 0) return -ENOSPC;
+
+    /* Create new inode sharing same data blocks */
+    sb.inodes[new_ino].type = DISKFS_INODE_FILE;
+    sb.inodes[new_ino].nlink = 2;
+    sb.inodes[new_ino].parent = parent->ino;
+    memset(sb.inodes[new_ino].name, 0, sizeof(sb.inodes[new_ino].name));
+    diskfs_strlcpy(sb.inodes[new_ino].name, name, sizeof(sb.inodes[new_ino].name));
+    sb.inodes[new_ino].start_lba = sb.inodes[src_ino].start_lba;
+    sb.inodes[new_ino].size_bytes = sb.inodes[src_ino].size_bytes;
+    sb.inodes[new_ino].cap_sectors = sb.inodes[src_ino].cap_sectors;
+
+    /* Update source inode nlink */
+    if (sb.inodes[src_ino].nlink < 2) sb.inodes[src_ino].nlink = 2;
+    else sb.inodes[src_ino].nlink++;
+
+    return diskfs_super_store(&sb);
+}
+
 static void diskfs_set_dir_ops(fs_node_t* vfs) {
     if (!vfs) return;
     vfs->create = &diskfs_vfs_create;
@@ -1008,6 +1049,7 @@ static void diskfs_set_dir_ops(fs_node_t* vfs) {
     vfs->unlink = &diskfs_vfs_unlink;
     vfs->rmdir = &diskfs_vfs_rmdir;
     vfs->rename = &diskfs_vfs_rename;
+    vfs->link = &diskfs_vfs_link;
 }
 
 fs_node_t* diskfs_create_root(void) {
index 3ab06fb25f8b45ef9e6ea7cba48cb851a4dd706a..158b6ea726bbfca3df95dc629f0589028c586333 100644 (file)
@@ -244,3 +244,17 @@ int vfs_truncate(const char* path, uint32_t length) {
     if (!node->truncate) return -ENOSYS;
     return node->truncate(node, length);
 }
+
+int vfs_link(const char* old_path, const char* new_path) {
+    if (!old_path || !new_path) return -EINVAL;
+    fs_node_t* target = vfs_lookup(old_path);
+    if (!target) return -ENOENT;
+    if (target->flags != FS_FILE) return -EPERM;
+
+    char name[128];
+    fs_node_t* parent = vfs_lookup_parent(new_path, name, sizeof(name));
+    if (!parent) return -ENOENT;
+    if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+    if (!parent->link) return -ENOSYS;
+    return parent->link(parent, name, target);
+}
index c7b613223f8a027996eea9f8983812fd43ae92e6..d31056524d6c245858bc3f2939e89fe2976f3da6 100644 (file)
@@ -1718,12 +1718,7 @@ static int syscall_link_impl(const char* user_oldpath, const char* user_newpath)
     if (rc1 < 0) return rc1;
     int rc2 = path_resolve_user(user_newpath, new_path, sizeof(new_path));
     if (rc2 < 0) return rc2;
-    extern int diskfs_link(const char*, const char*);
-    const char* old_rel = old_path;
-    const char* new_rel = new_path;
-    if (memcmp(old_path, "/disk/", 6) == 0) old_rel = old_path + 6;
-    if (memcmp(new_path, "/disk/", 6) == 0) new_rel = new_path + 6;
-    return diskfs_link(old_rel, new_rel);
+    return vfs_link(old_path, new_path);
 }
 
 static int syscall_chmod_impl(const char* user_path, uint32_t mode) {