xref: /dflybsd-src/contrib/grep/lib/fts_.h (revision 91b9ed38d3db6a8a8ac5b66da1d43e6e331e259a)
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