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

Reply via email to