1cf28ed85SJohn Marino /* Traverse a file hierarchy. 2cf28ed85SJohn Marino 3*09d4459fSDaniel Fojt Copyright (C) 2004-2020 Free Software Foundation, Inc. 4cf28ed85SJohn Marino 5cf28ed85SJohn Marino This program is free software: you can redistribute it and/or modify 6cf28ed85SJohn Marino it under the terms of the GNU General Public License as published by 7cf28ed85SJohn Marino the Free Software Foundation; either version 3 of the License, or 8cf28ed85SJohn Marino (at your option) any later version. 9cf28ed85SJohn Marino 10cf28ed85SJohn Marino This program is distributed in the hope that it will be useful, 11cf28ed85SJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of 12cf28ed85SJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13cf28ed85SJohn Marino GNU General Public License for more details. 14cf28ed85SJohn Marino 15cf28ed85SJohn Marino You should have received a copy of the GNU General Public License 16*09d4459fSDaniel Fojt along with this program. If not, see <https://www.gnu.org/licenses/>. */ 17cf28ed85SJohn Marino 18cf28ed85SJohn Marino /* 19cf28ed85SJohn Marino * Copyright (c) 1989, 1993 20cf28ed85SJohn Marino * The Regents of the University of California. All rights reserved. 21cf28ed85SJohn Marino * 22cf28ed85SJohn Marino * Redistribution and use in source and binary forms, with or without 23cf28ed85SJohn Marino * modification, are permitted provided that the following conditions 24cf28ed85SJohn Marino * are met: 25cf28ed85SJohn Marino * 1. Redistributions of source code must retain the above copyright 26cf28ed85SJohn Marino * notice, this list of conditions and the following disclaimer. 27cf28ed85SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright 28cf28ed85SJohn Marino * notice, this list of conditions and the following disclaimer in the 29cf28ed85SJohn Marino * documentation and/or other materials provided with the distribution. 30cf28ed85SJohn Marino * 4. Neither the name of the University nor the names of its contributors 31cf28ed85SJohn Marino * may be used to endorse or promote products derived from this software 32cf28ed85SJohn Marino * without specific prior written permission. 33cf28ed85SJohn Marino * 34cf28ed85SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND 35cf28ed85SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36cf28ed85SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37cf28ed85SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38cf28ed85SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39cf28ed85SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40cf28ed85SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41cf28ed85SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42cf28ed85SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43cf28ed85SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44cf28ed85SJohn Marino * SUCH DAMAGE. 45cf28ed85SJohn Marino * 46cf28ed85SJohn Marino * @(#)fts.h 8.3 (Berkeley) 8/14/94 47cf28ed85SJohn Marino */ 48cf28ed85SJohn Marino 49cf28ed85SJohn Marino #ifndef _FTS_H 50cf28ed85SJohn Marino # define _FTS_H 1 51cf28ed85SJohn Marino 52cf28ed85SJohn Marino # ifdef _LIBC 53cf28ed85SJohn Marino # include <features.h> 54dc7c36e4SJohn Marino # if __STDC_VERSION__ < 199901L 55dc7c36e4SJohn Marino # define __FLEXIBLE_ARRAY_MEMBER 1 56cf28ed85SJohn Marino # else 57dc7c36e4SJohn Marino # define __FLEXIBLE_ARRAY_MEMBER 58dc7c36e4SJohn Marino # endif 59dc7c36e4SJohn Marino # else 60dc7c36e4SJohn Marino # define __FLEXIBLE_ARRAY_MEMBER FLEXIBLE_ARRAY_MEMBER 61cf28ed85SJohn Marino # undef __THROW 62cf28ed85SJohn Marino # define __THROW 63cf28ed85SJohn Marino # undef __BEGIN_DECLS 64cf28ed85SJohn Marino # undef __END_DECLS 65cf28ed85SJohn Marino # ifdef __cplusplus 66cf28ed85SJohn Marino # define __BEGIN_DECLS extern "C" { 67cf28ed85SJohn Marino # define __END_DECLS } 68cf28ed85SJohn Marino # else 69cf28ed85SJohn Marino # define __BEGIN_DECLS 70cf28ed85SJohn Marino # define __END_DECLS 71cf28ed85SJohn Marino # endif 72cf28ed85SJohn Marino # endif 73cf28ed85SJohn Marino 74cf28ed85SJohn Marino # include <stddef.h> 75cf28ed85SJohn Marino # include <sys/types.h> 76cf28ed85SJohn Marino # include <dirent.h> 77cf28ed85SJohn Marino # include <sys/stat.h> 78cf28ed85SJohn Marino # include "i-ring.h" 79cf28ed85SJohn Marino 80cf28ed85SJohn Marino typedef struct { 81cf28ed85SJohn Marino struct _ftsent *fts_cur; /* current node */ 82cf28ed85SJohn Marino struct _ftsent *fts_child; /* linked list of children */ 83cf28ed85SJohn Marino struct _ftsent **fts_array; /* sort array */ 84cf28ed85SJohn Marino dev_t fts_dev; /* starting device # */ 85cf28ed85SJohn Marino char *fts_path; /* file name for this descent */ 86cf28ed85SJohn Marino int fts_rfd; /* fd for root */ 87cf28ed85SJohn Marino int fts_cwd_fd; /* the file descriptor on which the 88cf28ed85SJohn Marino virtual cwd is open, or AT_FDCWD */ 89cf28ed85SJohn Marino size_t fts_pathlen; /* sizeof(path) */ 90cf28ed85SJohn Marino size_t fts_nitems; /* elements in the sort array */ 91cf28ed85SJohn Marino int (*fts_compar) (struct _ftsent const **, struct _ftsent const **); 92cf28ed85SJohn Marino /* compare fn */ 93cf28ed85SJohn Marino 94cf28ed85SJohn Marino # define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */ 95cf28ed85SJohn Marino # define FTS_LOGICAL 0x0002 /* logical walk */ 96cf28ed85SJohn Marino # define FTS_NOCHDIR 0x0004 /* don't change directories */ 97cf28ed85SJohn Marino # define FTS_NOSTAT 0x0008 /* don't get stat info */ 98cf28ed85SJohn Marino # define FTS_PHYSICAL 0x0010 /* physical walk */ 99cf28ed85SJohn Marino # define FTS_SEEDOT 0x0020 /* return dot and dot-dot */ 100cf28ed85SJohn Marino # define FTS_XDEV 0x0040 /* don't cross devices */ 101cf28ed85SJohn Marino # define FTS_WHITEOUT 0x0080 /* return whiteout information */ 102cf28ed85SJohn Marino 103cf28ed85SJohn Marino /* There are two ways to detect cycles. 104cf28ed85SJohn Marino The lazy way (which works only with FTS_PHYSICAL), 105cf28ed85SJohn Marino with which one may process a directory that is a 106cf28ed85SJohn Marino part of the cycle several times before detecting the cycle. 107cf28ed85SJohn Marino The "tight" way, whereby fts uses more memory (proportional 108cf28ed85SJohn Marino to number of "active" directories, aka distance from root 109cf28ed85SJohn Marino of current tree to current directory -- see active_dir_ht) 110cf28ed85SJohn Marino to detect any cycle right away. For example, du must use 111cf28ed85SJohn Marino this option to avoid counting disk space in a cycle multiple 112cf28ed85SJohn Marino times, but chown -R need not. 113cf28ed85SJohn Marino The default is to use the constant-memory lazy way, when possible 114cf28ed85SJohn Marino (see below). 115cf28ed85SJohn Marino 116cf28ed85SJohn Marino However, with FTS_LOGICAL (when following symlinks, e.g., chown -L) 117cf28ed85SJohn Marino using lazy cycle detection is inadequate. For example, traversing 118cf28ed85SJohn Marino a directory containing a symbolic link to a peer directory, it is 119cf28ed85SJohn Marino possible to encounter the same directory twice even though there 120cf28ed85SJohn Marino is no cycle: 121cf28ed85SJohn Marino dir 122cf28ed85SJohn Marino ... 123cf28ed85SJohn Marino slink -> dir 124cf28ed85SJohn Marino So, when FTS_LOGICAL is selected, we have to use a different 125cf28ed85SJohn Marino mode of cycle detection: FTS_TIGHT_CYCLE_CHECK. */ 126cf28ed85SJohn Marino # define FTS_TIGHT_CYCLE_CHECK 0x0100 127cf28ed85SJohn Marino 128cf28ed85SJohn Marino /* Use this flag to enable semantics with which the parent 129cf28ed85SJohn Marino application may be made both more efficient and more robust. 130cf28ed85SJohn Marino Whereas the default is to visit each directory in a recursive 131cf28ed85SJohn Marino traversal (via chdir), using this flag makes it so the initial 132cf28ed85SJohn Marino working directory is never changed. Instead, these functions 133cf28ed85SJohn Marino perform the traversal via a virtual working directory, maintained 134cf28ed85SJohn Marino through the file descriptor member, fts_cwd_fd. */ 135cf28ed85SJohn Marino # define FTS_CWDFD 0x0200 136cf28ed85SJohn Marino 137cf28ed85SJohn Marino /* Historically, for each directory that fts initially encounters, it would 138cf28ed85SJohn Marino open it, read all entries, and stat each entry, storing the results, and 139cf28ed85SJohn Marino then it would process the first entry. But that behavior is bad for 140cf28ed85SJohn Marino locality of reference, and also causes trouble with inode-simulating 141cf28ed85SJohn Marino file systems like FAT, CIFS, FUSE-based ones, etc., when entries from 142cf28ed85SJohn Marino their name/inode cache are flushed too early. 143cf28ed85SJohn Marino Use this flag to make fts_open and fts_read defer the stat/lstat/fststat 144cf28ed85SJohn Marino of each entry until it is actually processed. However, note that if you 145cf28ed85SJohn Marino use this option and also specify a comparison function, that function may 146cf28ed85SJohn Marino not examine any data via fts_statp. However, when fts_statp->st_mode is 147cf28ed85SJohn Marino nonzero, the S_IFMT type bits are valid, with mapped dirent.d_type data. 148cf28ed85SJohn Marino Of course, that happens only on file systems that provide useful 149cf28ed85SJohn Marino dirent.d_type data. */ 150cf28ed85SJohn Marino # define FTS_DEFER_STAT 0x0400 151cf28ed85SJohn Marino 152680a9cb8SJohn Marino /* Use this flag to disable stripping of trailing slashes 153680a9cb8SJohn Marino from input path names during fts_open initialization. */ 154*09d4459fSDaniel Fojt # define FTS_VERBATIM 0x0800 155cf28ed85SJohn Marino 156*09d4459fSDaniel Fojt # define FTS_OPTIONMASK 0x0fff /* valid user option mask */ 157680a9cb8SJohn Marino 158*09d4459fSDaniel Fojt # define FTS_NAMEONLY 0x1000 /* (private) child names only */ 159*09d4459fSDaniel Fojt # define FTS_STOP 0x2000 /* (private) unrecoverable error */ 160cf28ed85SJohn Marino int fts_options; /* fts_open options, global flags */ 161cf28ed85SJohn Marino 162cf28ed85SJohn Marino /* Map a directory's device number to a boolean. The boolean is 163cf28ed85SJohn Marino true if for that file system (type determined by a single fstatfs 164cf28ed85SJohn Marino call per FS) st_nlink can be used to calculate the number of 165cf28ed85SJohn Marino sub-directory entries in a directory. 166cf28ed85SJohn Marino Using this table is an optimization that permits us to look up 167cf28ed85SJohn Marino file system type on a per-inode basis at the minimal cost of 168cf28ed85SJohn Marino calling fstatfs only once per traversed device. */ 169cf28ed85SJohn Marino struct hash_table *fts_leaf_optimization_works_ht; 170cf28ed85SJohn Marino 171cf28ed85SJohn Marino union { 172cf28ed85SJohn Marino /* This data structure is used if FTS_TIGHT_CYCLE_CHECK is 173cf28ed85SJohn Marino specified. It records the directories between a starting 174cf28ed85SJohn Marino point and the current directory. I.e., a directory is 175cf28ed85SJohn Marino recorded here IFF we have visited it once, but we have not 176cf28ed85SJohn Marino yet completed processing of all its entries. Every time we 177cf28ed85SJohn Marino visit a new directory, we add that directory to this set. 178cf28ed85SJohn Marino When we finish with a directory (usually by visiting it a 179cf28ed85SJohn Marino second time), we remove it from this set. Each entry in 180cf28ed85SJohn Marino this data structure is a device/inode pair. This data 181cf28ed85SJohn Marino structure is used to detect directory cycles efficiently and 182cf28ed85SJohn Marino promptly even when the depth of a hierarchy is in the tens 183cf28ed85SJohn Marino of thousands. */ 184cf28ed85SJohn Marino struct hash_table *ht; 185cf28ed85SJohn Marino 186cf28ed85SJohn Marino /* FIXME: rename these two members to have the fts_ prefix */ 187cf28ed85SJohn Marino /* This data structure uses a lazy cycle-detection algorithm, 188cf28ed85SJohn Marino as done by rm via cycle-check.c. It's the default, 189cf28ed85SJohn Marino but it's not appropriate for programs like du. */ 190cf28ed85SJohn Marino struct cycle_check_state *state; 191cf28ed85SJohn Marino } fts_cycle; 192cf28ed85SJohn Marino 193cf28ed85SJohn Marino /* A stack of the file descriptors corresponding to the 194cf28ed85SJohn Marino most-recently traversed parent directories. 195cf28ed85SJohn Marino Currently used only in FTS_CWDFD mode. */ 196cf28ed85SJohn Marino I_ring fts_fd_ring; 197cf28ed85SJohn Marino } FTS; 198cf28ed85SJohn Marino 199cf28ed85SJohn Marino typedef struct _ftsent { 200cf28ed85SJohn Marino struct _ftsent *fts_cycle; /* cycle node */ 201cf28ed85SJohn Marino struct _ftsent *fts_parent; /* parent directory */ 202cf28ed85SJohn Marino struct _ftsent *fts_link; /* next file in directory */ 203cf28ed85SJohn Marino DIR *fts_dirp; /* Dir pointer for any directory 204cf28ed85SJohn Marino containing more entries than we 205cf28ed85SJohn Marino read at one time. */ 206cf28ed85SJohn Marino long fts_number; /* local numeric value */ 207cf28ed85SJohn Marino void *fts_pointer; /* local address value */ 208cf28ed85SJohn Marino char *fts_accpath; /* access file name */ 209cf28ed85SJohn Marino char *fts_path; /* root name; == fts_fts->fts_path */ 210cf28ed85SJohn Marino int fts_errno; /* errno for this node */ 211cf28ed85SJohn Marino int fts_symfd; /* fd for symlink */ 212cf28ed85SJohn Marino size_t fts_pathlen; /* strlen(fts_path) */ 213cf28ed85SJohn Marino 214cf28ed85SJohn Marino FTS *fts_fts; /* the file hierarchy itself */ 215cf28ed85SJohn Marino 216cf28ed85SJohn Marino # define FTS_ROOTPARENTLEVEL (-1) 217cf28ed85SJohn Marino # define FTS_ROOTLEVEL 0 218cf28ed85SJohn Marino ptrdiff_t fts_level; /* depth (-1 to N) */ 219cf28ed85SJohn Marino 220cf28ed85SJohn Marino size_t fts_namelen; /* strlen(fts_name) */ 221*09d4459fSDaniel Fojt 222*09d4459fSDaniel Fojt /* If not (nlink_t) -1, an upper bound on the number of 223*09d4459fSDaniel Fojt remaining subdirectories of interest. If this becomes 224*09d4459fSDaniel Fojt zero, some work can be avoided. */ 225*09d4459fSDaniel Fojt nlink_t fts_n_dirs_remaining; 226cf28ed85SJohn Marino 227cf28ed85SJohn Marino # define FTS_D 1 /* preorder directory */ 228cf28ed85SJohn Marino # define FTS_DC 2 /* directory that causes cycles */ 229cf28ed85SJohn Marino # define FTS_DEFAULT 3 /* none of the above */ 230cf28ed85SJohn Marino # define FTS_DNR 4 /* unreadable directory */ 231cf28ed85SJohn Marino # define FTS_DOT 5 /* dot or dot-dot */ 232cf28ed85SJohn Marino # define FTS_DP 6 /* postorder directory */ 233cf28ed85SJohn Marino # define FTS_ERR 7 /* error; errno is set */ 234cf28ed85SJohn Marino # define FTS_F 8 /* regular file */ 235cf28ed85SJohn Marino # define FTS_INIT 9 /* initialized only */ 236cf28ed85SJohn Marino # define FTS_NS 10 /* stat(2) failed */ 237cf28ed85SJohn Marino # define FTS_NSOK 11 /* no stat(2) requested */ 238cf28ed85SJohn Marino # define FTS_SL 12 /* symbolic link */ 239cf28ed85SJohn Marino # define FTS_SLNONE 13 /* symbolic link without target */ 240cf28ed85SJohn Marino # define FTS_W 14 /* whiteout object */ 241cf28ed85SJohn Marino unsigned short int fts_info; /* user flags for FTSENT structure */ 242cf28ed85SJohn Marino 243cf28ed85SJohn Marino # define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ 244cf28ed85SJohn Marino # define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ 245cf28ed85SJohn Marino unsigned short int fts_flags; /* private flags for FTSENT structure */ 246cf28ed85SJohn Marino 247cf28ed85SJohn Marino # define FTS_AGAIN 1 /* read node again */ 248cf28ed85SJohn Marino # define FTS_FOLLOW 2 /* follow symbolic link */ 249cf28ed85SJohn Marino # define FTS_NOINSTR 3 /* no instructions */ 250cf28ed85SJohn Marino # define FTS_SKIP 4 /* discard node */ 251cf28ed85SJohn Marino unsigned short int fts_instr; /* fts_set() instructions */ 252cf28ed85SJohn Marino 253cf28ed85SJohn Marino struct stat fts_statp[1]; /* stat(2) information */ 254dc7c36e4SJohn Marino char fts_name[__FLEXIBLE_ARRAY_MEMBER]; /* file name */ 255cf28ed85SJohn Marino } FTSENT; 256cf28ed85SJohn Marino 257cf28ed85SJohn Marino #ifndef __GNUC_PREREQ 258cf28ed85SJohn Marino # if defined __GNUC__ && defined __GNUC_MINOR__ 259cf28ed85SJohn Marino # define __GNUC_PREREQ(maj, min) \ 260cf28ed85SJohn Marino ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) 261cf28ed85SJohn Marino # else 262cf28ed85SJohn Marino # define __GNUC_PREREQ(maj, min) 0 263cf28ed85SJohn Marino # endif 264cf28ed85SJohn Marino #endif 265cf28ed85SJohn Marino 266cf28ed85SJohn Marino #if __GNUC_PREREQ (3,4) 267cf28ed85SJohn Marino # undef __attribute_warn_unused_result__ 268cf28ed85SJohn Marino # define __attribute_warn_unused_result__ \ 269cf28ed85SJohn Marino __attribute__ ((__warn_unused_result__)) 270cf28ed85SJohn Marino #else 271cf28ed85SJohn Marino # define __attribute_warn_unused_result__ /* empty */ 272cf28ed85SJohn Marino #endif 273cf28ed85SJohn Marino 274cf28ed85SJohn Marino __BEGIN_DECLS 275cf28ed85SJohn Marino FTSENT *fts_children (FTS *, int) __THROW __attribute_warn_unused_result__; 276cf28ed85SJohn Marino int fts_close (FTS *) __THROW __attribute_warn_unused_result__; 277cf28ed85SJohn Marino FTS *fts_open (char * const *, int, 278cf28ed85SJohn Marino int (*)(const FTSENT **, const FTSENT **)) 279cf28ed85SJohn Marino __THROW __attribute_warn_unused_result__; 280cf28ed85SJohn Marino FTSENT *fts_read (FTS *) __THROW __attribute_warn_unused_result__; 281cf28ed85SJohn Marino int fts_set (FTS *, FTSENT *, int) __THROW; 282cf28ed85SJohn Marino __END_DECLS 283cf28ed85SJohn Marino 284cf28ed85SJohn Marino #endif /* fts.h */ 285