From 061d514beb30dc25a801dbd217a9dfdf23bb07e6 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 5 Jul 2020 17:13:38 +0300 Subject: [PATCH] Add mknod() and named pipes --- arch/amd64/syscall.c | 1 + fs/tar.c | 11 ++++++++ fs/vfs_ops.c | 55 ++++++++++++++++++++++++++++++++++++++++ include/fs/node.h | 3 +++ include/fs/vfs.h | 1 + include/sys/char/pipe.h | 2 ++ include/sys/sys_file.h | 1 + include/user/syscall.h | 1 + sys/char/pipe.c | 56 ++++++++++++++++++++++++++++++++++++++++- sys/sys_file.c | 23 +++++++++++++++++ 10 files changed, 153 insertions(+), 1 deletion(-) diff --git a/arch/amd64/syscall.c b/arch/amd64/syscall.c index 965895a..3b66bde 100644 --- a/arch/amd64/syscall.c +++ b/arch/amd64/syscall.c @@ -55,6 +55,7 @@ void *syscall_table[256] = { [SYSCALL_NR_READDIR] = sys_readdir, [SYSCALL_NR_CHMOD] = sys_chmod, [SYSCALL_NR_CHOWN] = sys_chown, + [SYSCALL_NR_MKNOD] = sys_mknod, // User control [SYSCALL_NR_GETUID] = sys_getuid, diff --git a/fs/tar.c b/fs/tar.c index 457d811..99bcab8 100644 --- a/fs/tar.c +++ b/fs/tar.c @@ -66,6 +66,7 @@ static int tarfs_vnode_chmod(struct vnode *node, mode_t mode); static int tarfs_vnode_chown(struct vnode *node, uid_t uid, gid_t gid); //static int tarfs_vnode_mkdir(struct vnode *at, const char *name, uid_t uid, gid_t gid, mode_t mode); //static int tarfs_vnode_creat(struct vnode *at, const char *name, uid_t uid, gid_t gid, mode_t mode); +static int tarfs_vnode_mknod(struct vnode *at, struct vnode *nod); static int tarfs_vnode_truncate(struct vnode *node, size_t length); static struct vnode_operations _tarfs_vnode_op = { @@ -77,6 +78,7 @@ static struct vnode_operations _tarfs_vnode_op = { .chown = tarfs_vnode_chown, .mkdir = NULL, //tarfs_vnode_mkdir, .creat = NULL, //tarfs_vnode_creat, + .mknod = tarfs_vnode_mknod, .write = NULL, //tarfs_vnode_write, .truncate = tarfs_vnode_truncate }; @@ -459,6 +461,15 @@ static int tarfs_vnode_stat(struct vnode *vn, struct stat *st) { // return 0; //} +static int tarfs_vnode_mknod(struct vnode *at, struct vnode *nod) { + _assert(at && at->type == VN_DIR && nod); + _assert(nod->name[0]); + + vnode_attach(at, nod); + + return 0; +} + static uintptr_t tarfs_block_addr(struct tar *hdr, uint32_t index) { if (index < TAR_DIRECT_BLOCKS) { return hdr->direct_blocks[index] & ~1; diff --git a/fs/vfs_ops.c b/fs/vfs_ops.c index 1ca4d00..1a4a0e4 100644 --- a/fs/vfs_ops.c +++ b/fs/vfs_ops.c @@ -358,6 +358,59 @@ int vfs_unlink(struct vfs_ioctx *ctx, const char *path) { return 0; } +int vfs_mknod(struct vfs_ioctx *ctx, const char *path, mode_t mode, struct vnode **_nod) { + char parent_path[PATH_MAX]; + const char *filename; + int res; + struct vnode *at; + + _assert(ctx); + _assert(path); + + filename = vfs_path_parent(path, parent_path); + if (filename[0] == 0) { + return -ENOENT; + } + + // Find parent vnode + if ((res = vfs_find(ctx, ctx->cwd_vnode, parent_path, 0, &at)) != 0) { + return res; + } + + // Check permission for writing + if ((res = vfs_access_node(ctx, at, W_OK)) != 0) { + return res; + } + + // TODO: check if such file already exists + if (!at->op || !at->op->mknod) { + // Assume it's a read-only filesystem + return -EROFS; + } + + enum vnode_type type; + switch (mode & S_IFMT) { + case S_IFIFO: + type = VN_FIFO; + break; + default: + panic("mknod: unsupported node type\n"); + } + struct vnode *nod = vnode_create(type, filename); + nod->mode = mode & VFS_MODE_MASK; + nod->uid = ctx->uid; + nod->gid = ctx->gid; + + if ((res = at->op->mknod(at, nod)) != 0) { + vnode_destroy(nod); + return res; + } + + *_nod = nod; + + return 0; +} + int vfs_creat(struct vfs_ioctx *ctx, const char *path, mode_t mode) { char parent_path[PATH_MAX]; const char *filename; @@ -532,6 +585,7 @@ ssize_t vfs_write(struct vfs_ioctx *ctx, struct ofile *fd, const void *buf, size switch (node->type) { case VN_REG: + case VN_FIFO: _assert(node->op && node->op->write); b = node->op->write(fd, buf, count); return b; @@ -565,6 +619,7 @@ ssize_t vfs_read(struct vfs_ioctx *ctx, struct ofile *fd, void *buf, size_t coun switch (node->type) { case VN_REG: + case VN_FIFO: _assert(node->op && node->op->read); b = node->op->read(fd, buf, count); return b; diff --git a/include/fs/node.h b/include/fs/node.h index d211a01..230bcfa 100644 --- a/include/fs/node.h +++ b/include/fs/node.h @@ -31,6 +31,7 @@ enum vnode_type { VN_BLK, VN_CHR, VN_LNK, + VN_FIFO, VN_UNK, VN_MNT, }; @@ -42,6 +43,8 @@ struct vnode_operations { int (*opendir) (struct ofile *fd); int (*open) (struct ofile *fd, int opt); void (*close) (struct ofile *fd); + // TODO: just merge all three? + int (*mknod) (struct vnode *at, struct vnode *nod); int (*creat) (struct vnode *at, const char *filename, uid_t uid, gid_t gid, mode_t mode); int (*mkdir) (struct vnode *at, const char *filename, uid_t uid, gid_t gid, mode_t mode); int (*truncate) (struct vnode *at, size_t size); diff --git a/include/fs/vfs.h b/include/fs/vfs.h index dddd8a1..da428f4 100644 --- a/include/fs/vfs.h +++ b/include/fs/vfs.h @@ -47,6 +47,7 @@ int vfs_readdir(struct vfs_ioctx *ctx, struct ofile *fd, struct dirent *ent); int vfs_unlink(struct vfs_ioctx *ctx, const char *path); int vfs_rmdir(struct vfs_ioctx *ctx, const char *path); int vfs_mkdir(struct vfs_ioctx *ctx, const char *path, mode_t mode); +int vfs_mknod(struct vfs_ioctx *ctx, const char *path, mode_t mode, struct vnode **nod); 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_ioctl(struct vfs_ioctx *ctx, struct ofile *fd, unsigned int cmd, void *arg); diff --git a/include/sys/char/pipe.h b/include/sys/char/pipe.h index 0f0476a..e98861a 100644 --- a/include/sys/char/pipe.h +++ b/include/sys/char/pipe.h @@ -1,5 +1,7 @@ #pragma once struct ofile; +struct vnode; int pipe_create(struct ofile **read, struct ofile **write); +int pipe_fifo_create(struct vnode *res); diff --git a/include/sys/sys_file.h b/include/sys/sys_file.h index 2c296a7..350b56e 100644 --- a/include/sys/sys_file.h +++ b/include/sys/sys_file.h @@ -27,3 +27,4 @@ int sys_dup2(int from, int to); int sys_chmod(const char *path, mode_t mode); int sys_chown(const char *path, uid_t uid, gid_t gid); off_t sys_lseek(int fd, off_t offset, int whence); +int sys_mknod(const char *filename, int mode, unsigned int dev); diff --git a/include/user/syscall.h b/include/user/syscall.h index 1876af4..f8f3e2a 100644 --- a/include/user/syscall.h +++ b/include/user/syscall.h @@ -25,6 +25,7 @@ #define SYSCALL_NR_READDIR 89 #define SYSCALL_NR_CHMOD 90 #define SYSCALL_NR_CHOWN 92 +#define SYSCALL_NR_MKNOD 133 #define SYSCALL_NR_NANOSLEEP 35 #define SYSCALL_NR_UNAME 63 diff --git a/sys/char/pipe.c b/sys/char/pipe.c index f93856c..89d0979 100644 --- a/sys/char/pipe.c +++ b/sys/char/pipe.c @@ -9,14 +9,18 @@ #define PIPE_RING_SIZE 1024 +static int pipe_vnode_open(struct ofile *of, int opt); static ssize_t pipe_vnode_write(struct ofile *of, const void *buf, size_t count); static ssize_t pipe_vnode_read(struct ofile *of, void *buf, size_t count); +static int pipe_vnode_stat(struct vnode *vn, struct stat *st); static void pipe_vnode_close(struct ofile *of); static struct vnode_operations pipe_vnode_ops = { + .open = pipe_vnode_open, .close = pipe_vnode_close, .write = pipe_vnode_write, - .read = pipe_vnode_read + .read = pipe_vnode_read, + .stat = pipe_vnode_stat }; int pipe_create(struct ofile **_read, struct ofile **_write) { @@ -51,6 +55,20 @@ int pipe_create(struct ofile **_read, struct ofile **_write) { return 0; } +int pipe_fifo_create(struct vnode *nod) { + _assert(nod); + nod->op = &pipe_vnode_ops; + nod->flags |= VN_MEMORY; + + struct ring *pipe_ring = kmalloc(sizeof(struct ring)); + _assert(pipe_ring); + ring_init(pipe_ring, PIPE_RING_SIZE); + + nod->fs_data = pipe_ring; + + return 0; +} + static ssize_t pipe_vnode_write(struct ofile *of, const void *buf, size_t count) { struct thread *thr = thread_self; _assert(thr); @@ -98,6 +116,42 @@ static void pipe_vnode_close(struct ofile *of) { if (of->flags & OF_WRITABLE) { ring_signal(of->file.priv_data, RING_SIGNAL_EOF); } + // TODO: this //kfree(((struct ring *) of->file.priv_data)->base); //kfree(of->file.priv_data); } + +static int pipe_vnode_open(struct ofile *of, int opt) { + _assert(!(of->flags & OF_SOCKET)); + _assert(of->file.vnode); + // TODO: allow only one reader and many writers + of->file.pos = 0; + of->file.priv_data = of->file.vnode->fs_data; + return 0; +} + +static int pipe_vnode_stat(struct vnode *vn, struct stat *st) { + _assert(vn && st); + struct ring *pipe_ring = vn->fs_data; + _assert(pipe_ring); + + st->st_size = pipe_ring->cap; + st->st_blksize = pipe_ring->cap; + st->st_blocks = 1; + + st->st_ino = 0; + + st->st_uid = vn->uid; + st->st_gid = vn->gid; + st->st_mode = vn->mode | S_IFIFO; + + st->st_atime = system_boot_time; + st->st_mtime = system_boot_time; + st->st_ctime = system_boot_time; + + st->st_nlink = 1; + st->st_rdev = 0; + st->st_dev = 0; + + return 0; +} diff --git a/sys/sys_file.c b/sys/sys_file.c index cc87f95..f4f7dc3 100644 --- a/sys/sys_file.c +++ b/sys/sys_file.c @@ -387,6 +387,29 @@ ssize_t sys_readdir(int fd, struct dirent *ent) { return vfs_readdir(&thr->ioctx, thr->fds[fd], ent); } +int sys_mknod(const char *filename, int mode, unsigned int dev) { + userptr_check(filename); + struct thread *thr = get_cpu()->thread; + _assert(thr); + + int type = mode & S_IFMT; + int res; + struct vnode *node; + + if ((res = vfs_mknod(&thr->ioctx, filename, mode, &node)) != 0) { + return res; + } + + _assert(node); + + switch (type) { + case S_IFIFO: + return pipe_fifo_create(node); + default: + return -EINVAL; + } +} + static int sys_select_get_ready(struct ofile *fd) { if (fd->flags & OF_SOCKET) { return socket_has_data(&fd->socket);