summaryrefslogtreecommitdiff
path: root/sys/compat/linux/common/linux_misc.c
diff options
context:
space:
mode:
authortron <tron@NetBSD.org>2002-05-10 14:38:08 +0000
committertron <tron@NetBSD.org>2002-05-10 14:38:08 +0000
commitadd83289ca6857ca1a8a94820eec2f912df13b80 (patch)
treea3085edc458bdff2567ff291050e01f609acfdc8 /sys/compat/linux/common/linux_misc.c
parent9dd6d667fa11c9c5ca9f88360f7808f23802d2bc (diff)
Move implementation of linux_sys_getdents64() to source file for
Linux 64bit filesystem calls.
Diffstat (limited to 'sys/compat/linux/common/linux_misc.c')
-rw-r--r--sys/compat/linux/common/linux_misc.c174
1 files changed, 2 insertions, 172 deletions
diff --git a/sys/compat/linux/common/linux_misc.c b/sys/compat/linux/common/linux_misc.c
index f9c8b8defda..af71ff7fb16 100644
--- a/sys/compat/linux/common/linux_misc.c
+++ b/sys/compat/linux/common/linux_misc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: linux_misc.c,v 1.107 2002/04/10 18:19:34 christos Exp $ */
+/* $NetBSD: linux_misc.c,v 1.108 2002/05/10 14:38:08 tron Exp $ */
/*-
* Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
@@ -64,7 +64,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.107 2002/04/10 18:19:34 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.108 2002/05/10 14:38:08 tron Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -792,176 +792,6 @@ out1:
}
/*
- * Linux 'readdir' call. This code is mostly taken from the
- * SunOS getdents call (see compat/sunos/sunos_misc.c), though
- * an attempt has been made to keep it a little cleaner (failing
- * miserably, because of the cruft needed if count 1 is passed).
- *
- * The d_off field should contain the offset of the next valid entry,
- * but in Linux it has the offset of the entry itself. We emulate
- * that bug here.
- *
- * Read in BSD-style entries, convert them, and copy them out.
- *
- * Note that this doesn't handle union-mounted filesystems.
- */
-int
-linux_sys_getdents64(p, v, retval)
- struct proc *p;
- void *v;
- register_t *retval;
-{
- struct linux_sys_getdents_args /* {
- syscallarg(int) fd;
- syscallarg(struct linux_dirent64 *) dent;
- syscallarg(unsigned int) count;
- } */ *uap = v;
- 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 file *fp;
- struct uio auio;
- struct iovec aiov;
- struct linux_dirent64 idb;
- off_t off; /* true file offset */
- int buflen, error, eofflag, nbytes, oldcall;
- struct vattr va;
- off_t *cookiebuf = NULL, *cookie;
- int ncookies;
-
- /* getvnode() will use the descriptor for us */
- if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
- return (error);
-
- if ((fp->f_flag & FREAD) == 0) {
- error = EBADF;
- goto out1;
- }
-
- vp = (struct vnode *)fp->f_data;
- if (vp->v_type != VDIR) {
- error = EINVAL;
- goto out1;
- }
-
- if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
- goto out1;
-
- nbytes = SCARG(uap, count);
- if (nbytes == 1) { /* emulating old, broken behaviour */
- nbytes = sizeof (idb);
- buflen = max(va.va_blocksize, nbytes);
- oldcall = 1;
- } else {
- buflen = min(MAXBSIZE, nbytes);
- if (buflen < va.va_blocksize)
- buflen = va.va_blocksize;
- oldcall = 0;
- }
- buf = malloc(buflen, M_TEMP, M_WAITOK);
-
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
- 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, &cookiebuf,
- &ncookies);
- if (error)
- goto out;
-
- inp = buf;
- outp = (caddr_t)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");
- 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 = bdp->d_fileno;
- idb.d_type = bdp->d_type;
- /*
- * The old readdir() call misuses the offset and reclen fields.
- */
- if (oldcall) {
- idb.d_off = linux_reclen;
- idb.d_reclen = (u_short)bdp->d_namlen;
- } else {
- if (sizeof (idb.d_off) < 4 && (off >> 32) != 0) {
- compat_offseterr(vp, "linux_getdents");
- error = EINVAL;
- goto out;
- }
- idb.d_off = off;
- idb.d_reclen = (u_short)linux_reclen;
- }
- strcpy(idb.d_name, bdp->d_name);
- 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 we squished out the whole block, try again */
- if (outp == (caddr_t)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);
- if (cookiebuf)
- free(cookiebuf, M_TEMP);
- free(buf, M_TEMP);
-out1:
- FILE_UNUSE(fp, p);
- return error;
-}
-
-/*
* Even when just using registers to pass arguments to syscalls you can
* have 5 of them on the i386. So this newer version of select() does
* this.