]> 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 623134a95d2ef14fafab33070f430c1e5072080f..38b5c2743f1cadbc24b6e65e0af04774c5eb5485 100644 (file)
@@ -122,10 +122,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 d751dbb703e53c41b05c8d78aaf9a0fa4daa593a..ac306bcc3ba4ce6f2b3276710cfeb125c0c0f8ab 100644 (file)
@@ -189,11 +189,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 cf73b125f7cd20793077f2ec51cbb3012c5bdc78..cb3640c3c433856496ce2654c3ecbee0f0ee89e4 100644 (file)
@@ -25,6 +25,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;
@@ -198,48 +232,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 76eee2ad0dc59a3a0814c9624f72db97fdac3709..87f8ad0bda9eba716c40ee90a16ba9d0d5d6d00c 100644 (file)
@@ -470,6 +470,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;
@@ -501,18 +528,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;
@@ -566,11 +592,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;
@@ -1077,10 +1102,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 26c5d4d1091f5923ee1a335f9ae292828143f96d..ae0618f1d5718271e8ff67d563343582e98b4fe5 100644 (file)
@@ -539,6 +539,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;
@@ -578,6 +598,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;
@@ -590,6 +611,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 afff7fb2910b12b178cd252946a5be86c08d5e0d..2b1a0d636efd4e694316854641db744c3de830c5 100644 (file)
@@ -490,6 +490,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;
@@ -522,11 +541,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 61ccf2d1718da0917d0774cc3cef0aee26111bf4..c59da3810cc542aeaa117fc4919dfdd0ae5fca9f 100644 (file)
@@ -96,6 +96,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;
@@ -119,10 +130,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;
 
@@ -162,8 +176,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) {
@@ -175,11 +193,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;
@@ -209,10 +233,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 c45775cf0fc06634de3300f966974866e015e709..3c6f40ba54f6ec1c6aca941ca02757f9d506942d 100644 (file)
@@ -408,6 +408,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));
@@ -418,18 +430,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++;
     }
@@ -2634,6 +2644,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;
@@ -2641,6 +2657,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 2efb38979c518e00ba7b4adb5b03c2c2630f3e7b..6cf2ee54af4a70272e3fa07c72b7ebca3eaaad47 100644 (file)
@@ -27,8 +27,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;
@@ -73,12 +84,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;
 }
@@ -206,12 +214,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;
 }
@@ -226,11 +231,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);
@@ -302,11 +305,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);
@@ -351,10 +352,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 5f3f70ca6f36cd24fb1c337bb11aac0da6432f3b..2255266d3d5aac6fa798375c433e4e12b0fcd8fd 100644 (file)
@@ -438,11 +438,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;
@@ -454,6 +462,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;