diff options
-rw-r--r-- | sys/compat/common/Makefile | 4 | ||||
-rw-r--r-- | sys/compat/common/compat_dir.c | 144 | ||||
-rw-r--r-- | sys/compat/common/compat_dir.h | 33 | ||||
-rw-r--r-- | sys/compat/ibcs2/ibcs2_misc.c | 307 | ||||
-rw-r--r-- | sys/compat/linux/linux_misc.c | 207 | ||||
-rw-r--r-- | sys/compat/sunos/sunos_misc.c | 148 | ||||
-rw-r--r-- | sys/compat/svr4/svr4_misc.c | 301 |
7 files changed, 506 insertions, 638 deletions
diff --git a/sys/compat/common/Makefile b/sys/compat/common/Makefile index 9c53d691d07..7681a235b6f 100644 --- a/sys/compat/common/Makefile +++ b/sys/compat/common/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.7 1999/05/22 21:22:33 weingart Exp $ +# $OpenBSD: Makefile,v 1.8 2001/01/23 05:48:04 csapuntz Exp $ # $NetBSD: Makefile,v 1.8 1996/05/18 15:52:19 christos Exp $ LIB= compat @@ -6,7 +6,7 @@ NOPIC= .PATH: ${COMPATDIR} -SRCS= compat_exec.c compat_util.c compat_vm.c kern_exit_43.c \ +SRCS= compat_exec.c compat_util.c compat_dir.c compat_vm.c kern_exit_43.c \ kern_info_09.c kern_info_43.c kern_prot_43.c kern_resource_43.c \ kern_sig_43.c tty_43.c uipc_syscalls_43.c vfs_syscalls_43.c vm_43.c diff --git a/sys/compat/common/compat_dir.c b/sys/compat/common/compat_dir.c new file mode 100644 index 00000000000..e7ecbd1e53f --- /dev/null +++ b/sys/compat/common/compat_dir.c @@ -0,0 +1,144 @@ +/* $OpenBSD: compat_dir.c,v 1.1 2001/01/23 05:48:04 csapuntz Exp $ */ + +/* + * Copyright (c) 2000 Constantine Sapuntzakis + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/namei.h> +#include <sys/proc.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/filedesc.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/dirent.h> + +#include <compat/common/compat_dir.h> + +int +readdir_with_callback(fp, off, nbytes, appendfunc, arg) + struct file *fp; + off_t *off; + u_long nbytes; + int (*appendfunc) __P((void *, struct dirent *, off_t)); + void *arg; +{ + caddr_t inp, buf; + int buflen; + struct uio auio; + struct iovec aiov; + int eofflag; + u_long *cookiebuf = NULL, *cookie; + int ncookies = 0; + int error, len, reclen; + off_t newoff = *off; + struct vnode *vp; + struct vattr va; + + if ((fp->f_flag & FREAD) == 0) + return (EBADF); + + vp = (struct vnode *)fp->f_data; + + if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ + return (EINVAL); + + if ((error = VOP_GETATTR(vp, &va, fp->f_cred, curproc)) != 0) + return (error); + + buflen = min(MAXBSIZE, nbytes); + buflen = max(buflen, va.va_blocksize); + buf = malloc(buflen, M_TEMP, M_WAITOK); + error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc); + if (error) + goto out; + +again: + aiov.iov_base = buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = curproc; + auio.uio_resid = buflen; + auio.uio_offset = newoff; + + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, + &cookiebuf); + if (error) + goto out; + + if (!cookiebuf && !eofflag) { + error = EPERM; + goto out; + } + + if ((len = buflen - auio.uio_resid) == 0) + goto eof; + + cookie = cookiebuf; + inp = buf; + + for (; + len > 0; + len -= reclen, inp += reclen, ++cookie) { + struct dirent *bdp = (struct dirent *)inp; + reclen = bdp->d_reclen; + + if (len < reclen) break; + if (reclen & 3) + panic("readdir_with_callback: bad reclen"); + + /* Skip holes */ + if (bdp->d_fileno != 0) { + if ((error = (*appendfunc) (arg, bdp, *cookie)) + != 0) { + if (error == ENOMEM) + error = 0; + break; + } + } + + newoff = *cookie; + } + + if (len <= 0 && !eofflag) + goto again; + + eof: + out: + if (error == 0) + *off = newoff; + + VOP_UNLOCK(vp, 0, curproc); + if (cookiebuf) + free(cookiebuf, M_TEMP); + free(buf, M_TEMP); + return (error); +} diff --git a/sys/compat/common/compat_dir.h b/sys/compat/common/compat_dir.h new file mode 100644 index 00000000000..d070d578138 --- /dev/null +++ b/sys/compat/common/compat_dir.h @@ -0,0 +1,33 @@ +/* $OpenBSD: compat_dir.h,v 1.1 2001/01/23 05:48:04 csapuntz Exp $ */ + +/* + * Copyright (c) 2000 Constantine Sapuntzakis + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef _KERNEL + +int readdir_with_callback __P((struct file *, off_t *, u_long, + int (*append_func) (void *, struct dirent *, off_t), void *)); + +#endif diff --git a/sys/compat/ibcs2/ibcs2_misc.c b/sys/compat/ibcs2/ibcs2_misc.c index 6a52735b32d..94313e9d47c 100644 --- a/sys/compat/ibcs2/ibcs2_misc.c +++ b/sys/compat/ibcs2/ibcs2_misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ibcs2_misc.c,v 1.16 2000/09/07 17:52:23 ericj Exp $ */ +/* $OpenBSD: ibcs2_misc.c,v 1.17 2001/01/23 05:48:05 csapuntz Exp $ */ /* $NetBSD: ibcs2_misc.c,v 1.23 1997/01/15 01:37:49 perry Exp $ */ /* @@ -104,6 +104,7 @@ #include <compat/ibcs2/ibcs2_syscallargs.h> #include <compat/ibcs2/ibcs2_sysi86.h> +#include <compat/common/compat_dir.h> int ibcs2_sys_ulimit(p, v, retval) @@ -335,6 +336,86 @@ ibcs2_sys_mount(p, v, retval) * This is quite ugly, but what do you expect from compatibility code? */ +int ibcs2_readdir_callback __P((void *, struct dirent *, off_t)); +int ibcs2_classicread_callback __P((void *, struct dirent *, off_t)); + +struct ibcs2_readdir_callback_args { + caddr_t outp; + int resid; +}; + +int +ibcs2_readdir_callback(arg, bdp, cookie) + void *arg; + struct dirent *bdp; + off_t cookie; +{ + struct ibcs2_dirent idb; + struct ibcs2_readdir_callback_args *cb = arg; + int ibcs2_reclen; + int error; + + ibcs2_reclen = IBCS2_RECLEN(&idb, bdp->d_namlen); + if (cb->resid < ibcs2_reclen) + return (ENOMEM); + + /* + * Massage in place to make a iBCS2-shaped dirent (otherwise + * we have to worry about touching user memory outside of + * the copyout() call). + */ + idb.d_ino = (ibcs2_ino_t)bdp->d_fileno; + idb.d_pad = 0; + idb.d_off = (ibcs2_off_t)cookie; + idb.d_reclen = (u_short)ibcs2_reclen; + strlcpy(idb.d_name, bdp->d_name, IBCS2_MAXNAMLEN+1); + error = copyout((caddr_t)&idb, cb->outp, ibcs2_reclen); + if (error) + return (error); + + /* advance output past iBCS2-shaped entry */ + cb->outp += ibcs2_reclen; + cb->resid -= ibcs2_reclen; + + return (0); +} + +int +ibcs2_classicread_callback(arg, bdp, cookie) + void *arg; + struct dirent *bdp; + off_t cookie; +{ + struct ibcs2_direct { + ibcs2_ino_t ino; + char name[14]; + } idb; + struct ibcs2_readdir_callback_args *cb = arg; + int ibcs2_reclen; + int error; + + ibcs2_reclen = 16; + if (cb->resid < ibcs2_reclen) + return (ENOMEM); + + /* + * TODO: if length(filename) > 14 then break filename into + * multiple entries and set inode = 0xffff except last + */ + idb.ino = (bdp->d_fileno > 0xfffe) ? 0xfffe : bdp->d_fileno; + bzero(&idb.name, sizeof(idb.name)); + strncpy(idb.name, bdp->d_name, 14); + error = copyout(&idb, cb->outp, ibcs2_reclen); + if (error) + return (error); + + /* advance output past iBCS2-shaped entry */ + cb->outp += ibcs2_reclen; + cb->resid -= ibcs2_reclen; + + return (0); +} + int ibcs2_sys_getdents(p, v, retval) struct proc *p; @@ -346,118 +427,23 @@ ibcs2_sys_getdents(p, v, retval) syscallarg(char *) buf; syscallarg(int) nbytes; } */ *uap = v; - register struct dirent *bdp; - struct vnode *vp; - caddr_t inp, buf; /* BSD-format */ - int len, reclen; /* BSD-format */ - caddr_t outp; /* iBCS2-format */ - int resid, ibcs2_reclen;/* iBCS2-format */ + struct ibcs2_readdir_callback_args args; struct file *fp; - struct uio auio; - struct iovec aiov; - struct ibcs2_dirent idb; - off_t off; /* true file offset */ - int buflen, error, eofflag; - u_long *cookiebuf = NULL, *cookie; - int ncookies = 0; + int error; if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) return (error); - if ((fp->f_flag & FREAD) == 0) - return (EBADF); - - vp = (struct vnode *)fp->f_data; - - if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ - return (EINVAL); - - buflen = min(MAXBSIZE, SCARG(uap, nbytes)); - buf = malloc(buflen, M_TEMP, M_WAITOK); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - off = fp->f_offset; -again: - aiov.iov_base = buf; - aiov.iov_len = buflen; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_resid = buflen; - auio.uio_offset = off; - /* - * First we read into the malloc'ed buffer, then - * we massage it into user space, one record at a time. - */ - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, - &cookiebuf); - if (error) - goto out; - - if (!error && !cookiebuf && !eofflag) { - error = EPERM; - goto out; - } - - inp = buf; - outp = SCARG(uap, buf); - resid = SCARG(uap, nbytes); - if ((len = buflen - auio.uio_resid) == 0) - goto eof; - - for (cookie = cookiebuf; len > 0; len -= reclen) { - bdp = (struct dirent *)inp; - reclen = bdp->d_reclen; - if (reclen & 3) - panic("ibcs2_getdents: bad reclen"); - if (bdp->d_fileno == 0) { - inp += reclen; /* it is a hole; squish it out */ - off = *cookie++; - continue; - } - ibcs2_reclen = IBCS2_RECLEN(&idb, bdp->d_namlen); - if (reclen > len || resid < ibcs2_reclen) { - /* entry too big for buffer, so just stop */ - outp++; - break; - } - off = *cookie++; /* each entry points to the next */ - - /* - * Massage in place to make a iBCS2-shaped dirent (otherwise - * we have to worry about touching user memory outside of - * the copyout() call). - */ - idb.d_ino = (ibcs2_ino_t)bdp->d_fileno; - idb.d_off = (ibcs2_off_t)off; - idb.d_reclen = (u_short)ibcs2_reclen; - strcpy(idb.d_name, bdp->d_name); - error = copyout((caddr_t)&idb, outp, ibcs2_reclen); - if (error) - goto out; - - /* advance past this real entry */ - inp += reclen; + args.resid = SCARG(uap, nbytes); + args.outp = (caddr_t)SCARG(uap, buf); + + if ((error = readdir_with_callback(fp, &fp->f_offset, args.resid, + ibcs2_readdir_callback, &args)) != 0) + return (error); - /* advance output past iBCS2-shaped entry */ - outp += ibcs2_reclen; - resid -= ibcs2_reclen; - } + *retval = SCARG(uap, nbytes) - args.resid; - /* if we squished out the whole block, try again */ - if (outp == SCARG(uap, buf)) - goto again; - fp->f_offset = off; /* update the vnode offset */ - -eof: - *retval = SCARG(uap, nbytes) - resid; -out: - VOP_UNLOCK(vp, 0, p); - if (cookiebuf) - free(cookiebuf, M_TEMP); - free(buf, M_TEMP); - return (error); + return (0); } int @@ -471,23 +457,10 @@ ibcs2_sys_read(p, v, retval) syscallarg(char *) buf; syscallarg(u_int) nbytes; } */ *uap = v; - register struct dirent *bdp; struct vnode *vp; - caddr_t inp, buf; /* BSD-format */ - int len, reclen; /* BSD-format */ - caddr_t outp; /* iBCS2-format */ - int resid, ibcs2_reclen;/* iBCS2-format */ + struct ibcs2_readdir_callback_args args; struct file *fp; - struct uio auio; - struct iovec aiov; - struct ibcs2_direct { - ibcs2_ino_t ino; - char name[14]; - } idb; - off_t off; /* true file offset */ - int buflen, error, eofflag, size; - u_long *cookiebuf = NULL, *cookie; - int ncookies = 0; + int error; if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) { if (error == EINVAL) @@ -500,89 +473,17 @@ ibcs2_sys_read(p, v, retval) vp = (struct vnode *)fp->f_data; if (vp->v_type != VDIR) return sys_read(p, uap, retval); - DPRINTF(("ibcs2_read: read directory\n")); - buflen = max(MAXBSIZE, SCARG(uap, nbytes)); - buf = malloc(buflen, M_TEMP, M_WAITOK); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - off = fp->f_offset; -again: - aiov.iov_base = buf; - aiov.iov_len = buflen; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_resid = buflen; - auio.uio_offset = off; - /* - * First we read into the malloc'ed buffer, then - * we massage it into user space, one record at a time. - */ - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, - &cookiebuf); - if (error) - goto out; - - if (!error && !cookiebuf && !eofflag) { - error = EPERM; - goto out; - } - inp = buf; - outp = SCARG(uap, buf); - resid = SCARG(uap, nbytes); - if ((len = buflen - auio.uio_resid) == 0) - goto eof; - for (cookie = cookiebuf; len > 0 && resid > 0; len -= reclen) { - bdp = (struct dirent *)inp; - reclen = bdp->d_reclen; - if (reclen & 3) - panic("ibcs2_read: bad reclen"); - if (bdp->d_fileno == 0) { - inp += reclen; /* it is a hole; squish it out */ - off = *cookie++; - continue; - } - ibcs2_reclen = 16; - if (reclen > len || resid < ibcs2_reclen) { - /* entry too big for buffer, so just stop */ - outp++; - break; - } - off = *cookie++; /* each entry points to the next */ - /* - * Massage in place to make a iBCS2-shaped dirent (otherwise - * we have to worry about touching user memory outside of - * the copyout() call). - * - * TODO: if length(filename) > 14, then break filename into - * multiple entries and set inode = 0xffff except last - */ - idb.ino = (bdp->d_fileno > 0xfffe) ? 0xfffe : bdp->d_fileno; - (void)copystr(bdp->d_name, idb.name, 14, &size); - bzero(idb.name + size, 14 - size); - error = copyout(&idb, outp, ibcs2_reclen); - if (error) - goto out; - /* advance past this real entry */ - inp += reclen; - /* advance output past iBCS2-shaped entry */ - outp += ibcs2_reclen; - resid -= ibcs2_reclen; - } - /* if we squished out the whole block, try again */ - if (outp == SCARG(uap, buf)) - goto again; - fp->f_offset = off; /* update the vnode offset */ -eof: - *retval = SCARG(uap, nbytes) - resid; -out: - VOP_UNLOCK(vp, 0, p); - if (cookiebuf) - free(cookiebuf, M_TEMP); - free(buf, M_TEMP); - return (error); + args.resid = SCARG(uap, nbytes); + args.outp = (caddr_t)SCARG(uap, buf); + + if ((error = readdir_with_callback(fp, &fp->f_offset, args.resid, + ibcs2_classicread_callback, &args)) != 0) + return (error); + + *retval = SCARG(uap, nbytes) - args.resid; + + return (0); } int diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index e8e6db8b4d5..a4e73229cc5 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_misc.c,v 1.33 2000/09/10 07:04:20 jasoni Exp $ */ +/* $OpenBSD: linux_misc.c,v 1.34 2001/01/23 05:48:05 csapuntz Exp $ */ /* $NetBSD: linux_misc.c,v 1.27 1996/05/20 01:59:21 fvdl Exp $ */ /* @@ -77,6 +77,8 @@ #include <compat/linux/linux_util.h> #include <compat/linux/linux_dirent.h> +#include <compat/common/compat_dir.h> + /* linux_misc.c */ static void bsd_to_linux_wstat __P((int *)); static void bsd_to_linux_statfs __P((struct statfs *, struct linux_statfs *)); @@ -902,6 +904,7 @@ linux_sys_readdir(p, v, retval) } */ *uap = v; SCARG(uap, count) = 1; + return linux_sys_getdents(p, uap, retval); } @@ -919,151 +922,101 @@ linux_sys_readdir(p, v, retval) * * Note that this doesn't handle union-mounted filesystems. */ +int linux_readdir_callback __P((void *, struct dirent *, off_t)); + +struct linux_readdir_callback_args { + caddr_t outp; + int resid; + int oldcall; +}; + +int +linux_readdir_callback(arg, bdp, cookie) + void *arg; + struct dirent *bdp; + off_t cookie; +{ + struct linux_dirent idb; + struct linux_readdir_callback_args *cb = arg; + int linux_reclen; + int error; + + if (cb->oldcall == 2) + return (ENOMEM); + + linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen); + if (cb->resid < linux_reclen) + return (ENOMEM); + + /* + * Massage in place to make a Linux-shaped dirent (otherwise + * we have to worry about touching user memory outside of + * the copyout() call). + */ + idb.d_ino = (linux_ino_t)bdp->d_fileno; + + /* + * The old readdir() call misuses the offset and reclen fields. + */ + if (cb->oldcall) { + idb.d_off = (linux_off_t)linux_reclen; + idb.d_reclen = (u_short)bdp->d_namlen; + } else { + idb.d_off = (linux_off_t)cookie; + idb.d_reclen = (u_short)linux_reclen; + } + + strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name)); + if ((error = copyout((caddr_t)&idb, cb->outp, linux_reclen))) + return (error); + + /* advance output past Linux-shaped entry */ + cb->outp += linux_reclen; + cb->resid -= linux_reclen; + + if (cb->oldcall == 1) + ++cb->oldcall; + + return (0); +} + int linux_sys_getdents(p, v, retval) struct proc *p; void *v; register_t *retval; { - struct linux_sys_readdir_args /* { + struct linux_sys_getdents_args /* { syscallarg(int) fd; - syscallarg(caddr_t) dent; - syscallarg(unsigned int) count; + syscallarg(void *) dirent; + syscallarg(unsigned) count; } */ *uap = v; - register struct dirent *bdp; - struct vnode *vp; - caddr_t inp, buf; /* BSD-format */ - int len, reclen; /* BSD-format */ - caddr_t outp; /* Linux-format */ - int resid, linux_reclen = 0; /* Linux-format */ + struct linux_readdir_callback_args args; struct file *fp; - struct uio auio; - struct iovec aiov; - struct linux_dirent idb; - off_t off; /* true file offset */ - int buflen, error, eofflag, nbytes, oldcall; - struct vattr va; - u_long *cookiebuf = NULL, *cookie; - int ncookies = 0; + int error; + int nbytes = SCARG(uap, count); if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) return (error); - if ((fp->f_flag & FREAD) == 0) - return (EBADF); - - vp = (struct vnode *)fp->f_data; - - if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ - return (EINVAL); - - if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) - return error; - - nbytes = SCARG(uap, count); if (nbytes == 1) { /* emulating old, broken behaviour */ - nbytes = sizeof (struct linux_dirent); - buflen = max(va.va_blocksize, nbytes); - oldcall = 1; + nbytes = sizeof(struct linux_dirent); + args.oldcall = 1; } else { - buflen = min(MAXBSIZE, nbytes); - oldcall = 0; + args.oldcall = 0; } - buf = malloc(buflen, M_TEMP, M_WAITOK); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - off = fp->f_offset; -again: - aiov.iov_base = buf; - aiov.iov_len = buflen; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_resid = buflen; - auio.uio_offset = off; - /* - * First we read into the malloc'ed buffer, then - * we massage it into user space, one record at a time. - */ - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, - &cookiebuf); - if (error) - goto out; - - if (!error && !cookiebuf) - goto out; - - inp = buf; - outp = SCARG(uap, dent); - resid = nbytes; - if ((len = buflen - auio.uio_resid) == 0) - goto eof; - - for (cookie = cookiebuf; len > 0; len -= reclen) { - bdp = (struct dirent *)inp; - reclen = bdp->d_reclen; - if (reclen & 3) - panic("linux_readdir: bad reclen"); - if (bdp->d_fileno == 0) { - inp += reclen; /* it is a hole; squish it out */ - off = *cookie++; - continue; - } - linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen); - if (reclen > len || resid < linux_reclen) { - /* entry too big for buffer, so just stop */ - outp++; - break; - } - /* - * Massage in place to make a Linux-shaped dirent (otherwise - * we have to worry about touching user memory outside of - * the copyout() call). - */ - idb.d_ino = (linux_ino_t)bdp->d_fileno; + args.resid = nbytes; + args.outp = (caddr_t)SCARG(uap, dirent); - /* - * The old readdir() call misuses the offset and reclen fields. - */ - if (oldcall) { - idb.d_off = (linux_off_t)linux_reclen; - idb.d_reclen = (u_short)bdp->d_namlen; - } else { - idb.d_off = (linux_off_t)off; - idb.d_reclen = (u_short)linux_reclen; - } - strncpy(idb.d_name, bdp->d_name, sizeof(idb.d_name) - 1); - idb.d_name[sizeof(idb.d_name) - 1] = '\0'; - if ((error = copyout((caddr_t)&idb, outp, linux_reclen))) - goto out; - /* advance past this real entry */ - inp += reclen; - off = *cookie++; /* each entry points to itself */ - /* advance output past Linux-shaped entry */ - outp += linux_reclen; - resid -= linux_reclen; - if (oldcall) - break; - } + if ((error = readdir_with_callback(fp, &fp->f_offset, nbytes, + linux_readdir_callback, &args)) != 0) + goto exit; + + *retval = nbytes - args.resid; - /* if we squished out the whole block, try again */ - if (outp == SCARG(uap, dent)) - goto again; - fp->f_offset = off; /* update the vnode offset */ - - if (oldcall) - nbytes = resid + linux_reclen; - -eof: - *retval = nbytes - resid; -out: - VOP_UNLOCK(vp, 0, p); - if (cookiebuf) - free(cookiebuf, M_TEMP); - free(buf, M_TEMP); - return error; + exit: + return (error); } /* diff --git a/sys/compat/sunos/sunos_misc.c b/sys/compat/sunos/sunos_misc.c index 77a5438ec25..e58a3e9d1f9 100644 --- a/sys/compat/sunos/sunos_misc.c +++ b/sys/compat/sunos/sunos_misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sunos_misc.c,v 1.23 2000/04/21 15:50:21 millert Exp $ */ +/* $OpenBSD: sunos_misc.c,v 1.24 2001/01/23 05:48:04 csapuntz Exp $ */ /* $NetBSD: sunos_misc.c,v 1.65 1996/04/22 01:44:31 christos Exp $ */ /* @@ -376,6 +376,43 @@ sunos_sys_sigpending(p, v, retval) * * This is quite ugly, but what do you expect from compatibility code? */ +int sunos_readdir_callback __P((void *, struct dirent *, off_t)); + +struct sunos_readdir_callback_args { + caddr_t outp; + int resid; +}; + +int +sunos_readdir_callback(arg, bdp, cookie) + void *arg; + struct dirent *bdp; + off_t cookie; +{ + struct sunos_dirent idb; + struct sunos_readdir_callback_args *cb = arg; + int sunos_reclen; + int error; + + sunos_reclen = SUNOS_RECLEN(&idb, bdp->d_namlen); + if (cb->resid < sunos_reclen) + return (ENOMEM); + + idb.d_fileno = bdp->d_fileno; + idb.d_off = cookie; + idb.d_reclen = sunos_reclen; + idb.d_namlen = bdp->d_namlen; + strlcpy(idb.d_name, bdp->d_name, SUNOS_MAXNAMLEN+1); + + if ((error = copyout((caddr_t)&idb, cb->outp, sunos_reclen))) + return (error); + + cb->outp += sunos_reclen; + cb->resid -= sunos_reclen; + + return (0); +} + int sunos_sys_getdents(p, v, retval) struct proc *p; @@ -387,117 +424,32 @@ sunos_sys_getdents(p, v, retval) syscallarg(char *) buf; syscallarg(int) nbytes; } */ *uap = v; - struct dirent *bdp; struct vnode *vp; - caddr_t inp, buf; /* BSD-format */ - int len, reclen; /* BSD-format */ - caddr_t outp; /* Sun-format */ - int resid, sunos_reclen;/* Sun-format */ struct file *fp; - struct uio auio; - struct iovec aiov; - struct sunos_dirent idb; - off_t off; /* true file offset */ - int buflen, error, eofflag; - u_long *cookiebuf = NULL, *cookie; - int ncookies; + int error; + struct sunos_readdir_callback_args args; if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) return (error); - if ((fp->f_flag & FREAD) == 0) - return (EBADF); - vp = (struct vnode *)fp->f_data; + vp = (struct vnode *)fp->f_data; /* SunOS returns ENOTDIR here, BSD would use EINVAL */ if (vp->v_type != VDIR) return (ENOTDIR); - if (SCARG(uap, nbytes) < sizeof(struct sunos_dirent)) - return (EINVAL); - - buflen = min(MAXBSIZE, SCARG(uap, nbytes)); - buf = malloc(buflen, M_TEMP, M_WAITOK); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - off = fp->f_offset; -again: - aiov.iov_base = buf; - aiov.iov_len = buflen; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_resid = buflen; - auio.uio_offset = off; - /* - * First we read into the malloc'ed buffer, then - * we massage it into user space, one record at a time. - */ - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, - &ncookies, &cookiebuf); - if (error) - goto out; - if (!cookiebuf) { - error = EPERM; - goto out; - } - inp = buf; - outp = SCARG(uap, buf); - resid = SCARG(uap, nbytes); - if ((len = buflen - auio.uio_resid) == 0) - goto eof; - - for (cookie = cookiebuf; len > 0; len -= reclen) { - bdp = (struct dirent *)inp; - reclen = bdp->d_reclen; - if (reclen & 3) - panic("sunos_getdents: bad reclen"); - if (bdp->d_fileno == 0) { - inp += reclen; /* it is a hole; squish it out */ - off = *cookie++; - continue; - } - sunos_reclen = SUNOS_RECLEN(&idb, bdp->d_namlen); - if (reclen > len || resid < sunos_reclen) { - /* entry too big for buffer, so just stop */ - outp++; - break; - } - off = *cookie++; /* each entry points to next */ - /* - * Massage in place to make a Sun-shaped dirent (otherwise - * we have to worry about touching user memory outside of - * the copyout() call). - */ - idb.d_fileno = bdp->d_fileno; - idb.d_off = off; - idb.d_reclen = sunos_reclen; - idb.d_namlen = bdp->d_namlen; - strcpy(idb.d_name, bdp->d_name); - if ((error = copyout((caddr_t)&idb, outp, sunos_reclen)) != 0) - goto out; - /* advance past this real entry */ - inp += reclen; - /* advance output past Sun-shaped entry */ - outp += sunos_reclen; - resid -= sunos_reclen; - } + args.resid = SCARG(uap, nbytes); + args.outp = (caddr_t)SCARG(uap, buf); + + if ((error = readdir_with_callback(fp, &fp->f_offset, args.resid, + sunos_readdir_callback, &args)) != 0) + return (error); - /* if we squished out the whole block, try again */ - if (outp == SCARG(uap, buf)) - goto again; - fp->f_offset = off; /* update the vnode offset */ + *retval = SCARG(uap, nbytes) - args.resid; -eof: - *retval = SCARG(uap, nbytes) - resid; -out: - VOP_UNLOCK(vp, 0, p); - if (cookiebuf) - free(cookiebuf, M_TEMP); - free(buf, M_TEMP); - return (error); + return (0); } + #define SUNOS__MAP_NEW 0x80000000 /* if not, old mmap & cannot handle */ int diff --git a/sys/compat/svr4/svr4_misc.c b/sys/compat/svr4/svr4_misc.c index d10fa9219ae..848e60871be 100644 --- a/sys/compat/svr4/svr4_misc.c +++ b/sys/compat/svr4/svr4_misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: svr4_misc.c,v 1.28 2000/11/10 18:15:46 art Exp $ */ +/* $OpenBSD: svr4_misc.c,v 1.29 2001/01/23 05:48:04 csapuntz Exp $ */ /* $NetBSD: svr4_misc.c,v 1.42 1996/12/06 03:22:34 christos Exp $ */ /* @@ -85,6 +85,8 @@ #include <compat/svr4/svr4_sysconfig.h> #include <compat/svr4/svr4_acl.h> +#include <compat/common/compat_dir.h> + #include <vm/vm.h> #if defined(UVM) @@ -217,244 +219,127 @@ svr4_sys_time(p, v, retval) * * This is quite ugly, but what do you expect from compatibility code? */ + +int svr4_readdir_callback __P((void *, struct dirent *, off_t)); +int svr4_readdir64_callback __P((void *, struct dirent *, off_t)); + +struct svr4_readdir_callback_args { + caddr_t outp; + int resid; +}; + int -svr4_sys_getdents(p, v, retval) - register struct proc *p; - void *v; - register_t *retval; +svr4_readdir_callback(arg, bdp, cookie) + void *arg; + struct dirent *bdp; + off_t cookie; { - struct svr4_sys_getdents_args *uap = v; - register struct dirent *bdp; - struct vnode *vp; - caddr_t inp, buf; /* BSD-format */ - int len, reclen; /* BSD-format */ - caddr_t outp; /* SVR4-format */ - int resid, svr4_reclen; /* SVR4-format */ - struct file *fp; - struct uio auio; - struct iovec aiov; struct svr4_dirent idb; - off_t off; /* true file offset */ - int buflen, error, eofflag; - u_long *cookiebuf = NULL, *cookie; - int ncookies = 0; - - if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) - return (error); + struct svr4_readdir_callback_args *cb = arg; + int svr4_reclen; + int error; - if ((fp->f_flag & FREAD) == 0) - return (EBADF); + svr4_reclen = SVR4_RECLEN(&idb, bdp->d_namlen); + if (cb->resid < svr4_reclen) + return (ENOMEM); - vp = (struct vnode *)fp->f_data; + idb.d_ino = (svr4_ino_t)bdp->d_fileno; + idb.d_off = (svr4_off_t)cookie; + idb.d_reclen = (u_short)svr4_reclen; + strlcpy(idb.d_name, bdp->d_name, SVR4_MAXNAMLEN+1); + if ((error = copyout((caddr_t)&idb, cb->outp, svr4_reclen))) + return (error); - if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ - return (EINVAL); + cb->outp += svr4_reclen; + cb->resid -= svr4_reclen; - buflen = min(MAXBSIZE, SCARG(uap, nbytes)); - buf = malloc(buflen, M_TEMP, M_WAITOK); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - off = fp->f_offset; -again: - aiov.iov_base = buf; - aiov.iov_len = buflen; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_resid = buflen; - auio.uio_offset = off; - /* - * First we read into the malloc'ed buffer, then - * we massage it into user space, one record at a time. - */ - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, - &cookiebuf); - if (error) - goto out; + return (0); +} - if (!error && !cookiebuf && !eofflag) { - error = EPERM; - goto out; - } +int +svr4_readdir64_callback(arg, bdp, cookie) + void *arg; + struct dirent *bdp; + off_t cookie; +{ + struct svr4_dirent64 idb; + struct svr4_readdir_callback_args *cb = arg; + int svr4_reclen; + int error; - inp = buf; - outp = SCARG(uap, buf); - resid = SCARG(uap, nbytes); - if ((len = buflen - auio.uio_resid) == 0) - goto eof; - - for (cookie = cookiebuf; len > 0; len -= reclen) { - bdp = (struct dirent *)inp; - reclen = bdp->d_reclen; - if (reclen & 3) - panic("svr4_getdents: bad reclen"); - if (bdp->d_fileno == 0) { - inp += reclen; /* it is a hole; squish it out */ - off = *cookie++; - continue; - } - svr4_reclen = SVR4_RECLEN(&idb, bdp->d_namlen); - if (reclen > len || resid < svr4_reclen) { - /* entry too big for buffer, so just stop */ - outp++; - break; - } - off = *cookie++; /* each entry points to the next */ + svr4_reclen = SVR4_RECLEN(&idb, bdp->d_namlen); + if (cb->resid < svr4_reclen) + return (ENOMEM); - /* - * Massage in place to make a SVR4-shaped dirent (otherwise - * we have to worry about touching user memory outside of - * the copyout() call). - */ - idb.d_ino = (svr4_ino_t)bdp->d_fileno; - idb.d_off = (svr4_off_t)off; - idb.d_reclen = (u_short)svr4_reclen; - strcpy(idb.d_name, bdp->d_name); - if ((error = copyout((caddr_t)&idb, outp, svr4_reclen))) - goto out; - - /* advance past this real entry */ - inp += reclen; - - /* advance output past SVR4-shaped entry */ - outp += svr4_reclen; - resid -= svr4_reclen; - } + /* + * Massage in place to make a SVR4-shaped dirent (otherwise + * we have to worry about touching user memory outside of + * the copyout() call). + */ + idb.d_ino = (svr4_ino64_t)bdp->d_fileno; + idb.d_off = (svr4_off64_t)cookie; + idb.d_reclen = (u_short)svr4_reclen; + strlcpy(idb.d_name, bdp->d_name, SVR4_MAXNAMLEN+1); + if ((error = copyout((caddr_t)&idb, cb->outp, svr4_reclen))) + return (error); - /* if we squished out the whole block, try again */ - if (outp == SCARG(uap, buf)) - goto again; - fp->f_offset = off; /* update the vnode offset */ + cb->outp += svr4_reclen; + cb->resid -= svr4_reclen; -eof: - *retval = SCARG(uap, nbytes) - resid; -out: - VOP_UNLOCK(vp, 0, p); - if (cookiebuf) - free(cookiebuf, M_TEMP); - free(buf, M_TEMP); - return error; + return (0); } + int -svr4_sys_getdents64(p, v, retval) +svr4_sys_getdents(p, v, retval) register struct proc *p; void *v; register_t *retval; { - struct svr4_sys_getdents64_args *uap = v; - register struct dirent *bdp; - struct vnode *vp; - caddr_t inp, buf; /* BSD-format */ - int len, reclen; /* BSD-format */ - caddr_t outp; /* SVR4-format */ - int resid, svr4_reclen; /* SVR4-format */ + struct svr4_sys_getdents_args *uap = v; + struct svr4_readdir_callback_args args; struct file *fp; - struct uio auio; - struct iovec aiov; - struct svr4_dirent64 idb; - off_t off; /* true file offset */ - int buflen, error, eofflag; - u_long *cookiebuf = NULL, *cookie; - int ncookies = 0; + int error; if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) return (error); - if ((fp->f_flag & FREAD) == 0) - return (EBADF); - - vp = (struct vnode *)fp->f_data; + args.resid = SCARG(uap, nbytes); + args.outp = (caddr_t)SCARG(uap, buf); + + if ((error = readdir_with_callback(fp, &fp->f_offset, SCARG(uap, nbytes), + svr4_readdir_callback, &args)) != 0) + return (error); - if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ - return (EINVAL); + *retval = SCARG(uap, nbytes) - args.resid; - buflen = min(MAXBSIZE, SCARG(uap, nbytes)); - buf = malloc(buflen, M_TEMP, M_WAITOK); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - off = fp->f_offset; -again: - aiov.iov_base = buf; - aiov.iov_len = buflen; - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - auio.uio_rw = UIO_READ; - auio.uio_segflg = UIO_SYSSPACE; - auio.uio_procp = p; - auio.uio_resid = buflen; - auio.uio_offset = off; - /* - * First we read into the malloc'ed buffer, then - * we massage it into user space, one record at a time. - */ - error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, - &cookiebuf); - if (error) - goto out; + return (0); +} - if (!error && !cookiebuf && !eofflag) { - error = EPERM; - goto out; - } +int +svr4_sys_getdents64(p, v, retval) + register struct proc *p; + void *v; + register_t *retval; +{ + struct svr4_sys_getdents64_args *uap = v; + struct svr4_readdir_callback_args args; + struct file *fp; + int error; - inp = buf; - outp = (char *) SCARG(uap, dp); - resid = SCARG(uap, nbytes); - if ((len = buflen - auio.uio_resid) == 0) - goto eof; - - for (cookie = cookiebuf; len > 0; len -= reclen) { - bdp = (struct dirent *)inp; - reclen = bdp->d_reclen; - if (reclen & 3) - panic("svr4_getdents64: bad reclen"); - if (bdp->d_fileno == 0) { - inp += reclen; /* it is a hole; squish it out */ - off = *cookie++; - continue; - } - svr4_reclen = SVR4_RECLEN(&idb, bdp->d_namlen); - if (reclen > len || resid < svr4_reclen) { - /* entry too big for buffer, so just stop */ - outp++; - break; - } - off = *cookie++; /* each entry points to the next */ + if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) + return (error); - /* - * Massage in place to make a SVR4-shaped dirent (otherwise - * we have to worry about touching user memory outside of - * the copyout() call). - */ - idb.d_ino = (svr4_ino64_t)bdp->d_fileno; - idb.d_off = (svr4_off64_t)off; - idb.d_reclen = (u_short)svr4_reclen; - strcpy(idb.d_name, bdp->d_name); - if ((error = copyout((caddr_t)&idb, outp, svr4_reclen))) - goto out; - - /* advance past this real entry */ - inp += reclen; - - /* advance output past SVR4-shaped entry */ - outp += svr4_reclen; - resid -= svr4_reclen; - } + args.resid = SCARG(uap, nbytes); + args.outp = (caddr_t)SCARG(uap, dp); + + if ((error = readdir_with_callback(fp, &fp->f_offset, SCARG(uap, nbytes), + svr4_readdir64_callback, &args)) != 0) + return (error); - /* if we squished out the whole block, try again */ - if (outp == (char *) SCARG(uap, dp)) - goto again; - fp->f_offset = off; /* update the vnode offset */ + *retval = SCARG(uap, nbytes) - args.resid; -eof: - *retval = SCARG(uap, nbytes) - resid; -out: - VOP_UNLOCK(vp, 0, p); - if (cookiebuf) - free(cookiebuf, M_TEMP); - free(buf, M_TEMP); - return error; + return (0); } int |