diff options
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r-- | sys/kern/kern_descrip.c | 107 |
1 files changed, 103 insertions, 4 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d122e89..d4c9885 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -149,6 +149,7 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) { char *kbuf = NULL; ssize_t n; + uint32_t seal; struct filedesc *filedes; struct sio_txn sio; scret_t retval = 0; @@ -159,8 +160,17 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) } filedes = fd_get(fd); - kbuf = dynalloc(count); + seal = filedes->flags; + + /* Check the seal */ + if (write && !ISSET(seal, O_ALLOW_WR)) { + return -EPERM; + } + if (!write && ISSET(seal, O_WRONLY)) { + return -EPERM; + } + kbuf = dynalloc(count); if (kbuf == NULL) { retval = -ENOMEM; goto done; @@ -187,6 +197,7 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) sio.buf = kbuf; sio.offset = filedes->offset; + spinlock_acquire(&filedes->lock); if (write) { /* Copy in user buffer */ if (copyin(buf, kbuf, count) < 0) { @@ -205,19 +216,52 @@ fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) goto done; } + /* End of file? */ + if (n == 0) { + retval = 0; + goto done; + } + if (copyout(kbuf, buf, count) < 0) { retval = -EFAULT; goto done; } } + + /* Increment the offset per read */ + filedes->offset += n; retval = count; done: if (kbuf != NULL) { dynfree(kbuf); } + spinlock_release(&filedes->lock); return retval; } +static int +fd_do_create(const char *path, struct nameidata *ndp) +{ + struct vop_create_args cargs; + struct vnode *dirvp = ndp->vp; + const struct vops *vops = dirvp->vops; + int error; + + if (vops->create == NULL) { + return -EINVAL; + } + + cargs.path = path; + cargs.ppath = ndp->path; + cargs.dirvp = dirvp; + cargs.vpp = &ndp->vp; + if ((error = vops->create(&cargs)) < 0) { + return error; + } + + return 0; +} + int fd_read(unsigned int fd, void *buf, size_t count) { @@ -236,18 +280,17 @@ fd_write(unsigned int fd, void *buf, size_t count) * * @pathname: Path of file to open. * @flags: Flags to use. - * - * TODO: Use of flags. */ int fd_open(const char *pathname, int flags) { int error; + const struct vops *vops; struct filedesc *filedes; struct nameidata nd; nd.path = pathname; - nd.flags = 0; + nd.flags = ISSET(flags, O_CREAT) ? NAMEI_WANTPARENT : 0; if ((error = namei(&nd)) < 0) { return error; @@ -258,6 +301,14 @@ fd_open(const char *pathname, int flags) return error; } + vops = nd.vp->vops; + if (ISSET(flags, O_CREAT) && vops->create != NULL) { + error = fd_do_create(pathname, &nd); + } + if (error < 0) { + return error; + } + filedes->vp = nd.vp; filedes->flags = flags; return filedes->fdno; @@ -285,3 +336,51 @@ fd_dup(int fd) new_desc->vp = tmp->vp; return new_desc->fdno; } + +off_t +fd_seek(int fildes, off_t offset, int whence) +{ + struct filedesc *tmp; + struct vattr attr; + struct vop_getattr_args getattr_args; + + tmp = fd_get(fildes); + if (tmp == NULL) { + return -EBADF; + } + + getattr_args.vp = tmp->vp; + getattr_args.res = &attr; + if ((vfs_vop_getattr(tmp->vp, &getattr_args)) < 0) { + return -EPIPE; + } + + switch (whence) { + case SEEK_SET: + tmp->offset = offset; + break; + case SEEK_CUR: + tmp->offset += offset; + break; + case SEEK_END: + tmp->offset = attr.size + offset; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * Update file offset + * + * arg0: `filedes' + * arg1: `offset' + * arg2: `whence' + */ +scret_t +sys_lseek(struct syscall_args *scargs) +{ + return fd_seek(scargs->arg0, scargs->arg1, scargs->arg2); +} |