int (*link)(struct fs_node* dir, const char* name, struct fs_node* target);
};
+/* Inode operations — namespace / metadata (no open fd required) */
+struct inode_operations {
+ struct fs_node* (*lookup)(struct fs_node* dir, const char* name);
+ int (*readdir)(struct fs_node* dir, uint32_t* inout_index, void* buf, uint32_t buf_len);
+ 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);
+ int (*link)(struct fs_node* dir, const char* name, struct fs_node* target);
+};
+
typedef struct fs_node {
char name[128];
uint32_t flags;
char symlink_target[128];
const struct file_operations* f_ops;
+ const struct inode_operations* i_ops;
} fs_node_t;
struct vfs_dirent {
if (!cur) return NULL;
fs_node_t* (*fn_finddir)(fs_node_t*, const char*) = NULL;
- if (cur->f_ops && cur->f_ops->finddir) fn_finddir = cur->f_ops->finddir;
+ if (cur->i_ops && cur->i_ops->lookup) fn_finddir = cur->i_ops->lookup;
+ else if (cur->f_ops && cur->f_ops->finddir) fn_finddir = cur->f_ops->finddir;
if (!fn_finddir) return NULL;
cur = fn_finddir(cur, part);
if (!cur) return NULL;
fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
if (!parent) return -ENOENT;
if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+ if (parent->i_ops && parent->i_ops->create)
+ return parent->i_ops->create(parent, name, flags, out);
if (parent->f_ops && parent->f_ops->create)
return parent->f_ops->create(parent, name, flags, out);
return -ENOSYS;
fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
if (!parent) return -ENOENT;
if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+ if (parent->i_ops && parent->i_ops->mkdir)
+ return parent->i_ops->mkdir(parent, name);
if (parent->f_ops && parent->f_ops->mkdir)
return parent->f_ops->mkdir(parent, name);
return -ENOSYS;
fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
if (!parent) return -ENOENT;
if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+ if (parent->i_ops && parent->i_ops->unlink)
+ return parent->i_ops->unlink(parent, name);
if (parent->f_ops && parent->f_ops->unlink)
return parent->f_ops->unlink(parent, name);
return -ENOSYS;
fs_node_t* parent = vfs_lookup_parent(path, name, sizeof(name));
if (!parent) return -ENOENT;
if (parent->flags != FS_DIRECTORY) return -ENOTDIR;
+ if (parent->i_ops && parent->i_ops->rmdir)
+ return parent->i_ops->rmdir(parent, name);
if (parent->f_ops && parent->f_ops->rmdir)
return parent->f_ops->rmdir(parent, name);
return -ENOSYS;
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->i_ops && old_parent->i_ops->rename)
+ return old_parent->i_ops->rename(old_parent, old_name, new_parent, new_name);
if (old_parent->f_ops && old_parent->f_ops->rename)
return old_parent->f_ops->rename(old_parent, old_name, new_parent, new_name);
return -ENOSYS;
fs_node_t* node = vfs_lookup(path);
if (!node) return -ENOENT;
if (node->flags != FS_FILE) return -EISDIR;
+ if (node->i_ops && node->i_ops->truncate)
+ return node->i_ops->truncate(node, length);
if (node->f_ops && node->f_ops->truncate)
return node->f_ops->truncate(node, length);
return -ENOSYS;
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->i_ops && parent->i_ops->link)
+ return parent->i_ops->link(parent, name, target);
if (parent->f_ops && parent->f_ops->link)
return parent->f_ops->link(parent, name, target);
return -ENOSYS;