]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
refactor: migrate all filesystems to struct file_operations
authorTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 21:23:05 +0000 (18:23 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 21:23:05 +0000 (18:23 -0300)
Every filesystem and device driver now defines static const
file_operations tables and assigns f_ops on every node:
- tmpfs: tmpfs_file_ops, tmpfs_dir_ops
- devfs: devfs_dir_ops, dev_null_ops, dev_zero_ops, dev_random_ops
- ext2: ext2_file_fops, ext2_dir_fops
- fat: fat_file_fops, fat_dir_fops
- diskfs: diskfs_file_fops, diskfs_dir_fops
- overlayfs: overlay_file_ops, overlay_dir_ops
- tty: tty_fops (console + tty)
- pipe: pipe_read_fops, pipe_write_fops
- socket: sock_fops
- vbe: fb0_fops
- keyboard: kbd_fops

VFS dispatch (fs.c + syscall.c) checks f_ops first, falls back to
legacy per-node pointers. Legacy pointers are still set (dual
assignment) for callers that access them directly (e.g. overlayfs
layer delegation). Phase B3 will remove legacy pointers after all
direct accesses are eliminated.

20/20 smoke tests pass, cppcheck clean.

src/drivers/keyboard.c
src/drivers/vbe.c
src/kernel/devfs.c
src/kernel/diskfs.c
src/kernel/ext2.c
src/kernel/fat.c
src/kernel/overlayfs.c
src/kernel/syscall.c
src/kernel/tmpfs.c
src/kernel/tty.c

index 439e0f4f9c7db9c070ea8d574dd6eb1c27cf7bea..f3fd89b02aab73d5b094acab818bcff273f116cc 100644 (file)
@@ -113,10 +113,16 @@ void keyboard_init(void) {
 }
 
 void keyboard_register_devfs(void) {
+    static const struct file_operations kbd_fops = {
+        .read = kbd_dev_read,
+        .poll = kbd_dev_poll,
+    };
+
     memset(&g_dev_kbd_node, 0, sizeof(g_dev_kbd_node));
     strcpy(g_dev_kbd_node.name, "kbd");
     g_dev_kbd_node.flags = FS_CHARDEVICE;
     g_dev_kbd_node.inode = 21;
+    g_dev_kbd_node.f_ops = &kbd_fops;
     g_dev_kbd_node.read = &kbd_dev_read;
     g_dev_kbd_node.poll = &kbd_dev_poll;
     devfs_register_device(&g_dev_kbd_node);
index 38d8ceaca9a66f81a820820c2cd828cc57633282..dbbb81df8e6f69f30b44930b08618aa28aebda27 100644 (file)
@@ -180,11 +180,19 @@ static uintptr_t fb0_mmap(fs_node_t* node, uintptr_t addr, uint32_t length, uint
 void vbe_register_devfs(void) {
     if (!g_vbe_ready) return;
 
+    static const struct file_operations fb0_fops = {
+        .read  = fb0_read,
+        .write = fb0_write,
+        .ioctl = fb0_ioctl,
+        .mmap  = fb0_mmap,
+    };
+
     memset(&g_dev_fb0_node, 0, sizeof(g_dev_fb0_node));
     strcpy(g_dev_fb0_node.name, "fb0");
     g_dev_fb0_node.flags = FS_CHARDEVICE;
     g_dev_fb0_node.inode = 20;
     g_dev_fb0_node.length = g_vbe.size;
+    g_dev_fb0_node.f_ops = &fb0_fops;
     g_dev_fb0_node.read = &fb0_read;
     g_dev_fb0_node.write = &fb0_write;
     g_dev_fb0_node.ioctl = &fb0_ioctl;
index bbb3a4aeafca4752b397cd12654d33d8ffcd6004..38d51e5238ac57c3934de9fd8d2bb1966e5aa340 100644 (file)
@@ -16,6 +16,40 @@ static fs_node_t g_dev_random;
 static fs_node_t g_dev_urandom;
 static uint32_t g_devfs_inited = 0;
 
+static struct fs_node* devfs_finddir_impl(struct fs_node* node, const char* name);
+static int devfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len);
+static uint32_t dev_null_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
+static uint32_t dev_null_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
+static uint32_t dev_zero_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
+static uint32_t dev_zero_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
+static uint32_t dev_random_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
+static uint32_t dev_random_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
+static int dev_null_poll(fs_node_t* node, int events);
+static int dev_always_ready_poll(fs_node_t* node, int events);
+
+static const struct file_operations devfs_dir_ops = {
+    .finddir = devfs_finddir_impl,
+    .readdir = devfs_readdir_impl,
+};
+
+static const struct file_operations dev_null_ops = {
+    .read  = dev_null_read,
+    .write = dev_null_write,
+    .poll  = dev_null_poll,
+};
+
+static const struct file_operations dev_zero_ops = {
+    .read  = dev_zero_read,
+    .write = dev_zero_write,
+    .poll  = dev_always_ready_poll,
+};
+
+static const struct file_operations dev_random_ops = {
+    .read  = dev_random_read,
+    .write = dev_random_write,
+    .poll  = dev_always_ready_poll,
+};
+
 /* --- Device registry --- */
 static fs_node_t* g_registered[DEVFS_MAX_DEVICES];
 static int g_registered_count = 0;
@@ -189,48 +223,45 @@ static void devfs_init_once(void) {
     g_dev_root.vfs.flags = FS_DIRECTORY;
     g_dev_root.vfs.inode = 1;
     g_dev_root.vfs.length = 0;
-    g_dev_root.vfs.read = 0;
-    g_dev_root.vfs.write = 0;
-    g_dev_root.vfs.open = 0;
-    g_dev_root.vfs.close = 0;
-    g_dev_root.vfs.finddir = &devfs_finddir_impl;
-    g_dev_root.vfs.readdir = &devfs_readdir_impl;
+    g_dev_root.vfs.f_ops = &devfs_dir_ops;
+    g_dev_root.vfs.finddir = devfs_finddir_impl;
+    g_dev_root.vfs.readdir = devfs_readdir_impl;
 
     memset(&g_dev_null, 0, sizeof(g_dev_null));
     strcpy(g_dev_null.name, "null");
     g_dev_null.flags = FS_CHARDEVICE;
     g_dev_null.inode = 2;
-    g_dev_null.length = 0;
-    g_dev_null.read = &dev_null_read;
-    g_dev_null.write = &dev_null_write;
-    g_dev_null.poll = &dev_null_poll;
-    g_dev_null.open = 0;
-    g_dev_null.close = 0;
-    g_dev_null.finddir = 0;
+    g_dev_null.f_ops = &dev_null_ops;
+    g_dev_null.read = dev_null_read;
+    g_dev_null.write = dev_null_write;
+    g_dev_null.poll = dev_null_poll;
 
     memset(&g_dev_zero, 0, sizeof(g_dev_zero));
     strcpy(g_dev_zero.name, "zero");
     g_dev_zero.flags = FS_CHARDEVICE;
     g_dev_zero.inode = 7;
-    g_dev_zero.read = &dev_zero_read;
-    g_dev_zero.write = &dev_zero_write;
-    g_dev_zero.poll = &dev_always_ready_poll;
+    g_dev_zero.f_ops = &dev_zero_ops;
+    g_dev_zero.read = dev_zero_read;
+    g_dev_zero.write = dev_zero_write;
+    g_dev_zero.poll = dev_always_ready_poll;
 
     memset(&g_dev_random, 0, sizeof(g_dev_random));
     strcpy(g_dev_random.name, "random");
     g_dev_random.flags = FS_CHARDEVICE;
     g_dev_random.inode = 8;
-    g_dev_random.read = &dev_random_read;
-    g_dev_random.write = &dev_random_write;
-    g_dev_random.poll = &dev_always_ready_poll;
+    g_dev_random.f_ops = &dev_random_ops;
+    g_dev_random.read = dev_random_read;
+    g_dev_random.write = dev_random_write;
+    g_dev_random.poll = dev_always_ready_poll;
 
     memset(&g_dev_urandom, 0, sizeof(g_dev_urandom));
     strcpy(g_dev_urandom.name, "urandom");
     g_dev_urandom.flags = FS_CHARDEVICE;
     g_dev_urandom.inode = 9;
-    g_dev_urandom.read = &dev_random_read;
-    g_dev_urandom.write = &dev_random_write;
-    g_dev_urandom.poll = &dev_always_ready_poll;
+    g_dev_urandom.f_ops = &dev_random_ops;
+    g_dev_urandom.read = dev_random_read;
+    g_dev_urandom.write = dev_random_write;
+    g_dev_urandom.poll = dev_always_ready_poll;
 }
 
 fs_node_t* devfs_create_root(void) {
index 15a506fbe221a4b4d7ba50e7f8e6b7da2899da80..fede86be0c9da29eb38f3f4cfa836a0f84dd4688 100644 (file)
@@ -461,6 +461,33 @@ static int diskfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void
 
 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);
+static int diskfs_vfs_create(struct fs_node* dir, const char* name, uint32_t flags, struct fs_node** out);
+static int diskfs_vfs_mkdir(struct fs_node* dir, const char* name);
+static int diskfs_vfs_unlink(struct fs_node* dir, const char* name);
+static int diskfs_vfs_rmdir(struct fs_node* dir, const char* name);
+static int diskfs_vfs_rename(struct fs_node* old_dir, const char* old_name,
+                              struct fs_node* new_dir, const char* new_name);
+static int diskfs_vfs_link(struct fs_node* dir, const char* name, struct fs_node* target);
+
+static const struct file_operations diskfs_file_fops = {
+    .read     = diskfs_read_impl,
+    .write    = diskfs_write_impl,
+    .close    = diskfs_close_impl,
+    .truncate = diskfs_vfs_truncate,
+};
+
+static const struct file_operations diskfs_dir_fops = {
+    .close   = diskfs_close_impl,
+    .finddir = diskfs_root_finddir,
+    .readdir = diskfs_readdir_impl,
+    .create  = diskfs_vfs_create,
+    .mkdir   = diskfs_vfs_mkdir,
+    .unlink  = diskfs_vfs_unlink,
+    .rmdir   = diskfs_vfs_rmdir,
+    .rename  = diskfs_vfs_rename,
+    .link    = diskfs_vfs_link,
+};
 
 static struct fs_node* diskfs_root_finddir(struct fs_node* node, const char* name) {
     struct diskfs_node* parent = (struct diskfs_node*)node;
@@ -492,18 +519,17 @@ static struct fs_node* diskfs_root_finddir(struct fs_node* node, const char* nam
     if (sb.inodes[cino].type == DISKFS_INODE_DIR) {
         dn->vfs.flags = FS_DIRECTORY;
         dn->vfs.length = 0;
-        dn->vfs.read = 0;
-        dn->vfs.write = 0;
+        dn->vfs.f_ops = &diskfs_dir_fops;
         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.f_ops = &diskfs_file_fops;
         dn->vfs.read = &diskfs_read_impl;
         dn->vfs.write = &diskfs_write_impl;
         dn->vfs.truncate = &diskfs_vfs_truncate;
-        dn->vfs.finddir = 0;
     }
 
     return &dn->vfs;
@@ -557,11 +583,10 @@ int diskfs_open_file(const char* rel_path, uint32_t flags, fs_node_t** out_node)
     dn->vfs.flags = FS_FILE;
     dn->vfs.inode = 100 + (uint32_t)ino;
     dn->vfs.length = sb.inodes[ino].size_bytes;
+    dn->vfs.f_ops = &diskfs_file_fops;
     dn->vfs.read = &diskfs_read_impl;
     dn->vfs.write = &diskfs_write_impl;
-    dn->vfs.open = 0;
     dn->vfs.close = &diskfs_close_impl;
-    dn->vfs.finddir = 0;
     dn->ino = ino;
 
     *out_node = &dn->vfs;
@@ -1068,10 +1093,7 @@ fs_node_t* diskfs_create_root(int drive) {
         g_root.vfs.flags = FS_DIRECTORY;
         g_root.vfs.inode = 100;
         g_root.vfs.length = 0;
-        g_root.vfs.read = 0;
-        g_root.vfs.write = 0;
-        g_root.vfs.open = 0;
-        g_root.vfs.close = 0;
+        g_root.vfs.f_ops = &diskfs_dir_fops;
         g_root.vfs.finddir = &diskfs_root_finddir;
         g_root.vfs.readdir = &diskfs_readdir_impl;
         diskfs_set_dir_ops(&g_root.vfs);
index f9f942e7777efdb757b67fa2a9e6e936ed040fd4..dea111ac721bcb6753cbdac276f13f4d29b642cb 100644 (file)
@@ -530,6 +530,26 @@ static int ext2_rename_impl(struct fs_node* old_dir, const char* old_name,
                              struct fs_node* new_dir, const char* new_name);
 static int ext2_truncate_impl(struct fs_node* node, uint32_t length);
 static int ext2_link_impl(struct fs_node* dir, const char* name, struct fs_node* target);
+static void ext2_close_impl(fs_node_t* node);
+
+static const struct file_operations ext2_file_fops = {
+    .read     = ext2_file_read,
+    .write    = ext2_file_write,
+    .close    = ext2_close_impl,
+    .truncate = ext2_truncate_impl,
+};
+
+static const struct file_operations ext2_dir_fops = {
+    .close   = ext2_close_impl,
+    .finddir = ext2_finddir,
+    .readdir = ext2_readdir_impl,
+    .create  = ext2_create_impl,
+    .mkdir   = ext2_mkdir_impl,
+    .unlink  = ext2_unlink_impl,
+    .rmdir   = ext2_rmdir_impl,
+    .rename  = ext2_rename_impl,
+    .link    = ext2_link_impl,
+};
 
 static void ext2_close_impl(fs_node_t* node) {
     if (!node) return;
@@ -569,6 +589,7 @@ static struct ext2_node* ext2_make_node(uint32_t ino, const struct ext2_inode* i
     if ((inode->i_mode & 0xF000) == EXT2_S_IFDIR) {
         en->vfs.flags = FS_DIRECTORY;
         en->vfs.length = inode->i_size;
+        en->vfs.f_ops = &ext2_dir_fops;
         ext2_set_dir_ops(&en->vfs);
     } else if ((inode->i_mode & 0xF000) == EXT2_S_IFLNK) {
         en->vfs.flags = FS_SYMLINK;
@@ -581,6 +602,7 @@ static struct ext2_node* ext2_make_node(uint32_t ino, const struct ext2_inode* i
     } else {
         en->vfs.flags = FS_FILE;
         en->vfs.length = inode->i_size;
+        en->vfs.f_ops = &ext2_file_fops;
         en->vfs.read = &ext2_file_read;
         en->vfs.write = &ext2_file_write;
         en->vfs.truncate = &ext2_truncate_impl;
index 46f8af267a56d68a41610f8710b2cdd901565a48..e7fa6b3ce60859d51b99b4323807f39f5cb3dd98 100644 (file)
@@ -481,6 +481,25 @@ static int fat_rmdir_impl(struct fs_node* dir, const char* name);
 static int fat_rename_impl(struct fs_node* old_dir, const char* old_name,
                             struct fs_node* new_dir, const char* new_name);
 static int fat_truncate_impl(struct fs_node* node, uint32_t length);
+static void fat_close_impl(fs_node_t* node);
+
+static const struct file_operations fat_file_fops = {
+    .read     = fat_file_read,
+    .write    = fat_file_write,
+    .close    = fat_close_impl,
+    .truncate = fat_truncate_impl,
+};
+
+static const struct file_operations fat_dir_fops = {
+    .close   = fat_close_impl,
+    .finddir = fat_finddir,
+    .readdir = fat_readdir_impl,
+    .create  = fat_create_impl,
+    .mkdir   = fat_mkdir_impl,
+    .unlink  = fat_unlink_impl,
+    .rmdir   = fat_rmdir_impl,
+    .rename  = fat_rename_impl,
+};
 
 static void fat_close_impl(fs_node_t* node) {
     if (!node) return;
@@ -513,11 +532,13 @@ static struct fat_node* fat_make_node(const struct fat_dirent* de, uint32_t pare
         fn->vfs.flags = FS_DIRECTORY;
         fn->vfs.length = 0;
         fn->vfs.inode = fn->first_cluster;
+        fn->vfs.f_ops = &fat_dir_fops;
         fat_set_dir_ops(&fn->vfs);
     } else {
         fn->vfs.flags = FS_FILE;
         fn->vfs.length = de->file_size;
         fn->vfs.inode = fn->first_cluster;
+        fn->vfs.f_ops = &fat_file_fops;
         fn->vfs.read = &fat_file_read;
         fn->vfs.write = &fat_file_write;
         fn->vfs.truncate = &fat_truncate_impl;
index d441a56a78e4184e4aec3e40d734c62d028fd7c6..d10f03795207aece0a015767d50ee92764527ace 100644 (file)
@@ -87,6 +87,17 @@ static uint32_t overlay_write_impl(fs_node_t* node, uint32_t offset, uint32_t si
     return wr;
 }
 
+static const struct file_operations overlay_file_ops = {
+    .read  = overlay_read_impl,
+    .write = overlay_write_impl,
+};
+
+static const struct file_operations overlay_dir_ops = {
+    .read    = overlay_read_impl,
+    .finddir = overlay_finddir_impl,
+    .readdir = overlay_readdir_impl,
+};
+
 static fs_node_t* overlay_wrap_child(struct overlay_node* parent, const char* name, fs_node_t* lower_child, fs_node_t* upper_child) {
     if (!parent || !parent->ofs || !name) return NULL;
     if (!lower_child && !upper_child) return NULL;
@@ -110,10 +121,13 @@ static fs_node_t* overlay_wrap_child(struct overlay_node* parent, const char* na
         c->vfs.length = lower_child->length;
     }
 
+    if (c->vfs.flags == FS_DIRECTORY) {
+        c->vfs.f_ops = &overlay_dir_ops;
+    } else {
+        c->vfs.f_ops = &overlay_file_ops;
+    }
     c->vfs.read = &overlay_read_impl;
     c->vfs.write = (c->vfs.flags == FS_FILE) ? &overlay_write_impl : 0;
-    c->vfs.open = 0;
-    c->vfs.close = 0;
     c->vfs.finddir = (c->vfs.flags == FS_DIRECTORY) ? &overlay_finddir_impl : 0;
     c->vfs.readdir = (c->vfs.flags == FS_DIRECTORY) ? &overlay_readdir_impl : 0;
 
@@ -153,8 +167,12 @@ static int overlay_readdir_impl(struct fs_node* node, uint32_t* inout_index, voi
 
     // Prefer upper layer readdir; fall back to lower.
     fs_node_t* src = dir->upper ? dir->upper : dir->lower;
-    if (!src || !src->readdir) return 0;
-    return src->readdir(src, inout_index, buf, buf_len);
+    if (!src) return 0;
+    if (src->f_ops && src->f_ops->readdir)
+        return src->f_ops->readdir(src, inout_index, buf, buf_len);
+    if (src->readdir)
+        return src->readdir(src, inout_index, buf, buf_len);
+    return 0;
 }
 
 static struct fs_node* overlay_finddir_impl(struct fs_node* node, const char* name) {
@@ -166,11 +184,17 @@ static struct fs_node* overlay_finddir_impl(struct fs_node* node, const char* na
     fs_node_t* upper_child = NULL;
     fs_node_t* lower_child = NULL;
 
-    if (dir->upper && dir->upper->finddir) {
-        upper_child = dir->upper->finddir(dir->upper, name);
+    if (dir->upper) {
+        if (dir->upper->f_ops && dir->upper->f_ops->finddir)
+            upper_child = dir->upper->f_ops->finddir(dir->upper, name);
+        else if (dir->upper->finddir)
+            upper_child = dir->upper->finddir(dir->upper, name);
     }
-    if (dir->lower && dir->lower->finddir) {
-        lower_child = dir->lower->finddir(dir->lower, name);
+    if (dir->lower) {
+        if (dir->lower->f_ops && dir->lower->f_ops->finddir)
+            lower_child = dir->lower->f_ops->finddir(dir->lower, name);
+        else if (dir->lower->finddir)
+            lower_child = dir->lower->finddir(dir->lower, name);
     }
 
     if (!upper_child && !lower_child) return 0;
@@ -200,10 +224,7 @@ fs_node_t* overlayfs_create_root(fs_node_t* lower_root, fs_node_t* upper_root) {
     root->vfs.flags = FS_DIRECTORY;
     root->vfs.inode = upper_root->inode;
     root->vfs.length = 0;
-    root->vfs.read = 0;
-    root->vfs.write = 0;
-    root->vfs.open = 0;
-    root->vfs.close = 0;
+    root->vfs.f_ops = &overlay_dir_ops;
     root->vfs.finddir = &overlay_finddir_impl;
     root->vfs.readdir = &overlay_readdir_impl;
 
index 8a6f4efbf1767e51de2944811ee4802006681656..45a630717224a3679fd8471ba302e63bce4abc64 100644 (file)
@@ -399,6 +399,18 @@ static int pipe_poll(fs_node_t* n, int events) {
     return revents;
 }
 
+static const struct file_operations pipe_read_fops = {
+    .read  = pipe_read,
+    .close = pipe_close,
+    .poll  = pipe_poll,
+};
+
+static const struct file_operations pipe_write_fops = {
+    .write = pipe_write,
+    .close = pipe_close,
+    .poll  = pipe_poll,
+};
+
 static int pipe_node_create(struct pipe_state* ps, int is_read_end, fs_node_t** out_node) {
     if (!ps || !out_node) return -EINVAL;
     struct pipe_node* pn = (struct pipe_node*)kmalloc(sizeof(*pn));
@@ -409,18 +421,16 @@ static int pipe_node_create(struct pipe_state* ps, int is_read_end, fs_node_t**
     pn->is_read_end = is_read_end ? 1U : 0U;
     pn->node.flags = FS_FILE;
     pn->node.length = 0;
-    pn->node.open = NULL;
-    pn->node.finddir = NULL;
     pn->node.close = pipe_close;
     pn->node.poll = pipe_poll;
     if (pn->is_read_end) {
         strcpy(pn->node.name, "pipe:r");
+        pn->node.f_ops = &pipe_read_fops;
         pn->node.read = pipe_read;
-        pn->node.write = NULL;
         ps->readers++;
     } else {
         strcpy(pn->node.name, "pipe:w");
-        pn->node.read = NULL;
+        pn->node.f_ops = &pipe_write_fops;
         pn->node.write = pipe_write;
         ps->writers++;
     }
@@ -2625,6 +2635,12 @@ static void sock_node_close(fs_node_t* node) {
     kfree(node);
 }
 
+static const struct file_operations sock_fops = {
+    .read  = sock_node_read,
+    .write = sock_node_write,
+    .close = sock_node_close,
+};
+
 static fs_node_t* sock_node_create(int sid) {
     fs_node_t* n = (fs_node_t*)kmalloc(sizeof(fs_node_t));
     if (!n) return NULL;
@@ -2632,6 +2648,7 @@ static fs_node_t* sock_node_create(int sid) {
     strcpy(n->name, "socket");
     n->flags = FS_SOCKET;
     n->inode = (uint32_t)sid;
+    n->f_ops = &sock_fops;
     n->read = sock_node_read;
     n->write = sock_node_write;
     n->close = sock_node_close;
index a1fd840e8fcc8d7b74f29c4766eef4820e886683..d62c3c7a33f50f189bdc3a31cda639893811ae20 100644 (file)
@@ -18,8 +18,19 @@ static uint32_t g_tmpfs_next_inode = 1;
 
 static struct fs_node* tmpfs_finddir_impl(struct fs_node* node, const char* name);
 static int tmpfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len);
+static uint32_t tmpfs_read_impl(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer);
 static uint32_t tmpfs_write_impl(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer);
 
+static const struct file_operations tmpfs_file_ops = {
+    .read    = tmpfs_read_impl,
+    .write   = tmpfs_write_impl,
+};
+
+static const struct file_operations tmpfs_dir_ops = {
+    .finddir = tmpfs_finddir_impl,
+    .readdir = tmpfs_readdir_impl,
+};
+
 static struct tmpfs_node* tmpfs_node_alloc(const char* name, uint32_t flags) {
     struct tmpfs_node* n = (struct tmpfs_node*)kmalloc(sizeof(*n));
     if (!n) return NULL;
@@ -64,12 +75,9 @@ static struct tmpfs_node* tmpfs_child_ensure_dir(struct tmpfs_node* dir, const c
 
     struct tmpfs_node* nd = tmpfs_node_alloc(name, FS_DIRECTORY);
     if (!nd) return NULL;
-    nd->vfs.read = 0;
-    nd->vfs.write = 0;
-    nd->vfs.open = 0;
-    nd->vfs.close = 0;
-    nd->vfs.finddir = &tmpfs_finddir_impl;
-    nd->vfs.readdir = &tmpfs_readdir_impl;
+    nd->vfs.f_ops = &tmpfs_dir_ops;
+    nd->vfs.finddir = tmpfs_finddir_impl;
+    nd->vfs.readdir = tmpfs_readdir_impl;
     tmpfs_child_add(dir, nd);
     return nd;
 }
@@ -197,12 +205,9 @@ fs_node_t* tmpfs_create_root(void) {
     struct tmpfs_node* root = tmpfs_node_alloc("", FS_DIRECTORY);
     if (!root) return NULL;
 
-    root->vfs.read = 0;
-    root->vfs.write = 0;
-    root->vfs.open = 0;
-    root->vfs.close = 0;
-    root->vfs.finddir = &tmpfs_finddir_impl;
-    root->vfs.readdir = &tmpfs_readdir_impl;
+    root->vfs.f_ops = &tmpfs_dir_ops;
+    root->vfs.finddir = tmpfs_finddir_impl;
+    root->vfs.readdir = tmpfs_readdir_impl;
 
     return &root->vfs;
 }
@@ -217,11 +222,9 @@ int tmpfs_add_file(fs_node_t* root_dir, const char* name, const uint8_t* data, u
     struct tmpfs_node* f = tmpfs_node_alloc(name, FS_FILE);
     if (!f) return -ENOMEM;
 
-    f->vfs.read = &tmpfs_read_impl;
-    f->vfs.write = &tmpfs_write_impl;
-    f->vfs.open = 0;
-    f->vfs.close = 0;
-    f->vfs.finddir = 0;
+    f->vfs.f_ops = &tmpfs_file_ops;
+    f->vfs.read = tmpfs_read_impl;
+    f->vfs.write = tmpfs_write_impl;
 
     if (len) {
         f->data = (uint8_t*)kmalloc(len);
@@ -293,11 +296,9 @@ fs_node_t* tmpfs_create_file(fs_node_t* root_dir, const char* path, const uint8_
     struct tmpfs_node* f = tmpfs_node_alloc(leaf, FS_FILE);
     if (!f) return NULL;
 
-    f->vfs.read = &tmpfs_read_impl;
-    f->vfs.write = &tmpfs_write_impl;
-    f->vfs.open = 0;
-    f->vfs.close = 0;
-    f->vfs.finddir = 0;
+    f->vfs.f_ops = &tmpfs_file_ops;
+    f->vfs.read = tmpfs_read_impl;
+    f->vfs.write = tmpfs_write_impl;
 
     if (len && data) {
         f->data = (uint8_t*)kmalloc(len);
@@ -342,10 +343,7 @@ int tmpfs_create_symlink(fs_node_t* root_dir, const char* link_path, const char*
 
     strcpy(ln->vfs.symlink_target, target);
     ln->vfs.length = (uint32_t)strlen(target);
-    ln->vfs.read = 0;
-    ln->vfs.write = 0;
-    ln->vfs.finddir = 0;
-    ln->vfs.readdir = 0;
+    /* symlinks have no f_ops */
 
     tmpfs_child_add(cur, ln);
     return 0;
index 009452d06c9287f5b63ce51ad43293be1c7d09ea..91da6f750da64d1f9496649cb6e871df3f06f405 100644 (file)
@@ -429,11 +429,19 @@ void tty_init(void) {
 
     keyboard_set_callback(tty_keyboard_cb);
 
+    static const struct file_operations tty_fops = {
+        .read  = tty_devfs_read,
+        .write = tty_devfs_write,
+        .ioctl = tty_devfs_ioctl,
+        .poll  = tty_devfs_poll,
+    };
+
     /* Register /dev/console */
     memset(&g_dev_console_node, 0, sizeof(g_dev_console_node));
     strcpy(g_dev_console_node.name, "console");
     g_dev_console_node.flags = FS_CHARDEVICE;
     g_dev_console_node.inode = 10;
+    g_dev_console_node.f_ops = &tty_fops;
     g_dev_console_node.read = &tty_devfs_read;
     g_dev_console_node.write = &tty_devfs_write;
     g_dev_console_node.ioctl = &tty_devfs_ioctl;
@@ -445,6 +453,7 @@ void tty_init(void) {
     strcpy(g_dev_tty_node.name, "tty");
     g_dev_tty_node.flags = FS_CHARDEVICE;
     g_dev_tty_node.inode = 3;
+    g_dev_tty_node.f_ops = &tty_fops;
     g_dev_tty_node.read = &tty_devfs_read;
     g_dev_tty_node.write = &tty_devfs_write;
     g_dev_tty_node.ioctl = &tty_devfs_ioctl;