From 565f67188aa2a885e8d2374266e8f008dc72e02c Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 10 Jan 2020 14:09:45 +0200 Subject: [PATCH] Remove old VFS implementation --- etc/make/conf.mk | 25 +- include/sys/blk.h | 4 +- include/sys/fs/ext2.h | 4 +- include/sys/fs/fs.h | 6 +- include/sys/fs/node.h | 52 +- include/sys/fs/ofile.h | 4 +- include/sys/fs/pty.h | 4 +- include/sys/fs/vfs.h | 165 +-- sys/amd64/hw/ps2.c | 2 +- sys/amd64/hw/rs232.c | 2 +- sys/amd64/kernel.c | 6 +- sys/amd64/sys/sched.c | 168 +-- sys/amd64/sys/thread.c | 55 +- sys/amd64/sys_file.c | 189 +-- sys/blk.c | 8 +- sys/dev.c | 222 +-- sys/vfs/fs_class.c | 2 +- sys/vfs/node.c | 236 +-- sys/vfs/vfs.c | 3154 ++++++++++++++++++++-------------------- 19 files changed, 2087 insertions(+), 2221 deletions(-) diff --git a/etc/make/conf.mk b/etc/make/conf.mk index 7877011..829b065 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -48,13 +48,23 @@ OBJS+=$(O)/sys/debug.o \ $(O)/sys/string.o \ $(O)/sys/panic.o \ $(O)/sys/errno.o \ + $(O)/sys/vfs/fs_class.o \ + $(O)/sys/chr.o \ $(O)/sys/blk.o \ $(O)/sys/dev.o \ - $(O)/sys/tty.o \ - $(O)/sys/chr.o \ - $(O)/sys/vfs/fs_class.o \ $(O)/sys/vfs/node.o \ $(O)/sys/vfs/vfs.o \ + $(O)/sys/ring.o \ + $(O)/sys/net/eth.o \ + $(O)/sys/net/arp.o \ + $(O)/sys/net/in.o \ + $(O)/sys/net/netdev.o \ + $(O)/sys/reboot.o \ + $(O)/sys/random.o + +# $(O)/sys/vfs/pseudo.o \ + $(O)/sys/tty.o \ + $(O)/sys/vfs/pty.o \ $(O)/sys/vfs/ext2/ext2alloc.o \ $(O)/sys/vfs/ext2/ext2blk.o \ $(O)/sys/vfs/ext2/ext2.o \ @@ -62,15 +72,6 @@ OBJS+=$(O)/sys/debug.o \ $(O)/sys/vfs/ext2/ext2vnop.o \ $(O)/sys/vfs/tar.o \ $(O)/sys/blk/ram.o \ - $(O)/sys/ring.o \ - $(O)/sys/net/eth.o \ - $(O)/sys/net/arp.o \ - $(O)/sys/net/in.o \ - $(O)/sys/net/netdev.o \ - $(O)/sys/vfs/pseudo.o \ - $(O)/sys/vfs/pty.o \ - $(O)/sys/reboot.o \ - $(O)/sys/random.o ifeq ($(VESA_ENABLE),1) OBJS+=$(O)/sys/psf.o \ diff --git a/include/sys/blk.h b/include/sys/blk.h index db85812..ed20b32 100644 --- a/include/sys/blk.h +++ b/include/sys/blk.h @@ -2,7 +2,7 @@ #include "sys/types.h" #include "sys/dev.h" -struct vfs_node; +struct vnode; struct blkdev { void *dev_data; @@ -17,7 +17,7 @@ struct blkdev { ssize_t blk_read(struct blkdev *blk, void *buf, size_t off, size_t count); ssize_t blk_write(struct blkdev *blk, const void *buf, size_t off, size_t count); -int blk_mount_auto(struct vfs_node *at, struct blkdev *blkdev, const char *opt); +int blk_mount_auto(struct vnode *at, struct blkdev *blkdev, const char *opt); struct blkdev *blk_by_name(const char *name); int blk_enumerate_partitions(struct blkdev *blk); diff --git a/include/sys/fs/ext2.h b/include/sys/fs/ext2.h index 4908fbd..14ee758 100644 --- a/include/sys/fs/ext2.h +++ b/include/sys/fs/ext2.h @@ -141,7 +141,7 @@ int ext2_free_inode(fs_t *ext2, uint32_t ino); int ext2_alloc_inode(fs_t *ext2, uint32_t *ino); // Implemented in ext2dir.c -int ext2_dir_add_inode(fs_t *ext2, vnode_t *dir, const char *name, uint32_t ino); -int ext2_dir_remove_inode(fs_t *ext2, vnode_t *dir, const char *name, uint32_t ino); +int ext2_dir_add_inode(fs_t *ext2, struct vnode *dir, const char *name, uint32_t ino); +int ext2_dir_remove_inode(fs_t *ext2, struct vnode *dir, const char *name, uint32_t ino); extern struct vnode_operations ext2_vnode_ops; diff --git a/include/sys/fs/fs.h b/include/sys/fs/fs.h index 21ea879..787e34f 100644 --- a/include/sys/fs/fs.h +++ b/include/sys/fs/fs.h @@ -19,7 +19,7 @@ struct fs_class { int opt; - vnode_t *(*get_root) (fs_t *fs); + struct vnode *(*get_root) (fs_t *fs); int (*mount) (fs_t *fs, const char *opt); int (*umount) (fs_t *fs); int (*statvfs) (fs_t *fs, struct statvfs *st); @@ -30,7 +30,7 @@ struct fs_class { // one per each mount struct fs { // Mount details here - vnode_t *mnt_at; + struct vnode *mnt_at; // Block device on which the filesystem resides struct blkdev *blk; @@ -41,7 +41,7 @@ struct fs { struct fs_class *cls; }; -struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, vnode_t *mnt_at); +struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, struct vnode *mnt_at); void fs_release(struct fs *fs); struct fs_class *fs_class_by_name(const char *name); int fs_class_register(struct fs_class *cls); diff --git a/include/sys/fs/node.h b/include/sys/fs/node.h index 5338584..dec44f3 100644 --- a/include/sys/fs/node.h +++ b/include/sys/fs/node.h @@ -8,9 +8,11 @@ #include "dirent.h" #include "sys/stat.h" +#define NODE_MAXLEN 256 + struct ofile; struct vfs_ioctx; -typedef struct vnode vnode_t; +struct vnode; typedef struct fs fs_t; enum vnode_type { @@ -18,7 +20,7 @@ enum vnode_type { VN_DIR, VN_BLK, VN_CHR, - VN_LNK +// VN_LNK }; /** @@ -26,28 +28,28 @@ enum vnode_type { */ struct vnode_operations { // File tree traversal, node instance operations - int (*find) (vnode_t *node, const char *path, vnode_t **res); - void (*destroy) (vnode_t *node); + int (*find) (struct vnode *node, const char *path, struct vnode **res); + void (*destroy) (struct vnode *node); // Symlink - int (*readlink) (vnode_t *node, char *path); - int (*symlink) (vnode_t *at, struct vfs_ioctx *ctx, const char *name, const char *dst); +// int (*readlink) (struct vnode *node, char *path); +// int (*symlink) (struct vnode *at, struct vfs_ioctx *ctx, const char *name, const char *dst); // File entry operations - int (*access) (vnode_t *node, uid_t *uid, gid_t *gid, mode_t *mode); - int (*creat) (vnode_t *node, struct vfs_ioctx *ctx, const char *name, mode_t mode, int opt, vnode_t **res); - int (*mkdir) (vnode_t *at, const char *name, mode_t mode); - int (*unlink) (vnode_t *at, vnode_t *vn, const char *name); - int (*stat) (vnode_t *node, struct stat *st); - int (*chmod) (vnode_t *node, mode_t mode); - int (*chown) (vnode_t *node, uid_t uid, gid_t gid); + int (*access) (struct vnode *node, uid_t *uid, gid_t *gid, mode_t *mode); + int (*creat) (struct vnode *node, struct vfs_ioctx *ctx, const char *name, mode_t mode, int opt, struct vnode **res); + int (*mkdir) (struct vnode *at, const char *name, mode_t mode); + int (*unlink) (struct vnode *at, struct vnode *vn, const char *name); + int (*stat) (struct vnode *node, struct stat *st); + int (*chmod) (struct vnode *node, mode_t mode); + int (*chown) (struct vnode *node, uid_t uid, gid_t gid); // Directory access - int (*opendir) (vnode_t *node, int opt); + int (*opendir) (struct vnode *node, int opt); int (*readdir) (struct ofile *fd); // File access - int (*open) (vnode_t *node, int opt); + int (*open) (struct vnode *node, int opt); void (*close) (struct ofile *fd); ssize_t (*read) (struct ofile *fd, void *buf, size_t count); ssize_t (*write) (struct ofile *fd, const void *buf, size_t count); @@ -57,24 +59,28 @@ struct vnode_operations { struct vnode { enum vnode_type type; + char name[NODE_MAXLEN]; + + struct vnode *first_child; + struct vnode *next_child; + struct vnode *parent; + uint32_t refcount; + uint64_t ino; fs_t *fs; - // Private filesystem-specific data (like inode struct) void *fs_data; - // Private filesystem-specific number (like inode number) - uint32_t fs_number; - /* * (struct blkdev *) if type == VN_BLK * (struct chrdev *) if type == VN_CHR */ void *dev; - void *tree_node; struct vnode_operations *op; }; -void vnode_ref(vnode_t *vn); -void vnode_unref(vnode_t *vn); -void vnode_free(vnode_t *vn); +struct vnode *vnode_create(const char *name); + +//void vnode_ref(vnode_t *vn); +//void vnode_unref(vnode_t *vn); +//void vnode_free(vnode_t *vn); diff --git a/include/sys/fs/ofile.h b/include/sys/fs/ofile.h index f601895..85664d6 100644 --- a/include/sys/fs/ofile.h +++ b/include/sys/fs/ofile.h @@ -4,8 +4,6 @@ struct ofile { int flags; - vnode_t *vnode; + struct vnode *vnode; size_t pos; - // Dirent buffer - char dirent_buf[512]; }; diff --git a/include/sys/fs/pty.h b/include/sys/fs/pty.h index e0f808a..06787af 100644 --- a/include/sys/fs/pty.h +++ b/include/sys/fs/pty.h @@ -5,8 +5,8 @@ struct pty { int number; - vnode_t *master; - vnode_t *slave; + struct vnode *master; + struct vnode *slave; // TODO: winsize/termios struct chrdev dev_master; diff --git a/include/sys/fs/vfs.h b/include/sys/fs/vfs.h index 5131b6e..7ab722e 100644 --- a/include/sys/fs/vfs.h +++ b/include/sys/fs/vfs.h @@ -15,21 +15,21 @@ * with any location in the filesystem tree, * we use this struct to keep things in order. */ -struct vfs_node { - char name[256]; - // Current vnode unless mnt, otherwise the root node of - // the mounted filesystem - vnode_t *vnode; - // Real vnode if mountpoint - vnode_t *real_vnode; - // Is 1 when node is a mountpoint - int ismount; - // Parent ref - struct vfs_node *parent; - // Linked list of children - struct vfs_node *child; - struct vfs_node *cdr; -}; +//struct vfs_node { +// char name[256]; +// // Current vnode unless mnt, otherwise the root node of +// // the mounted filesystem +// vnode_t *vnode; +// // Real vnode if mountpoint +// vnode_t *real_vnode; +// // Is 1 when node is a mountpoint +// int ismount; +// // Parent ref +// struct vfs_node *parent; +// // Linked list of children +// struct vfs_node *child; +// struct vfs_node *cdr; +//}; /** * @brief Process-specific I/O context details @@ -38,7 +38,7 @@ struct vfs_node { */ struct vfs_ioctx { // Process' current working directory - vnode_t *cwd_vnode; + struct vnode *cwd_vnode; uid_t uid; gid_t gid; }; @@ -74,78 +74,63 @@ void vfs_dump_tree(void); * @param path The result path * @param vn vnode */ -void vfs_vnode_path(char *path, vnode_t *vn); +void vfs_vnode_path(char *path, struct vnode *vn); -// Tree node ops -/** - * @brief Free internal VFS node struct - * @param n Tree node - */ -void vfs_node_free(struct vfs_node *n); -/** - * @brief Allocate a new node and associate it with - * a vnode - * @param name Name to be given to the tree node - * @param vn The vnode to bind it to - * @return Non-NULL (struct vfs_node *) on success, NULL otherwise - */ -struct vfs_node *vfs_node_create(const char *name, vnode_t *vn); - -int vfs_mount_internal(struct vfs_node *at, void *blkdev, const char *fs_name, const char *opt); -/** - * @brief Create a mountpoint in a filesystem tree so that - * a "source" directory actually refers to the root - * node of a "target" filesystem. - * @param ctx I/O context - * @param at Path to create mountpoint at - * @param blk Block device on which a filesystem shall be mounted - * @param fs_name Filesystem name - * @param fs_opt Filesystem mounting options - * @return 0 on success, - * -EACCES if the caller context's UID is not zero, - * -EBUSY if trying to create a mountpoint at a - * directory which is not empty, - * -ENOENT if the directory does not exist - */ -int vfs_mount(struct vfs_ioctx *ctx, const char *at, void *blk, const char *fs_name, const char *fs_opt); -/** - * @brief Destroy a mountpoint in a filesystem tree - * @param ctx I/O context - * @param target Path to unmount - * @return 0 on success, - * -EBUSY if there are any used filesystem objects inside - * the mountpoint, - * -EACCES if the caller context's UID is not zero, - * -ENOENT if the directory does not exist - */ -int vfs_umount(struct vfs_ioctx *ctx, const char *target); - -/** - * @brief Read symlink's destination path into a buffer - * @param ctx I/O context - * @param path - */ -int vfs_readlink(struct vfs_ioctx *ctx, const char *path, char *buf); -int vfs_readlinkat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, char *buf); -int vfs_symlink(struct vfs_ioctx *ctx, const char *target, const char *linkpath); - -// File ops -int vfs_truncate(struct vfs_ioctx *ctx, struct ofile *fd, size_t length); -int vfs_creat(struct vfs_ioctx *ctx, struct ofile *fd, const char *path, int mode, int opt); -int vfs_open(struct vfs_ioctx *ctx, struct ofile *fd, const char *path, int mode, int opt); -int vfs_open_node(struct vfs_ioctx *ctx, struct ofile *fd, vnode_t *vn, int opt); -void vfs_close(struct vfs_ioctx *ctx, struct ofile *fd); -ssize_t vfs_read(struct vfs_ioctx *ctx, struct ofile *fd, void *buf, size_t count); -ssize_t vfs_write(struct vfs_ioctx *ctx, struct ofile *fd, const void *buf, size_t count); -int vfs_unlink(struct vfs_ioctx *ctx, const char *path, int is_rmdir); - -int vfs_stat(struct vfs_ioctx *ctx, const char *path, struct stat *st); -int vfs_statat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, struct stat *st); -int vfs_chmod(struct vfs_ioctx *ctx, const char *path, mode_t mode); -int vfs_chown(struct vfs_ioctx *ctx, const char *path, uid_t uid, gid_t gid); -int vfs_access(struct vfs_ioctx *ctx, const char *path, int mode); -// Directroy ops -int vfs_mkdir(struct vfs_ioctx *ctx, const char *path, mode_t mode); -struct dirent *vfs_readdir(struct vfs_ioctx *ctx, struct ofile *fd); - -int vfs_statvfs(struct vfs_ioctx *ctx, const char *path, struct statvfs *st); +//int vfs_mount_internal(struct vfs_node *at, void *blkdev, const char *fs_name, const char *opt); +////** +// * @brief Create a mountpoint in a filesystem tree so that +// * a "source" directory actually refers to the root +// * node of a "target" filesystem. +// * @param ctx I/O context +// * @param at Path to create mountpoint at +// * @param blk Block device on which a filesystem shall be mounted +// * @param fs_name Filesystem name +// * @param fs_opt Filesystem mounting options +// * @return 0 on success, +// * -EACCES if the caller context's UID is not zero, +// * -EBUSY if trying to create a mountpoint at a +// * directory which is not empty, +// * -ENOENT if the directory does not exist +// */ +//int vfs_mount(struct vfs_ioctx *ctx, const char *at, void *blk, const char *fs_name, const char *fs_opt); +///** +// * @brief Destroy a mountpoint in a filesystem tree +// * @param ctx I/O context +// * @param target Path to unmount +// * @return 0 on success, +// * -EBUSY if there are any used filesystem objects inside +// * the mountpoint, +// * -EACCES if the caller context's UID is not zero, +// * -ENOENT if the directory does not exist +// */ +//int vfs_umount(struct vfs_ioctx *ctx, const char *target); +// +///** +// * @brief Read symlink's destination path into a buffer +// * @param ctx I/O context +// * @param path +// */ +//int vfs_readlink(struct vfs_ioctx *ctx, const char *path, char *buf); +//int vfs_readlinkat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, char *buf); +//int vfs_symlink(struct vfs_ioctx *ctx, const char *target, const char *linkpath); +// +//// File ops +//int vfs_truncate(struct vfs_ioctx *ctx, struct ofile *fd, size_t length); +//int vfs_creat(struct vfs_ioctx *ctx, struct ofile *fd, const char *path, int mode, int opt); +//int vfs_open(struct vfs_ioctx *ctx, struct ofile *fd, const char *path, int mode, int opt); +//int vfs_open_node(struct vfs_ioctx *ctx, struct ofile *fd, vnode_t *vn, int opt); +//void vfs_close(struct vfs_ioctx *ctx, struct ofile *fd); +//ssize_t vfs_read(struct vfs_ioctx *ctx, struct ofile *fd, void *buf, size_t count); +//ssize_t vfs_write(struct vfs_ioctx *ctx, struct ofile *fd, const void *buf, size_t count); +//int vfs_unlink(struct vfs_ioctx *ctx, const char *path, int is_rmdir); +// +//int vfs_stat(struct vfs_ioctx *ctx, const char *path, struct stat *st); +//int vfs_statat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, struct stat *st); +//int vfs_chmod(struct vfs_ioctx *ctx, const char *path, mode_t mode); +//int vfs_chown(struct vfs_ioctx *ctx, const char *path, uid_t uid, gid_t gid); +//int vfs_access(struct vfs_ioctx *ctx, const char *path, int mode); +//// Directroy ops +//int vfs_mkdir(struct vfs_ioctx *ctx, const char *path, mode_t mode); +//struct dirent *vfs_readdir(struct vfs_ioctx *ctx, struct ofile *fd); +// +//int vfs_statvfs(struct vfs_ioctx *ctx, const char *path, struct statvfs *st); diff --git a/sys/amd64/hw/ps2.c b/sys/amd64/hw/ps2.c index a36523b..e94dcc7 100644 --- a/sys/amd64/hw/ps2.c +++ b/sys/amd64/hw/ps2.c @@ -33,7 +33,7 @@ uint32_t ps2_irq_keyboard(void *ctx) { char key_char = ps2_key_table_0[key]; if (key_char != 0) { - tty_buffer_write(0, key_char); + //tty_buffer_write(0, key_char); } } diff --git a/sys/amd64/hw/rs232.c b/sys/amd64/hw/rs232.c index 7b19080..ba71fb7 100644 --- a/sys/amd64/hw/rs232.c +++ b/sys/amd64/hw/rs232.c @@ -48,7 +48,7 @@ static uint32_t rs232_irq(void *ctx) { c = '\n'; } - tty_buffer_write(0, c); + //tty_buffer_write(0, c); } return has_data ? IRQ_HANDLED : IRQ_UNHANDLED; diff --git a/sys/amd64/kernel.c b/sys/amd64/kernel.c index 8ea4d3e..7cae684 100644 --- a/sys/amd64/kernel.c +++ b/sys/amd64/kernel.c @@ -61,11 +61,11 @@ void kernel_main(struct amd64_loader_data *data) { pci_init(); vfs_init(); - tty_init(); + //tty_init(); if (data->initrd_ptr) { // Create ram0 block device - ramblk_init(MM_VIRTUALIZE(data->initrd_ptr), data->initrd_len); - tarfs_init(); + //ramblk_init(MM_VIRTUALIZE(data->initrd_ptr), data->initrd_len); + //tarfs_init(); } // Initial random seed diff --git a/sys/amd64/sys/sched.c b/sys/amd64/sys/sched.c index 47e0b17..b25a84d 100644 --- a/sys/amd64/sys/sched.c +++ b/sys/amd64/sys/sched.c @@ -73,114 +73,114 @@ void init_func(void *arg) { kdebug("Entering [init]\n"); // Mount rootfs if available - struct blkdev *root_blk = blk_by_name("ram0"); + //struct blkdev *root_blk = blk_by_name("ram0"); struct vfs_ioctx ioctx = {0}; struct ofile fd; struct stat st; int res; - ext2_class_init(); + //ext2_class_init(); - if (root_blk) { - if ((res = vfs_mount(&ioctx, "/", root_blk, "ustar", NULL)) != 0) { - panic("mount rootfs: %s\n", kstrerror(res)); - } + //if (root_blk) { + // if ((res = vfs_mount(&ioctx, "/", root_blk, "ustar", NULL)) != 0) { + // panic("mount rootfs: %s\n", kstrerror(res)); + // } - // Mount devfs - if ((res = vfs_mount(&ioctx, "/dev", NULL, "devfs", NULL)) != 0) { - panic("mount devfs: %s\n", kstrerror(res)); - } + // // Mount devfs + // if ((res = vfs_mount(&ioctx, "/dev", NULL, "devfs", NULL)) != 0) { + // panic("mount devfs: %s\n", kstrerror(res)); + // } - // Try to mount /dev/sda1 at /mnt (don't panic on failure, though) - struct blkdev *sda1_blk = blk_by_name("sda1"); - if (sda1_blk) { - kinfo("Trying to mount /dev/sda1 -> /mnt\n"); + // // Try to mount /dev/sda1 at /mnt (don't panic on failure, though) + // struct blkdev *sda1_blk = blk_by_name("sda1"); + // if (sda1_blk) { + // kinfo("Trying to mount /dev/sda1 -> /mnt\n"); - if ((res = vfs_mount(&ioctx, "/mnt", sda1_blk, "auto", NULL)) != 0) { - kwarn("/dev/sda1: %s\n", kstrerror(res)); - } - } else { - // Maybe an IDE drive? - sda1_blk = blk_by_name("hda1"); - if (sda1_blk) { - kinfo("Trying to mount /dev/hda1 -> /mnt\n"); + // if ((res = vfs_mount(&ioctx, "/mnt", sda1_blk, "auto", NULL)) != 0) { + // kwarn("/dev/sda1: %s\n", kstrerror(res)); + // } + // } else { + // // Maybe an IDE drive? + // sda1_blk = blk_by_name("hda1"); + // if (sda1_blk) { + // kinfo("Trying to mount /dev/hda1 -> /mnt\n"); - if ((res = vfs_mount(&ioctx, "/mnt", sda1_blk, "auto", NULL)) != 0) { - kwarn("/dev/sda1: %s\n", kstrerror(res)); - } - } - } + // if ((res = vfs_mount(&ioctx, "/mnt", sda1_blk, "auto", NULL)) != 0) { + // kwarn("/dev/sda1: %s\n", kstrerror(res)); + // } + // } + // } - if ((res = vfs_stat(&ioctx, "/init", &st)) != 0) { - panic("/init: %s\n", kstrerror(res)); - } + // if ((res = vfs_stat(&ioctx, "/init", &st)) != 0) { + // panic("/init: %s\n", kstrerror(res)); + // } - if ((st.st_mode & S_IFMT) != S_IFREG) { - panic("/init: not a regular file\n"); - } + // if ((st.st_mode & S_IFMT) != S_IFREG) { + // panic("/init: not a regular file\n"); + // } - if (!(st.st_mode & 0111)) { - panic("/init: not executable\n"); - } + // if (!(st.st_mode & 0111)) { + // panic("/init: not executable\n"); + // } - kdebug("/init is %S\n", st.st_size); + // kdebug("/init is %S\n", st.st_size); - void *exec_buf = kmalloc(st.st_size); - size_t pos = 0; - ssize_t bread; - assert(exec_buf, "Failed to allocate buffer for reading\n"); + // void *exec_buf = kmalloc(st.st_size); + // size_t pos = 0; + // ssize_t bread; + // assert(exec_buf, "Failed to allocate buffer for reading\n"); - if ((res = vfs_open(&ioctx, &fd, "/init", 0, O_RDONLY)) != 0) { - panic("open(): %s\n", kstrerror(res)); - } + // if ((res = vfs_open(&ioctx, &fd, "/init", 0, O_RDONLY)) != 0) { + // panic("open(): %s\n", kstrerror(res)); + // } - while ((bread = vfs_read(&ioctx, &fd, (char *) exec_buf + pos, MIN(512, st.st_size - pos))) > 0) { - pos += bread; - } + // while ((bread = vfs_read(&ioctx, &fd, (char *) exec_buf + pos, MIN(512, st.st_size - pos))) > 0) { + // pos += bread; + // } - vfs_close(&ioctx, &fd); + // vfs_close(&ioctx, &fd); - kdebug("Successfully read init\n"); + // kdebug("Successfully read init\n"); - struct thread *init_thread = (struct thread *) kmalloc(sizeof(struct thread)); - _assert(init_thread); - mm_space_t thread_space = amd64_mm_pool_alloc(); - _assert(thread_space); - mm_space_clone(thread_space, mm_kernel, MM_CLONE_FLG_KERNEL); + // struct thread *init_thread = (struct thread *) kmalloc(sizeof(struct thread)); + // _assert(init_thread); + // mm_space_t thread_space = amd64_mm_pool_alloc(); + // _assert(thread_space); + // mm_space_clone(thread_space, mm_kernel, MM_CLONE_FLG_KERNEL); - if (thread_init( - init_thread, - thread_space, - 0, - 0, - 0, - 0, - 0, - 0, - NULL) < 0) { - panic("Failed to setup init task\n"); - } + // if (thread_init( + // init_thread, + // thread_space, + // 0, + // 0, + // 0, + // 0, + // 0, + // 0, + // NULL) < 0) { + // panic("Failed to setup init task\n"); + // } - if ((res = elf_load(init_thread, exec_buf)) < 0) { - panic("Failed to load binary: %s\n", kstrerror(res)); - } + // if ((res = elf_load(init_thread, exec_buf)) < 0) { + // panic("Failed to load binary: %s\n", kstrerror(res)); + // } - // Free memory - kfree(exec_buf); + // // Free memory + // kfree(exec_buf); - // FIXME: this way of opening requires devfs to be mounted at /dev, I guess - // I can just have dev_entry have a vnode for each of them (and remove - // ones used in devfs mapper) - // Set tty0 input - if ((res = vfs_open(&init_thread->ioctx, &init_thread->fds[0], "/dev/tty0", O_RDONLY, 0)) < 0) { - panic("Failed to set up tty0 for input: %s\n", kstrerror(res)); - } - if ((res = vfs_open(&init_thread->ioctx, &init_thread->fds[1], "/dev/tty0", O_WRONLY, 0)) < 0) { - panic("Failed to set up tty0 for output: %s\n", kstrerror(res)); - } + // // FIXME: this way of opening requires devfs to be mounted at /dev, I guess + // // I can just have dev_entry have a vnode for each of them (and remove + // // ones used in devfs mapper) + // // Set tty0 input + // if ((res = vfs_open(&init_thread->ioctx, &init_thread->fds[0], "/dev/tty0", O_RDONLY, 0)) < 0) { + // panic("Failed to set up tty0 for input: %s\n", kstrerror(res)); + // } + // if ((res = vfs_open(&init_thread->ioctx, &init_thread->fds[1], "/dev/tty0", O_WRONLY, 0)) < 0) { + // panic("Failed to set up tty0 for output: %s\n", kstrerror(res)); + // } - kdebug("Done\n"); - sched_add(init_thread); - } + // kdebug("Done\n"); + // sched_add(init_thread); + //} while (1) { asm volatile ("sti; hlt"); diff --git a/sys/amd64/sys/thread.c b/sys/amd64/sys/thread.c index b4de167..dd8820b 100644 --- a/sys/amd64/sys/thread.c +++ b/sys/amd64/sys/thread.c @@ -153,7 +153,7 @@ void thread_cleanup(struct thread *t) { // Release files for (size_t i = 0; i < 4; ++i) { if (t->fds[i].vnode) { - vfs_close(&t->ioctx, &t->fds[i]); + //vfs_close(&t->ioctx, &t->fds[i]); } } @@ -190,32 +190,33 @@ int sys_execve(const char *filename, const char *const argv[], const char *const ssize_t bread; int res; - if ((res = vfs_stat(&thr->ioctx, filename, &st)) < 0) { - return res; - } + //if ((res = vfs_stat(&thr->ioctx, filename, &st)) < 0) { + // return res; + //} - if ((st.st_mode & S_IFMT) != S_IFREG) { - return -ENOEXEC; - } + //if ((st.st_mode & S_IFMT) != S_IFREG) { + // return -ENOEXEC; + //} - if (!(st.st_mode & 0111)) { - return -ENOEXEC; - } + //if (!(st.st_mode & 0111)) { + // return -ENOEXEC; + //} - file_buf = kmalloc(st.st_size); - if (!file_buf) { - return -ENOMEM; - } + //file_buf = kmalloc(st.st_size); + //if (!file_buf) { + // return -ENOMEM; + //} - if ((res = vfs_open(&thr->ioctx, &fd, filename, 0, O_RDONLY)) != 0) { - return res; - } + return -EINVAL; + //if ((res = vfs_open(&thr->ioctx, &fd, filename, 0, O_RDONLY)) != 0) { + // return res; + //} - while ((bread = vfs_read(&thr->ioctx, &fd, (char *) file_buf + pos, MIN(512, st.st_size - pos))) > 0) { - pos += bread; - } + //while ((bread = vfs_read(&thr->ioctx, &fd, (char *) file_buf + pos, MIN(512, st.st_size - pos))) > 0) { + // pos += bread; + //} - vfs_close(&thr->ioctx, &fd); + //vfs_close(&thr->ioctx, &fd); mm_space_t space = thr->space; @@ -355,12 +356,12 @@ int sys_fork(void) { memset(&thr_dst->ioctx, 0, sizeof(thr_dst->ioctx)); memset(thr_dst->fds, 0, sizeof(thr_dst->fds)); - if ((res = vfs_open(&thr_dst->ioctx, &thr_dst->fds[0], "/dev/tty0", O_RDONLY, 0)) < 0) { - panic("Failed to set up tty0 for input: %s\n", kstrerror(res)); - } - if ((res = vfs_open(&thr_dst->ioctx, &thr_dst->fds[1], "/dev/tty0", O_WRONLY, 0)) < 0) { - panic("Failed to set up tty0 for output: %s\n", kstrerror(res)); - } + //if ((res = vfs_open(&thr_dst->ioctx, &thr_dst->fds[0], "/dev/tty0", O_RDONLY, 0)) < 0) { + // panic("Failed to set up tty0 for input: %s\n", kstrerror(res)); + //} + //if ((res = vfs_open(&thr_dst->ioctx, &thr_dst->fds[1], "/dev/tty0", O_WRONLY, 0)) < 0) { + // panic("Failed to set up tty0 for output: %s\n", kstrerror(res)); + //} sched_add(thr_dst); diff --git a/sys/amd64/sys_file.c b/sys/amd64/sys_file.c index 04d2e2e..8cebf99 100644 --- a/sys/amd64/sys_file.c +++ b/sys/amd64/sys_file.c @@ -10,215 +10,72 @@ #include "sys/debug.h" ssize_t sys_read(int fd, void *buf, size_t lim) { - if (fd >= 4 || fd < 0) { - return -EBADF; - } - struct thread *thr = get_cpu()->thread; - _assert(thr); + return -EINVAL; + //if (fd >= 4 || fd < 0) { + // return -EBADF; + //} + //struct thread *thr = get_cpu()->thread; + //_assert(thr); - struct ofile *of = &thr->fds[fd]; + //struct ofile *of = &thr->fds[fd]; - if (!of->vnode) { - return -EBADF; - } + //if (!of->vnode) { + // return -EBADF; + //} - return vfs_read(&thr->ioctx, of, buf, lim); + //return vfs_read(&thr->ioctx, of, buf, lim); } ssize_t sys_write(int fd, const void *buf, size_t lim) { - if (fd >= 4 || fd < 0) { - return -EBADF; - } - struct thread *thr = get_cpu()->thread; - _assert(thr); - - struct ofile *of = &thr->fds[fd]; - - if (!of->vnode) { - return -EBADF; - } - - return vfs_write(&thr->ioctx, of, buf, lim); + return -EINVAL; } ssize_t sys_readdir(int fd, struct dirent *ent) { - if (fd >= 4 || fd < 0) { - return -EBADF; - } - struct thread *thr = get_cpu()->thread; - _assert(thr); - - struct ofile *of = &thr->fds[fd]; - - if (!of->vnode) { - return -EBADF; - } - - struct dirent *src = vfs_readdir(&thr->ioctx, of); - - if (!src) { - return -1; - } - - // XXX: safe? - memcpy(ent, src, sizeof(struct dirent) + strlen(src->d_name)); - - return src->d_reclen; + return -EINVAL; } int sys_creat(const char *pathname, int mode) { - return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); + return -EINVAL; } int sys_mkdir(const char *pathname, int mode) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - - return vfs_mkdir(&thr->ioctx, pathname, mode); + return -EINVAL; } int sys_unlink(const char *pathname) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - - return vfs_unlink(&thr->ioctx, pathname, 0); + return -EINVAL; } int sys_rmdir(const char *pathname) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - - return vfs_unlink(&thr->ioctx, pathname, 1); + return -EINVAL; } int sys_chdir(const char *filename) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - _assert(filename); - - return vfs_chdir(&thr->ioctx, filename); + return -EINVAL; } // Kinda incompatible with linux, but who cares as long as it's // POSIX on the libc side int sys_getcwd(char *buf, size_t lim) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - _assert(buf); - char tmpbuf[512]; - size_t len; - - vfs_vnode_path(tmpbuf, thr->ioctx.cwd_vnode); - len = strlen(tmpbuf); - - if (lim < len + 1) { - return -1; - } - - strcpy(buf, tmpbuf); - - return 0; + return -EINVAL; } int sys_open(const char *filename, int flags, int mode) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - int fd = -1; - - for (int i = 0; i < 4; ++i) { - if (!thr->fds[i].vnode) { - fd = i; - break; - } - } - - if (fd != -1) { - struct ofile *of = &thr->fds[fd]; - - int res = vfs_open(&thr->ioctx, of, filename, mode, flags); - - if (res != 0) { - of->vnode = NULL; - return res; - } - - return fd; - } else { - return -1; - } + return -EINVAL; } void sys_close(int fd) { - if (fd >= 4 || fd < 0) { - return; - } - struct thread *thr = get_cpu()->thread; - _assert(thr); - - struct ofile *of = &thr->fds[fd]; - - if (!of->vnode) { - return; - } - - vfs_close(&thr->ioctx, of); - of->vnode = NULL; } int sys_stat(const char *filename, struct stat *st) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - - int res = vfs_stat(&thr->ioctx, filename, st); - - return res; + return -EINVAL; } int sys_access(const char *path, int mode) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - return vfs_access(&thr->ioctx, path, mode); + return -EINVAL; } int sys_openpty(int *master, int *slave) { - struct thread *thr = get_cpu()->thread; - _assert(thr); - // Find two free file descriptors - int fd_master = -1, fd_slave = -1; - int res; - - for (int i = 0; i < 4; ++i) { - if (!thr->fds[i].vnode) { - if (fd_master == -1) { - fd_master = i; - continue; - } - fd_slave = i; - break; - } - } - - if (fd_master == -1 || fd_slave == -1) { - return -EMFILE; - } - - struct ofile *of_master = &thr->fds[fd_master]; - struct ofile *of_slave = &thr->fds[fd_slave]; - - struct pty *pty = pty_create(); - _assert(pty); - - of_master->vnode = pty->master; - of_master->flags = O_RDWR; - of_master->pos = 0; - - of_slave->vnode = pty->slave; - of_slave->flags = O_RDWR; - of_slave->pos = 0; - - *master = fd_master; - *slave = fd_slave; - - return 0; + return -EINVAL; } diff --git a/sys/blk.c b/sys/blk.c index 77e1436..db3b44b 100644 --- a/sys/blk.c +++ b/sys/blk.c @@ -79,12 +79,12 @@ struct blk_part { uint64_t lba_size; }; -int blk_mount_auto(struct vfs_node *at, struct blkdev *blk, const char *opt) { +int blk_mount_auto(struct vnode *at, struct blkdev *blk, const char *opt) { int res; - if ((res = vfs_mount_internal(at, blk, "ext2", opt)) == 0) { - return 0; - } + //if ((res = vfs_mount_internal(at, blk, "ext2", opt)) == 0) { + // return 0; + //} return -1; } diff --git a/sys/dev.c b/sys/dev.c index dc4c5b5..679c46d 100644 --- a/sys/dev.c +++ b/sys/dev.c @@ -90,115 +90,115 @@ struct dev_entry *dev_iter(void) { return dev_begin; } -static int devfs_node_mapper(fs_t *devfs, struct vfs_node **root); -static int devfs_node_stat(vnode_t *node, struct stat *st); +//static int devfs_node_mapper(fs_t *devfs, struct vfs_node **root); +//static int devfs_node_stat(vnode_t *node, struct stat *st); -static struct fs_class _devfs = { - .name = "devfs", - .opt = FS_NODE_MAPPER, - .mapper = devfs_node_mapper -}; - -static struct vnode_operations _devfs_vnode_op = { - .stat = devfs_node_stat -}; - -static int devfs_node_stat(vnode_t *node, struct stat *st) { - // TODO: device modes (permissions) - - st->st_size = 0; - st->st_blocks = 0; - st->st_blksize = 0; - - st->st_atime = 0; - st->st_mtime = 0; - st->st_ctime = 0; - - st->st_dev = 0; - st->st_rdev = 0; - - st->st_ino = 0; - st->st_nlink = 1; - - st->st_uid = 0; - st->st_gid = 0; - - if (node == devfs_root_node->vnode) { - st->st_mode = S_IFDIR | 0755; - } else { - struct dev_entry *ent = node->fs_data; - _assert(ent); - if (ent->dev_class == DEV_CLASS_BLOCK) { - st->st_mode = S_IFBLK | 0600; - } else { - st->st_mode = S_IFCHR | 0600; - } - } - - return 0; -} - -static vnode_t *devfs_create_vnode(fs_t *fs, struct vfs_node *node) { - vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t)); - res->tree_node = node; - res->fs = fs; - res->fs_data = NULL; - res->refcount = 0; - res->op = &_devfs_vnode_op; - res->type = VN_DIR; - return res; -} - -static int devfs_node_mapper(fs_t *devfs, struct vfs_node **root) { - _assert(!devfs_root_node); - struct vfs_node *_root; - struct dev_entry *it; - - // Make a root node - _root = (struct vfs_node *) kmalloc(sizeof(struct vfs_node)); - _root->child = NULL; - _root->cdr = NULL; - _root->ismount = 0; - _root->parent = NULL; - _root->real_vnode = NULL; - _root->vnode = NULL; - - // TODO: directory-categories (like "by-uuid" or something) - for (it = dev_iter(); it; it = it->cdr) { - struct vfs_node *ent_node = kmalloc(sizeof(struct vfs_node)); - ent_node->child = NULL; - ent_node->ismount = 0; - ent_node->real_vnode = NULL; - strcpy(ent_node->name, it->dev_name); - - // Create a vnode for device - vnode_t *ent_vnode = devfs_create_vnode(devfs, ent_node); - if (it->dev_class == DEV_CLASS_BLOCK) { - ent_vnode->type = VN_BLK; - } else if (it->dev_class == DEV_CLASS_CHAR) { - ent_vnode->type = VN_CHR; - } else { - panic("Unsupported device class\n"); - } - ent_vnode->fs_data = it; - ent_vnode->dev = it->dev; - - ent_node->vnode = ent_vnode; - - ent_node->parent = _root; - ent_node->cdr = _root->child; - _root->child = ent_node; - } - - vnode_t *vnode = devfs_create_vnode(devfs, _root); - _root->vnode = vnode; - - *root = _root; - devfs_root_node = _root; - - return 0; -} - -static __init void devfs_init(void) { - fs_class_register(&_devfs); -} +//static struct fs_class _devfs = { +// .name = "devfs", +// .opt = FS_NODE_MAPPER, +// .mapper = devfs_node_mapper +//}; +// +//static struct vnode_operations _devfs_vnode_op = { +// .stat = devfs_node_stat +//}; +// +//static int devfs_node_stat(vnode_t *node, struct stat *st) { +// // TODO: device modes (permissions) +// +// st->st_size = 0; +// st->st_blocks = 0; +// st->st_blksize = 0; +// +// st->st_atime = 0; +// st->st_mtime = 0; +// st->st_ctime = 0; +// +// st->st_dev = 0; +// st->st_rdev = 0; +// +// st->st_ino = 0; +// st->st_nlink = 1; +// +// st->st_uid = 0; +// st->st_gid = 0; +// +// if (node == devfs_root_node->vnode) { +// st->st_mode = S_IFDIR | 0755; +// } else { +// struct dev_entry *ent = node->fs_data; +// _assert(ent); +// if (ent->dev_class == DEV_CLASS_BLOCK) { +// st->st_mode = S_IFBLK | 0600; +// } else { +// st->st_mode = S_IFCHR | 0600; +// } +// } +// +// return 0; +//} +// +//static vnode_t *devfs_create_vnode(fs_t *fs, struct vfs_node *node) { +// vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t)); +// res->tree_node = node; +// res->fs = fs; +// res->fs_data = NULL; +// res->refcount = 0; +// res->op = &_devfs_vnode_op; +// res->type = VN_DIR; +// return res; +//} +// +//static int devfs_node_mapper(fs_t *devfs, vnode_t **root) { +// _assert(!devfs_root_node); +// struct vfs_node *_root; +// struct dev_entry *it; +// +// // Make a root node +// _root = (struct vfs_node *) kmalloc(sizeof(struct vfs_node)); +// _root->child = NULL; +// _root->cdr = NULL; +// _root->ismount = 0; +// _root->parent = NULL; +// _root->real_vnode = NULL; +// _root->vnode = NULL; +// +// // TODO: directory-categories (like "by-uuid" or something) +// for (it = dev_iter(); it; it = it->cdr) { +// struct vfs_node *ent_node = kmalloc(sizeof(struct vfs_node)); +// ent_node->child = NULL; +// ent_node->ismount = 0; +// ent_node->real_vnode = NULL; +// strcpy(ent_node->name, it->dev_name); +// +// // Create a vnode for device +// vnode_t *ent_vnode = devfs_create_vnode(devfs, ent_node); +// if (it->dev_class == DEV_CLASS_BLOCK) { +// ent_vnode->type = VN_BLK; +// } else if (it->dev_class == DEV_CLASS_CHAR) { +// ent_vnode->type = VN_CHR; +// } else { +// panic("Unsupported device class\n"); +// } +// ent_vnode->fs_data = it; +// ent_vnode->dev = it->dev; +// +// ent_node->vnode = ent_vnode; +// +// ent_node->parent = _root; +// ent_node->cdr = _root->child; +// _root->child = ent_node; +// } +// +// vnode_t *vnode = devfs_create_vnode(devfs, _root); +// _root->vnode = vnode; +// +// *root = _root; +// devfs_root_node = _root; +// +// return 0; +//} +// +//static __init void devfs_init(void) { +// fs_class_register(&_devfs); +//} diff --git a/sys/vfs/fs_class.c b/sys/vfs/fs_class.c index d804bf5..2cc48ae 100644 --- a/sys/vfs/fs_class.c +++ b/sys/vfs/fs_class.c @@ -9,7 +9,7 @@ static struct fs_class *fses[10] = { NULL }; static struct fs mounts[10]; -struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, vnode_t *at) { +struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, struct vnode *at) { for (size_t i = 0; i < 10; ++i) { if (mounts[i].cls == NULL) { mounts[i].cls = cls; diff --git a/sys/vfs/node.c b/sys/vfs/node.c index 420aee4..bdf5fd9 100644 --- a/sys/vfs/node.c +++ b/sys/vfs/node.c @@ -7,119 +7,137 @@ #include "sys/heap.h" #include "sys/string.h" -static void vfs_node_remove(struct vfs_node *node) { - // If node->parent == NULL, we've called this - // function on [root], which should not be possible - if (!node || !node->parent) { - return; - } +struct vnode *vnode_create(const char *name) { + struct vnode *node = (struct vnode *) kmalloc(sizeof(struct vnode)); + _assert(node); - struct vfs_node *parent = node->parent; + node->parent = NULL; + node->first_child = NULL; + node->next_child = NULL; - if (parent->child == node) { - parent->child = node->cdr; + if (name) { + _assert(strlen(name) < NODE_MAXLEN); + strcpy(node->name, name); } else { - for (struct vfs_node *it = parent->child; it; it = it->cdr) { - if (it->cdr == node) { - it->cdr = node->cdr; - break; - } - } - - // TODO: handle case when for some reason node is absent in - // parent's children list + node->name[0] = 0; } - // Decrement refcount for parent, unless it's [root] - if (parent->parent && !parent->child && !parent->vnode->refcount) { - vnode_free(parent->vnode); - } - - // Just a wrapper around free() - vfs_node_free(node); + return node; } -void vnode_free(vnode_t *vn) { - _assert(vn && vn->op); - _assert(!vn->refcount); - struct vfs_node *node = vn->tree_node; - struct vfs_node *link_node = NULL; - - if (node->ismount) { - return; - } - - if (vn->op->destroy) { - // This will free/release underlying fs_data - vn->op->destroy(vn); - } - - if (node) { - vfs_node_remove(node); - } - - memset(vn, 0, sizeof(vnode_t)); - kfree(vn); -} - -void vnode_ref(vnode_t *vn) { -// char buf[1024]; -// vfs_vnode_path(buf, vn); -// printf("++refcount for %s\n", buf); - _assert(vn); - if (vn->type == VN_BLK || vn->type == VN_CHR) { - return; - } - _assert(vn->fs); - _assert(vn->fs->cls); - - // FS_NODE_MAPPER means persistent vnodes - if (vn->fs->cls->opt & FS_NODE_MAPPER) { - return; - } - - struct vfs_node *node = (struct vfs_node *) vn->tree_node; - if (node && !node->parent) { - // Don't change refcounter for root nodes - return; - } - - ++vn->refcount; -} - -void vnode_unref(vnode_t *vn) { - _assert(vn); - if (vn->type == VN_BLK || vn->type == VN_CHR) { - return; - } - - _assert(vn->fs); - _assert(vn->fs->cls); - - // FS_NODE_MAPPER means persistent vnodes - if (vn->fs->cls->opt & FS_NODE_MAPPER) { - return; - } - - struct vfs_node *node = (struct vfs_node *) vn->tree_node; - if (!node->parent) { - return; - } - - if (vn->refcount > 0) { - --vn->refcount; - - if (vn->refcount == 0) { - if (node->child) { - return; - } - - // Free vnode - vnode_free(vn); - } - } else { - _assert(node->child); - - kdebug("--refcount with 0 but child\n"); - } -} +//static void vfs_node_remove(struct vfs_node *node) { +// // If node->parent == NULL, we've called this +// // function on [root], which should not be possible +// if (!node || !node->parent) { +// return; +// } +// +// struct vfs_node *parent = node->parent; +// +// if (parent->child == node) { +// parent->child = node->cdr; +// } else { +// for (struct vfs_node *it = parent->child; it; it = it->cdr) { +// if (it->cdr == node) { +// it->cdr = node->cdr; +// break; +// } +// } +// +// // TODO: handle case when for some reason node is absent in +// // parent's children list +// } +// +// // Decrement refcount for parent, unless it's [root] +// if (parent->parent && !parent->child && !parent->vnode->refcount) { +// vnode_free(parent->vnode); +// } +// +// // Just a wrapper around free() +// vfs_node_free(node); +//} +// +//void vnode_free(vnode_t *vn) { +// _assert(vn && vn->op); +// _assert(!vn->refcount); +// struct vfs_node *node = vn->tree_node; +// struct vfs_node *link_node = NULL; +// +// if (node->ismount) { +// return; +// } +// +// if (vn->op->destroy) { +// // This will free/release underlying fs_data +// vn->op->destroy(vn); +// } +// +// if (node) { +// vfs_node_remove(node); +// } +// +// memset(vn, 0, sizeof(vnode_t)); +// kfree(vn); +//} +// +//void vnode_ref(vnode_t *vn) { +//// char buf[1024]; +//// vfs_vnode_path(buf, vn); +//// printf("++refcount for %s\n", buf); +// _assert(vn); +// if (vn->type == VN_BLK || vn->type == VN_CHR) { +// return; +// } +// _assert(vn->fs); +// _assert(vn->fs->cls); +// +// // FS_NODE_MAPPER means persistent vnodes +// if (vn->fs->cls->opt & FS_NODE_MAPPER) { +// return; +// } +// +// struct vfs_node *node = (struct vfs_node *) vn->tree_node; +// if (node && !node->parent) { +// // Don't change refcounter for root nodes +// return; +// } +// +// ++vn->refcount; +//} +// +//void vnode_unref(vnode_t *vn) { +// _assert(vn); +// if (vn->type == VN_BLK || vn->type == VN_CHR) { +// return; +// } +// +// _assert(vn->fs); +// _assert(vn->fs->cls); +// +// // FS_NODE_MAPPER means persistent vnodes +// if (vn->fs->cls->opt & FS_NODE_MAPPER) { +// return; +// } +// +// struct vfs_node *node = (struct vfs_node *) vn->tree_node; +// if (!node->parent) { +// return; +// } +// +// if (vn->refcount > 0) { +// --vn->refcount; +// +// if (vn->refcount == 0) { +// if (node->child) { +// return; +// } +// +// // Free vnode +// vnode_free(vn); +// } +// } else { +// _assert(node->child); +// +// kdebug("--refcount with 0 but child\n"); +// } +//} diff --git a/sys/vfs/vfs.c b/sys/vfs/vfs.c index 0cb2f6c..82bf94e 100644 --- a/sys/vfs/vfs.c +++ b/sys/vfs/vfs.c @@ -18,221 +18,221 @@ // // #include -static struct vfs_node vfs_root_node; +//static struct vfs_node vfs_root_node; +// +//static int vfs_find(vnode_t *cwd_vnode, const char *path, vnode_t **res_vnode); +//static int vfs_access_internal(struct vfs_ioctx *ctx, int desm, mode_t mode, uid_t uid, gid_t gid); +//static int vfs_vnode_access(struct vfs_ioctx *ctx, vnode_t *vn, int mode); +// +//static int vfs_setcwd_rel(struct vfs_ioctx *ctx, vnode_t *at, const char *path) { +// // cwd is absolute path +// vnode_t *new_cwd; +// int res; +// if ((res = vfs_find(at, path, &new_cwd)) != 0) { +// return res; +// } +// +// vnode_ref(new_cwd); +// if (new_cwd->type != VN_DIR) { +// vnode_unref(new_cwd); +// return -ENOTDIR; +// } +// +// if ((res = vfs_vnode_access(ctx, new_cwd, X_OK)) < 0) { +// vnode_unref(new_cwd); +// return res; +// } +// +// if (ctx->cwd_vnode) { +// vnode_unref(ctx->cwd_vnode); +// } +// ctx->cwd_vnode = new_cwd; +// +// return 0; +//} -static int vfs_find(vnode_t *cwd_vnode, const char *path, vnode_t **res_vnode); -static int vfs_access_internal(struct vfs_ioctx *ctx, int desm, mode_t mode, uid_t uid, gid_t gid); -static int vfs_vnode_access(struct vfs_ioctx *ctx, vnode_t *vn, int mode); +//int vfs_setcwd(struct vfs_ioctx *ctx, const char *cwd) { +// return vfs_setcwd_rel(ctx, NULL, cwd); +//} -static int vfs_setcwd_rel(struct vfs_ioctx *ctx, vnode_t *at, const char *path) { - // cwd is absolute path - vnode_t *new_cwd; - int res; - if ((res = vfs_find(at, path, &new_cwd)) != 0) { - return res; - } +//int vfs_chdir(struct vfs_ioctx *ctx, const char *cwd_rel) { +// return vfs_setcwd_rel(ctx, ctx->cwd_vnode, cwd_rel); +//} - vnode_ref(new_cwd); - if (new_cwd->type != VN_DIR) { - vnode_unref(new_cwd); - return -ENOTDIR; - } - - if ((res = vfs_vnode_access(ctx, new_cwd, X_OK)) < 0) { - vnode_unref(new_cwd); - return res; - } - - if (ctx->cwd_vnode) { - vnode_unref(ctx->cwd_vnode); - } - ctx->cwd_vnode = new_cwd; - - return 0; -} - -int vfs_setcwd(struct vfs_ioctx *ctx, const char *cwd) { - return vfs_setcwd_rel(ctx, NULL, cwd); -} - -int vfs_chdir(struct vfs_ioctx *ctx, const char *cwd_rel) { - return vfs_setcwd_rel(ctx, ctx->cwd_vnode, cwd_rel); -} - -void vfs_vnode_path(char *path, vnode_t *vn) { - size_t c = 0; - if (!vn) { - path[0] = '/'; - path[1] = 0; - return; - } - struct vfs_node *node = vn->tree_node; - struct vfs_node *backstack[10] = { NULL }; - if (!node) { - panic("Unhandled: NULL node\n"); - } - if (!node->parent) { - path[0] = '/'; - path[1] = 0; - return; - } - size_t bstp = 10; - while (node) { - if (bstp == 0) { - panic("Node stack overflow\n"); - } - - backstack[--bstp] = node; - node = node->parent; - } - - for (size_t i = bstp; i < 10; ++i) { - size_t len; - if (backstack[i]->parent) { - // Non-root - len = strlen(backstack[i]->name); - strcpy(path + c, backstack[i]->name); - } else { - len = 0; - } - c += len; - if (i != 9) { - path[c] = '/'; - } - ++c; - } -} - -static int vfs_open_access_mask(int oflags) { - if (oflags & O_EXEC) { - return X_OK; - } - - switch (oflags & O_ACCMODE) { - case O_WRONLY: - return W_OK; - case O_RDONLY: - return R_OK; - case O_RDWR: - return R_OK | W_OK; - default: - panic("Unknown access mode\n"); - } -} - -static int vfs_access_internal(struct vfs_ioctx *ctx, int desm, mode_t mode, uid_t uid, gid_t gid) { - if (ctx->uid == 0) { - if (desm & X_OK) { - // Check if anyone at all can execute this - if (!(mode & (S_IXOTH | S_IXGRP | S_IXUSR))) { - return -EACCES; - } - } - - return 0; - } - - if (uid == ctx->uid) { - if ((desm & R_OK) && !(mode & S_IRUSR)) { - return -EACCES; - } - if ((desm & W_OK) && !(mode & S_IWUSR)) { - return -EACCES; - } - if ((desm & X_OK) && !(mode & S_IXUSR)) { - return -EACCES; - } - } else if (gid == ctx->gid) { - if ((desm & R_OK) && !(mode & S_IRGRP)) { - return -EACCES; - } - if ((desm & W_OK) && !(mode & S_IWGRP)) { - return -EACCES; - } - if ((desm & X_OK) && !(mode & S_IXGRP)) { - return -EACCES; - } - } else { - if ((desm & R_OK) && !(mode & S_IROTH)) { - return -EACCES; - } - if ((desm & W_OK) && !(mode & S_IWOTH)) { - return -EACCES; - } - if ((desm & X_OK) && !(mode & S_IXOTH)) { - return -EACCES; - } - } - - return 0; -} - -static int vfs_vnode_access(struct vfs_ioctx *ctx, vnode_t *vn, int mode) { - mode_t vn_mode; - uid_t vn_uid; - gid_t vn_gid; - int res; - - // Filesystem does not have permissions - if (!vn->op || !vn->op->access) { - return 0; - } - - if ((res = vn->op->access(vn, &vn_uid, &vn_gid, &vn_mode)) < 0) { - return res; - } - - return vfs_access_internal(ctx, mode, vn_mode, vn_uid, vn_gid); -} +//void vfs_vnode_path(char *path, vnode_t *vn) { +// size_t c = 0; +// if (!vn) { +// path[0] = '/'; +// path[1] = 0; +// return; +// } +// struct vfs_node *node = vn->tree_node; +// struct vfs_node *backstack[10] = { NULL }; +// if (!node) { +// panic("Unhandled: NULL node\n"); +// } +// if (!node->parent) { +// path[0] = '/'; +// path[1] = 0; +// return; +// } +// size_t bstp = 10; +// while (node) { +// if (bstp == 0) { +// panic("Node stack overflow\n"); +// } +// +// backstack[--bstp] = node; +// node = node->parent; +// } +// +// for (size_t i = bstp; i < 10; ++i) { +// size_t len; +// if (backstack[i]->parent) { +// // Non-root +// len = strlen(backstack[i]->name); +// strcpy(path + c, backstack[i]->name); +// } else { +// len = 0; +// } +// c += len; +// if (i != 9) { +// path[c] = '/'; +// } +// ++c; +// } +//} +// +//static int vfs_open_access_mask(int oflags) { +// if (oflags & O_EXEC) { +// return X_OK; +// } +// +// switch (oflags & O_ACCMODE) { +// case O_WRONLY: +// return W_OK; +// case O_RDONLY: +// return R_OK; +// case O_RDWR: +// return R_OK | W_OK; +// default: +// panic("Unknown access mode\n"); +// } +//} +// +//static int vfs_access_internal(struct vfs_ioctx *ctx, int desm, mode_t mode, uid_t uid, gid_t gid) { +// if (ctx->uid == 0) { +// if (desm & X_OK) { +// // Check if anyone at all can execute this +// if (!(mode & (S_IXOTH | S_IXGRP | S_IXUSR))) { +// return -EACCES; +// } +// } +// +// return 0; +// } +// +// if (uid == ctx->uid) { +// if ((desm & R_OK) && !(mode & S_IRUSR)) { +// return -EACCES; +// } +// if ((desm & W_OK) && !(mode & S_IWUSR)) { +// return -EACCES; +// } +// if ((desm & X_OK) && !(mode & S_IXUSR)) { +// return -EACCES; +// } +// } else if (gid == ctx->gid) { +// if ((desm & R_OK) && !(mode & S_IRGRP)) { +// return -EACCES; +// } +// if ((desm & W_OK) && !(mode & S_IWGRP)) { +// return -EACCES; +// } +// if ((desm & X_OK) && !(mode & S_IXGRP)) { +// return -EACCES; +// } +// } else { +// if ((desm & R_OK) && !(mode & S_IROTH)) { +// return -EACCES; +// } +// if ((desm & W_OK) && !(mode & S_IWOTH)) { +// return -EACCES; +// } +// if ((desm & X_OK) && !(mode & S_IXOTH)) { +// return -EACCES; +// } +// } +// +// return 0; +//} +// +//static int vfs_vnode_access(struct vfs_ioctx *ctx, vnode_t *vn, int mode) { +// mode_t vn_mode; +// uid_t vn_uid; +// gid_t vn_gid; +// int res; +// +// // Filesystem does not have permissions +// if (!vn->op || !vn->op->access) { +// return 0; +// } +// +// if ((res = vn->op->access(vn, &vn_uid, &vn_gid, &vn_mode)) < 0) { +// return res; +// } +// +// return vfs_access_internal(ctx, mode, vn_mode, vn_uid, vn_gid); +//} void vfs_init(void) { - // Setup root node - strcpy(vfs_root_node.name, "[root]"); - vfs_root_node.vnode = NULL; - vfs_root_node.real_vnode = NULL; - vfs_root_node.parent = NULL; - vfs_root_node.cdr = NULL; - vfs_root_node.child = NULL; +// // Setup root node +// strcpy(vfs_root_node.name, "[root]"); +// vfs_root_node.vnode = NULL; +// vfs_root_node.real_vnode = NULL; +// vfs_root_node.parent = NULL; +// vfs_root_node.cdr = NULL; +// vfs_root_node.child = NULL; } -static const char *vfs_path_element(char *dst, const char *src) { - const char *sep = strchr(src, '/'); - if (!sep) { - strcpy(dst, src); - return NULL; - } else { - strncpy(dst, src, sep - src); - dst[sep - src] = 0; - while (*sep == '/') { - ++sep; - } - if (!*sep) { - return NULL; - } - return sep; - } -} +//static const char *vfs_path_element(char *dst, const char *src) { +// const char *sep = strchr(src, '/'); +// if (!sep) { +// strcpy(dst, src); +// return NULL; +// } else { +// strncpy(dst, src, sep - src); +// dst[sep - src] = 0; +// while (*sep == '/') { +// ++sep; +// } +// if (!*sep) { +// return NULL; +// } +// return sep; +// } +//} -void vfs_node_free(struct vfs_node *node) { - _assert(node && node->vnode); - _assert(node->vnode->refcount == 0); - kfree(node); -} - -struct vfs_node *vfs_node_create(const char *name, vnode_t *vn) { - _assert(vn); - struct vfs_node *node = (struct vfs_node *) kmalloc(sizeof(struct vfs_node)); - vn->refcount = 0; - vn->tree_node = node; - node->vnode = vn; - strcpy(node->name, name); - node->ismount = 0; - node->real_vnode = NULL; - node->parent = NULL; - node->child = NULL; - node->cdr = NULL; - return node; -} +//void vfs_node_free(struct vfs_node *node) { +// _assert(node && node->vnode); +// _assert(node->vnode->refcount == 0); +// kfree(node); +//} +// +//struct vfs_node *vfs_node_create(const char *name, vnode_t *vn) { +// _assert(vn); +// struct vfs_node *node = (struct vfs_node *) kmalloc(sizeof(struct vfs_node)); +// vn->refcount = 0; +// vn->tree_node = node; +// node->vnode = vn; +// strcpy(node->name, name); +// node->ismount = 0; +// node->real_vnode = NULL; +// node->parent = NULL; +// node->child = NULL; +// node->cdr = NULL; +// return node; +//} /** * @brief The same as vfs_find, but more internal to the VFS - it operates @@ -240,1373 +240,1373 @@ struct vfs_node *vfs_node_create(const char *name, vnode_t *vn) { * * XXX: ".." will leave you with dangling nodes in the tree */ -static int vfs_find_tree(struct vfs_node *root_node, const char *path, struct vfs_node **res_node) { - if (!path || !*path) { - // The path refers to the node itself - *res_node = root_node; - return 0; - } - - // Assuming the path is normalized - char path_element[256]; - const char *child_path = vfs_path_element(path_element, path); - - // TODO: this should also be handled by path canonicalizer - while (!strcmp(path_element, ".")) { - if (!child_path) { - // The node we're looking for is this node - *res_node = root_node; - return 0; - } - child_path = vfs_path_element(path_element, child_path); - } - if (!strcmp(path_element, "..")) { - if (root_node->parent) { - return vfs_find_tree(root_node->parent, child_path, res_node); - } else { - while (!strcmp(path_element, "..")) { - if (!child_path) { - *res_node = root_node; - return 0; - } - child_path = vfs_path_element(path_element, child_path); - } - } - } - - vnode_t *root_vnode = root_node->vnode; - _assert(root_vnode); - - // This shouldn't happen - _assert(root_vnode->type != VN_LNK); - - int res; - - // 1. Make sure we're either looking inside a directory - if (root_vnode->type == VN_DIR) { - // 3.1. It's a directory, try looking up path element inside - // the path tree - for (struct vfs_node *it = root_node->child; it; it = it->cdr) { - if (!strcmp(it->name, path_element)) { - // Found matching path element - if (!child_path) { - // We're at terminal path element - which means we've - // found what we're looking for - //vnode_ref(root_vnode); - *res_node = it; - return 0; - } else { - //printf("Entering vfs_node %s\n", it->name); - // Continue searching deeper - if ((res = vfs_find_tree(it, child_path, res_node)) != 0) { - // Nothing found - return res; - } - - // Found something - return 0; - } - } - } - - // Check if the node belongs to a mapper-based filesystem - _assert(root_vnode->fs && root_vnode->fs->cls); - if (root_vnode->fs->cls->opt & FS_NODE_MAPPER) { - return -ENOENT; - } - - // 3.2. Nothing found in path tree - request the fs to find - // the vnode for the path element given - vnode_t *child_vnode = NULL; - struct vfs_node *child_node = NULL; - _assert(root_vnode->op && root_vnode->op->find); - - //printf("Calling op->find on %s\n", root_node->name); - if ((res = root_vnode->op->find(root_vnode, path_element, &child_vnode)) != 0) { - // fs didn't find anything - no such file or directory exists - return res; - } - - // We've found a link and there's still some path to traverse - if (child_vnode->type == VN_LNK && child_path) { - char linkbuf[1024]; - struct vfs_node *link_node; - _assert(child_vnode->op && child_vnode->op->readlink); - child_node = vfs_node_create(path_element, child_vnode); - - if ((res = child_vnode->op->readlink(child_vnode, linkbuf)) < 0) { - return res; - } - - if ((res = vfs_find_tree(root_node->parent ? - root_node->parent : - &vfs_root_node, linkbuf, &link_node)) < 0) { - return res; - } - - if ((res = vfs_find_tree(link_node, child_path, res_node)) < 0) { - return res; - } - - return 0; - } - - // 3.3. Found some vnode, attach it to the VFS tree - child_node = vfs_node_create(path_element, child_vnode); - - // Prepend it to parent's child list - child_node->parent = root_node; - child_node->cdr = root_node->child; - root_node->child = child_node; - - if (!child_path) { - // We're at terminal path element - return the node - *res_node = child_node; - return 0; - } else { - //printf("Entering vfs_node %s\n", child_node->name); - if ((res = vfs_find_tree(child_node, child_path, res_node)) != 0) { - // Nothing found in the child - return res; - } - - // Found what we're looking for - // Now have not only a child reference, but also someone uses the - // node down the tree, so increment the refcounter - return 0; - } - } else { - // Not a directory/mountpoint - cannot contain anything - return -ENOENT; - } -} - -static int vfs_find_at(vnode_t *root_vnode, const char *path, vnode_t **res_vnode) { - // The input path should be without leading slash and relative to root_vnode - struct vfs_node *res_node = NULL; - int res; - - if (!root_vnode) { - // Root node contains no vnode - which means there's no root - // at all - if (!vfs_root_node.vnode) { - return -ENOENT; - } - - res = vfs_find_tree(&vfs_root_node, path, &res_node); - } else { - _assert(root_vnode->tree_node); - - res = vfs_find_tree((struct vfs_node *) root_vnode->tree_node, path, &res_node); - } - - if (res != 0) { - return res; - } - - _assert(res_node); - *res_vnode = res_node->vnode; - return 0; -} - -static int vfs_find(vnode_t *cwd_vnode, const char *path, vnode_t **res_vnode) { - if (*path != '/') { - return vfs_find_at(cwd_vnode, path, res_vnode); - } else { - // Use root as search base - while (*path == '/') { - ++path; - } - - return vfs_find_at(NULL, path, res_vnode); - } -} - -int vfs_mount_internal(struct vfs_node *at, void *blkdev, const char *fs_name, const char *opt) { - struct fs_class *fs_class; - - if (!strcmp(fs_name, "auto")) { - return blk_mount_auto(at, blkdev, opt); - } - - if ((fs_class = fs_class_by_name(fs_name)) == NULL) { - kdebug("Unknown filesystem class: %s\n", fs_name); - return -EINVAL; - } - - // Create a new fs instance/mount - struct fs *fs; - - if ((fs = fs_create(fs_class, blkdev, NULL)) == NULL) { - return -EINVAL; - } - - if (!at) { - at = &vfs_root_node; - } - - vnode_t *old_vnode = at->vnode; - vnode_t *fs_root; - int res; - - if ((fs_class->mount != NULL) && (fs_class->mount(fs, opt) != 0)) { - return -1; - } - - if (at->child) { - // Target directory already has child nodes loaded in memory, return "busy" - // TODO: destroy fs - return -EBUSY; - } - - if (at->ismount) { - // TODO: report error and destroy fs - panic("Trying to mount a filesystem at a destination which already is a mount\n"); - } - - if (fs->cls->opt & FS_NODE_MAPPER) { - _assert(fs_class->mapper); - // Request the driver to map VFS tree for us - struct vfs_node *fs_root_node; - - if ((res = fs_class->mapper(fs, &fs_root_node)) < 0) { - panic("Node mapper function failed\n"); - } - _assert(fs_root_node); - _assert(fs_root_node->vnode); - fs_root = fs_root_node->vnode; - - // Reparent vnode to the actual mountpoint - fs_root->tree_node = at; - _assert(!at->child); - - // Reparent fs_root_node children to the actual mountpoint - struct vfs_node *child = fs_root_node->child; - while (child) { - struct vfs_node *cdr = child->cdr; - child->parent = at; - child->cdr = at->child; - at->child = child; - child = cdr; - } - - // Root node can be freed - kfree(fs_root_node); - } else { - _assert(fs_class->get_root); - // Try to get root - if ((fs_root = fs_class->get_root(fs)) == NULL) { - // TODO: report error and destroy fs - panic("Failed to get root node of the filesystem\n"); - } - } - - // If it's a root mount, set root vnode - kdebug("Mounting new fs on %s\n", at->name); - at->vnode = fs_root; - at->real_vnode = old_vnode; - at->ismount = 1; - fs_root->tree_node = at; - - return 0; -} - -int vfs_mount(struct vfs_ioctx *ctx, const char *target, void *blkdev, const char *fs_name, const char *opt) { - if (ctx->uid != 0) { - return -EACCES; - } - - struct vfs_node *mount_at; - vnode_t *vnode_mount_at; - int res; - - if (!vfs_root_node.vnode) { - // Root does not yet exist, check if we're mounting root: - if (!strcmp(target, "/")) { - return vfs_mount_internal(NULL, blkdev, fs_name, opt); - } - - // Otherwise we cannot perform mounting - return -ENOENT; - } - - // Lookup the tree node we're mounting at - if ((res = vfs_find(ctx->cwd_vnode, target, &vnode_mount_at)) != 0) { - return res; - } - - // Get tree node - mount_at = vnode_mount_at->tree_node; - _assert(mount_at); - - return vfs_mount_internal(mount_at, blkdev, fs_name, opt); -} - -int vfs_umount(struct vfs_ioctx *ctx, const char *target) { - if (ctx->uid != 0) { - return -EACCES; - } - if (!vfs_root_node.vnode) { - // No root, don't even bother umounting anything - return -ENOENT; - } - - // Lookup target vnode's tree_node - _assert(target); - vnode_t *at_vnode; - struct vfs_node *at; - int res; - - if ((res = vfs_find(ctx->cwd_vnode, target, &at_vnode)) != 0) { - return res; - } - - at = at_vnode->tree_node; - _assert(at); - - if (!at->ismount) { - // Not mounted - return -EINVAL; - } - - if (at->child) { - // There're some used vnodes down the tree - return -EBUSY; - } - - at->vnode = at->real_vnode; - at->ismount = 0; - - if (at_vnode == ctx->cwd_vnode) { - // Umounting the cwd - ctx->cwd_vnode = NULL; - } - at_vnode->refcount = 0; - vnode_free(at_vnode); - - return 0; -} - -static void vfs_path_parent(char *dst, const char *path) { - // The function expects normalized paths without . and .. - // Possible inputs: - // "/" -> "/" - // "/dir/x/y" -> "/dir/x" - - const char *slash = strrchr(path, '/'); - if (!slash) { - dst[0] = 0; - return; - } - - strncpy(dst, path, slash - path); - dst[slash - path] = 0; -} - -static const char *vfs_path_basename(const char *path) { - const char *slash = strrchr(path, '/'); - if (!slash) { - return path; - } - - return slash + 1; -} - -static int vfs_creat_internal(struct vfs_ioctx *ctx, vnode_t *at, const char *name, int mode, int opt, vnode_t **resvn) { - // Create a file without opening it - _assert(at && at->op && at->tree_node); - int res; - - if (!at->op->creat) { - return -EROFS; - } - - if ((res = at->op->creat(at, ctx, name, mode, opt, resvn)) != 0) { - return res; - } - - struct vfs_node *parent_node = at->tree_node; - struct vfs_node *child_node = vfs_node_create(name, *resvn); - - // Prepend it to parent's child list - child_node->parent = parent_node; - child_node->cdr = parent_node->child; - parent_node->child = child_node; - - return 0; -} - -int vfs_creat(struct vfs_ioctx *ctx, struct ofile *of, const char *path, int mode, int opt) { - vnode_t *parent_vnode = NULL; - vnode_t *vnode = NULL; - int res; - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) == 0) { - vnode_ref(vnode); - if ((res = vfs_open_node(ctx, of, vnode, opt & ~O_CREAT)) < 0) { - vnode_unref(vnode); - } - return res; - } - - if (*path == '/') { - // Get parent vnode - char parent_path[1024]; - vfs_path_parent(parent_path, path); - - if ((res = vfs_find(NULL, parent_path, &parent_vnode)) != 0) { - kerror("Parent does not exist: %s\n", parent_path); - // Parent doesn't exist, too - error - return res; - } - } else { - char parent_path[1024]; - vfs_path_parent(parent_path, path); - - if (!*parent_path) { - parent_path[0] = '.'; - parent_path[1] = 0; - } - - // Find parent - if ((res = vfs_find(ctx->cwd_vnode, parent_path, &parent_vnode)) != 0) { - kerror("Parent does not exist: %s\n", parent_path); - return res; - } - } - - vnode_ref(parent_vnode); - - if (parent_vnode->type == VN_LNK) { - _assert(parent_vnode->op); - _assert(parent_vnode->op->readlink); - char lnk[1024]; - vnode_t *vn_lnk; - struct vfs_node *vn_node = (struct vfs_node *) parent_vnode->tree_node; - struct vfs_node *vn_lnk_node; - _assert(vn_node); - - if ((res = parent_vnode->op->readlink(parent_vnode, lnk)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - vn_lnk = vn_lnk_node->vnode; - vnode_ref(vn_lnk); - vnode_unref(parent_vnode); - - parent_vnode = vn_lnk; - } - - if (parent_vnode->type != VN_DIR) { - vnode_unref(parent_vnode); - // Parent is not a directory - return -ENOTDIR; - } - - if (vfs_vnode_access(ctx, parent_vnode, W_OK) < 0) { - vnode_unref(parent_vnode); - return -EACCES; - } - - kdebug("Path: %s\n", path); - path = vfs_path_basename(path); - - if (!path) { - return -EINVAL; - } - - if ((res = vfs_creat_internal(ctx, parent_vnode, path, mode, opt & ~O_CREAT, &vnode)) != 0) { - vnode_unref(parent_vnode); - // Could not create entry - return res; - } - - vnode_ref(vnode); - vnode_unref(parent_vnode); - - if (!of) { - vnode_unref(vnode); - // Need opening the file, but no descriptor provided - return -EINVAL; - } - - if ((res = vfs_open_node(ctx, of, vnode, opt & ~O_CREAT)) < 0) { - vnode_unref(vnode); - } - - return res; -} - -int vfs_open(struct vfs_ioctx *ctx, struct ofile *of, const char *path, int mode, int opt) { - _assert(of); - // Try to find the file - int res; - vnode_t *vnode = NULL; - - // TODO: normalize path - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) != 0) { - if (!(opt & O_CREAT)) { - return -ENOENT; - } - - return vfs_creat(ctx, of, path, mode, opt); - } - - vnode_ref(vnode); - - // Resolve symlink to open the resource it's pointing to - if (vnode->type == VN_LNK) { - _assert(vnode->op); - _assert(vnode->op->readlink); - char lnk[1024]; - vnode_t *vn_lnk; - struct vfs_node *vn_node = (struct vfs_node *) vnode->tree_node; - struct vfs_node *vn_lnk_node; - _assert(vn_node); - - if ((res = vnode->op->readlink(vnode, lnk)) < 0) { - vnode_unref(vnode); - return res; - } - - if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { - vnode_unref(vnode); - return res; - } - - vn_lnk = vn_lnk_node->vnode; - vnode_ref(vn_lnk); - vnode_unref(vnode); - - vnode = vn_lnk; - } - - if ((res = vfs_open_node(ctx, of, vnode, opt & ~O_CREAT)) < 0) { - vnode_unref(vnode); - return res; - } - - // Leave refcount + 1'd, ioctx is using the node - return 0; -} - -int vfs_open_node(struct vfs_ioctx *ctx, struct ofile *of, vnode_t *vn, int opt) { - // TODO: O_APPEND - _assert(vn && vn->op && of); - kdebug("vfs_open_node %p\n", of); - int res; - - if (vfs_vnode_access(ctx, vn, vfs_open_access_mask(opt)) < 0) { - return -EACCES; - } - - if (opt & O_DIRECTORY) { - _assert((opt & O_ACCMODE) == O_RDONLY); - // How does one truncate a directory? - _assert(!(opt & O_TRUNC)); - _assert(!(opt & O_CREAT)); - - if (vn->type != VN_DIR) { - return -ENOTDIR; - } - - _assert(vn->fs && vn->fs->cls); - if (vn->fs->cls->opt & FS_NODE_MAPPER) { - // XXX: This is totally read-only - // Mapper means all the needed nodes are already in vnode tree - // just use (vfs_node *) as offset - _assert(sizeof(of->pos) >= sizeof(uintptr_t)); - _assert(vn->tree_node); - - of->pos = (uintptr_t) ((struct vfs_node *) vn->tree_node)->child; - of->flags = opt; - of->vnode = vn; - - return 0; - } else { - // opendir - if (vn->op->opendir) { - if ((res = vn->op->opendir(vn, opt)) != 0) { - return res; - } - } else { - return -EINVAL; - } - - of->flags = opt; - of->vnode = vn; - of->pos = 0; - } - - return res; - } - - // Check flag sanity - // Can't have O_CREAT here - if (opt & O_CREAT) { - return -EINVAL; - } - // Can't be both (RD|WR) and EX - if (opt & O_EXEC) { - if (opt & O_ACCMODE) { - return -EACCES; - } - } - - if (vn->type == VN_DIR) { - return -EISDIR; - } - - of->vnode = vn; - of->flags = opt; - of->pos = 0; - - if (opt & O_APPEND) { - // TODO: rewrite open() to accept struct ofile * - // instead of vnode so that open() function of the - // vnode can properly set of->pos - //fprintf(stderr, "O_APPEND not yet implemented\n"); - kerror("O_APPEND not yet implemented\n"); - return -EINVAL; - } - - // Check if file has to be truncated before opening it - if (opt & O_TRUNC) { - if (!vn->op->truncate) { - return -EINVAL; - } - - if ((res = vn->op->truncate(of, 0)) != 0) { - return res; - } - } - - if (vn->op->open) { - if ((res = vn->op->open(vn, opt)) != 0) { - return res; - } - } - - return 0; -} - -void vfs_close(struct vfs_ioctx *ctx, struct ofile *of) { - _assert(of); - vnode_t *vn = of->vnode; - switch (vn->type) { - case VN_REG: - case VN_DIR: - _assert(vn); - - if (vn->op->close) { - vn->op->close(of); - } - break; - - // TODO: maybe call something special for that - case VN_CHR: - case VN_BLK: - break; - - default: - panic("Unhandled vnode type\n"); - } - - vnode_unref(of->vnode); -} - -int vfs_statat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, struct stat *st) { - _assert(at && path && st); - int res; - vnode_t *vnode; - - if ((res = vfs_find(at, path, &vnode)) != 0) { - return res; - } - - vnode_ref(vnode); - - if (!vnode->op || !vnode->op->stat) { - res = -EINVAL; - } else { - res = vnode->op->stat(vnode, st); - } - - vnode_unref(vnode); - return res; -} - -int vfs_stat(struct vfs_ioctx *ctx, const char *path, struct stat *st) { - _assert(path && st); - vnode_t *vnode; - int res; - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) != 0) { - return res; - } - - vnode_ref(vnode); - - if (!vnode->op || !vnode->op->stat) { - res = -EINVAL; - } else { - res = vnode->op->stat(vnode, st); - } - - vnode_unref(vnode); - return res; -} - -ssize_t vfs_read(struct vfs_ioctx *ctx, struct ofile *fd, void *buf, size_t count) { - _assert(fd); - vnode_t *vn = fd->vnode; - _assert(vn); - - ssize_t nr; - - switch (vn->type) { - case VN_REG: - _assert(vn->op); - // XXX: should these be checked on every read? - if (vfs_vnode_access(ctx, vn, R_OK) < 0) { - return -EACCES; - } - - if (fd->flags & O_DIRECTORY) { - return -EISDIR; - } - if ((fd->flags & O_ACCMODE) == O_WRONLY) { - return -EINVAL; - } - if (vn->op->read == NULL) { - return -EINVAL; - } - - nr = vn->op->read(fd, buf, count); - - if (nr > 0) { - fd->pos += nr; - } - - return nr; - - // We don't need filesystem at all to read from devices - case VN_BLK: - _assert(vn->dev); - - if ((nr = blk_read((struct blkdev *) vn->dev, buf, fd->pos, count)) > 0) { - fd->pos += nr; - } - - return nr; - case VN_CHR: - _assert(vn->dev); - return chr_read((struct chrdev *) vn->dev, buf, fd->pos, count); - - default: - panic("Not supported\n"); - } -} - -ssize_t vfs_write(struct vfs_ioctx *ctx, struct ofile *fd, const void *buf, size_t count) { - _assert(fd); - vnode_t *vn = fd->vnode; - _assert(vn); - - switch (vn->type) { - case VN_REG: - _assert(vn->op); - - // XXX: should these be checked on every write? - if (vfs_vnode_access(ctx, vn, W_OK) < 0) { - return -EACCES; - } - - if (fd->flags & O_DIRECTORY) { - return -EISDIR; - } - if ((fd->flags & O_ACCMODE) == O_RDONLY) { - return -EINVAL; - } - if (vn->op->write == NULL) { - return -EINVAL; - } - - return vn->op->write(fd, buf, count); - - // We don't need filesystem at all to write to devices - case VN_BLK: - _assert(vn->dev); - return blk_write((struct blkdev *) vn->dev, buf, fd->pos, count); - case VN_CHR: - _assert(vn->dev); - return chr_write((struct chrdev *) vn->dev, buf, fd->pos, count); - - default: - panic("Not supported\n"); - } -} - -int vfs_truncate(struct vfs_ioctx *ctx, struct ofile *of, size_t length) { - _assert(of); - if ((of->flags & O_ACCMODE) == O_RDONLY) { - return -EINVAL; - } - if ((of->flags & O_DIRECTORY)) { - return -EINVAL; - } - vnode_t *vn = of->vnode; - _assert(vn && vn->op); - // XXX: should these be checked on every write? - if (vfs_vnode_access(ctx, vn, W_OK) < 0) { - return -EACCES; - } - - if (!vn->op->truncate) { - return -EINVAL; - } - - return vn->op->truncate(of, length); -} - -int vfs_unlink(struct vfs_ioctx *ctx, const char *path, int is_rmdir) { - // XXX: validate this with removing mounted roots - _assert(path); - // Find the vnode to unlink - int res; - vnode_t *parent_vnode, *vnode; - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { - return res; - } - - _assert(vnode && vnode->op); - vnode_ref(vnode); - - if (vnode->type != VN_DIR && is_rmdir) { - return -ENOTDIR; - } - if (vnode->type == VN_DIR && !is_rmdir) { - return -EISDIR; - } - - // Get node parent - struct vfs_node *node = vnode->tree_node; - _assert(node); - - if (!node->parent) { - // Trying to unlink root node? - vnode_unref(vnode); - return -EACCES; - } - - if (vnode->refcount != 0) { - // Trying to unlink the file someone is using. - // Good solution would be to (TODO) defer the - // actual unlinking and perform it once no one - // is using it or notify writers/reader that the - // file is slated for removal. I think just adding - // a flag to vnode like "deleted" should suffice. - // For now, just check if vfs_ctx is trying to shoot - // its' leg off by unlinking the CWD - if (vnode == ctx->cwd_vnode) { - return -EINVAL; - } - } - - parent_vnode = node->parent->vnode; - vnode_ref(parent_vnode); - - // Can only remove a child in a directory - if (parent_vnode->type != VN_DIR) { - vnode_unref(vnode); - vnode_unref(parent_vnode); - return res; - } - - if ((res = vfs_vnode_access(ctx, parent_vnode, W_OK)) < 0) { - vnode_unref(vnode); - vnode_unref(parent_vnode); - return res; - } - - if (parent_vnode->op->unlink) { - // TODO: handle - // unlink("path/to/node/./.") - path = vfs_path_basename(path); - _assert(path); - - if ((res = parent_vnode->op->unlink(parent_vnode, vnode, path)) < 0) { - vnode_unref(vnode); - vnode_unref(parent_vnode); - return res; - } - - vnode_unref(vnode); - vnode_unref(parent_vnode); - return 0; - } else { - //fprintf(stderr, "File system does not implement unlink()\n"); - kerror("Filesystem does not implement unlink()\n"); - // File node does not support unlinking - vnode_unref(vnode); - vnode_unref(parent_vnode); - return -EINVAL; - } -} - -int vfs_chmod(struct vfs_ioctx *ctx, const char *path, mode_t mode) { - _assert(path); - vnode_t *vnode; - int res; - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { - return res; - } - - vnode_ref(vnode); - _assert(vnode && vnode->op); - - if (vnode->op->access) { - mode_t vn_mode; - uid_t vn_uid; - gid_t vn_gid; - - if ((res = vnode->op->access(vnode, &vn_uid, &vn_gid, &vn_mode)) < 0) { - return res; - } - - // To chmod, the uid of the user has to match - // the node's one - if ((vn_uid != ctx->uid) && (ctx->uid != 0)) { - return -EACCES; - } - } - - if (!vnode->op->chmod) { - return -EINVAL; - } - - res = vnode->op->chmod(vnode, mode); - - vnode_unref(vnode); - return res; -} - -int vfs_chown(struct vfs_ioctx *ctx, const char *path, uid_t uid, gid_t gid) { - _assert(path); - vnode_t *vnode; - int res; - - if (ctx->uid != 0) { - // For now, only root can change ownership of the nodes - return -EACCES; - } - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { - return res; - } - - vnode_ref(vnode); - _assert(vnode && vnode->op); - - if (!vnode->op->chown) { - return -EINVAL; - } - - res = vnode->op->chown(vnode, uid, gid); - - vnode_unref(vnode); - return res; -} - -// TODO: change signature so it can return errno -struct dirent *vfs_readdir(struct vfs_ioctx *ctx, struct ofile *fd) { - _assert(fd); - if (!(fd->flags & O_DIRECTORY)) { - return NULL; - } - vnode_t *vn = fd->vnode; - _assert(vn && vn->op); - - if (vfs_vnode_access(ctx, vn, R_OK) < 0) { - return NULL; - } - - _assert(vn->fs && vn->fs->cls); - if (vn->fs->cls->opt & FS_NODE_MAPPER) { - _assert(sizeof(fd->pos) >= sizeof(uintptr_t)); - struct vfs_node *item_node = (struct vfs_node *) fd->pos; - struct dirent *ent_buf = (struct dirent *) fd->dirent_buf; - - if (item_node) { - fd->pos = (uintptr_t) (item_node->cdr); - } else { - return NULL; - } - - _assert(item_node->vnode); - - // Describe the node into dirent buffer - // TODO: size checks - strcpy(ent_buf->d_name, item_node->name); - ent_buf->d_ino = /* TODO use something as inode number for node mapper */ -1; - ent_buf->d_off = 0; - ent_buf->d_reclen = strlen(item_node->name) + sizeof(struct dirent); - // TODO: blk/chr - switch (item_node->vnode->type) { - case VN_REG: - ent_buf->d_type = DT_REG; - break; - case VN_DIR: - ent_buf->d_type = DT_DIR; - break; - case VN_BLK: - ent_buf->d_type = DT_BLK; - break; - case VN_CHR: - ent_buf->d_type = DT_CHR; - break; - default: - kwarn("Unsupported vnode type: %d\n", item_node->vnode->type); - ent_buf->d_type = DT_UNKNOWN; - break; - } - - return ent_buf; - } else { - if (!vn->op->readdir) { - return NULL; - } - - if (vn->op->readdir(fd) == 0) { - return (struct dirent *) fd->dirent_buf; - } - - return NULL; - } -} - -int vfs_mkdir(struct vfs_ioctx *ctx, const char *path, mode_t mode) { - vnode_t *parent_vnode = NULL; - vnode_t *vnode = NULL; - int res; - - // Check if a directory with such name already exists - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) == 0) { - vnode_ref(vnode); - vnode_unref(vnode); - return -EEXIST; - } - - // Just copypasted this from creat() - if (*path == '/') { - // Get parent vnode - char parent_path[1024]; - vfs_path_parent(parent_path, path); - - if ((res = vfs_find(NULL, parent_path, &parent_vnode)) != 0) { - kerror("Parent does not exist: %s\n", parent_path); - // Parent doesn't exist, too - error - return res; - } - } else { - char parent_path[1024]; - vfs_path_parent(parent_path, path); - - if (!*parent_path) { - parent_path[0] = '.'; - parent_path[1] = 0; - } - - // Find parent - if ((res = vfs_find(ctx->cwd_vnode, parent_path, &parent_vnode)) != 0) { - kerror("Parent does not exist: %s\n", parent_path); - return res; - } - } - - vnode_ref(parent_vnode); - - if (parent_vnode->type == VN_LNK) { - _assert(parent_vnode->op); - _assert(parent_vnode->op->readlink); - char lnk[1024]; - vnode_t *vn_lnk; - struct vfs_node *vn_node = (struct vfs_node *) parent_vnode->tree_node; - struct vfs_node *vn_lnk_node; - _assert(vn_node); - - if ((res = parent_vnode->op->readlink(parent_vnode, lnk)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - vn_lnk = vn_lnk_node->vnode; - vnode_ref(vn_lnk); - vnode_unref(parent_vnode); - - parent_vnode = vn_lnk; - } - - if (parent_vnode->type != VN_DIR) { - // Parent is not a directory - vnode_unref(parent_vnode); - return -ENOTDIR; - } - - // Need write permission - if ((res = vfs_vnode_access(ctx, parent_vnode, W_OK)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - kdebug("Path: %s\n", path); - path = vfs_path_basename(path); - - if (!path) { - vnode_unref(parent_vnode); - return -EINVAL; - } - - if (!parent_vnode->op || !parent_vnode->op->mkdir) { - vnode_unref(parent_vnode); - return -EINVAL; - } - - if ((res = parent_vnode->op->mkdir(parent_vnode, path, mode)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - vnode_unref(parent_vnode); - return res; -} - -int vfs_access(struct vfs_ioctx *ctx, const char *path, int mode) { - _assert(path); - vnode_t *vnode; - int res; - - mode_t vn_mode; - uid_t vn_uid; - gid_t vn_gid; - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) != 0) { - return res; - } - - vnode_ref(vnode); - if (mode == F_OK) { - vnode_unref(vnode); - return 0; - } - - _assert(vnode->op); - - if (!vnode->op->access) { - vnode_unref(vnode); - // Filesystem has no permissions? - return -EINVAL; - } - - if ((res = vnode->op->access(vnode, &vn_uid, &vn_gid, &vn_mode)) < 0) { - vnode_unref(vnode); - return res; - } - - vnode_unref(vnode); - - return vfs_access_internal(ctx, mode, vn_mode, vn_uid, vn_gid); -} - -int vfs_statvfs(struct vfs_ioctx *ctx, const char *path, struct statvfs *st) { - _assert(ctx && path && st); - vnode_t *vnode; - int res; - fs_t *fs; - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { - return res; - } - - vnode_ref(vnode); - - if (!(fs = vnode->fs)) { - vnode_unref(vnode); - return -EINVAL; - } - - vnode_unref(vnode); - - if (!fs->cls || !fs->cls->statvfs) { - return -EINVAL; - } - - return fs->cls->statvfs(fs, st); -} - -int vfs_readlinkat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, char *buf) { - int res; - vnode_t *vnode; - - if ((res = vfs_find(at, path, &vnode)) < 0) { - return res; - } - - vnode_ref(vnode); - - if (!vnode->op || !vnode->op->readlink) { - vnode_unref(vnode); - return -EINVAL; - } - if (vnode->type != VN_LNK) { - vnode_unref(vnode); - return -EINVAL; - } - - res = vnode->op->readlink(vnode, buf); - vnode_unref(vnode); - return res; -} - -int vfs_readlink(struct vfs_ioctx *ctx, const char *path, char *buf) { - int res; - vnode_t *vnode; - - if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { - return res; - } - - vnode_ref(vnode); - - if (!vnode->op || !vnode->op->readlink) { - vnode_unref(vnode); - return -EINVAL; - } - if (vnode->type != VN_LNK) { - vnode_unref(vnode); - return -EINVAL; - } - - res = vnode->op->readlink(vnode, buf); - vnode_unref(vnode); - return res; -} - -int vfs_symlink(struct vfs_ioctx *ctx, const char *target, const char *linkpath) { - vnode_t *parent_vnode = NULL; - vnode_t *vnode = NULL; - int res; - - // Check if a directory with such name already exists - if ((res = vfs_find(ctx->cwd_vnode, linkpath, &vnode)) == 0) { - vnode_ref(vnode); - vnode_unref(vnode); - return -EEXIST; - } - - // Just copypasted this from creat() - if (*linkpath == '/') { - // Get parent vnode - char parent_path[1024]; - vfs_path_parent(parent_path, linkpath); - - if ((res = vfs_find(NULL, parent_path, &parent_vnode)) != 0) { - kerror("Parent does not exist: %s\n", parent_path); - // Parent doesn't exist, too - error - return res; - } - } else { - char parent_path[1024]; - vfs_path_parent(parent_path, linkpath); - - if (!*parent_path) { - parent_path[0] = '.'; - parent_path[1] = 0; - } - - // Find parent - if ((res = vfs_find(ctx->cwd_vnode, parent_path, &parent_vnode)) != 0) { - kerror("Parent does not exist: %s\n", parent_path); - return res; - } - } - - vnode_ref(parent_vnode); - - if (parent_vnode->type == VN_LNK) { - _assert(parent_vnode->op); - _assert(parent_vnode->op->readlink); - char lnk[1024]; - vnode_t *vn_lnk; - struct vfs_node *vn_node = (struct vfs_node *) parent_vnode->tree_node; - struct vfs_node *vn_lnk_node; - _assert(vn_node); - - if ((res = parent_vnode->op->readlink(parent_vnode, lnk)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - vn_lnk = vn_lnk_node->vnode; - vnode_ref(vn_lnk); - vnode_unref(parent_vnode); - - parent_vnode = vn_lnk; - } - - if (parent_vnode->type != VN_DIR) { - // Parent is not a directory - vnode_unref(parent_vnode); - return -ENOTDIR; - } - - // Need write permission - if ((res = vfs_vnode_access(ctx, parent_vnode, W_OK)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - kdebug("Path: %s\n", linkpath); - linkpath = vfs_path_basename(linkpath); - - if (!linkpath) { - vnode_unref(parent_vnode); - return -EINVAL; - } - - if (!parent_vnode->op || !parent_vnode->op->symlink) { - vnode_unref(parent_vnode); - return -EINVAL; - } - - // if ((res = parent_vnode->op->mkdir(parent_vnode, linkpath, mode)) < 0) { - // vnode_unref(parent_vnode); - // return res; - // } - if ((res = parent_vnode->op->symlink(parent_vnode, ctx, linkpath, target)) < 0) { - vnode_unref(parent_vnode); - return res; - } - - vnode_unref(parent_vnode); - return res; -} +//static int vfs_find_tree(struct vfs_node *root_node, const char *path, struct vfs_node **res_node) { +// if (!path || !*path) { +// // The path refers to the node itself +// *res_node = root_node; +// return 0; +// } +// +// // Assuming the path is normalized +// char path_element[256]; +// const char *child_path = vfs_path_element(path_element, path); +// +// // TODO: this should also be handled by path canonicalizer +// while (!strcmp(path_element, ".")) { +// if (!child_path) { +// // The node we're looking for is this node +// *res_node = root_node; +// return 0; +// } +// child_path = vfs_path_element(path_element, child_path); +// } +// if (!strcmp(path_element, "..")) { +// if (root_node->parent) { +// return vfs_find_tree(root_node->parent, child_path, res_node); +// } else { +// while (!strcmp(path_element, "..")) { +// if (!child_path) { +// *res_node = root_node; +// return 0; +// } +// child_path = vfs_path_element(path_element, child_path); +// } +// } +// } +// +// vnode_t *root_vnode = root_node->vnode; +// _assert(root_vnode); +// +// // This shouldn't happen +// _assert(root_vnode->type != VN_LNK); +// +// int res; +// +// // 1. Make sure we're either looking inside a directory +// if (root_vnode->type == VN_DIR) { +// // 3.1. It's a directory, try looking up path element inside +// // the path tree +// for (struct vfs_node *it = root_node->child; it; it = it->cdr) { +// if (!strcmp(it->name, path_element)) { +// // Found matching path element +// if (!child_path) { +// // We're at terminal path element - which means we've +// // found what we're looking for +// //vnode_ref(root_vnode); +// *res_node = it; +// return 0; +// } else { +// //printf("Entering vfs_node %s\n", it->name); +// // Continue searching deeper +// if ((res = vfs_find_tree(it, child_path, res_node)) != 0) { +// // Nothing found +// return res; +// } +// +// // Found something +// return 0; +// } +// } +// } +// +// // Check if the node belongs to a mapper-based filesystem +// _assert(root_vnode->fs && root_vnode->fs->cls); +// if (root_vnode->fs->cls->opt & FS_NODE_MAPPER) { +// return -ENOENT; +// } +// +// // 3.2. Nothing found in path tree - request the fs to find +// // the vnode for the path element given +// vnode_t *child_vnode = NULL; +// struct vfs_node *child_node = NULL; +// _assert(root_vnode->op && root_vnode->op->find); +// +// //printf("Calling op->find on %s\n", root_node->name); +// if ((res = root_vnode->op->find(root_vnode, path_element, &child_vnode)) != 0) { +// // fs didn't find anything - no such file or directory exists +// return res; +// } +// +// // We've found a link and there's still some path to traverse +// if (child_vnode->type == VN_LNK && child_path) { +// char linkbuf[1024]; +// struct vfs_node *link_node; +// _assert(child_vnode->op && child_vnode->op->readlink); +// child_node = vfs_node_create(path_element, child_vnode); +// +// if ((res = child_vnode->op->readlink(child_vnode, linkbuf)) < 0) { +// return res; +// } +// +// if ((res = vfs_find_tree(root_node->parent ? +// root_node->parent : +// &vfs_root_node, linkbuf, &link_node)) < 0) { +// return res; +// } +// +// if ((res = vfs_find_tree(link_node, child_path, res_node)) < 0) { +// return res; +// } +// +// return 0; +// } +// +// // 3.3. Found some vnode, attach it to the VFS tree +// child_node = vfs_node_create(path_element, child_vnode); +// +// // Prepend it to parent's child list +// child_node->parent = root_node; +// child_node->cdr = root_node->child; +// root_node->child = child_node; +// +// if (!child_path) { +// // We're at terminal path element - return the node +// *res_node = child_node; +// return 0; +// } else { +// //printf("Entering vfs_node %s\n", child_node->name); +// if ((res = vfs_find_tree(child_node, child_path, res_node)) != 0) { +// // Nothing found in the child +// return res; +// } +// +// // Found what we're looking for +// // Now have not only a child reference, but also someone uses the +// // node down the tree, so increment the refcounter +// return 0; +// } +// } else { +// // Not a directory/mountpoint - cannot contain anything +// return -ENOENT; +// } +//} +// +//static int vfs_find_at(vnode_t *root_vnode, const char *path, vnode_t **res_vnode) { +// // The input path should be without leading slash and relative to root_vnode +// struct vfs_node *res_node = NULL; +// int res; +// +// if (!root_vnode) { +// // Root node contains no vnode - which means there's no root +// // at all +// if (!vfs_root_node.vnode) { +// return -ENOENT; +// } +// +// res = vfs_find_tree(&vfs_root_node, path, &res_node); +// } else { +// _assert(root_vnode->tree_node); +// +// res = vfs_find_tree((struct vfs_node *) root_vnode->tree_node, path, &res_node); +// } +// +// if (res != 0) { +// return res; +// } +// +// _assert(res_node); +// *res_vnode = res_node->vnode; +// return 0; +//} +// +//static int vfs_find(vnode_t *cwd_vnode, const char *path, vnode_t **res_vnode) { +// if (*path != '/') { +// return vfs_find_at(cwd_vnode, path, res_vnode); +// } else { +// // Use root as search base +// while (*path == '/') { +// ++path; +// } +// +// return vfs_find_at(NULL, path, res_vnode); +// } +//} + +//int vfs_mount_internal(struct vfs_node *at, void *blkdev, const char *fs_name, const char *opt) { +// struct fs_class *fs_class; +// +// if (!strcmp(fs_name, "auto")) { +// return blk_mount_auto(at, blkdev, opt); +// } +// +// if ((fs_class = fs_class_by_name(fs_name)) == NULL) { +// kdebug("Unknown filesystem class: %s\n", fs_name); +// return -EINVAL; +// } +// +// // Create a new fs instance/mount +// struct fs *fs; +// +// if ((fs = fs_create(fs_class, blkdev, NULL)) == NULL) { +// return -EINVAL; +// } +// +// if (!at) { +// at = &vfs_root_node; +// } +// +// vnode_t *old_vnode = at->vnode; +// vnode_t *fs_root; +// int res; +// +// if ((fs_class->mount != NULL) && (fs_class->mount(fs, opt) != 0)) { +// return -1; +// } +// +// if (at->child) { +// // Target directory already has child nodes loaded in memory, return "busy" +// // TODO: destroy fs +// return -EBUSY; +// } +// +// if (at->ismount) { +// // TODO: report error and destroy fs +// panic("Trying to mount a filesystem at a destination which already is a mount\n"); +// } +// +// if (fs->cls->opt & FS_NODE_MAPPER) { +// _assert(fs_class->mapper); +// // Request the driver to map VFS tree for us +// struct vfs_node *fs_root_node; +// +// if ((res = fs_class->mapper(fs, &fs_root_node)) < 0) { +// panic("Node mapper function failed\n"); +// } +// _assert(fs_root_node); +// _assert(fs_root_node->vnode); +// fs_root = fs_root_node->vnode; +// +// // Reparent vnode to the actual mountpoint +// fs_root->tree_node = at; +// _assert(!at->child); +// +// // Reparent fs_root_node children to the actual mountpoint +// struct vfs_node *child = fs_root_node->child; +// while (child) { +// struct vfs_node *cdr = child->cdr; +// child->parent = at; +// child->cdr = at->child; +// at->child = child; +// child = cdr; +// } +// +// // Root node can be freed +// kfree(fs_root_node); +// } else { +// _assert(fs_class->get_root); +// // Try to get root +// if ((fs_root = fs_class->get_root(fs)) == NULL) { +// // TODO: report error and destroy fs +// panic("Failed to get root node of the filesystem\n"); +// } +// } +// +// // If it's a root mount, set root vnode +// kdebug("Mounting new fs on %s\n", at->name); +// at->vnode = fs_root; +// at->real_vnode = old_vnode; +// at->ismount = 1; +// fs_root->tree_node = at; +// +// return 0; +//} +// +//int vfs_mount(struct vfs_ioctx *ctx, const char *target, void *blkdev, const char *fs_name, const char *opt) { +// if (ctx->uid != 0) { +// return -EACCES; +// } +// +// struct vfs_node *mount_at; +// vnode_t *vnode_mount_at; +// int res; +// +// if (!vfs_root_node.vnode) { +// // Root does not yet exist, check if we're mounting root: +// if (!strcmp(target, "/")) { +// return vfs_mount_internal(NULL, blkdev, fs_name, opt); +// } +// +// // Otherwise we cannot perform mounting +// return -ENOENT; +// } +// +// // Lookup the tree node we're mounting at +// if ((res = vfs_find(ctx->cwd_vnode, target, &vnode_mount_at)) != 0) { +// return res; +// } +// +// // Get tree node +// mount_at = vnode_mount_at->tree_node; +// _assert(mount_at); +// +// return vfs_mount_internal(mount_at, blkdev, fs_name, opt); +//} + +//int vfs_umount(struct vfs_ioctx *ctx, const char *target) { +// if (ctx->uid != 0) { +// return -EACCES; +// } +// if (!vfs_root_node.vnode) { +// // No root, don't even bother umounting anything +// return -ENOENT; +// } +// +// // Lookup target vnode's tree_node +// _assert(target); +// vnode_t *at_vnode; +// struct vfs_node *at; +// int res; +// +// if ((res = vfs_find(ctx->cwd_vnode, target, &at_vnode)) != 0) { +// return res; +// } +// +// at = at_vnode->tree_node; +// _assert(at); +// +// if (!at->ismount) { +// // Not mounted +// return -EINVAL; +// } +// +// if (at->child) { +// // There're some used vnodes down the tree +// return -EBUSY; +// } +// +// at->vnode = at->real_vnode; +// at->ismount = 0; +// +// if (at_vnode == ctx->cwd_vnode) { +// // Umounting the cwd +// ctx->cwd_vnode = NULL; +// } +// at_vnode->refcount = 0; +// vnode_free(at_vnode); +// +// return 0; +//} + +//static void vfs_path_parent(char *dst, const char *path) { +// // The function expects normalized paths without . and .. +// // Possible inputs: +// // "/" -> "/" +// // "/dir/x/y" -> "/dir/x" +// +// const char *slash = strrchr(path, '/'); +// if (!slash) { +// dst[0] = 0; +// return; +// } +// +// strncpy(dst, path, slash - path); +// dst[slash - path] = 0; +//} + +//static const char *vfs_path_basename(const char *path) { +// const char *slash = strrchr(path, '/'); +// if (!slash) { +// return path; +// } +// +// return slash + 1; +//} + +//static int vfs_creat_internal(struct vfs_ioctx *ctx, vnode_t *at, const char *name, int mode, int opt, vnode_t **resvn) { +// // Create a file without opening it +// _assert(at && at->op && at->tree_node); +// int res; +// +// if (!at->op->creat) { +// return -EROFS; +// } +// +// if ((res = at->op->creat(at, ctx, name, mode, opt, resvn)) != 0) { +// return res; +// } +// +// struct vfs_node *parent_node = at->tree_node; +// struct vfs_node *child_node = vfs_node_create(name, *resvn); +// +// // Prepend it to parent's child list +// child_node->parent = parent_node; +// child_node->cdr = parent_node->child; +// parent_node->child = child_node; +// +// return 0; +//} + +//int vfs_creat(struct vfs_ioctx *ctx, struct ofile *of, const char *path, int mode, int opt) { +// vnode_t *parent_vnode = NULL; +// vnode_t *vnode = NULL; +// int res; +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) == 0) { +// vnode_ref(vnode); +// if ((res = vfs_open_node(ctx, of, vnode, opt & ~O_CREAT)) < 0) { +// vnode_unref(vnode); +// } +// return res; +// } +// +// if (*path == '/') { +// // Get parent vnode +// char parent_path[1024]; +// vfs_path_parent(parent_path, path); +// +// if ((res = vfs_find(NULL, parent_path, &parent_vnode)) != 0) { +// kerror("Parent does not exist: %s\n", parent_path); +// // Parent doesn't exist, too - error +// return res; +// } +// } else { +// char parent_path[1024]; +// vfs_path_parent(parent_path, path); +// +// if (!*parent_path) { +// parent_path[0] = '.'; +// parent_path[1] = 0; +// } +// +// // Find parent +// if ((res = vfs_find(ctx->cwd_vnode, parent_path, &parent_vnode)) != 0) { +// kerror("Parent does not exist: %s\n", parent_path); +// return res; +// } +// } +// +// vnode_ref(parent_vnode); +// +// if (parent_vnode->type == VN_LNK) { +// _assert(parent_vnode->op); +// _assert(parent_vnode->op->readlink); +// char lnk[1024]; +// vnode_t *vn_lnk; +// struct vfs_node *vn_node = (struct vfs_node *) parent_vnode->tree_node; +// struct vfs_node *vn_lnk_node; +// _assert(vn_node); +// +// if ((res = parent_vnode->op->readlink(parent_vnode, lnk)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// vn_lnk = vn_lnk_node->vnode; +// vnode_ref(vn_lnk); +// vnode_unref(parent_vnode); +// +// parent_vnode = vn_lnk; +// } +// +// if (parent_vnode->type != VN_DIR) { +// vnode_unref(parent_vnode); +// // Parent is not a directory +// return -ENOTDIR; +// } +// +// if (vfs_vnode_access(ctx, parent_vnode, W_OK) < 0) { +// vnode_unref(parent_vnode); +// return -EACCES; +// } +// +// kdebug("Path: %s\n", path); +// path = vfs_path_basename(path); +// +// if (!path) { +// return -EINVAL; +// } +// +// if ((res = vfs_creat_internal(ctx, parent_vnode, path, mode, opt & ~O_CREAT, &vnode)) != 0) { +// vnode_unref(parent_vnode); +// // Could not create entry +// return res; +// } +// +// vnode_ref(vnode); +// vnode_unref(parent_vnode); +// +// if (!of) { +// vnode_unref(vnode); +// // Need opening the file, but no descriptor provided +// return -EINVAL; +// } +// +// if ((res = vfs_open_node(ctx, of, vnode, opt & ~O_CREAT)) < 0) { +// vnode_unref(vnode); +// } +// +// return res; +//} +// +//int vfs_open(struct vfs_ioctx *ctx, struct ofile *of, const char *path, int mode, int opt) { +// _assert(of); +// // Try to find the file +// int res; +// vnode_t *vnode = NULL; +// +// // TODO: normalize path +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) != 0) { +// if (!(opt & O_CREAT)) { +// return -ENOENT; +// } +// +// return vfs_creat(ctx, of, path, mode, opt); +// } +// +// vnode_ref(vnode); +// +// // Resolve symlink to open the resource it's pointing to +// if (vnode->type == VN_LNK) { +// _assert(vnode->op); +// _assert(vnode->op->readlink); +// char lnk[1024]; +// vnode_t *vn_lnk; +// struct vfs_node *vn_node = (struct vfs_node *) vnode->tree_node; +// struct vfs_node *vn_lnk_node; +// _assert(vn_node); +// +// if ((res = vnode->op->readlink(vnode, lnk)) < 0) { +// vnode_unref(vnode); +// return res; +// } +// +// if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { +// vnode_unref(vnode); +// return res; +// } +// +// vn_lnk = vn_lnk_node->vnode; +// vnode_ref(vn_lnk); +// vnode_unref(vnode); +// +// vnode = vn_lnk; +// } +// +// if ((res = vfs_open_node(ctx, of, vnode, opt & ~O_CREAT)) < 0) { +// vnode_unref(vnode); +// return res; +// } +// +// // Leave refcount + 1'd, ioctx is using the node +// return 0; +//} +// +//int vfs_open_node(struct vfs_ioctx *ctx, struct ofile *of, vnode_t *vn, int opt) { +// // TODO: O_APPEND +// _assert(vn && vn->op && of); +// kdebug("vfs_open_node %p\n", of); +// int res; +// +// if (vfs_vnode_access(ctx, vn, vfs_open_access_mask(opt)) < 0) { +// return -EACCES; +// } +// +// if (opt & O_DIRECTORY) { +// _assert((opt & O_ACCMODE) == O_RDONLY); +// // How does one truncate a directory? +// _assert(!(opt & O_TRUNC)); +// _assert(!(opt & O_CREAT)); +// +// if (vn->type != VN_DIR) { +// return -ENOTDIR; +// } +// +// _assert(vn->fs && vn->fs->cls); +// if (vn->fs->cls->opt & FS_NODE_MAPPER) { +// // XXX: This is totally read-only +// // Mapper means all the needed nodes are already in vnode tree +// // just use (vfs_node *) as offset +// _assert(sizeof(of->pos) >= sizeof(uintptr_t)); +// _assert(vn->tree_node); +// +// of->pos = (uintptr_t) ((struct vfs_node *) vn->tree_node)->child; +// of->flags = opt; +// of->vnode = vn; +// +// return 0; +// } else { +// // opendir +// if (vn->op->opendir) { +// if ((res = vn->op->opendir(vn, opt)) != 0) { +// return res; +// } +// } else { +// return -EINVAL; +// } +// +// of->flags = opt; +// of->vnode = vn; +// of->pos = 0; +// } +// +// return res; +// } +// +// // Check flag sanity +// // Can't have O_CREAT here +// if (opt & O_CREAT) { +// return -EINVAL; +// } +// // Can't be both (RD|WR) and EX +// if (opt & O_EXEC) { +// if (opt & O_ACCMODE) { +// return -EACCES; +// } +// } +// +// if (vn->type == VN_DIR) { +// return -EISDIR; +// } +// +// of->vnode = vn; +// of->flags = opt; +// of->pos = 0; +// +// if (opt & O_APPEND) { +// // TODO: rewrite open() to accept struct ofile * +// // instead of vnode so that open() function of the +// // vnode can properly set of->pos +// //fprintf(stderr, "O_APPEND not yet implemented\n"); +// kerror("O_APPEND not yet implemented\n"); +// return -EINVAL; +// } +// +// // Check if file has to be truncated before opening it +// if (opt & O_TRUNC) { +// if (!vn->op->truncate) { +// return -EINVAL; +// } +// +// if ((res = vn->op->truncate(of, 0)) != 0) { +// return res; +// } +// } +// +// if (vn->op->open) { +// if ((res = vn->op->open(vn, opt)) != 0) { +// return res; +// } +// } +// +// return 0; +//} +// +//void vfs_close(struct vfs_ioctx *ctx, struct ofile *of) { +// _assert(of); +// vnode_t *vn = of->vnode; +// switch (vn->type) { +// case VN_REG: +// case VN_DIR: +// _assert(vn); +// +// if (vn->op->close) { +// vn->op->close(of); +// } +// break; +// +// // TODO: maybe call something special for that +// case VN_CHR: +// case VN_BLK: +// break; +// +// default: +// panic("Unhandled vnode type\n"); +// } +// +// vnode_unref(of->vnode); +//} +// +//int vfs_statat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, struct stat *st) { +// _assert(at && path && st); +// int res; +// vnode_t *vnode; +// +// if ((res = vfs_find(at, path, &vnode)) != 0) { +// return res; +// } +// +// vnode_ref(vnode); +// +// if (!vnode->op || !vnode->op->stat) { +// res = -EINVAL; +// } else { +// res = vnode->op->stat(vnode, st); +// } +// +// vnode_unref(vnode); +// return res; +//} +// +//int vfs_stat(struct vfs_ioctx *ctx, const char *path, struct stat *st) { +// _assert(path && st); +// vnode_t *vnode; +// int res; +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) != 0) { +// return res; +// } +// +// vnode_ref(vnode); +// +// if (!vnode->op || !vnode->op->stat) { +// res = -EINVAL; +// } else { +// res = vnode->op->stat(vnode, st); +// } +// +// vnode_unref(vnode); +// return res; +//} +// +//ssize_t vfs_read(struct vfs_ioctx *ctx, struct ofile *fd, void *buf, size_t count) { +// _assert(fd); +// vnode_t *vn = fd->vnode; +// _assert(vn); +// +// ssize_t nr; +// +// switch (vn->type) { +// case VN_REG: +// _assert(vn->op); +// // XXX: should these be checked on every read? +// if (vfs_vnode_access(ctx, vn, R_OK) < 0) { +// return -EACCES; +// } +// +// if (fd->flags & O_DIRECTORY) { +// return -EISDIR; +// } +// if ((fd->flags & O_ACCMODE) == O_WRONLY) { +// return -EINVAL; +// } +// if (vn->op->read == NULL) { +// return -EINVAL; +// } +// +// nr = vn->op->read(fd, buf, count); +// +// if (nr > 0) { +// fd->pos += nr; +// } +// +// return nr; +// +// // We don't need filesystem at all to read from devices +// case VN_BLK: +// _assert(vn->dev); +// +// if ((nr = blk_read((struct blkdev *) vn->dev, buf, fd->pos, count)) > 0) { +// fd->pos += nr; +// } +// +// return nr; +// case VN_CHR: +// _assert(vn->dev); +// return chr_read((struct chrdev *) vn->dev, buf, fd->pos, count); +// +// default: +// panic("Not supported\n"); +// } +//} +// +//ssize_t vfs_write(struct vfs_ioctx *ctx, struct ofile *fd, const void *buf, size_t count) { +// _assert(fd); +// vnode_t *vn = fd->vnode; +// _assert(vn); +// +// switch (vn->type) { +// case VN_REG: +// _assert(vn->op); +// +// // XXX: should these be checked on every write? +// if (vfs_vnode_access(ctx, vn, W_OK) < 0) { +// return -EACCES; +// } +// +// if (fd->flags & O_DIRECTORY) { +// return -EISDIR; +// } +// if ((fd->flags & O_ACCMODE) == O_RDONLY) { +// return -EINVAL; +// } +// if (vn->op->write == NULL) { +// return -EINVAL; +// } +// +// return vn->op->write(fd, buf, count); +// +// // We don't need filesystem at all to write to devices +// case VN_BLK: +// _assert(vn->dev); +// return blk_write((struct blkdev *) vn->dev, buf, fd->pos, count); +// case VN_CHR: +// _assert(vn->dev); +// return chr_write((struct chrdev *) vn->dev, buf, fd->pos, count); +// +// default: +// panic("Not supported\n"); +// } +//} + +//int vfs_truncate(struct vfs_ioctx *ctx, struct ofile *of, size_t length) { +// _assert(of); +// if ((of->flags & O_ACCMODE) == O_RDONLY) { +// return -EINVAL; +// } +// if ((of->flags & O_DIRECTORY)) { +// return -EINVAL; +// } +// vnode_t *vn = of->vnode; +// _assert(vn && vn->op); +// // XXX: should these be checked on every write? +// if (vfs_vnode_access(ctx, vn, W_OK) < 0) { +// return -EACCES; +// } +// +// if (!vn->op->truncate) { +// return -EINVAL; +// } +// +// return vn->op->truncate(of, length); +//} +// +//int vfs_unlink(struct vfs_ioctx *ctx, const char *path, int is_rmdir) { +// // XXX: validate this with removing mounted roots +// _assert(path); +// // Find the vnode to unlink +// int res; +// vnode_t *parent_vnode, *vnode; +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { +// return res; +// } +// +// _assert(vnode && vnode->op); +// vnode_ref(vnode); +// +// if (vnode->type != VN_DIR && is_rmdir) { +// return -ENOTDIR; +// } +// if (vnode->type == VN_DIR && !is_rmdir) { +// return -EISDIR; +// } +// +// // Get node parent +// struct vfs_node *node = vnode->tree_node; +// _assert(node); +// +// if (!node->parent) { +// // Trying to unlink root node? +// vnode_unref(vnode); +// return -EACCES; +// } +// +// if (vnode->refcount != 0) { +// // Trying to unlink the file someone is using. +// // Good solution would be to (TODO) defer the +// // actual unlinking and perform it once no one +// // is using it or notify writers/reader that the +// // file is slated for removal. I think just adding +// // a flag to vnode like "deleted" should suffice. +// // For now, just check if vfs_ctx is trying to shoot +// // its' leg off by unlinking the CWD +// if (vnode == ctx->cwd_vnode) { +// return -EINVAL; +// } +// } +// +// parent_vnode = node->parent->vnode; +// vnode_ref(parent_vnode); +// +// // Can only remove a child in a directory +// if (parent_vnode->type != VN_DIR) { +// vnode_unref(vnode); +// vnode_unref(parent_vnode); +// return res; +// } +// +// if ((res = vfs_vnode_access(ctx, parent_vnode, W_OK)) < 0) { +// vnode_unref(vnode); +// vnode_unref(parent_vnode); +// return res; +// } +// +// if (parent_vnode->op->unlink) { +// // TODO: handle +// // unlink("path/to/node/./.") +// path = vfs_path_basename(path); +// _assert(path); +// +// if ((res = parent_vnode->op->unlink(parent_vnode, vnode, path)) < 0) { +// vnode_unref(vnode); +// vnode_unref(parent_vnode); +// return res; +// } +// +// vnode_unref(vnode); +// vnode_unref(parent_vnode); +// return 0; +// } else { +// //fprintf(stderr, "File system does not implement unlink()\n"); +// kerror("Filesystem does not implement unlink()\n"); +// // File node does not support unlinking +// vnode_unref(vnode); +// vnode_unref(parent_vnode); +// return -EINVAL; +// } +//} +// +//int vfs_chmod(struct vfs_ioctx *ctx, const char *path, mode_t mode) { +// _assert(path); +// vnode_t *vnode; +// int res; +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { +// return res; +// } +// +// vnode_ref(vnode); +// _assert(vnode && vnode->op); +// +// if (vnode->op->access) { +// mode_t vn_mode; +// uid_t vn_uid; +// gid_t vn_gid; +// +// if ((res = vnode->op->access(vnode, &vn_uid, &vn_gid, &vn_mode)) < 0) { +// return res; +// } +// +// // To chmod, the uid of the user has to match +// // the node's one +// if ((vn_uid != ctx->uid) && (ctx->uid != 0)) { +// return -EACCES; +// } +// } +// +// if (!vnode->op->chmod) { +// return -EINVAL; +// } +// +// res = vnode->op->chmod(vnode, mode); +// +// vnode_unref(vnode); +// return res; +//} +// +//int vfs_chown(struct vfs_ioctx *ctx, const char *path, uid_t uid, gid_t gid) { +// _assert(path); +// vnode_t *vnode; +// int res; +// +// if (ctx->uid != 0) { +// // For now, only root can change ownership of the nodes +// return -EACCES; +// } +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { +// return res; +// } +// +// vnode_ref(vnode); +// _assert(vnode && vnode->op); +// +// if (!vnode->op->chown) { +// return -EINVAL; +// } +// +// res = vnode->op->chown(vnode, uid, gid); +// +// vnode_unref(vnode); +// return res; +//} +// +//// TODO: change signature so it can return errno +//struct dirent *vfs_readdir(struct vfs_ioctx *ctx, struct ofile *fd) { +// _assert(fd); +// if (!(fd->flags & O_DIRECTORY)) { +// return NULL; +// } +// vnode_t *vn = fd->vnode; +// _assert(vn && vn->op); +// +// if (vfs_vnode_access(ctx, vn, R_OK) < 0) { +// return NULL; +// } +// +// _assert(vn->fs && vn->fs->cls); +// if (vn->fs->cls->opt & FS_NODE_MAPPER) { +// _assert(sizeof(fd->pos) >= sizeof(uintptr_t)); +// struct vfs_node *item_node = (struct vfs_node *) fd->pos; +// struct dirent *ent_buf = (struct dirent *) fd->dirent_buf; +// +// if (item_node) { +// fd->pos = (uintptr_t) (item_node->cdr); +// } else { +// return NULL; +// } +// +// _assert(item_node->vnode); +// +// // Describe the node into dirent buffer +// // TODO: size checks +// strcpy(ent_buf->d_name, item_node->name); +// ent_buf->d_ino = /* TODO use something as inode number for node mapper */ -1; +// ent_buf->d_off = 0; +// ent_buf->d_reclen = strlen(item_node->name) + sizeof(struct dirent); +// // TODO: blk/chr +// switch (item_node->vnode->type) { +// case VN_REG: +// ent_buf->d_type = DT_REG; +// break; +// case VN_DIR: +// ent_buf->d_type = DT_DIR; +// break; +// case VN_BLK: +// ent_buf->d_type = DT_BLK; +// break; +// case VN_CHR: +// ent_buf->d_type = DT_CHR; +// break; +// default: +// kwarn("Unsupported vnode type: %d\n", item_node->vnode->type); +// ent_buf->d_type = DT_UNKNOWN; +// break; +// } +// +// return ent_buf; +// } else { +// if (!vn->op->readdir) { +// return NULL; +// } +// +// if (vn->op->readdir(fd) == 0) { +// return (struct dirent *) fd->dirent_buf; +// } +// +// return NULL; +// } +//} +// +//int vfs_mkdir(struct vfs_ioctx *ctx, const char *path, mode_t mode) { +// vnode_t *parent_vnode = NULL; +// vnode_t *vnode = NULL; +// int res; +// +// // Check if a directory with such name already exists +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) == 0) { +// vnode_ref(vnode); +// vnode_unref(vnode); +// return -EEXIST; +// } +// +// // Just copypasted this from creat() +// if (*path == '/') { +// // Get parent vnode +// char parent_path[1024]; +// vfs_path_parent(parent_path, path); +// +// if ((res = vfs_find(NULL, parent_path, &parent_vnode)) != 0) { +// kerror("Parent does not exist: %s\n", parent_path); +// // Parent doesn't exist, too - error +// return res; +// } +// } else { +// char parent_path[1024]; +// vfs_path_parent(parent_path, path); +// +// if (!*parent_path) { +// parent_path[0] = '.'; +// parent_path[1] = 0; +// } +// +// // Find parent +// if ((res = vfs_find(ctx->cwd_vnode, parent_path, &parent_vnode)) != 0) { +// kerror("Parent does not exist: %s\n", parent_path); +// return res; +// } +// } +// +// vnode_ref(parent_vnode); +// +// if (parent_vnode->type == VN_LNK) { +// _assert(parent_vnode->op); +// _assert(parent_vnode->op->readlink); +// char lnk[1024]; +// vnode_t *vn_lnk; +// struct vfs_node *vn_node = (struct vfs_node *) parent_vnode->tree_node; +// struct vfs_node *vn_lnk_node; +// _assert(vn_node); +// +// if ((res = parent_vnode->op->readlink(parent_vnode, lnk)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// vn_lnk = vn_lnk_node->vnode; +// vnode_ref(vn_lnk); +// vnode_unref(parent_vnode); +// +// parent_vnode = vn_lnk; +// } +// +// if (parent_vnode->type != VN_DIR) { +// // Parent is not a directory +// vnode_unref(parent_vnode); +// return -ENOTDIR; +// } +// +// // Need write permission +// if ((res = vfs_vnode_access(ctx, parent_vnode, W_OK)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// kdebug("Path: %s\n", path); +// path = vfs_path_basename(path); +// +// if (!path) { +// vnode_unref(parent_vnode); +// return -EINVAL; +// } +// +// if (!parent_vnode->op || !parent_vnode->op->mkdir) { +// vnode_unref(parent_vnode); +// return -EINVAL; +// } +// +// if ((res = parent_vnode->op->mkdir(parent_vnode, path, mode)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// vnode_unref(parent_vnode); +// return res; +//} +// +//int vfs_access(struct vfs_ioctx *ctx, const char *path, int mode) { +// _assert(path); +// vnode_t *vnode; +// int res; +// +// mode_t vn_mode; +// uid_t vn_uid; +// gid_t vn_gid; +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) != 0) { +// return res; +// } +// +// vnode_ref(vnode); +// if (mode == F_OK) { +// vnode_unref(vnode); +// return 0; +// } +// +// _assert(vnode->op); +// +// if (!vnode->op->access) { +// vnode_unref(vnode); +// // Filesystem has no permissions? +// return -EINVAL; +// } +// +// if ((res = vnode->op->access(vnode, &vn_uid, &vn_gid, &vn_mode)) < 0) { +// vnode_unref(vnode); +// return res; +// } +// +// vnode_unref(vnode); +// +// return vfs_access_internal(ctx, mode, vn_mode, vn_uid, vn_gid); +//} +// +//int vfs_statvfs(struct vfs_ioctx *ctx, const char *path, struct statvfs *st) { +// _assert(ctx && path && st); +// vnode_t *vnode; +// int res; +// fs_t *fs; +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { +// return res; +// } +// +// vnode_ref(vnode); +// +// if (!(fs = vnode->fs)) { +// vnode_unref(vnode); +// return -EINVAL; +// } +// +// vnode_unref(vnode); +// +// if (!fs->cls || !fs->cls->statvfs) { +// return -EINVAL; +// } +// +// return fs->cls->statvfs(fs, st); +//} +// +//int vfs_readlinkat(struct vfs_ioctx *ctx, vnode_t *at, const char *path, char *buf) { +// int res; +// vnode_t *vnode; +// +// if ((res = vfs_find(at, path, &vnode)) < 0) { +// return res; +// } +// +// vnode_ref(vnode); +// +// if (!vnode->op || !vnode->op->readlink) { +// vnode_unref(vnode); +// return -EINVAL; +// } +// if (vnode->type != VN_LNK) { +// vnode_unref(vnode); +// return -EINVAL; +// } +// +// res = vnode->op->readlink(vnode, buf); +// vnode_unref(vnode); +// return res; +//} +// +//int vfs_readlink(struct vfs_ioctx *ctx, const char *path, char *buf) { +// int res; +// vnode_t *vnode; +// +// if ((res = vfs_find(ctx->cwd_vnode, path, &vnode)) < 0) { +// return res; +// } +// +// vnode_ref(vnode); +// +// if (!vnode->op || !vnode->op->readlink) { +// vnode_unref(vnode); +// return -EINVAL; +// } +// if (vnode->type != VN_LNK) { +// vnode_unref(vnode); +// return -EINVAL; +// } +// +// res = vnode->op->readlink(vnode, buf); +// vnode_unref(vnode); +// return res; +//} +// +//int vfs_symlink(struct vfs_ioctx *ctx, const char *target, const char *linkpath) { +// vnode_t *parent_vnode = NULL; +// vnode_t *vnode = NULL; +// int res; +// +// // Check if a directory with such name already exists +// if ((res = vfs_find(ctx->cwd_vnode, linkpath, &vnode)) == 0) { +// vnode_ref(vnode); +// vnode_unref(vnode); +// return -EEXIST; +// } +// +// // Just copypasted this from creat() +// if (*linkpath == '/') { +// // Get parent vnode +// char parent_path[1024]; +// vfs_path_parent(parent_path, linkpath); +// +// if ((res = vfs_find(NULL, parent_path, &parent_vnode)) != 0) { +// kerror("Parent does not exist: %s\n", parent_path); +// // Parent doesn't exist, too - error +// return res; +// } +// } else { +// char parent_path[1024]; +// vfs_path_parent(parent_path, linkpath); +// +// if (!*parent_path) { +// parent_path[0] = '.'; +// parent_path[1] = 0; +// } +// +// // Find parent +// if ((res = vfs_find(ctx->cwd_vnode, parent_path, &parent_vnode)) != 0) { +// kerror("Parent does not exist: %s\n", parent_path); +// return res; +// } +// } +// +// vnode_ref(parent_vnode); +// +// if (parent_vnode->type == VN_LNK) { +// _assert(parent_vnode->op); +// _assert(parent_vnode->op->readlink); +// char lnk[1024]; +// vnode_t *vn_lnk; +// struct vfs_node *vn_node = (struct vfs_node *) parent_vnode->tree_node; +// struct vfs_node *vn_lnk_node; +// _assert(vn_node); +// +// if ((res = parent_vnode->op->readlink(parent_vnode, lnk)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// if ((res = vfs_find_tree(vn_node->parent, lnk, &vn_lnk_node)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// vn_lnk = vn_lnk_node->vnode; +// vnode_ref(vn_lnk); +// vnode_unref(parent_vnode); +// +// parent_vnode = vn_lnk; +// } +// +// if (parent_vnode->type != VN_DIR) { +// // Parent is not a directory +// vnode_unref(parent_vnode); +// return -ENOTDIR; +// } +// +// // Need write permission +// if ((res = vfs_vnode_access(ctx, parent_vnode, W_OK)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// kdebug("Path: %s\n", linkpath); +// linkpath = vfs_path_basename(linkpath); +// +// if (!linkpath) { +// vnode_unref(parent_vnode); +// return -EINVAL; +// } +// +// if (!parent_vnode->op || !parent_vnode->op->symlink) { +// vnode_unref(parent_vnode); +// return -EINVAL; +// } +// +// // if ((res = parent_vnode->op->mkdir(parent_vnode, linkpath, mode)) < 0) { +// // vnode_unref(parent_vnode); +// // return res; +// // } +// if ((res = parent_vnode->op->symlink(parent_vnode, ctx, linkpath, target)) < 0) { +// vnode_unref(parent_vnode); +// return res; +// } +// +// vnode_unref(parent_vnode); +// return res; +//}