Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/compat/linux/common Move implementation of linux_sys_get...



details:   https://anonhg.NetBSD.org/src/rev/d107380d6764
branches:  trunk
changeset: 526778:d107380d6764
user:      tron <tron%NetBSD.org@localhost>
date:      Fri May 10 14:38:08 2002 +0000

description:
Move implementation of linux_sys_getdents64() to source file for
Linux 64bit filesystem calls.

diffstat:

 sys/compat/linux/common/linux_file64.c |  176 ++++++++++++++++++++++++++++++++-
 sys/compat/linux/common/linux_misc.c   |  174 +--------------------------------
 2 files changed, 176 insertions(+), 174 deletions(-)

diffs (truncated from 402 to 300 lines):

diff -r 5a4aa56de9ef -r d107380d6764 sys/compat/linux/common/linux_file64.c
--- a/sys/compat/linux/common/linux_file64.c    Fri May 10 13:17:57 2002 +0000
+++ b/sys/compat/linux/common/linux_file64.c    Fri May 10 14:38:08 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: linux_file64.c,v 1.10 2002/03/22 17:14:18 christos Exp $       */
+/*     $NetBSD: linux_file64.c,v 1.11 2002/05/10 14:38:08 tron Exp $   */
 
 /*-
  * Copyright (c) 1995, 1998, 2000 The NetBSD Foundation, Inc.
@@ -41,12 +41,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_file64.c,v 1.10 2002/03/22 17:14:18 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_file64.c,v 1.11 2002/05/10 14:38:08 tron Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/namei.h>
 #include <sys/proc.h>
+#include <sys/dirent.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/filedesc.h>
@@ -65,6 +66,7 @@
 #include <compat/linux/common/linux_fcntl.h>
 #include <compat/linux/common/linux_util.h>
 #include <compat/linux/common/linux_machdep.h>
+#include <compat/linux/common/linux_dirent.h>
 
 #include <compat/linux/linux_syscallargs.h>
 
@@ -334,4 +336,174 @@
 
        return error;
 }
+
+/*
+ * 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;
+}
 #endif /* __mips__ || __i386__ */
diff -r 5a4aa56de9ef -r d107380d6764 sys/compat/linux/common/linux_misc.c
--- a/sys/compat/linux/common/linux_misc.c      Fri May 10 13:17:57 2002 +0000
+++ b/sys/compat/linux/common/linux_misc.c      Fri May 10 14:38:08 2002 +0000
@@ -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 @@
 }
 
 /*
- * 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);
-



Home | Main Index | Thread Index | Old Index