changeset 15529:894e5e6ae541

fts: add/use new struct member, fts_dirp We are about to use this to manage any directory with too many entries to read all of them into memory at once. To do that, we'll need to save the DIR* pointer in each affected FTSENT struct. * lib/fts_.h: Include <dirent.h>. (struct FTSENT) [fts_dirp]: New member. * lib/fts.c (closedir_and_clear): Define. Use it in place of closedir so that we are sure to clear the new fts_dirp member when done with it. (fts_alloc): Initialize the new member. (fts_lfree): Free, if needed.
author Jim Meyering <meyering@redhat.com>
date Wed, 17 Aug 2011 09:20:41 +0200
parents 8203b056cc79
children ddc76c261e25
files ChangeLog lib/fts.c lib/fts_.h
diffstat 3 files changed, 38 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
 2011-08-19  Jim Meyering  <meyering@redhat.com>
 
+	fts: add/use new struct member, fts_dirp
+	We are about to use this to manage any directory with
+	too many entries to read all of them into memory at once.
+	To do that, we'll need to save the DIR* pointer in each
+	affected FTSENT struct.
+	* lib/fts_.h: Include <dirent.h>.
+	(struct FTSENT) [fts_dirp]: New member.
+	* lib/fts.c (closedir_and_clear): Define.
+	Use it in place of closedir so that we are sure to
+	clear the new fts_dirp member when done with it.
+	(fts_alloc): Initialize the new member.
+	(fts_lfree): Free, if needed.
+
 	maint: fts: give __opendir2 a new parameter and rename
 	* lib/fts.c (__opendir2): Give it a new parameter, Pdir_fd, rather
 	than surreptitiously using sole caller's "dir_fd".
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -1192,6 +1192,14 @@
   st->st_mode = type;
 }
 
+#define closedir_and_clear(dirp)                \
+  do                                            \
+    {                                           \
+      closedir (dirp);                          \
+      dirp = NULL;                              \
+    }                                           \
+  while (0)
+
 #define fts_opendir(file, Pdir_fd)                              \
         opendirat((! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD)     \
                    ? sp->fts_cwd_fd : AT_FDCWD),                \
@@ -1224,8 +1232,7 @@
         register struct dirent *dp;
         register FTSENT *p, *head;
         register size_t nitems;
-        FTSENT *cur, *tail;
-        DIR *dirp;
+        FTSENT *tail;
         void *oldaddr;
         int saved_errno;
         bool descend;
@@ -1236,13 +1243,11 @@
         size_t len, maxlen, new_len;
         char *cp;
         int dir_fd;
-
-        /* Set current node pointer. */
-        cur = sp->fts_cur;
+        FTSENT *cur = sp->fts_cur;
 
         /* Open the directory for reading.  If this fails, we're done.
            If being called from fts_read, set the fts_info field.  */
-        if ((dirp = fts_opendir(cur->fts_accpath, &dir_fd)) == NULL) {
+        if ((cur->fts_dirp = fts_opendir(cur->fts_accpath, &dir_fd)) == NULL) {
                 if (type == BREAD) {
                         cur->fts_info = FTS_DNR;
                         cur->fts_errno = errno;
@@ -1313,10 +1318,10 @@
                                 cur->fts_errno = errno;
                         cur->fts_flags |= FTS_DONTCHDIR;
                         descend = false;
-                        closedir(dirp);
+                        closedir_and_clear(cur->fts_dirp);
                         if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
                                 close (dir_fd);
-                        dirp = NULL;
+                        cur->fts_dirp = NULL;
                 } else
                         descend = true;
         } else
@@ -1347,7 +1352,7 @@
 
         /* Read the directory, attaching each entry to the `link' pointer. */
         doadjust = false;
-        for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
+        for (head = tail = NULL, nitems = 0; cur->fts_dirp && (dp = readdir(cur->fts_dirp));) {
                 bool is_dir;
 
                 if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
@@ -1368,7 +1373,7 @@
 mem1:                           saved_errno = errno;
                                 free(p);
                                 fts_lfree(head);
-                                closedir(dirp);
+                                closedir_and_clear(cur->fts_dirp);
                                 cur->fts_info = FTS_ERR;
                                 SET(FTS_STOP);
                                 __set_errno (saved_errno);
@@ -1393,7 +1398,7 @@
                          */
                         free(p);
                         fts_lfree(head);
-                        closedir(dirp);
+                        closedir_and_clear(cur->fts_dirp);
                         cur->fts_info = FTS_ERR;
                         SET(FTS_STOP);
                         __set_errno (ENAMETOOLONG);
@@ -1459,8 +1464,8 @@
                 }
                 ++nitems;
         }
-        if (dirp)
-                closedir(dirp);
+        if (cur->fts_dirp)
+                closedir_and_clear(cur->fts_dirp);
 
         /*
          * If realloc() changed the address of the file name, adjust the
@@ -1803,6 +1808,7 @@
         p->fts_fts = sp;
         p->fts_path = sp->fts_path;
         p->fts_errno = 0;
+        p->fts_dirp = NULL;
         p->fts_flags = 0;
         p->fts_instr = FTS_NOINSTR;
         p->fts_number = 0;
@@ -1819,6 +1825,8 @@
         /* Free a linked list of structures. */
         while ((p = head)) {
                 head = head->fts_link;
+                if (p->fts_dirp)
+                        closedir (p->fts_dirp);
                 free(p);
         }
 }
--- a/lib/fts_.h
+++ b/lib/fts_.h
@@ -67,6 +67,7 @@
 
 # include <stddef.h>
 # include <sys/types.h>
+# include <dirent.h>
 # include <sys/stat.h>
 # include "i-ring.h"
 
@@ -191,6 +192,9 @@
         struct _ftsent *fts_cycle;      /* cycle node */
         struct _ftsent *fts_parent;     /* parent directory */
         struct _ftsent *fts_link;       /* next file in directory */
+        DIR *fts_dirp;                  /* Dir pointer for any directory
+                                           containing more entries than we
+                                           read at one time.  */
         long fts_number;                /* local numeric value */
         void *fts_pointer;              /* local address value */
         char *fts_accpath;              /* access file name */