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