Here is the new diff. I tried to replicate the work done in
other *BSD and added a syscall.
The new syscall is named getdents(), it's almost an exact copy of
getdirentries() without the last (problematic) parameter.
I extended dd_seek and dd_rewind fields in DIR struct to off_t and
switched readdir() to getdents() and lseek().
libexec/ld.so portion is not complete, because I am scared of
touching machdep code of anything besides x86.
diff -ur /mnt/include/dirent.h src/include/dirent.h
--- /mnt/include/dirent.h Tue Jun 5 22:11:48 2007
+++ src/include/dirent.h Sun Oct 17 17:44:59 2010
@@ -46,7 +46,7 @@
/*
* The kernel defines the format of directory entries returned by
- * the getdirentries(2) system call.
+ * the getdirentries(2) and getdents(2) system calls.
*/
#include <sys/dirent.h>
@@ -67,8 +67,8 @@
long dd_size; /* amount of data returned by getdirentries */
char *dd_buf; /* data buffer */
int dd_len; /* size of data buffer */
- long dd_seek; /* magic cookie returned by getdirentries */
- long dd_rewind; /* magic cookie for rewinding */
+ off_t dd_seek; /* magic cookie returned by getdirentries */
+ off_t dd_rewind; /* magic cookie for rewinding */
int dd_flags; /* flags for readdir */
struct _telldir *dd_td; /* telldir position recording */
void *dd_lock; /* mutex to protect struct */
@@ -106,6 +106,7 @@
int alphasort(const void *, const void *);
int getdirentries(int, char *, int, long *)
__attribute__ ((__bounded__(__string__,2,3)));
+int getdents(int, char *, int);
#endif /* __BSD_VISIBLE */
#if __XPG_VISIBLE
long telldir(DIR *);
diff -ur /mnt/lib/libc/gen/readdir.c src/lib/libc/gen/readdir.c
--- /mnt/lib/libc/gen/readdir.c Wed Nov 18 10:43:22 2009
+++ src/lib/libc/gen/readdir.c Sun Oct 17 17:50:51 2010
@@ -29,6 +29,7 @@
*/
#include <dirent.h>
+#include <unistd.h>
#include "thread_private.h"
/*
@@ -44,8 +45,9 @@
if (dirp->dd_loc >= dirp->dd_size)
dirp->dd_loc = 0;
if (dirp->dd_loc == 0) {
- dirp->dd_size = getdirentries(dirp->dd_fd,
- dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
+ dirp->dd_seek = lseek(dirp->dd_fd, 0, SEEK_CUR);
+ dirp->dd_size = getdents(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len);
if (dirp->dd_size == 0)
return (0);
if (dirp->dd_size < 0)
diff -ur /mnt/lib/libc/gen/telldir.h src/lib/libc/gen/telldir.h
--- /mnt/lib/libc/gen/telldir.h Sat Oct 13 02:41:42 2007
+++ src/lib/libc/gen/telldir.h Sun Oct 17 17:53:21 2010
@@ -38,12 +38,12 @@
/*
* One of these structures is malloced to describe the current directory
- * position each time telldir is called. It records the current magic
- * cookie returned by getdirentries and the offset within the buffer
+ * position each time telldir is called. It records the current position
+ * returned by lseek(2) and the offset within the buffer
* associated with that return value.
*/
struct ddloc {
- long loc_seek; /* magic cookie returned by getdirentries */
+ off_t loc_seek; /* position returned by lseek(2) */
long loc_loc; /* offset of entry in buffer */
};
diff -ur /mnt/lib/libc/sys/Makefile.inc src/lib/libc/sys/Makefile.inc
--- /mnt/lib/libc/sys/Makefile.inc Sat Jul 3 08:44:51 2010
+++ src/lib/libc/sys/Makefile.inc Mon Oct 18 00:51:51 2010
@@ -42,7 +42,7 @@
close.o closefrom.o connect.o dup.o dup2.o execve.o fchdir.o \
fchflags.o fchmod.o fchown.o fcntl.o fhopen.o fhstat.o fhstatfs.o \
flock.o fpathconf.o fstat.o \
- fstatfs.o fsync.o futimes.o getdirentries.o getegid.o geteuid.o \
+ fstatfs.o fsync.o futimes.o getdirentries.o getdents.o getegid.o
geteuid.o \
getfh.o getfsstat.o getgid.o getgroups.o getitimer.o \
getpeername.o \
getpgid.o \
@@ -249,6 +249,7 @@
MLINKS+=clock_gettime.2 clock_getres.2
MLINKS+=execve.2 exect.2
MLINKS+=fhopen.2 fhstat.2 fhopen.2 fhstatfs.2
+MLINKS+=getdirentries.2 getdents.2
MLINKS+=getgid.2 getegid.2
MLINKS+=getitimer.2 setitimer.2
MLINKS+=getitimer.2 timeradd.3
diff -ur /mnt/lib/libc/sys/getdirentries.2 src/lib/libc/sys/getdirentries.2
--- /mnt/lib/libc/sys/getdirentries.2 Sun Oct 17 00:50:11 2010
+++ src/lib/libc/sys/getdirentries.2 Mon Oct 18 00:47:17 2010
@@ -34,15 +34,20 @@
.Dt GETDIRENTRIES 2
.Os
.Sh NAME
-.Nm getdirentries
+.Nm getdirentries ,
+.Nm getdents
.Nd "get directory entries in a filesystem independent format"
.Sh SYNOPSIS
.Fd #include <dirent.h>
.Ft int
.Fn getdirentries "int fd" "char *buf" "int nbytes" "long *basep"
+.Ft int
+.Fn getdents "int fd" "char *buf" "int nbytes"
.Sh DESCRIPTION
.Fn getdirentries
-reads directory entries from the directory
+and
+.Fn getdents
+read directory entries from the directory
referenced by the file descriptor
.Fa fd
into the buffer pointed to by
@@ -179,6 +184,8 @@
.Ed
.Sh ERRORS
.Fn getdirentries
+and
+.Fn getdents
will fail if:
.Bl -tag -width Er
.It Bq Er EBADF
@@ -212,3 +219,7 @@
.Fn getdirentries
function first appeared in
.Bx 4.4 .
+The
+.Fn getdents
+function first appeared in
+.Ox 4.8 .
diff -ur /mnt/libexec/ld.so/amd64/ldasm.S src/libexec/ld.so/amd64/ldasm.S
--- /mnt/libexec/ld.so/amd64/ldasm.S Sun Oct 17 00:50:16 2010
+++ src/libexec/ld.so/amd64/ldasm.S Mon Oct 18 00:55:05 2010
@@ -86,7 +86,7 @@
DL_SYSCALL(write)
DL_SYSCALL(close)
DL_SYSCALL(issetugid)
-DL_SYSCALL(getdirentries)
+DL_SYSCALL(getdents)
DL_SYSCALL(mprotect)
DL_SYSCALL(munmap)
DL_SYSCALL(gettimeofday)
diff -ur /mnt/libexec/ld.so/amd64/syscall.h src/libexec/ld.so/amd64/syscall.h
--- /mnt/libexec/ld.so/amd64/syscall.h Sun Oct 17 00:50:16 2010
+++ src/libexec/ld.so/amd64/syscall.h Mon Oct 18 00:54:37 2010
@@ -50,7 +50,7 @@
int _dl_stat(const char *, struct stat *);
int _dl_fstat(int, struct stat *);
int _dl_fcntl(int, int, ...);
-int _dl_getdirentries(int, char*, int, long *);
+int _dl_getdents(int, char*, int);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
diff -ur /mnt/libexec/ld.so/dir.c src/libexec/ld.so/dir.c
--- /mnt/libexec/ld.so/dir.c Sun Oct 17 00:50:16 2010
+++ src/libexec/ld.so/dir.c Sun Oct 17 19:46:39 2010
@@ -116,8 +116,9 @@
dirp->dd_loc = 0;
}
if (dirp->dd_loc == 0) {
- dirp->dd_size = _dl_getdirentries(dirp->dd_fd,
- dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
+ dirp->dd_seek = _dl_lseek(dirp->dd_fd, 0, SEEK_CUR);
+ dirp->dd_size = _dl_getdents(dirp->dd_fd,
+ dirp->dd_buf, dirp->dd_len);
if (dirp->dd_size <= 0)
return (NULL);
}
diff -ur /mnt/libexec/ld.so/i386/ldasm.S src/libexec/ld.so/i386/ldasm.S
--- /mnt/libexec/ld.so/i386/ldasm.S Sun Oct 17 00:50:16 2010
+++ src/libexec/ld.so/i386/ldasm.S Sun Oct 17 19:47:21 2010
@@ -119,7 +119,7 @@
DL_SYSCALL(fcntl)
DL_SYSCALL(gettimeofday)
DL_SYSCALL2(sysctl,__sysctl)
-DL_SYSCALL(getdirentries)
+DL_SYSCALL(getdents)
.L_cerr:
/* error: result = -errno; - handled here. */
diff -ur /mnt/libexec/ld.so/i386/syscall.h src/libexec/ld.so/i386/syscall.h
--- /mnt/libexec/ld.so/i386/syscall.h Sun Oct 17 00:50:16 2010
+++ src/libexec/ld.so/i386/syscall.h Sun Oct 17 19:47:13 2010
@@ -50,7 +50,7 @@
int _dl_stat(const char *, struct stat *);
int _dl_fstat(int, struct stat *);
int _dl_fcntl(int, int, ...);
-int _dl_getdirentries(int, char*, int, long *);
+int _dl_getdents(int, char*, int);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
diff -ur /mnt/sys/kern/init_sysent.c src/sys/kern/init_sysent.c
--- /mnt/sys/kern/init_sysent.c Mon Sep 20 11:20:35 2010
+++ src/sys/kern/init_sysent.c Sun Oct 17 17:42:08 2010
@@ -1,4 +1,4 @@
-/* $OpenBSD: init_sysent.c,v 1.115 2010/09/20 07:20:35 deraadt Exp $
*/
+/* $OpenBSD$ */
/*
* System call switch table.
@@ -821,5 +821,7 @@
sys_setrtable }, /* 310 = setrtable */
{ 0, 0, 0,
sys_getrtable }, /* 311 = getrtable */
+ { 3, s(struct sys_getdents_args), 0,
+ sys_getdents }, /* 312 = getdents */
};
diff -ur /mnt/sys/kern/syscalls.c src/sys/kern/syscalls.c
--- /mnt/sys/kern/syscalls.c Mon Sep 20 11:20:35 2010
+++ src/sys/kern/syscalls.c Sun Oct 17 17:42:08 2010
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscalls.c,v 1.116 2010/09/20 07:20:35 deraadt Exp $ */
+/* $OpenBSD$ */
/*
* System call names.
@@ -421,4 +421,5 @@
"fhstatfs", /* 309 = fhstatfs */
"setrtable", /* 310 = setrtable */
"getrtable", /* 311 = getrtable */
+ "getdents", /* 312 = getdents */
};
diff -ur /mnt/sys/kern/syscalls.master src/sys/kern/syscalls.master
--- /mnt/sys/kern/syscalls.master Mon Sep 20 11:18:03 2010
+++ src/sys/kern/syscalls.master Sun Oct 17 17:41:54 2010
@@ -607,3 +607,5 @@
struct statfs *buf); }
310 STD { int sys_setrtable(int rtableid); }
311 STD { int sys_getrtable(void); }
+312 STD { int sys_getdents(int fd, char *buf, \
+ int count); }
diff -ur /mnt/sys/kern/vfs_syscalls.c src/sys/kern/vfs_syscalls.c
--- /mnt/sys/kern/vfs_syscalls.c Fri Jul 2 02:03:32 2010
+++ src/sys/kern/vfs_syscalls.c Mon Oct 18 00:17:40 2010
@@ -2287,6 +2287,7 @@
/*
* Read a block of directory entries in a file system independent format.
+ * Note: compatibility only.
*/
int
sys_getdirentries(struct proc *p, void *v, register_t *retval)
@@ -2338,6 +2339,61 @@
goto bad;
error = copyout(&loff, SCARG(uap, basep),
sizeof(long));
+ *retval = SCARG(uap, count) - auio.uio_resid;
+bad:
+ FRELE(fp);
+ return (error);
+}
+
+/*
+ * Read a block of directory entries in a file system independent format.
+ */
+int
+sys_getdents(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_getdirentries_args /* {
+ syscallarg(int) fd;
+ syscallarg(char *) buf;
+ syscallarg(int) count;
+ } */ *uap = v;
+ struct vnode *vp;
+ struct file *fp;
+ struct uio auio;
+ struct iovec aiov;
+ int error, eofflag;
+
+ if (SCARG(uap, count) < 0)
+ return EINVAL;
+ if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
+ return (error);
+ if ((fp->f_flag & FREAD) == 0) {
+ error = EBADF;
+ goto bad;
+ }
+ if (fp->f_offset < 0) {
+ error = EINVAL;
+ goto bad;
+ }
+ vp = (struct vnode *)fp->f_data;
+ if (vp->v_type != VDIR) {
+ error = EINVAL;
+ goto bad;
+ }
+ aiov.iov_base = SCARG(uap, buf);
+ aiov.iov_len = SCARG(uap, count);
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_procp = p;
+ auio.uio_resid = SCARG(uap, count);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ auio.uio_offset = fp->f_offset;
+ error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 0, 0);
+ fp->f_offset = auio.uio_offset;
+ VOP_UNLOCK(vp, 0, p);
+ if (error)
+ goto bad;
*retval = SCARG(uap, count) - auio.uio_resid;
bad:
FRELE(fp);
diff -ur /mnt/sys/sys/dirent.h src/sys/sys/dirent.h
--- /mnt/sys/sys/dirent.h Thu Aug 17 16:40:11 2006
+++ src/sys/sys/dirent.h Sun Oct 17 17:43:19 2010
@@ -39,7 +39,7 @@
/*
* The dirent structure defines the format of directory entries returned by
- * the getdirentries(2) system call.
+ * the getdirentries(2) and getdents(2) system calls.
*
* A directory entry has a struct dirent at the front of it, containing its
* inode number, the length of the entry, and the length of the name
diff -ur /mnt/sys/sys/syscall.h src/sys/sys/syscall.h
--- /mnt/sys/sys/syscall.h Mon Sep 20 11:20:35 2010
+++ src/sys/sys/syscall.h Sun Oct 17 17:42:08 2010
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.115 2010/09/20 07:20:35 deraadt Exp $ */
+/* $OpenBSD$ */
/*
* System call numbers.
@@ -687,4 +687,7 @@
/* syscall: "getrtable" ret: "int" args: */
#define SYS_getrtable 311
-#define SYS_MAXSYSCALL 312
+/* syscall: "getdents" ret: "int" args: "int" "char *" "int" */
+#define SYS_getdents 312
+
+#define SYS_MAXSYSCALL 313
diff -ur /mnt/sys/sys/syscallargs.h src/sys/sys/syscallargs.h
--- /mnt/sys/sys/syscallargs.h Mon Sep 20 11:20:35 2010
+++ src/sys/sys/syscallargs.h Sun Oct 17 17:42:08 2010
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscallargs.h,v 1.117 2010/09/20 07:20:35 deraadt Exp $
*/
+/* $OpenBSD$ */
/*
* System call argument lists.
@@ -1221,6 +1221,12 @@
syscallarg(int) rtableid;
};
+struct sys_getdents_args {
+ syscallarg(int) fd;
+ syscallarg(char *) buf;
+ syscallarg(int) count;
+};
+
/*
* System call prototypes.
*/
@@ -1533,3 +1539,4 @@
int sys_fhstatfs(struct proc *, void *, register_t *);
int sys_setrtable(struct proc *, void *, register_t *);
int sys_getrtable(struct proc *, void *, register_t *);
+int sys_getdents(struct proc *, void *, register_t *);
diff -ur /mnt/usr.bin/cvs/file.c src/usr.bin/cvs/file.c
--- /mnt/usr.bin/cvs/file.c Sun Oct 17 00:50:13 2010
+++ src/usr.bin/cvs/file.c Sun Oct 17 20:25:08 2010
@@ -393,7 +393,6 @@
int l, type;
FILE *fp;
int nbytes;
- long base;
size_t bufsize;
struct stat st;
struct dirent *dp;
@@ -472,7 +471,7 @@
RB_INIT(&fl);
RB_INIT(&dl);
- while ((nbytes = getdirentries(cf->fd, buf, bufsize, &base)) > 0) {
+ while ((nbytes = getdents(cf->fd, buf, bufsize)) > 0) {
ebuf = buf + nbytes;
cp = buf;
diff -ur /mnt/usr.bin/cvs/update.c src/usr.bin/cvs/update.c
--- /mnt/usr.bin/cvs/update.c Sun Oct 17 00:50:13 2010
+++ src/usr.bin/cvs/update.c Sun Oct 17 20:25:00 2010
@@ -235,7 +235,6 @@
void
cvs_update_leavedir(struct cvs_file *cf)
{
- long base;
int nbytes;
int isempty;
size_t bufsize;
@@ -272,7 +271,7 @@
if (lseek(cf->fd, 0, SEEK_SET) == -1)
fatal("cvs_update_leavedir: %s", strerror(errno));
- while ((nbytes = getdirentries(cf->fd, buf, bufsize, &base)) > 0) {
+ while ((nbytes = getdents(cf->fd, buf, bufsize)) > 0) {
ebuf = buf + nbytes;
cp = buf;
diff -ur /mnt/usr.bin/diff/diffdir.c src/usr.bin/diff/diffdir.c
--- /mnt/usr.bin/diff/diffdir.c Sun Oct 17 00:50:14 2010
+++ src/usr.bin/diff/diffdir.c Sun Oct 17 20:25:43 2010
@@ -167,7 +167,6 @@
{
char *buf, *ebuf, *cp;
size_t bufsize, have, need;
- long base;
int fd, nbytes, entries;
struct stat sb;
struct dirent **dirlist, *dp;
@@ -201,7 +200,7 @@
ebuf = cp + (ebuf - buf);
buf = cp;
}
- nbytes = getdirentries(fd, ebuf, have, &base);
+ nbytes = getdents(fd, ebuf, have);
if (nbytes == -1) {
warn("%s", path);
xfree(buf);
Comments?
--
Alexander Polakov | plhk.ru