X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ffts.c;h=4d07d0969295b873db27f726b0b1945e9ee96e6c;hb=1062e7a84e38a0e708fa3a7de81bba8ad45a2d45;hp=1daf69c3059a947ae32dc7a62b15a5e62fa49b4f;hpb=0971365ee6f6638cbeec77db08fbdfe5f3bab53d;p=gnulib.git diff --git a/lib/fts.c b/lib/fts.c index 1daf69c30..4d07d0969 100644 --- a/lib/fts.c +++ b/lib/fts.c @@ -1,6 +1,6 @@ /* 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 @@ -160,8 +160,6 @@ enum Fts_stat # define fchdir __fchdir # undef open # define open __open -# undef opendir -# define opendir __opendir # undef readdir # define readdir __readdir #else @@ -290,7 +288,7 @@ fts_set_stat_required (FTSENT *p, bool required) /* FIXME: if others need this function, move it into lib/openat.c */ static inline DIR * internal_function -opendirat (int fd, char const *dir, int extra_flags) +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 @@ -301,7 +299,9 @@ opendirat (int fd, char const *dir, int extra_flags) 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); @@ -349,7 +349,8 @@ internal_function diropen (FTS const *sp, char const *dir) { int open_flags = (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK - | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0)); + | (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) @@ -406,7 +407,8 @@ fts_open (char * const *argv, 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_SEARCH); + 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 @@ -628,7 +630,7 @@ fts_close (FTS *sp) #if defined __linux__ \ && HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE -#include +# include /* Linux-specific constants from coreutils' src/fs.h */ # define S_MAGIC_TMPFS 0x1021994 @@ -710,7 +712,7 @@ leaf_optimization_applies (int dir_fd _GL_UNUSED) { return false; } #endif /* 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; @@ -1190,6 +1192,25 @@ set_stat_type (struct stat *st, unsigned int dtype) 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), \ + file, \ + (((ISSET(FTS_PHYSICAL) \ + && ! (ISSET(FTS_COMFOLLOW) \ + && cur->fts_level == FTS_ROOTLEVEL)) \ + ? O_NOFOLLOW : 0) \ + | (ISSET (FTS_NOATIME) ? O_NOATIME : 0)), \ + Pdir_fd) + /* * This is the tricky part -- do not casually change *anything* in here. The * idea is to build the linked list of entries that are used by fts_children @@ -1211,8 +1232,7 @@ fts_build (register FTS *sp, int type) 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; @@ -1222,61 +1242,42 @@ fts_build (register FTS *sp, int type) bool nostat; size_t len, maxlen, new_len; char *cp; + int dir_fd; + FTSENT *cur = sp->fts_cur; - /* Set current node pointer. */ - 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 defined FTS_WHITEOUT && 0 - if (ISSET(FTS_WHITEOUT)) - oflag = DTF_NODUP|DTF_REWIND; - else - oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; -#else -# define __opendir2(file, flag) \ - ( ! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD) \ - ? opendirat(sp->fts_cwd_fd, file, \ - ((ISSET(FTS_PHYSICAL) \ - && ! (cur->fts_level == FTS_ROOTLEVEL \ - && ISSET(FTS_COMFOLLOW))) \ - ? O_NOFOLLOW : 0)) \ - : opendir(file)) -#endif - if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + /* Open the directory for reading. If this fails, we're done. + If being called from fts_read, set the fts_info field. */ + if ((cur->fts_dirp = fts_opendir(cur->fts_accpath, &dir_fd)) == NULL) { if (type == BREAD) { cur->fts_info = FTS_DNR; cur->fts_errno = errno; } return (NULL); } - /* Rather than calling fts_stat for each and every entry encountered - in the readdir loop (below), stat each directory only right after - 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; - } - } + /* Rather than calling fts_stat for each and every entry encountered + in the readdir loop (below), stat each directory only right after + 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 - * directory if we're cheating on stat calls, 0 if we're not doing - * any stat calls at all, (nlink_t) -1 if we're statting everything. - */ + /* Nlinks is the number of possible entries of type directory in the + directory if we're cheating on stat calls, 0 if we're not doing + any stat calls at all, (nlink_t) -1 if we're statting everything. */ if (type == BNAMES) { nlinks = 0; /* Be quiet about nostat, GCC. */ @@ -1306,8 +1307,7 @@ fts_build (register FTS *sp, int type) * 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); if (0 <= dir_fd) @@ -1318,10 +1318,10 @@ fts_build (register FTS *sp, int type) 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 @@ -1352,7 +1352,7 @@ fts_build (register FTS *sp, int type) /* 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)) @@ -1373,7 +1373,7 @@ fts_build (register FTS *sp, int type) 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); @@ -1398,7 +1398,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 (ENAMETOOLONG); @@ -1408,10 +1408,6 @@ mem1: saved_errno = errno; p->fts_parent = sp->fts_cur; p->fts_pathlen = new_len; -#if defined FTS_WHITEOUT && 0 - if (dp->d_type == DT_WHT) - p->fts_flags |= FTS_ISW; -#endif /* Store dirent.d_ino, in case we need to sort entries before processing them. */ p->fts_statp->st_ino = D_INO (dp); @@ -1468,8 +1464,8 @@ mem1: saved_errno = errno; } ++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 @@ -1652,7 +1648,7 @@ fd_ring_check (FTS const *sp) int fd = i_ring_pop (&fd_w); if (0 <= fd) { - int parent_fd = openat (cwd_fd, "..", O_SEARCH); + int parent_fd = openat (cwd_fd, "..", O_SEARCH | O_NOATIME); if (parent_fd < 0) { // Warn? @@ -1686,15 +1682,6 @@ fts_stat(FTS *sp, register FTSENT *p, bool follow) if (p->fts_level == FTS_ROOTLEVEL && ISSET(FTS_COMFOLLOW)) follow = true; -#if defined FTS_WHITEOUT && 0 - /* check for whiteout */ - if (p->fts_flags & FTS_ISW) { - memset(sbp, '\0', sizeof (*sbp)); - sbp->st_mode = S_IFWHT; - return (FTS_W); - } -#endif - /* * If doing a logical walk, or application requested FTS_FOLLOW, do * a stat(2). If that fails, check for a non-existent symlink. If @@ -1821,6 +1808,7 @@ fts_alloc (FTS *sp, const char *name, register size_t namelen) 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; @@ -1837,6 +1825,8 @@ fts_lfree (register FTSENT *head) /* Free a linked list of structures. */ while ((p = head)) { head = head->fts_link; + if (p->fts_dirp) + closedir (p->fts_dirp); free(p); } }