summaryrefslogtreecommitdiff
path: root/sys/compat/linux
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
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')
-rw-r--r--sys/compat/linux/linux_dirent.h10
-rw-r--r--sys/compat/linux/linux_dummy.c3
-rw-r--r--sys/compat/linux/linux_misc.c75
-rw-r--r--sys/compat/linux/linux_syscall.h6
-rw-r--r--sys/compat/linux/linux_syscallargs.h10
-rw-r--r--sys/compat/linux/linux_syscalls.c4
-rw-r--r--sys/compat/linux/linux_sysent.c6
-rw-r--r--sys/compat/linux/linux_types.h4
8 files changed, 84 insertions, 34 deletions
diff --git a/sys/compat/linux/linux_dirent.h b/sys/compat/linux/linux_dirent.h
index 5eeec661746..04e1aeaa97d 100644
--- a/sys/compat/linux/linux_dirent.h
+++ b/sys/compat/linux/linux_dirent.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: linux_dirent.h,v 1.2 1996/04/17 05:23:43 mickey Exp $ */
+/* $OpenBSD: linux_dirent.h,v 1.3 2002/10/28 03:39:30 fgsch Exp $ */
/* $NetBSD: linux_dirent.h,v 1.3 1995/10/07 06:26:59 mycroft Exp $ */
/*
@@ -44,6 +44,14 @@ struct linux_dirent {
char d_name[LINUX_MAXNAMLEN + 1];
};
+struct linux_dirent64 {
+ linux_ino64_t d_ino;
+ linux_off64_t d_off;
+ u_short d_reclen;
+ u_char d_type;
+ char d_name[LINUX_MAXNAMLEN + 1];
+};
+
#define LINUX_NAMEOFF(dp) ((char *)&(dp)->d_name - (char *)dp)
#define LINUX_RECLEN(de,namlen) ALIGN((LINUX_NAMEOFF(de) + (namlen) + 1))
diff --git a/sys/compat/linux/linux_dummy.c b/sys/compat/linux/linux_dummy.c
index 7a0e732d4d6..ac06b9a0451 100644
--- a/sys/compat/linux/linux_dummy.c
+++ b/sys/compat/linux/linux_dummy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: linux_dummy.c,v 1.8 2002/06/02 22:49:59 deraadt Exp $ */
+/* $OpenBSD: linux_dummy.c,v 1.9 2002/10/28 03:39:30 fgsch Exp $ */
/*-
* Copyright (c) 1994-1995 Søren Schmidt
@@ -121,4 +121,3 @@ DUMMY(setfsgid); /* #216 */
DUMMY(pivot_root); /* #217 */
DUMMY(mincore); /* #218 */
DUMMY(madvise); /* #219 */
-DUMMY(getdents64); /* #220 */
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)
diff --git a/sys/compat/linux/linux_syscall.h b/sys/compat/linux/linux_syscall.h
index a175e4f3528..fa2805a5755 100644
--- a/sys/compat/linux/linux_syscall.h
+++ b/sys/compat/linux/linux_syscall.h
@@ -1,10 +1,10 @@
-/* $OpenBSD: linux_syscall.h,v 1.35 2002/06/05 19:43:44 jasoni Exp $ */
+/* $OpenBSD: linux_syscall.h,v 1.36 2002/10/28 03:39:30 fgsch Exp $ */
/*
* System call numbers.
*
* DO NOT EDIT-- this file is automatically generated.
- * created from OpenBSD: syscalls.master,v 1.34 2002/06/05 19:43:25 jasoni Exp
+ * created from OpenBSD: syscalls.master,v 1.35 2002/10/28 03:35:53 fgsch Exp
*/
/* syscall: "syscall" ret: "int" args: */
@@ -676,7 +676,7 @@
/* syscall: "madvise" ret: "int" args: */
#define LINUX_SYS_madvise 219
-/* syscall: "getdents64" ret: "int" args: */
+/* syscall: "getdents64" ret: "int" args: "int" "void *" "unsigned" */
#define LINUX_SYS_getdents64 220
/* syscall: "fcntl64" ret: "int" args: "u_int" "u_int" "void *" */
diff --git a/sys/compat/linux/linux_syscallargs.h b/sys/compat/linux/linux_syscallargs.h
index f1c17c1b1a9..67fbd53602e 100644
--- a/sys/compat/linux/linux_syscallargs.h
+++ b/sys/compat/linux/linux_syscallargs.h
@@ -1,10 +1,10 @@
-/* $OpenBSD: linux_syscallargs.h,v 1.37 2002/06/05 19:43:44 jasoni Exp $ */
+/* $OpenBSD: linux_syscallargs.h,v 1.38 2002/10/28 03:39:30 fgsch Exp $ */
/*
* System call argument lists.
*
* DO NOT EDIT-- this file is automatically generated.
- * created from OpenBSD: syscalls.master,v 1.34 2002/06/05 19:43:25 jasoni Exp
+ * created from OpenBSD: syscalls.master,v 1.35 2002/10/28 03:35:53 fgsch Exp
*/
#ifdef syscallarg
@@ -517,6 +517,12 @@ struct linux_sys_setfsuid_args {
syscallarg(uid_t) uid;
};
+struct linux_sys_getdents64_args {
+ syscallarg(int) fd;
+ syscallarg(void *) dirent;
+ syscallarg(unsigned) count;
+};
+
struct linux_sys_fcntl64_args {
syscallarg(u_int) fd;
syscallarg(u_int) cmd;
diff --git a/sys/compat/linux/linux_syscalls.c b/sys/compat/linux/linux_syscalls.c
index 1cd5c1af95c..4c3143de7c5 100644
--- a/sys/compat/linux/linux_syscalls.c
+++ b/sys/compat/linux/linux_syscalls.c
@@ -1,10 +1,10 @@
-/* $OpenBSD: linux_syscalls.c,v 1.35 2002/06/05 19:43:44 jasoni Exp $ */
+/* $OpenBSD: linux_syscalls.c,v 1.36 2002/10/28 03:39:30 fgsch Exp $ */
/*
* System call names.
*
* DO NOT EDIT-- this file is automatically generated.
- * created from OpenBSD: syscalls.master,v 1.34 2002/06/05 19:43:25 jasoni Exp
+ * created from OpenBSD: syscalls.master,v 1.35 2002/10/28 03:35:53 fgsch Exp
*/
char *linux_syscallnames[] = {
diff --git a/sys/compat/linux/linux_sysent.c b/sys/compat/linux/linux_sysent.c
index 93c5b9b3b31..ecc28670251 100644
--- a/sys/compat/linux/linux_sysent.c
+++ b/sys/compat/linux/linux_sysent.c
@@ -1,10 +1,10 @@
-/* $OpenBSD: linux_sysent.c,v 1.36 2002/06/05 19:43:44 jasoni Exp $ */
+/* $OpenBSD: linux_sysent.c,v 1.37 2002/10/28 03:39:30 fgsch Exp $ */
/*
* System call switch table.
*
* DO NOT EDIT-- this file is automatically generated.
- * created from OpenBSD: syscalls.master,v 1.34 2002/06/05 19:43:25 jasoni Exp
+ * created from OpenBSD: syscalls.master,v 1.35 2002/10/28 03:35:53 fgsch Exp
*/
#include <sys/param.h>
@@ -480,7 +480,7 @@ struct sysent linux_sysent[] = {
linux_sys_mincore }, /* 218 = mincore */
{ 0, 0,
linux_sys_madvise }, /* 219 = madvise */
- { 0, 0,
+ { 3, s(struct linux_sys_getdents64_args),
linux_sys_getdents64 }, /* 220 = getdents64 */
{ 3, s(struct linux_sys_fcntl64_args),
linux_sys_fcntl64 }, /* 221 = fcntl64 */
diff --git a/sys/compat/linux/linux_types.h b/sys/compat/linux/linux_types.h
index 368ddc04fa7..d43783e3880 100644
--- a/sys/compat/linux/linux_types.h
+++ b/sys/compat/linux/linux_types.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: linux_types.h,v 1.5 2002/02/04 20:04:52 provos Exp $ */
+/* $OpenBSD: linux_types.h,v 1.6 2002/10/28 03:39:30 fgsch Exp $ */
/* $NetBSD: linux_types.h,v 1.5 1996/05/20 01:59:28 fvdl Exp $ */
/*
@@ -42,11 +42,13 @@ typedef struct {
typedef unsigned short linux_uid_t;
typedef unsigned short linux_gid_t;
typedef unsigned short linux_dev_t;
+typedef unsigned long long linux_ino64_t;
typedef unsigned long linux_ino_t;
typedef unsigned short linux_mode_t;
typedef unsigned short linux_nlink_t;
typedef long linux_time_t;
typedef long linux_clock_t;
+typedef long long linux_off64_t;
typedef long linux_off_t;
typedef u_int64_t linux_loff_t;
typedef int linux_pid_t;