The following reply was made to PR system/6477; it has been noted by GNATS.
From: Alexander Polakov <[email protected]> To: [email protected], [email protected] Cc: Subject: Re: system/6477: NFS directory listing incomplete Date: Wed, 20 Oct 2010 02:04:32 +0400 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
