Ignore my previous post, I was tired and forgot about dup(). How about
something like this? (attached)

I only tested this on Ubuntu, I don't have an OS X machine. I still went
with readdir_r because the AIX and Solaris man pages for readdir were
vague about its behavior when called from multiple threads (glibc, musl,
FreeBSD look pretty safe).

Cheers,
David

On Sat, Apr 8, 2017, at 03:27 AM, David Arroyo wrote:
> This should be doable with some combination of fdopendir(3) and
> readdir(3). I'm not sure how to avoid leaking memory through the
> returned DIR pointer and any memory allocated with by readdir(3).
> This is usually free'd by closedir(3), which we can't use without
> closing the underlying file.
> 
> It should be OK to use free() on the return value of fdopendir, and
> stick to the uglier readdir_r(3) interface. I can definitely see why
> Russ went with  the simpler  system-specific interfaces on this.
> 
> David
> 
> On Sat, Apr 8, 2017, at 02:46 AM, Ori Bernstein wrote:
> > On Sat, 8 Apr 2017 15:21:47 +0900, arisawa <karis...@gmail.com> wrote:
> > 
> > > but how to?
> > > 
> > > unix doesn’t have something like fdreaddir(int fd).
> > > my guess: russ unwillingly used a low level function such as
> > > int getdirentries(int fd, char *buf, int nbytes, long *basep).
> > > 
> > > readdirall() might be OK in regular usage.
> > 
> > I don't use OSX regularly, although I do maintain the syscall
> > layer for Myrddin on it.
> > 
> > Getdirentries64 exists, and rudimentary testing doesn't show
> > any difficulties with using it.
> > 
> > -- 
> >     Ori Bernstein
> > 
> 
diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c
index 40fbe3c..6c00dff 100644
--- a/src/lib9/dirread.c
+++ b/src/lib9/dirread.c
@@ -3,54 +3,46 @@
 #include <libc.h>
 #include <sys/stat.h>
 #include <dirent.h>
+#include <errno.h>
 
 extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
 
-#if defined(__linux__)
+#if defined(__DragonFly__)
+static inline int d_reclen(struct dirent *de) { return _DIRENT_DIRSIZ(de); }
+#else
+static inline int d_reclen(struct dirent *de) { return de->d_reclen; }
+#endif
+
 static int
 mygetdents(int fd, struct dirent *buf, int n)
 {
-       off_t off;
-       int nn;
+       int err, nn;
+       DIR *dirp;
+       
+       /* use to calculate max size of a dirent */
+       struct dirent de;
+       int max_sz = (sizeof de - sizeof de.d_name) + NAME_MAX + 1;
+
+       if ((dirp = fdopendir(dup(fd))) == nil)
+               return -1;
 
-       /* This doesn't match the man page, but it works in Debian with a 2.2 
kernel */
-       off = p9seek(fd, 0, 1);
-       nn = getdirentries(fd, (void*)buf, n, &off);
+       nn = 0;
+       while(n >= max_sz){
+               if ((err = readdir_r(dirp, buf, &buf)) != 0){
+                       errno = err;
+                       if(nn == 0)
+                               nn = -1;
+                       break;
+               }
+               if (buf == nil)
+                       break;
+               nn += d_reclen(buf);
+               n -= d_reclen(buf);
+               buf = ((char*)buf) + d_reclen(buf);
+       }
+       closedir(dirp);
        return nn;
 }
-#elif defined(__APPLE__) 
-static int
-mygetdents(int fd, struct dirent *buf, int n)
-{
-       long off;
-       return getdirentries(fd, (void*)buf, n, &off);
-}
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
-static int
-mygetdents(int fd, struct dirent *buf, int n)
-{
-       off_t off;
-       return getdirentries(fd, (void*)buf, n, &off);
-}
-#elif defined(__sun__) || defined(__NetBSD__) || defined(__OpenBSD__)
-static int
-mygetdents(int fd, struct dirent *buf, int n)
-{
-       return getdents(fd, (void*)buf, n);
-}
-#elif defined(__AIX__)
-static int
-mygetdents(int fd, struct dirent *buf, int n)
-{
-       return getdirent(fd, (void*)buf, n);
-}
-#endif
-
-#if defined(__DragonFly__)
-static inline int d_reclen(struct dirent *de) { return _DIRENT_DIRSIZ(de); }
-#else
-static inline int d_reclen(struct dirent *de) { return de->d_reclen; }
-#endif
 
 static int
 countde(char *p, int n)

Reply via email to