/* Traverse a file hierarchy.
- Copyright (C) 2004-2010 Free Software Foundation, Inc.
+ Copyright (C) 2004-2011 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
# define fchdir __fchdir
# undef open
# define open __open
-# undef opendir
-# define opendir __opendir
# undef readdir
# define readdir __readdir
#else
static int fts_safe_changedir (FTS *, FTSENT *, int, const char *)
internal_function;
-#if GNULIB_FTS
-# include "fts-cycle.c"
-#else
-static bool enter_dir (FTS *fts, FTSENT *ent) { return true; }
-static void leave_dir (FTS *fts, FTSENT *ent) {}
-static bool setup_dir (FTS *fts) { return true; }
-static void free_dir (FTS *fts) {}
-#endif
+#include "fts-cycle.c"
#ifndef MAX
# define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
-#define STREQ(a, b) (strcmp ((a), (b)) == 0)
+#define STREQ(a, b) (strcmp (a, b) == 0)
#define CLR(opt) (sp->fts_options &= ~(opt))
#define ISSET(opt) (sp->fts_options & (opt))
/* FIXME: if others need this function, move it into lib/openat.c */
static inline DIR *
internal_function
-opendirat (int fd, char const *dir)
+opendirat (int fd, char const *dir, int extra_flags, int *pdir_fd)
{
int new_fd = openat (fd, dir,
- O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
+ (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
+ | extra_flags));
DIR *dirp;
if (new_fd < 0)
return NULL;
set_cloexec_flag (new_fd, true);
dirp = fdopendir (new_fd);
- if (dirp == NULL)
+ if (dirp)
+ *pdir_fd = new_fd;
+ else
{
int saved_errno = errno;
close (new_fd);
internal_function
diropen (FTS const *sp, char const *dir)
{
- int open_flags = (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
- | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0));
+ int open_flags = (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
+ | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0)
+ | (ISSET (FTS_NOATIME) ? O_NOATIME : 0));
int fd = (ISSET (FTS_CWDFD)
? openat (sp->fts_cwd_fd, dir, open_flags)
early, doing it here saves us the trouble of ensuring
later (where it'd be messier) that "." can in fact
be opened. If not, revert to FTS_NOCHDIR mode. */
- int fd = open (".", O_RDONLY);
+ int fd = open (".",
+ O_SEARCH | (ISSET (FTS_NOATIME) ? O_NOATIME : 0));
if (fd < 0)
{
/* Even if `.' is unreadable, don't revert to FTS_NOCHDIR mode
fd_ring_clear (&sp->fts_fd_ring);
-#if GNULIB_FTS
if (sp->fts_leaf_optimization_works_ht)
hash_free (sp->fts_leaf_optimization_works_ht);
-#endif
free_dir (sp);
#if defined __linux__ \
&& HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE
-#include <sys/vfs.h>
+# include <sys/vfs.h>
/* Linux-specific constants from coreutils' src/fs.h */
# define S_MAGIC_TMPFS 0x1021994
leaf_optimization_applies (int dir_fd _GL_UNUSED) { return false; }
#endif
-#if GNULIB_FTS
/* link-count-optimization entry:
- map an stat.st_dev number to a boolean: leaf_optimization_works */
+ map a stat.st_dev number to a boolean: leaf_optimization_works */
struct LCO_ent
{
dev_t st_dev;
return opt_ok;
}
-#endif
/*
* Special case of "/" at the end of the file name so that slashes aren't
bool nostat;
size_t len, maxlen, new_len;
char *cp;
+ int dir_fd;
/* Set current node pointer. */
cur = sp->fts_cur;
oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
#else
# define __opendir2(file, flag) \
- ( ! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD) \
- ? opendirat(sp->fts_cwd_fd, file) \
- : opendir(file))
+ opendirat((! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD) \
+ ? sp->fts_cwd_fd : AT_FDCWD), \
+ file, \
+ (((ISSET(FTS_PHYSICAL) \
+ && ! (ISSET(FTS_COMFOLLOW) \
+ && cur->fts_level == FTS_ROOTLEVEL)) \
+ ? O_NOFOLLOW : 0) \
+ | (ISSET (FTS_NOATIME) ? O_NOATIME : 0)), \
+ &dir_fd)
#endif
if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
if (type == BREAD) {
* checking FTS_NS on the returned nodes.
*/
if (nlinks || type == BREAD) {
- int dir_fd = dirfd(dirp);
- if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
+ if (ISSET(FTS_CWDFD))
{
dir_fd = dup (dir_fd);
- set_cloexec_flag (dir_fd, true);
+ if (0 <= dir_fd)
+ set_cloexec_flag (dir_fd, true);
}
if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) {
if (nlinks && type == BREAD)
int fd = i_ring_pop (&fd_w);
if (0 <= fd)
{
- int parent_fd = openat (cwd_fd, "..", O_RDONLY);
+ int parent_fd = openat (cwd_fd, "..", O_SEARCH | O_NOATIME);
if (parent_fd < 0)
{
// Warn?
return (p->fts_level == FTS_ROOTLEVEL ? FTS_D : FTS_DOT);
}
-#if !GNULIB_FTS
- {
- /*
- * Cycle detection is done by brute force when the directory
- * is first encountered. If the tree gets deep enough or the
- * number of symbolic links to directories is high enough,
- * something faster might be worthwhile.
- */
- FTSENT *t;
-
- for (t = p->fts_parent;
- t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
- if (sbp->st_ino == t->fts_statp->st_ino
- && sbp->st_dev == t->fts_statp->st_dev)
- {
- p->fts_cycle = t;
- return (FTS_DC);
- }
- }
-#endif
-
return (FTS_D);
}
if (S_ISLNK(sbp->st_mode))