getgroups: avoid calling exit
[gnulib.git] / lib / fts.c
index ebf66fc..21c6658 100644 (file)
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -71,6 +71,10 @@ static char sccsid[] = "@(#)fts.c    8.6 (Berkeley) 8/14/94";
 # include "fcntl--.h"
 # include "dirent--.h"
 # include "unistd--.h"
+/* FIXME - use fcntl(F_DUPFD_CLOEXEC)/openat(O_CLOEXEC) once they are
+   supported.  */
+# include "cloexec.h"
+# include "openat.h"
 # include "same-inode.h"
 #endif
 
@@ -169,16 +173,6 @@ enum Fts_stat
 # define __set_errno(Val) errno = (Val)
 #endif
 
-#ifndef __attribute__
-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
-#  define __attribute__(x) /* empty */
-# endif
-#endif
-
-#ifndef ATTRIBUTE_UNUSED
-# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-#endif
-
 /* If this host provides the openat function, then we can avoid
    attempting to open "." in some initialization code below.  */
 #ifdef HAVE_OPENAT
@@ -311,6 +305,7 @@ opendirat (int fd, char const *dir)
 
   if (new_fd < 0)
     return NULL;
+  set_cloexec_flag (new_fd, true);
   dirp = fdopendir (new_fd);
   if (dirp == NULL)
     {
@@ -362,9 +357,12 @@ diropen (FTS const *sp, char const *dir)
   int open_flags = (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0));
 
-  return (ISSET (FTS_CWDFD)
-         ? openat (sp->fts_cwd_fd, dir, open_flags)
-         : open (dir, open_flags));
+  int fd = (ISSET (FTS_CWDFD)
+            ? openat (sp->fts_cwd_fd, dir, open_flags)
+            : open (dir, open_flags));
+  if (0 <= fd)
+    set_cloexec_flag (fd, true);
+  return fd;
 }
 
 FTS *
@@ -718,8 +716,10 @@ leaf_optimization_applies (int dir_fd)
 }
 
 #else
-static bool dirent_inode_sort_may_be_useful (int dir_fd) { return true; }
-static bool leaf_optimization_applies (int dir_fd) { return false; }
+static bool
+dirent_inode_sort_may_be_useful (int dir_fd _UNUSED_PARAMETER_) { return true; }
+static bool
+leaf_optimization_applies (int dir_fd _UNUSED_PARAMETER_) { return false; }
 #endif
 
 #if GNULIB_FTS
@@ -1069,7 +1069,7 @@ check_for_dir:
  */
 /* ARGSUSED */
 int
-fts_set(FTS *sp ATTRIBUTE_UNUSED, FTSENT *p, int instr)
+fts_set(FTS *sp _UNUSED_PARAMETER_, FTSENT *p, int instr)
 {
        if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
            instr != FTS_NOINSTR && instr != FTS_SKIP) {
@@ -1268,6 +1268,20 @@ fts_build (register FTS *sp, int type)
          opening it.  */
        if (cur->fts_info == FTS_NSOK)
         cur->fts_info = fts_stat(sp, cur, false);
+       else if (sp->fts_options & FTS_TIGHT_CYCLE_CHECK) {
+               /* Now read the stat info again after opening a directory to
+                * reveal eventual changes caused by a submount triggered by
+                * the traversal.  But do it only for utilities which use
+                * FTS_TIGHT_CYCLE_CHECK.  Therefore, only find and du
+                * benefit/suffer from this feature for now.
+                */
+               LEAVE_DIR (sp, cur, "4");
+               fts_stat (sp, cur, false);
+               if (! enter_dir (sp, cur)) {
+                        __set_errno (ENOMEM);
+                        return NULL;
+               }
+       }
 
        /*
         * Nlinks is the number of possible entries of type directory in the
@@ -1305,7 +1319,10 @@ fts_build (register FTS *sp, int type)
        if (nlinks || type == BREAD) {
                int dir_fd = dirfd(dirp);
                if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
-                 dir_fd = dup (dir_fd);
+                 {
+                   dir_fd = dup (dir_fd);
+                   set_cloexec_flag (dir_fd, true);
+                 }
                if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) {
                        if (nlinks && type == BREAD)
                                cur->fts_errno = errno;