Port-alpha archive

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

COMPAT_OSF1 getdirentries(2) fix



I'd like to commit, unless someone objects, the following patch.

It fix the compat_osf1 getdirentries syscall which seems to have been
broken for quite some time now ... mostly because native and osf1
struct dirent differs (members number and types).

-- 
Nicolas Joly

Biological Software and Databanks.
Institut Pasteur, Paris.
Index: sys/compat/osf1/osf1_dirent.h
===================================================================
RCS file: sys/compat/osf1/osf1_dirent.h
diff -N sys/compat/osf1/osf1_dirent.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/compat/osf1/osf1_dirent.h       1 Dec 2008 16:25:10 -0000
@@ -0,0 +1,47 @@
+/*     $NetBSD$         */
+
+/*-
+ * Copyright (c) 1994 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+
+#ifndef        _OSF1_DIRENT_H_
+#define        _OSF1_DIRENT_H_
+
+#define OSF1_MAXNAMLEN 255
+
+struct osf1_dirent {
+       osf1_ino_t      d_ino;
+       u_short         d_reclen;
+       u_short         d_namlen;
+       char            d_name[OSF1_MAXNAMLEN + 1];
+};
+
+#define OSF1_NAMEOFF(dp)       ((char *)&(dp)->d_name - (char *)dp)
+#define OSF1_RECLEN(de,namlen) ALIGN((OSF1_NAMEOFF(de) + (namlen) + 1))
+
+#endif /* !_OSF1_DIRENT_H_ */
Index: sys/compat/osf1/osf1_file.c
===================================================================
RCS file: /cvsroot/src/sys/compat/osf1/osf1_file.c,v
retrieving revision 1.30
diff -u -p -r1.30 osf1_file.c
--- sys/compat/osf1/osf1_file.c 21 Mar 2008 21:54:59 -0000      1.30
+++ sys/compat/osf1/osf1_file.c 1 Dec 2008 16:25:10 -0000
@@ -86,11 +86,13 @@ __KERNEL_RCSID(0, "$NetBSD: osf1_file.c,
 #include <sys/resourcevar.h>
 #include <sys/wait.h>
 #include <sys/vfs_syscalls.h>
+#include <sys/dirent.h>
 
 #include <compat/osf1/osf1.h>
 #include <compat/osf1/osf1_syscallargs.h>
 #include <compat/common/compat_util.h>
 #include <compat/osf1/osf1_cvt.h>
+#include <compat/osf1/osf1_dirent.h>
 
 int
 osf1_sys_access(struct lwp *l, const struct osf1_sys_access_args *uap, 
register_t *retval)
@@ -121,6 +123,129 @@ osf1_sys_execve(struct lwp *l, const str
        return sys_execve(l, &ap, retval);
 }
 
+int
+osf1_sys_getdirentries(struct lwp *l, const struct osf1_sys_getdirentries_args 
*uap, register_t *retval)
+{
+       /* {
+               syscallarg(int) fd;
+               syscallarg(char *) buf;
+               syscallarg(u_int) nbytes;
+               syscallarg(long *) basep;
+       } */
+       struct dirent *bdp;
+       struct vnode *vp;
+       char *inp, *buf;        /* BSD-format */
+       int len, reclen;        /* BSD-format */
+       char *outp;             /* OSF1-format */
+       int resid, osf1_reclen; /* OSF1-format */
+       struct file *fp;
+       struct uio auio;
+       struct iovec aiov;
+       struct osf1_dirent idb;
+       off_t off;              /* true file offset */
+       int buflen, error, eofflag;
+       off_t *cookiebuf = NULL, *cookie;
+       int ncookies, fd;
+
+       fd = SCARG(uap, fd);
+       if ((error = fd_getvnode(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;
+       }
+
+       buflen = min(MAXBSIZE, SCARG(uap, nbytes));
+       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_resid = buflen;
+       auio.uio_offset = off;
+       UIO_SETUP_SYSSPACE(&auio);
+       /*
+        * 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 = (char *)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("osf1_sys_getdirentries: bad reclen");
+               if (cookie)
+                       off = *cookie++; /* each entry points to the next */
+               else
+                       off += reclen;
+               if ((off >> 32) != 0) {
+                       compat_offseterr(vp, "osf1_sys_getdirentries");
+                       error = EINVAL;
+                       goto out;
+               }
+               osf1_reclen = OSF1_RECLEN(&idb, bdp->d_namlen);
+               if (reclen > len || resid < osf1_reclen) {
+                       /* entry too big for buffer, so just stop */
+                       outp++;
+                       break;
+               }
+               /*
+                * Massage in place to make a OSF1-shaped dirent (otherwise
+                * we have to worry about touching user memory outside of
+                * the copyout() call).
+                */
+               idb.d_ino = (osf1_ino_t)bdp->d_fileno;
+               idb.d_reclen = (u_short)osf1_reclen;
+               idb.d_namlen = (u_short)bdp->d_namlen;
+               strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name));
+               if ((error = copyout((void *)&idb, outp, osf1_reclen)))
+                       goto out;
+               /* advance past this real entry */
+               inp += reclen;
+               /* advance output past OSF1-shaped entry */
+               outp += osf1_reclen;
+               resid -= osf1_reclen;
+       }
+
+       /* if we squished out the whole block, try again */
+       if (outp == (char *)SCARG(uap, buf))
+               goto again;
+       fp->f_offset = off;     /* update the vnode offset */
+
+eof:
+       *retval = SCARG(uap, nbytes) - resid;
+out:
+       VOP_UNLOCK(vp, 0);
+       if (cookiebuf)
+               free(cookiebuf, M_TEMP);
+       free(buf, M_TEMP);
+out1:
+       fd_putfile(fd);
+       if (SCARG(uap, basep) != NULL)
+               error = copyout(&eofflag, SCARG(uap, basep), sizeof(long));
+       return error;
+}
+
 /*
  * Get file status; this version does not follow links.
  */
Index: sys/compat/osf1/syscalls.master
===================================================================
RCS file: /cvsroot/src/sys/compat/osf1/syscalls.master,v
retrieving revision 1.46
diff -u -p -r1.46 syscalls.master
--- sys/compat/osf1/syscalls.master     24 Nov 2008 00:25:30 -0000      1.46
+++ sys/compat/osf1/syscalls.master     1 Dec 2008 16:25:11 -0000
@@ -266,8 +266,8 @@
                            struct osf1_sigaction *osa); }
 157    UNIMPL          sigwaitprim
 158    UNIMPL          nfssvc
-159    NOARGS          { int compat_43_sys_getdirentries(int fd, char *buf, \
-                           u_int count, long *basep); }
+159    STD             { int osf1_sys_getdirentries(int fd, char *buf, \
+                           int nbytes, long *basep); }
 160    STD             { int osf1_sys_statfs(const char *path, \
                            struct osf1_statfs *buf, int len); }
 161    STD             { int osf1_sys_fstatfs(int fd, \


Home | Main Index | Thread Index | Old Index