From 0976602c599c5657e57872a11e21836ac9c7dc48 Mon Sep 17 00:00:00 2001 From: jasoni Date: Tue, 4 Apr 2000 05:31:50 +0000 Subject: [PATCH] Implement Linux's pread(2) and pwrite(2). --- sys/compat/linux/linux_file.c | 155 +++++++++++++++++++++++++++++-- sys/compat/linux/syscalls.master | 8 +- 2 files changed, 154 insertions(+), 9 deletions(-) diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c index 3761ad27c97..ccd5271353a 100644 --- a/sys/compat/linux/linux_file.c +++ b/sys/compat/linux/linux_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_file.c,v 1.10 2000/02/28 13:29:29 jasoni Exp $ */ +/* $OpenBSD: linux_file.c,v 1.11 2000/04/04 05:31:50 jasoni Exp $ */ /* $NetBSD: linux_file.c,v 1.15 1996/05/20 01:59:09 fvdl Exp $ */ /* @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include #include @@ -63,6 +65,8 @@ static void bsd_to_linux_flock __P((struct flock *, struct linux_flock *)); static void linux_to_bsd_flock __P((struct linux_flock *, struct flock *)); static void bsd_to_linux_stat __P((struct stat *, struct linux_stat *)); static int linux_stat1 __P((struct proc *, void *, register_t *, int)); +static int linux_set_pos __P((struct proc *, int, off_t, off_t *)); + /* * Some file-related calls are handled here. The usual flag conversion @@ -70,7 +74,7 @@ static int linux_stat1 __P((struct proc *, void *, register_t *, int)); */ /* - * The next two functions convert between the Linux and NetBSD values + * The next two functions convert between the Linux and OpenBSD values * of the flags used in open(2) and fcntl(2). */ static int @@ -146,7 +150,7 @@ linux_sys_creat(p, v, retval) /* * open(2). Take care of the different flag values, and let the - * NetBSD syscall do the real work. See if this operation + * OpenBSD syscall do the real work. See if this operation * gives the current process a controlling terminal. * (XXX is this necessary?) */ @@ -236,7 +240,7 @@ linux_sys_llseek(p, v, retval) /* * The next two functions take care of converting the flock - * structure back and forth between Linux and NetBSD format. + * structure back and forth between Linux and OpenBSD format. * The only difference in the structures is the order of * the fields, and the 'whence' value. */ @@ -288,7 +292,7 @@ linux_to_bsd_flock(lfp, bfp) /* * Most actions in the fcntl() call are straightforward; simply - * pass control to the NetBSD system call. A few commands need + * pass control to the OpenBSD system call. A few commands need * conversions after the actual system call has done its work, * because the flag values and lock structure are different. */ @@ -431,7 +435,7 @@ linux_sys_fcntl(p, v, retval) } /* - * Convert a NetBSD stat structure to a Linux stat structure. + * Convert a OpenBSD stat structure to a Linux stat structure. * Only the order of the fields and the padding in the structure * is different. linux_fakedev is a machine-dependent function * which optionally converts device driver major/minor numbers @@ -849,3 +853,142 @@ linux_sys_fdatasync(p, v, retval) } */ *uap = v; return sys_fsync(p, uap, retval); } + +/* + * sys_lseek trimmed down + */ +static int +linux_set_pos(p, fd, offset, ooffset) + struct proc *p; + int fd; + off_t offset; + off_t *ooffset; +{ + register struct filedesc *fdp = p->p_fd; + register struct file *fp; + struct vnode *vp; + int special; + + if ((u_int)fd >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[fd]) == NULL) + return (EBADF); + if (fp->f_type != DTYPE_VNODE) + return (ESPIPE); + vp = (struct vnode *)fp->f_data; + if (vp->v_type == VFIFO) + return (ESPIPE); + if (vp->v_type == VCHR) + special = 1; + else + special = 0; + if (!special && offset < 0) + return (EINVAL); + *ooffset = fp->f_offset; + fp->f_offset = offset; + return (0); +} + +/* + * pread(2). + */ +int +linux_sys_pread(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct linux_sys_pread_args /* { + syscallarg(int) fd; + syscallarg(void *) buf; + syscallarg(size_t) nbyte; + syscallarg(linux_off_t) offset; + } */ *uap = v; + register struct file *fp; + register struct filedesc *fdp = p->p_fd; + struct uio auio; + struct iovec aiov; + long cnt, error = 0; + off_t save_offset; + + /* Don't allow nbyte to be larger than max return val */ + if (SCARG(uap, nbyte) > SSIZE_MAX) + return(EINVAL); + if ((error = linux_set_pos(p, SCARG(uap, fd), SCARG(uap, offset), + &save_offset))) + return (error); + fp = fdp->fd_ofiles[SCARG(uap, fd)]; + aiov.iov_base = (caddr_t)SCARG(uap, buf); + aiov.iov_len = SCARG(uap, nbyte); + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = SCARG(uap, nbyte); + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; + cnt = SCARG(uap, nbyte); + error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred); + if (error) + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + cnt -= auio.uio_resid; + fp->f_offset = save_offset; + *retval = cnt; + return (error); +} + +/* + * pwrite(2). + */ +int +linux_sys_pwrite(p, v, retval) + struct proc *p; + void *v; + register_t *retval; +{ + struct linux_sys_pwrite_args /* { + syscallarg(int) fd; + syscallarg(char *) buf; + syscallarg(size_t) nbyte; + syscallarg(linux_off_t) offset; + } */ *uap = v; + register struct file *fp; + register struct filedesc *fdp = p->p_fd; + struct uio auio; + struct iovec aiov; + long cnt, error = 0; + off_t save_offset; + + /* Don't allow nbyte to be larger than max return val */ + if (SCARG(uap, nbyte) > SSIZE_MAX) + return(EINVAL); + if ((error = linux_set_pos(p, SCARG(uap, fd), SCARG(uap, offset), + &save_offset))) + return (error); + fp = fdp->fd_ofiles[SCARG(uap, fd)]; + if ((fp->f_flag & FWRITE) == 0) { + fp->f_offset = save_offset; + return (EBADF); + } + aiov.iov_base = (caddr_t)SCARG(uap, buf); + aiov.iov_len = SCARG(uap, nbyte); + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = SCARG(uap, nbyte); + auio.uio_rw = UIO_WRITE; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = p; + cnt = SCARG(uap, nbyte); + error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred); + if (error) { + if (auio.uio_resid != cnt && (error == ERESTART || + error == EINTR || error == EWOULDBLOCK)) + error = 0; + if (error == EPIPE) + psignal(p, SIGPIPE); + } + cnt -= auio.uio_resid; + *retval = cnt; + fp->f_offset = save_offset; + return (error); +} diff --git a/sys/compat/linux/syscalls.master b/sys/compat/linux/syscalls.master index ccbf7cbb1c7..21162ac8a98 100644 --- a/sys/compat/linux/syscalls.master +++ b/sys/compat/linux/syscalls.master @@ -1,4 +1,4 @@ - $OpenBSD: syscalls.master,v 1.20 2000/03/28 06:35:57 jasoni Exp $ + $OpenBSD: syscalls.master,v 1.21 2000/04/04 05:31:50 jasoni Exp $ ; $NetBSD: syscalls.master,v 1.15 1995/12/18 14:35:10 fvdl Exp $ ; @(#)syscalls.master 8.1 (Berkeley) 7/19/93 @@ -288,8 +288,10 @@ 178 UNIMPL rt_queueinfo 179 STD { int linux_sys_rt_sigsuspend(linux_sigset_t *unewset, \ size_t sigsetsize); } -180 UNIMPL pread -181 UNIMPL pwrite +180 STD { int linux_sys_pread(int fd, char *buf, \ + size_t nbyte, linux_off_t offset); } +181 STD { int linux_sys_pwrite(int fd, char *buf, \ + size_t nbyte, linux_off_t offset); } 182 STD { int linux_sys_chown(char *path, int uid, int gid); } 183 STD { int linux_sys_getcwd(char *bufp, size_t length); } 184 UNIMPL capget -- 2.20.1