summaryrefslogtreecommitdiff
path: root/sys/compat/svr4
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-01-23 05:48:06 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>2001-01-23 05:48:06 +0000
commit0d359a25c5e8b08e0beec6bc5d040d7bb39b8f3b (patch)
tree1592996dc097c795719a7fb2e50ea4a8e31bc663 /sys/compat/svr4
parent5469037bfddd3618643b8d46aea72cdcc35a4869 (diff)
SunOS, IBCS2, Linux, and SVR4 all require translations of directory entries
from OpenBSD format to their respective native formats. A lot of common code here for interfacing with OpenBSD VOP_READDIR. Most of this code and logic has been moved to common/compat_dir.c When reading a portion of the directory, the compatibility layer registers a callback which is passed an OpenBSD-style dirent and the cookie/offset.
Diffstat (limited to 'sys/compat/svr4')
-rw-r--r--sys/compat/svr4/svr4_misc.c301
1 files changed, 93 insertions, 208 deletions
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