struct fs_node; /* forward declaration for file_operations */
-/* Shared file operations table — filesystems define one static instance
- * per node type (file, dir, device) and point every node's f_ops at it.
- * During the migration period, the VFS checks f_ops first, then falls
- * back to per-node function pointers (legacy). */
+/* File operations — per-open-fd I/O (requires an open file descriptor) */
struct file_operations {
uint32_t (*read)(struct fs_node* node, uint32_t offset, uint32_t size, uint8_t* buffer);
uint32_t (*write)(struct fs_node* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
void (*open)(struct fs_node* node);
void (*close)(struct fs_node* node);
- struct fs_node* (*finddir)(struct fs_node* node, const char* name);
- 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);
int (*poll)(struct fs_node* node, int events);
- 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);
};
/* Inode operations — namespace / metadata (no open fd required) */
.read = initrd_read_impl,
};
-static const struct file_operations initrd_dir_ops = {
- .finddir = initrd_finddir,
+static const struct file_operations initrd_dir_ops = {0};
+
+static const struct inode_operations initrd_dir_iops = {
+ .lookup = initrd_finddir,
};
static void initrd_finalize_nodes(void) {
n->f_ops = &initrd_file_ops;
} else if (e->flags & FS_DIRECTORY) {
n->f_ops = &initrd_dir_ops;
+ n->i_ops = &initrd_dir_iops;
}
}
}
.read = ext2_file_read,
.write = ext2_file_write,
.close = ext2_close_impl,
+};
+
+static const struct inode_operations ext2_file_iops = {
.truncate = ext2_truncate_impl,
};
static const struct file_operations ext2_dir_fops = {
.close = ext2_close_impl,
- .finddir = ext2_finddir,
+};
+
+static const struct inode_operations ext2_dir_iops = {
+ .lookup = ext2_finddir,
.readdir = ext2_readdir_impl,
.create = ext2_create_impl,
.mkdir = ext2_mkdir_impl,
en->vfs.flags = FS_DIRECTORY;
en->vfs.length = inode->i_size;
en->vfs.f_ops = &ext2_dir_fops;
+ en->vfs.i_ops = &ext2_dir_iops;
} else if ((inode->i_mode & 0xF000) == EXT2_S_IFLNK) {
en->vfs.flags = FS_SYMLINK;
en->vfs.length = inode->i_size;
en->vfs.flags = FS_FILE;
en->vfs.length = inode->i_size;
en->vfs.f_ops = &ext2_file_fops;
+ en->vfs.i_ops = &ext2_file_iops;
}
return en;
g_ext2_root.vfs.mode = root_inode.i_mode;
g_ext2_root.ino = EXT2_ROOT_INO;
g_ext2_root.vfs.f_ops = &ext2_dir_fops;
+ g_ext2_root.vfs.i_ops = &ext2_dir_iops;
g_ext2_ready = 1;
if (!cur) return NULL;
fs_node_t* (*fn_finddir)(fs_node_t*, const char*) = NULL;
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;
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
}
int (*fn_readdir)(struct fs_node*, uint32_t*, void*, uint32_t) = NULL;
- if (dir->f_ops && dir->f_ops->readdir) fn_readdir = dir->f_ops->readdir;
+ if (dir->i_ops && dir->i_ops->readdir) fn_readdir = dir->i_ops->readdir;
if (!fn_readdir) {
kprintf("ls: not a directory\n");
return;
if (!src) return 0;
if (src->i_ops && src->i_ops->readdir)
return src->i_ops->readdir(src, inout_index, buf, buf_len);
- if (src->f_ops && src->f_ops->readdir)
- return src->f_ops->readdir(src, inout_index, buf, buf_len);
return 0;
}
fs_node_t* upper_child = NULL;
fs_node_t* lower_child = NULL;
- if (dir->upper) {
- if (dir->upper->i_ops && dir->upper->i_ops->lookup)
- upper_child = dir->upper->i_ops->lookup(dir->upper, name);
- else if (dir->upper->f_ops && dir->upper->f_ops->finddir)
- upper_child = dir->upper->f_ops->finddir(dir->upper, name);
- }
- if (dir->lower) {
- if (dir->lower->i_ops && dir->lower->i_ops->lookup)
- lower_child = dir->lower->i_ops->lookup(dir->lower, name);
- else if (dir->lower->f_ops && dir->lower->f_ops->finddir)
- lower_child = dir->lower->f_ops->finddir(dir->lower, name);
- }
+ if (dir->upper && dir->upper->i_ops && dir->upper->i_ops->lookup)
+ upper_child = dir->upper->i_ops->lookup(dir->upper, name);
+ if (dir->lower && dir->lower->i_ops && dir->lower->i_ops->lookup)
+ lower_child = dir->lower->i_ops->lookup(dir->lower, name);
if (!upper_child && !lower_child) return 0;
return overlay_wrap_child(dir, name, lower_child, upper_child);
return -ENOENT;
} else if ((flags & 0x200U) != 0U && node->flags == FS_FILE) {
/* O_TRUNC on existing file */
- if (node->f_ops && node->f_ops->truncate) {
- node->f_ops->truncate(node, 0);
+ if (node->i_ops && node->i_ops->truncate) {
+ node->i_ops->truncate(node, 0);
node->length = 0;
}
}
if (f->node->flags != FS_DIRECTORY) return -ENOTDIR;
int (*fn_readdir)(struct fs_node*, uint32_t*, void*, uint32_t) = NULL;
if (f->node->i_ops && f->node->i_ops->readdir) fn_readdir = f->node->i_ops->readdir;
- else if (f->node->f_ops && f->node->f_ops->readdir) fn_readdir = f->node->f_ops->readdir;
if (!fn_readdir) return -ENOSYS;
uint8_t kbuf[256];
fs_node_t* dir = vfs_lookup(parent);
if (!dir) return -ENOENT;
fs_node_t* (*fn_finddir)(fs_node_t*, const char*) = NULL;
- if (dir->f_ops && dir->f_ops->finddir) fn_finddir = dir->f_ops->finddir;
+ if (dir->i_ops && dir->i_ops->lookup) fn_finddir = dir->i_ops->lookup;
if (!fn_finddir) return -ENOENT;
fs_node_t* node = fn_finddir(dir, leaf);