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 {
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);
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;
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) {
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);
+}
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) {