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