summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/compat/common/Makefile4
-rw-r--r--sys/compat/common/compat_dir.c144
-rw-r--r--sys/compat/common/compat_dir.h33
-rw-r--r--sys/compat/ibcs2/ibcs2_misc.c307
-rw-r--r--sys/compat/linux/linux_misc.c207
-rw-r--r--sys/compat/sunos/sunos_misc.c148
-rw-r--r--sys/compat/svr4/svr4_misc.c301
7 files changed, 506 insertions, 638 deletions
diff --git a/sys/compat/common/Makefile b/sys/compat/common/Makefile
index 9c53d691d07..7681a235b6f 100644
--- a/sys/compat/common/Makefile
+++ b/sys/compat/common/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.7 1999/05/22 21:22:33 weingart Exp $
+# $OpenBSD: Makefile,v 1.8 2001/01/23 05:48:04 csapuntz Exp $
# $NetBSD: Makefile,v 1.8 1996/05/18 15:52:19 christos Exp $
LIB= compat
@@ -6,7 +6,7 @@ NOPIC=
.PATH: ${COMPATDIR}
-SRCS= compat_exec.c compat_util.c compat_vm.c kern_exit_43.c \
+SRCS= compat_exec.c compat_util.c compat_dir.c compat_vm.c kern_exit_43.c \
kern_info_09.c kern_info_43.c kern_prot_43.c kern_resource_43.c \
kern_sig_43.c tty_43.c uipc_syscalls_43.c vfs_syscalls_43.c vm_43.c
diff --git a/sys/compat/common/compat_dir.c b/sys/compat/common/compat_dir.c
new file mode 100644
index 00000000000..e7ecbd1e53f
--- /dev/null
+++ b/sys/compat/common/compat_dir.c
@@ -0,0 +1,144 @@
+/* $OpenBSD: compat_dir.c,v 1.1 2001/01/23 05:48:04 csapuntz Exp $ */
+
+/*
+ * Copyright (c) 2000 Constantine Sapuntzakis
+ * All rights reserved.
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/filedesc.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/dirent.h>
+
+#include <compat/common/compat_dir.h>
+
+int
+readdir_with_callback(fp, off, nbytes, appendfunc, arg)
+ struct file *fp;
+ off_t *off;
+ u_long nbytes;
+ int (*appendfunc) __P((void *, struct dirent *, off_t));
+ void *arg;
+{
+ caddr_t inp, buf;
+ int buflen;
+ struct uio auio;
+ struct iovec aiov;
+ int eofflag;
+ u_long *cookiebuf = NULL, *cookie;
+ int ncookies = 0;
+ int error, len, reclen;
+ off_t newoff = *off;
+ struct vnode *vp;
+ struct vattr va;
+
+ if ((fp->f_flag & FREAD) == 0)
+ return (EBADF);
+
+ vp = (struct vnode *)fp->f_data;
+
+ if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */
+ return (EINVAL);
+
+ if ((error = VOP_GETATTR(vp, &va, fp->f_cred, curproc)) != 0)
+ return (error);
+
+ buflen = min(MAXBSIZE, nbytes);
+ buflen = max(buflen, va.va_blocksize);
+ buf = malloc(buflen, M_TEMP, M_WAITOK);
+ error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
+ if (error)
+ goto out;
+
+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 = curproc;
+ auio.uio_resid = buflen;
+ auio.uio_offset = newoff;
+
+ error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
+ &cookiebuf);
+ if (error)
+ goto out;
+
+ if (!cookiebuf && !eofflag) {
+ error = EPERM;
+ goto out;
+ }
+
+ if ((len = buflen - auio.uio_resid) == 0)
+ goto eof;
+
+ cookie = cookiebuf;
+ inp = buf;
+
+ for (;
+ len > 0;
+ len -= reclen, inp += reclen, ++cookie) {
+ struct dirent *bdp = (struct dirent *)inp;
+ reclen = bdp->d_reclen;
+
+ if (len < reclen) break;
+ if (reclen & 3)
+ panic("readdir_with_callback: bad reclen");
+
+ /* Skip holes */
+ if (bdp->d_fileno != 0) {
+ if ((error = (*appendfunc) (arg, bdp, *cookie))
+ != 0) {
+ if (error == ENOMEM)
+ error = 0;
+ break;
+ }
+ }
+
+ newoff = *cookie;
+ }
+
+ if (len <= 0 && !eofflag)
+ goto again;
+
+ eof:
+ out:
+ if (error == 0)
+ *off = newoff;
+
+ VOP_UNLOCK(vp, 0, curproc);
+ if (cookiebuf)
+ free(cookiebuf, M_TEMP);
+ free(buf, M_TEMP);
+ return (error);
+}
diff --git a/sys/compat/common/compat_dir.h b/sys/compat/common/compat_dir.h
new file mode 100644
index 00000000000..d070d578138
--- /dev/null
+++ b/sys/compat/common/compat_dir.h
@@ -0,0 +1,33 @@
+/* $OpenBSD: compat_dir.h,v 1.1 2001/01/23 05:48:04 csapuntz Exp $ */
+
+/*
+ * Copyright (c) 2000 Constantine Sapuntzakis
+ * All rights reserved.
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+#ifdef _KERNEL
+
+int readdir_with_callback __P((struct file *, off_t *, u_long,
+ int (*append_func) (void *, struct dirent *, off_t), void *));
+
+#endif
diff --git a/sys/compat/ibcs2/ibcs2_misc.c b/sys/compat/ibcs2/ibcs2_misc.c
index 6a52735b32d..94313e9d47c 100644
--- a/sys/compat/ibcs2/ibcs2_misc.c
+++ b/sys/compat/ibcs2/ibcs2_misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ibcs2_misc.c,v 1.16 2000/09/07 17:52:23 ericj Exp $ */
+/* $OpenBSD: ibcs2_misc.c,v 1.17 2001/01/23 05:48:05 csapuntz Exp $ */
/* $NetBSD: ibcs2_misc.c,v 1.23 1997/01/15 01:37:49 perry Exp $ */
/*
@@ -104,6 +104,7 @@
#include <compat/ibcs2/ibcs2_syscallargs.h>
#include <compat/ibcs2/ibcs2_sysi86.h>
+#include <compat/common/compat_dir.h>
int
ibcs2_sys_ulimit(p, v, retval)
@@ -335,6 +336,86 @@ ibcs2_sys_mount(p, v, retval)
* This is quite ugly, but what do you expect from compatibility code?
*/
+int ibcs2_readdir_callback __P((void *, struct dirent *, off_t));
+int ibcs2_classicread_callback __P((void *, struct dirent *, off_t));
+
+struct ibcs2_readdir_callback_args {
+ caddr_t outp;
+ int resid;
+};
+
+int
+ibcs2_readdir_callback(arg, bdp, cookie)
+ void *arg;
+ struct dirent *bdp;
+ off_t cookie;
+{
+ struct ibcs2_dirent idb;
+ struct ibcs2_readdir_callback_args *cb = arg;
+ int ibcs2_reclen;
+ int error;
+
+ ibcs2_reclen = IBCS2_RECLEN(&idb, bdp->d_namlen);
+ if (cb->resid < ibcs2_reclen)
+ return (ENOMEM);
+
+ /*
+ * Massage in place to make a iBCS2-shaped dirent (otherwise
+ * we have to worry about touching user memory outside of
+ * the copyout() call).
+ */
+ idb.d_ino = (ibcs2_ino_t)bdp->d_fileno;
+ idb.d_pad = 0;
+ idb.d_off = (ibcs2_off_t)cookie;
+ idb.d_reclen = (u_short)ibcs2_reclen;
+ strlcpy(idb.d_name, bdp->d_name, IBCS2_MAXNAMLEN+1);
+ error = copyout((caddr_t)&idb, cb->outp, ibcs2_reclen);
+ if (error)
+ return (error);
+
+ /* advance output past iBCS2-shaped entry */
+ cb->outp += ibcs2_reclen;
+ cb->resid -= ibcs2_reclen;
+
+ return (0);
+}
+
+int
+ibcs2_classicread_callback(arg, bdp, cookie)
+ void *arg;
+ struct dirent *bdp;
+ off_t cookie;
+{
+ struct ibcs2_direct {
+ ibcs2_ino_t ino;
+ char name[14];
+ } idb;
+ struct ibcs2_readdir_callback_args *cb = arg;
+ int ibcs2_reclen;
+ int error;
+
+ ibcs2_reclen = 16;
+ if (cb->resid < ibcs2_reclen)
+ return (ENOMEM);
+
+ /*
+ * TODO: if length(filename) > 14 then break filename into
+ * multiple entries and set inode = 0xffff except last
+ */
+ idb.ino = (bdp->d_fileno > 0xfffe) ? 0xfffe : bdp->d_fileno;
+ bzero(&idb.name, sizeof(idb.name));
+ strncpy(idb.name, bdp->d_name, 14);
+ error = copyout(&idb, cb->outp, ibcs2_reclen);
+ if (error)
+ return (error);
+
+ /* advance output past iBCS2-shaped entry */
+ cb->outp += ibcs2_reclen;
+ cb->resid -= ibcs2_reclen;
+
+ return (0);
+}
+
int
ibcs2_sys_getdents(p, v, retval)
struct proc *p;
@@ -346,118 +427,23 @@ ibcs2_sys_getdents(p, v, retval)
syscallarg(char *) buf;
syscallarg(int) nbytes;
} */ *uap = v;
- register struct dirent *bdp;
- struct vnode *vp;
- caddr_t inp, buf; /* BSD-format */
- int len, reclen; /* BSD-format */
- caddr_t outp; /* iBCS2-format */
- int resid, ibcs2_reclen;/* iBCS2-format */
+ struct ibcs2_readdir_callback_args args;
struct file *fp;
- struct uio auio;
- struct iovec aiov;
- struct ibcs2_dirent 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;
-
- if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */
- return (EINVAL);
-
- 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;
-
- if (!error && !cookiebuf && !eofflag) {
- error = EPERM;
- goto out;
- }
-
- 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("ibcs2_getdents: bad reclen");
- if (bdp->d_fileno == 0) {
- inp += reclen; /* it is a hole; squish it out */
- off = *cookie++;
- continue;
- }
- ibcs2_reclen = IBCS2_RECLEN(&idb, bdp->d_namlen);
- if (reclen > len || resid < ibcs2_reclen) {
- /* entry too big for buffer, so just stop */
- outp++;
- break;
- }
- off = *cookie++; /* each entry points to the next */
-
- /*
- * Massage in place to make a iBCS2-shaped dirent (otherwise
- * we have to worry about touching user memory outside of
- * the copyout() call).
- */
- idb.d_ino = (ibcs2_ino_t)bdp->d_fileno;
- idb.d_off = (ibcs2_off_t)off;
- idb.d_reclen = (u_short)ibcs2_reclen;
- strcpy(idb.d_name, bdp->d_name);
- error = copyout((caddr_t)&idb, outp, ibcs2_reclen);
- if (error)
- goto out;
-
- /* advance past this real entry */
- inp += reclen;
+ args.resid = SCARG(uap, nbytes);
+ args.outp = (caddr_t)SCARG(uap, buf);
+
+ if ((error = readdir_with_callback(fp, &fp->f_offset, args.resid,
+ ibcs2_readdir_callback, &args)) != 0)
+ return (error);
- /* advance output past iBCS2-shaped entry */
- outp += ibcs2_reclen;
- resid -= ibcs2_reclen;
- }
+ *retval = SCARG(uap, nbytes) - args.resid;
- /* if we squished out the whole block, try again */
- if (outp == SCARG(uap, buf))
- goto again;
- fp->f_offset = off; /* update the vnode offset */
-
-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
@@ -471,23 +457,10 @@ ibcs2_sys_read(p, v, retval)
syscallarg(char *) buf;
syscallarg(u_int) nbytes;
} */ *uap = v;
- register struct dirent *bdp;
struct vnode *vp;
- caddr_t inp, buf; /* BSD-format */
- int len, reclen; /* BSD-format */
- caddr_t outp; /* iBCS2-format */
- int resid, ibcs2_reclen;/* iBCS2-format */
+ struct ibcs2_readdir_callback_args args;
struct file *fp;
- struct uio auio;
- struct iovec aiov;
- struct ibcs2_direct {
- ibcs2_ino_t ino;
- char name[14];
- } idb;
- off_t off; /* true file offset */
- int buflen, error, eofflag, size;
- u_long *cookiebuf = NULL, *cookie;
- int ncookies = 0;
+ int error;
if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) {
if (error == EINVAL)
@@ -500,89 +473,17 @@ ibcs2_sys_read(p, v, retval)
vp = (struct vnode *)fp->f_data;
if (vp->v_type != VDIR)
return sys_read(p, uap, retval);
- DPRINTF(("ibcs2_read: read directory\n"));
- buflen = max(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;
-
- if (!error && !cookiebuf && !eofflag) {
- error = EPERM;
- goto out;
- }
- inp = buf;
- outp = SCARG(uap, buf);
- resid = SCARG(uap, nbytes);
- if ((len = buflen - auio.uio_resid) == 0)
- goto eof;
- for (cookie = cookiebuf; len > 0 && resid > 0; len -= reclen) {
- bdp = (struct dirent *)inp;
- reclen = bdp->d_reclen;
- if (reclen & 3)
- panic("ibcs2_read: bad reclen");
- if (bdp->d_fileno == 0) {
- inp += reclen; /* it is a hole; squish it out */
- off = *cookie++;
- continue;
- }
- ibcs2_reclen = 16;
- if (reclen > len || resid < ibcs2_reclen) {
- /* entry too big for buffer, so just stop */
- outp++;
- break;
- }
- off = *cookie++; /* each entry points to the next */
- /*
- * Massage in place to make a iBCS2-shaped dirent (otherwise
- * we have to worry about touching user memory outside of
- * the copyout() call).
- *
- * TODO: if length(filename) > 14, then break filename into
- * multiple entries and set inode = 0xffff except last
- */
- idb.ino = (bdp->d_fileno > 0xfffe) ? 0xfffe : bdp->d_fileno;
- (void)copystr(bdp->d_name, idb.name, 14, &size);
- bzero(idb.name + size, 14 - size);
- error = copyout(&idb, outp, ibcs2_reclen);
- if (error)
- goto out;
- /* advance past this real entry */
- inp += reclen;
- /* advance output past iBCS2-shaped entry */
- outp += ibcs2_reclen;
- resid -= ibcs2_reclen;
- }
- /* if we squished out the whole block, try again */
- if (outp == SCARG(uap, buf))
- goto again;
- fp->f_offset = off; /* update the vnode offset */
-eof:
- *retval = SCARG(uap, nbytes) - resid;
-out:
- VOP_UNLOCK(vp, 0, p);
- if (cookiebuf)
- free(cookiebuf, M_TEMP);
- free(buf, M_TEMP);
- return (error);
+ args.resid = SCARG(uap, nbytes);
+ args.outp = (caddr_t)SCARG(uap, buf);
+
+ if ((error = readdir_with_callback(fp, &fp->f_offset, args.resid,
+ ibcs2_classicread_callback, &args)) != 0)
+ return (error);
+
+ *retval = SCARG(uap, nbytes) - args.resid;
+
+ return (0);
}
int
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index e8e6db8b4d5..a4e73229cc5 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: linux_misc.c,v 1.33 2000/09/10 07:04:20 jasoni Exp $ */
+/* $OpenBSD: linux_misc.c,v 1.34 2001/01/23 05:48:05 csapuntz Exp $ */
/* $NetBSD: linux_misc.c,v 1.27 1996/05/20 01:59:21 fvdl Exp $ */
/*
@@ -77,6 +77,8 @@
#include <compat/linux/linux_util.h>
#include <compat/linux/linux_dirent.h>
+#include <compat/common/compat_dir.h>
+
/* linux_misc.c */
static void bsd_to_linux_wstat __P((int *));
static void bsd_to_linux_statfs __P((struct statfs *, struct linux_statfs *));
@@ -902,6 +904,7 @@ linux_sys_readdir(p, v, retval)
} */ *uap = v;
SCARG(uap, count) = 1;
+
return linux_sys_getdents(p, uap, retval);
}
@@ -919,151 +922,101 @@ linux_sys_readdir(p, v, retval)
*
* Note that this doesn't handle union-mounted filesystems.
*/
+int linux_readdir_callback __P((void *, struct dirent *, off_t));
+
+struct linux_readdir_callback_args {
+ caddr_t outp;
+ int resid;
+ int oldcall;
+};
+
+int
+linux_readdir_callback(arg, bdp, cookie)
+ void *arg;
+ struct dirent *bdp;
+ off_t cookie;
+{
+ struct linux_dirent idb;
+ struct linux_readdir_callback_args *cb = arg;
+ int linux_reclen;
+ int error;
+
+ if (cb->oldcall == 2)
+ return (ENOMEM);
+
+ linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
+ if (cb->resid < linux_reclen)
+ return (ENOMEM);
+
+ /*
+ * 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 = (linux_ino_t)bdp->d_fileno;
+
+ /*
+ * The old readdir() call misuses the offset and reclen fields.
+ */
+ if (cb->oldcall) {
+ idb.d_off = (linux_off_t)linux_reclen;
+ idb.d_reclen = (u_short)bdp->d_namlen;
+ } else {
+ idb.d_off = (linux_off_t)cookie;
+ idb.d_reclen = (u_short)linux_reclen;
+ }
+
+ strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name));
+ if ((error = copyout((caddr_t)&idb, cb->outp, linux_reclen)))
+ return (error);
+
+ /* advance output past Linux-shaped entry */
+ cb->outp += linux_reclen;
+ cb->resid -= linux_reclen;
+
+ if (cb->oldcall == 1)
+ ++cb->oldcall;
+
+ return (0);
+}
+
int
linux_sys_getdents(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
- struct linux_sys_readdir_args /* {
+ struct linux_sys_getdents_args /* {
syscallarg(int) fd;
- syscallarg(caddr_t) dent;
- syscallarg(unsigned int) count;
+ syscallarg(void *) dirent;
+ syscallarg(unsigned) count;
} */ *uap = v;
- register 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 linux_readdir_callback_args args;
struct file *fp;
- struct uio auio;
- struct iovec aiov;
- struct linux_dirent idb;
- off_t off; /* true file offset */
- int buflen, error, eofflag, nbytes, oldcall;
- struct vattr va;
- u_long *cookiebuf = NULL, *cookie;
- int ncookies = 0;
+ int error;
+ int nbytes = SCARG(uap, count);
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;
-
- if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */
- return (EINVAL);
-
- if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
- return error;
-
- nbytes = SCARG(uap, count);
if (nbytes == 1) { /* emulating old, broken behaviour */
- nbytes = sizeof (struct linux_dirent);
- buflen = max(va.va_blocksize, nbytes);
- oldcall = 1;
+ nbytes = sizeof(struct linux_dirent);
+ args.oldcall = 1;
} else {
- buflen = min(MAXBSIZE, nbytes);
- oldcall = 0;
+ args.oldcall = 0;
}
- 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;
-
- if (!error && !cookiebuf)
- goto out;
-
- inp = buf;
- outp = 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: bad reclen");
- 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 = (linux_ino_t)bdp->d_fileno;
+ args.resid = nbytes;
+ args.outp = (caddr_t)SCARG(uap, dirent);
- /*
- * The old readdir() call misuses the offset and reclen fields.
- */
- if (oldcall) {
- idb.d_off = (linux_off_t)linux_reclen;
- idb.d_reclen = (u_short)bdp->d_namlen;
- } else {
- idb.d_off = (linux_off_t)off;
- idb.d_reclen = (u_short)linux_reclen;
- }
- strncpy(idb.d_name, bdp->d_name, sizeof(idb.d_name) - 1);
- idb.d_name[sizeof(idb.d_name) - 1] = '\0';
- 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 ((error = readdir_with_callback(fp, &fp->f_offset, nbytes,
+ linux_readdir_callback, &args)) != 0)
+ goto exit;
+
+ *retval = nbytes - args.resid;
- /* if we squished out the whole block, try again */
- if (outp == 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, p);
- if (cookiebuf)
- free(cookiebuf, M_TEMP);
- free(buf, M_TEMP);
- return error;
+ exit:
+ return (error);
}
/*
diff --git a/sys/compat/sunos/sunos_misc.c b/sys/compat/sunos/sunos_misc.c
index 77a5438ec25..e58a3e9d1f9 100644
--- a/sys/compat/sunos/sunos_misc.c
+++ b/sys/compat/sunos/sunos_misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sunos_misc.c,v 1.23 2000/04/21 15:50:21 millert Exp $ */
+/* $OpenBSD: sunos_misc.c,v 1.24 2001/01/23 05:48:04 csapuntz Exp $ */
/* $NetBSD: sunos_misc.c,v 1.65 1996/04/22 01:44:31 christos Exp $ */
/*
@@ -376,6 +376,43 @@ sunos_sys_sigpending(p, v, retval)
*
* This is quite ugly, but what do you expect from compatibility code?
*/
+int sunos_readdir_callback __P((void *, struct dirent *, off_t));
+
+struct sunos_readdir_callback_args {
+ caddr_t outp;
+ int resid;
+};
+
+int
+sunos_readdir_callback(arg, bdp, cookie)
+ void *arg;
+ struct dirent *bdp;
+ off_t cookie;
+{
+ struct sunos_dirent idb;
+ struct sunos_readdir_callback_args *cb = arg;
+ int sunos_reclen;
+ int error;
+
+ sunos_reclen = SUNOS_RECLEN(&idb, bdp->d_namlen);
+ if (cb->resid < sunos_reclen)
+ return (ENOMEM);
+
+ idb.d_fileno = bdp->d_fileno;
+ idb.d_off = cookie;
+ idb.d_reclen = sunos_reclen;
+ idb.d_namlen = bdp->d_namlen;
+ strlcpy(idb.d_name, bdp->d_name, SUNOS_MAXNAMLEN+1);
+
+ if ((error = copyout((caddr_t)&idb, cb->outp, sunos_reclen)))
+ return (error);
+
+ cb->outp += sunos_reclen;
+ cb->resid -= sunos_reclen;
+
+ return (0);
+}
+
int
sunos_sys_getdents(p, v, retval)
struct proc *p;
@@ -387,117 +424,32 @@ sunos_sys_getdents(p, v, retval)
syscallarg(char *) buf;
syscallarg(int) nbytes;
} */ *uap = v;
- struct dirent *bdp;
struct vnode *vp;
- caddr_t inp, buf; /* BSD-format */
- int len, reclen; /* BSD-format */
- caddr_t outp; /* Sun-format */
- int resid, sunos_reclen;/* Sun-format */
struct file *fp;
- struct uio auio;
- struct iovec aiov;
- struct sunos_dirent idb;
- off_t off; /* true file offset */
- int buflen, error, eofflag;
- u_long *cookiebuf = NULL, *cookie;
- int ncookies;
+ int error;
+ struct sunos_readdir_callback_args args;
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;
+ vp = (struct vnode *)fp->f_data;
/* SunOS returns ENOTDIR here, BSD would use EINVAL */
if (vp->v_type != VDIR)
return (ENOTDIR);
- if (SCARG(uap, nbytes) < sizeof(struct sunos_dirent))
- return (EINVAL);
-
- 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;
- if (!cookiebuf) {
- error = EPERM;
- goto out;
- }
- 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("sunos_getdents: bad reclen");
- if (bdp->d_fileno == 0) {
- inp += reclen; /* it is a hole; squish it out */
- off = *cookie++;
- continue;
- }
- sunos_reclen = SUNOS_RECLEN(&idb, bdp->d_namlen);
- if (reclen > len || resid < sunos_reclen) {
- /* entry too big for buffer, so just stop */
- outp++;
- break;
- }
- off = *cookie++; /* each entry points to next */
- /*
- * Massage in place to make a Sun-shaped dirent (otherwise
- * we have to worry about touching user memory outside of
- * the copyout() call).
- */
- idb.d_fileno = bdp->d_fileno;
- idb.d_off = off;
- idb.d_reclen = sunos_reclen;
- idb.d_namlen = bdp->d_namlen;
- strcpy(idb.d_name, bdp->d_name);
- if ((error = copyout((caddr_t)&idb, outp, sunos_reclen)) != 0)
- goto out;
- /* advance past this real entry */
- inp += reclen;
- /* advance output past Sun-shaped entry */
- outp += sunos_reclen;
- resid -= sunos_reclen;
- }
+ args.resid = SCARG(uap, nbytes);
+ args.outp = (caddr_t)SCARG(uap, buf);
+
+ if ((error = readdir_with_callback(fp, &fp->f_offset, args.resid,
+ sunos_readdir_callback, &args)) != 0)
+ 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 */
+ *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);
}
+
#define SUNOS__MAP_NEW 0x80000000 /* if not, old mmap & cannot handle */
int
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