summaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_misc.c
diff options
context:
space:
mode:
authorFederico G. Schwindt <fgsch@cvs.openbsd.org>2002-10-28 03:39:31 +0000
committerFederico G. Schwindt <fgsch@cvs.openbsd.org>2002-10-28 03:39:31 +0000
commitfb0e880601a674837feb396dd34ea76f09ce9f89 (patch)
tree7dc1d2b69234f52c74a38385b8f6f9eee6fd75fe /sys/compat/linux/linux_misc.c
parent6b50a28cb283d9ba12a9a06cab9232f5146b8a3d (diff)
getdents64 support, based on FreeBSD.
thanks to jpmk@fibertel.com.ar for providing a testbed; jasoni ok.
Diffstat (limited to 'sys/compat/linux/linux_misc.c')
-rw-r--r--sys/compat/linux/linux_misc.c75
1 files changed, 55 insertions, 20 deletions
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index d392fc85dda..58b4910cbd5 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.45 2002/08/23 15:39:31 art Exp $ */
+/* $OpenBSD: linux_misc.c,v 1.46 2002/10/28 03:39:30 fgsch Exp $ */
/* $NetBSD: linux_misc.c,v 1.27 1996/05/20 01:59:21 fvdl Exp $ */
/*
@@ -84,6 +84,7 @@
static void bsd_to_linux_statfs(struct statfs *, struct linux_statfs *);
int linux_select1(struct proc *, register_t *, int, fd_set *,
fd_set *, fd_set *, struct timeval *);
+static int getdents_common(struct proc *, void *, register_t *, int);
/*
* The information on a terminated (or stopped) process needs
@@ -940,6 +941,7 @@ struct linux_readdir_callback_args {
caddr_t outp;
int resid;
int oldcall;
+ int is64bit;
};
int
@@ -948,6 +950,7 @@ linux_readdir_callback(arg, bdp, cookie)
struct dirent *bdp;
off_t cookie;
{
+ struct linux_dirent64 idb64;
struct linux_dirent idb;
struct linux_readdir_callback_args *cb = arg;
int linux_reclen;
@@ -956,30 +959,37 @@ linux_readdir_callback(arg, bdp, cookie)
if (cb->oldcall == 2)
return (ENOMEM);
- linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
+ linux_reclen = (cb->is64bit) ?
+ LINUX_RECLEN(&idb64, bdp->d_namlen) :
+ 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;
+ if (cb->is64bit) {
+ idb64.d_ino = (linux_ino64_t)bdp->d_fileno;
+ idb64.d_off = (linux_off64_t)cookie;
+ idb64.d_reclen = (u_short)linux_reclen;
+ idb64.d_type = bdp->d_type;
+ strlcpy(idb64.d_name, bdp->d_name, sizeof(idb64.d_name));
+ error = copyout((caddr_t)&idb64, cb->outp, linux_reclen);
} else {
- idb.d_off = (linux_off_t)cookie;
- idb.d_reclen = (u_short)linux_reclen;
+ idb.d_ino = (linux_ino_t)bdp->d_fileno;
+ if (cb->oldcall) {
+ /*
+ * The old readdir() call misuses the offset
+ * and reclen fields.
+ */
+ 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));
+ error = copyout((caddr_t)&idb, cb->outp, linux_reclen);
}
-
- strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name));
- if ((error = copyout((caddr_t)&idb, cb->outp, linux_reclen)))
+ if (error)
return (error);
/* advance output past Linux-shaped entry */
@@ -993,11 +1003,30 @@ linux_readdir_callback(arg, bdp, cookie)
}
int
+linux_sys_getdents64(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ return getdents_common(p, v, retval, 1);
+}
+
+int
linux_sys_getdents(p, v, retval)
struct proc *p;
void *v;
register_t *retval;
{
+ return getdents_common(p, v, retval, 0);
+}
+
+static int
+getdents_common(p, v, retval, is64bit)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+ int is64bit;
+{
struct linux_sys_getdents_args /* {
syscallarg(int) fd;
syscallarg(void *) dirent;
@@ -1012,6 +1041,11 @@ linux_sys_getdents(p, v, retval)
return (error);
if (nbytes == 1) { /* emulating old, broken behaviour */
+ /* readdir(2) case. Always struct dirent. */
+ if (is64bit) {
+ FRELE(fp);
+ return (EINVAL);
+ }
nbytes = sizeof(struct linux_dirent);
args.oldcall = 1;
} else {
@@ -1020,6 +1054,7 @@ linux_sys_getdents(p, v, retval)
args.resid = nbytes;
args.outp = (caddr_t)SCARG(uap, dirent);
+ args.is64bit = is64bit;
if ((error = readdir_with_callback(fp, &fp->f_offset, nbytes,
linux_readdir_callback, &args)) != 0)