When checking to see if a filesystem has changed state, use an
[findutils.git] / find / find.c
blob37898488c7055061ecba2245e29bf33ec3a4c5af
1 /* find -- search for files in a directory hierarchy
2 Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA.*/
19 /* GNU find was written by Eric Decker <cire@cisco.com>,
20 with enhancements by David MacKenzie <djm@gnu.ai.mit.edu>,
21 Jay Plett <jay@silence.princeton.nj.us>,
22 and Tim Wood <axolotl!tim@toad.com>.
23 The idea for -print0 and xargs -0 came from
24 Dan Bernstein <brnstnd@kramden.acf.nyu.edu>. */
26 #include "defs.h"
28 #include <errno.h>
29 #include <assert.h>
32 #ifdef HAVE_FCNTL_H
33 #include <fcntl.h>
34 #else
35 #include <sys/file.h>
36 #endif
37 #include "../gnulib/lib/human.h"
38 #include "../gnulib/lib/canonicalize.h"
39 #include <modetype.h>
40 #include "../gnulib/lib/savedir.h"
42 #ifdef HAVE_LOCALE_H
43 #include <locale.h>
44 #endif
46 #if ENABLE_NLS
47 # include <libintl.h>
48 # define _(Text) gettext (Text)
49 #else
50 # define _(Text) Text
51 #define textdomain(Domain)
52 #define bindtextdomain(Package, Directory)
53 #endif
54 #ifdef gettext_noop
55 # define N_(String) gettext_noop (String)
56 #else
57 /* See locate.c for explanation as to why not use (String) */
58 # define N_(String) String
59 #endif
61 #define apply_predicate(pathname, stat_buf_ptr, node) \
62 (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
65 static void init_mount_point_list(void);
66 static void process_top_path PARAMS((char *pathname));
67 static int process_path PARAMS((char *pathname, char *name, boolean leaf, char *parent));
68 static void process_dir PARAMS((char *pathname, char *name, int pathlen, struct stat *statp, char *parent));
69 #if 0
70 static boolean no_side_effects PARAMS((struct predicate *pred));
71 #endif
72 static boolean default_prints PARAMS((struct predicate *pred));
74 /* Name this program was run with. */
75 char *program_name;
77 /* All predicates for each path to process. */
78 struct predicate *predicates;
80 /* The last predicate allocated. */
81 struct predicate *last_pred;
83 /* The root of the evaluation tree. */
84 static struct predicate *eval_tree;
86 /* If true, process directory before contents. True unless -depth given. */
87 boolean do_dir_first;
89 /* If >=0, don't descend more than this many levels of subdirectories. */
90 int maxdepth;
92 /* If >=0, don't process files above this level. */
93 int mindepth;
95 /* Current depth; 0 means current path is a command line arg. */
96 int curdepth;
98 /* Output block size. */
99 int output_block_size;
101 /* Time at start of execution. */
102 time_t start_time;
104 /* Seconds between 00:00 1/1/70 and either one day before now
105 (the default), or the start of today (if -daystart is given). */
106 time_t cur_day_start;
108 /* If true, cur_day_start has been adjusted to the start of the day. */
109 boolean full_days;
111 /* If true, do not assume that files in directories with nlink == 2
112 are non-directories. */
113 boolean no_leaf_check;
115 /* If true, don't cross filesystem boundaries. */
116 boolean stay_on_filesystem;
118 /* If true, don't descend past current directory.
119 Can be set by -prune, -maxdepth, and -xdev/-mount. */
120 boolean stop_at_current_level;
122 /* The full path of the initial working directory, or "." if
123 STARTING_DESC is nonnegative. */
124 char const *starting_dir = ".";
126 /* A file descriptor open to the initial working directory.
127 Doing it this way allows us to work when the i.w.d. has
128 unreadable parents. */
129 int starting_desc;
131 /* The stat buffer of the initial working directory. */
132 struct stat starting_stat_buf;
134 /* If true, we have called stat on the current path. */
135 boolean have_stat;
137 /* The file being operated on, relative to the current directory.
138 Used for stat, readlink, remove, and opendir. */
139 char *rel_pathname;
141 /* Length of current path. */
142 int path_length;
144 /* true if following symlinks. Should be consistent with xstat. */
145 /* boolean dereference; */
146 enum SymlinkOption symlink_handling;
149 /* Pointer to the function used to stat files. */
150 int (*xstat) ();
152 /* Status value to return to system. */
153 int exit_status;
155 /* If true, we ignore the problem where we find that a directory entry
156 * no longer exists by the time we get around to processing it.
158 boolean ignore_readdir_race;
161 /* If true, we issue warning messages
163 boolean warnings;
166 enum TraversalDirection
168 TraversingUp,
169 TraversingDown
173 /* optionh_stat() implements the stat operation when the -H option is
174 * in effect.
176 * If the item to be examined is a command-line argument, we follow
177 * symbolic links. If the stat() call fails on the command-line item,
178 * we fall back on the properties of the symbolic link.
180 * If the item to be examined is not a command-line argument, we
181 * examine the link itself.
183 int
184 optionh_stat(const char *name, struct stat *p)
186 if (0 == curdepth)
188 /* This file is from the command line; deference the link (if it
189 * is a link).
191 if (0 == stat(name, p))
193 /* success */
194 return 0;
196 else
198 /* fallback - return the information for the link itself. */
199 return lstat(name, p);
202 else
204 /* Not a file on the command line; do not derefernce the link.
206 return lstat(name, p);
210 /* optionl_stat() implements the stat operation when the -L option is
211 * in effect. That option makes us examine the thing the symbolic
212 * link points to, not the symbolic link itself.
214 int
215 optionl_stat(const char *name, struct stat *p)
217 if (0 == stat(name, p))
219 return 0; /* normal case. */
221 else
223 return lstat(name, p); /* can't follow link, return the link itself. */
227 /* optionp_stat() implements the stat operation when the -P option is
228 * in effect (this is also the default). That option makes us examine
229 * the symbolic link itself, not the thing it points to.
231 int
232 optionp_stat(const char *name, struct stat *p)
234 return lstat(name, p);
237 #ifdef DEBUG_STAT
238 static int
239 debug_stat (const char *file, struct stat *bufp)
241 fprintf (stderr, "debug_stat (%s)\n", file);
242 switch (symlink_handling)
244 case SYMLINK_ALWAYS_DEREF:
245 return optionl_stat(file, bufp);
246 case SYMLINK_DEREF_ARGSONLY:
247 return optionh_stat(file, bufp);
248 case SYMLINK_NEVER_DEREF:
249 return optionp_stat(file, bufp);
252 #endif /* DEBUG_STAT */
254 void
255 set_follow_state(enum SymlinkOption opt)
257 switch (opt)
259 case SYMLINK_ALWAYS_DEREF: /* -L */
260 xstat = optionl_stat;
261 no_leaf_check = false;
262 break;
264 case SYMLINK_NEVER_DEREF: /* -P (default) */
265 xstat = optionp_stat;
266 /* Can't turn on no_leaf_check because the user might have specified
267 * -noleaf anyway
269 break;
271 case SYMLINK_DEREF_ARGSONLY: /* -H */
272 xstat = optionh_stat;
273 no_leaf_check = true;
276 /* For DBEUG_STAT, the choice is made at runtime within debug_stat()
277 * by checking the contents of the symlink_handling variable.
279 #if defined(DEBUG_STAT)
280 xstat = debug_stat;
281 #endif /* !DEBUG_STAT */
286 main (int argc, char **argv)
288 int i;
289 PFB parse_function; /* Pointer to the function which parses. */
290 struct predicate *cur_pred;
291 char *predicate_name; /* Name of predicate being parsed. */
292 int end_of_leading_options = 0; /* First arg after any -H/-L etc. */
293 program_name = argv[0];
295 #ifdef HAVE_SETLOCALE
296 setlocale (LC_ALL, "");
297 #endif
298 bindtextdomain (PACKAGE, LOCALEDIR);
299 textdomain (PACKAGE);
301 if (isatty(0))
303 warnings = true;
305 else
307 warnings = false;
311 predicates = NULL;
312 last_pred = NULL;
313 do_dir_first = true;
314 maxdepth = mindepth = -1;
315 start_time = time (NULL);
316 cur_day_start = start_time - DAYSECS;
317 full_days = false;
318 no_leaf_check = false;
319 stay_on_filesystem = false;
320 ignore_readdir_race = false;
321 exit_status = 0;
323 #if defined(DEBUG_STAT)
324 xstat = debug_stat;
325 #endif /* !DEBUG_STAT */
327 #if 0
328 human_block_size (getenv ("FIND_BLOCK_SIZE"), 0, &output_block_size);
329 #else
330 if (getenv("POSIXLY_CORRECT"))
331 output_block_size = 512;
332 else
333 output_block_size = 1024;
335 if (getenv("FIND_BLOCK_SIZE"))
337 error (1, 0, _("The environment variable FIND_BLOCK_SIZE is not supported, the only thing that affects the block size is the POSIXLY_CORRECT environment variable"));
340 set_follow_state(SYMLINK_NEVER_DEREF); /* The default is equivalent to -P. */
342 init_mount_point_list();
344 #endif
346 #ifdef DEBUG
347 printf ("cur_day_start = %s", ctime (&cur_day_start));
348 #endif /* DEBUG */
350 /* Check for -P, -H or -L options. */
351 for (i=1; (end_of_leading_options = i) < argc; ++i)
353 if (0 == strcmp("-H", argv[i]))
355 /* Meaning: dereference symbolic links on command line, but nowhere else. */
356 set_follow_state(SYMLINK_DEREF_ARGSONLY);
358 else if (0 == strcmp("-L", argv[i]))
360 /* Meaning: dereference all symbolic links. */
361 set_follow_state(SYMLINK_ALWAYS_DEREF);
363 else if (0 == strcmp("-P", argv[i]))
365 /* Meaning: never dereference symbolic links (default). */
366 set_follow_state(SYMLINK_NEVER_DEREF);
368 else if (0 == strcmp("--", argv[i]))
370 /* -- signifies the end of options. */
371 end_of_leading_options = i+1; /* Next time start with the next option */
372 break;
374 else
376 /* Hmm, must be one of
377 * (a) A path name
378 * (b) A predicate
380 end_of_leading_options = i; /* Next time start with this option */
381 break;
385 /* We are now processing the part of the "find" command line
386 * after the -H/-L options (if any).
389 /* fprintf(stderr, "rest: optind=%ld\n", (long)optind); */
391 /* Find where in ARGV the predicates begin. */
392 for (i = end_of_leading_options; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
394 /* fprintf(stderr, "Looks like %s is not a predicate\n", argv[i]); */
395 /* Do nothing. */ ;
398 /* Enclose the expression in `( ... )' so a default -print will
399 apply to the whole expression. */
400 parse_open (argv, &argc);
401 /* Build the input order list. */
402 while (i < argc)
404 if (strchr ("-!(),", argv[i][0]) == NULL)
405 usage (_("paths must precede expression"));
406 predicate_name = argv[i];
407 parse_function = find_parser (predicate_name);
408 if (parse_function == NULL)
409 /* Command line option not recognized */
410 error (1, 0, _("invalid predicate `%s'"), predicate_name);
411 i++;
412 if (!(*parse_function) (argv, &i))
414 if (argv[i] == NULL)
415 /* Command line option requires an argument */
416 error (1, 0, _("missing argument to `%s'"), predicate_name);
417 else
418 error (1, 0, _("invalid argument `%s' to `%s'"),
419 argv[i], predicate_name);
422 if (predicates->pred_next == NULL)
424 /* No predicates that do something other than set a global variable
425 were given; remove the unneeded initial `(' and add `-print'. */
426 cur_pred = predicates;
427 predicates = last_pred = predicates->pred_next;
428 free ((char *) cur_pred);
429 parse_print (argv, &argc);
431 else if (!default_prints (predicates->pred_next))
433 /* One or more predicates that produce output were given;
434 remove the unneeded initial `('. */
435 cur_pred = predicates;
436 predicates = predicates->pred_next;
437 free ((char *) cur_pred);
439 else
441 /* `( user-supplied-expression ) -print'. */
442 parse_close (argv, &argc);
443 parse_print (argv, &argc);
446 #ifdef DEBUG
447 printf (_("Predicate List:\n"));
448 print_list (predicates);
449 #endif /* DEBUG */
451 /* Done parsing the predicates. Build the evaluation tree. */
452 cur_pred = predicates;
453 eval_tree = get_expr (&cur_pred, NO_PREC);
455 /* Check if we have any left-over predicates (this fixes
456 * Debian bug #185202).
458 if (cur_pred != NULL)
460 error (1, 0, _("unexpected extra predicate"));
463 #ifdef DEBUG
464 printf (_("Eval Tree:\n"));
465 print_tree (eval_tree, 0);
466 #endif /* DEBUG */
468 /* Rearrange the eval tree in optimal-predicate order. */
469 opt_expr (&eval_tree);
471 /* Determine the point, if any, at which to stat the file. */
472 mark_stat (eval_tree);
474 #ifdef DEBUG
475 printf (_("Optimized Eval Tree:\n"));
476 print_tree (eval_tree, 0);
477 #endif /* DEBUG */
479 starting_desc = open (".", O_RDONLY);
480 if (0 <= starting_desc && fchdir (starting_desc) != 0)
482 close (starting_desc);
483 starting_desc = -1;
485 if (starting_desc < 0)
487 starting_dir = xgetcwd ();
488 if (! starting_dir)
489 error (1, errno, _("cannot get current directory"));
491 if ((*xstat) (".", &starting_stat_buf) != 0)
492 error (1, errno, _("cannot get current directory"));
494 /* If no paths are given, default to ".". */
495 for (i = end_of_leading_options; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
497 process_top_path (argv[i]);
500 /* If there were no path arguments, default to ".". */
501 if (i == end_of_leading_options)
504 * We use a temporary variable here because some actions modify
505 * the path temporarily. Hence if we use a string constant,
506 * we get a coredump. The best example of this is if we say
507 * "find -printf %H" (note, not "find . -printf %H").
509 char defaultpath[2] = ".";
510 process_top_path (defaultpath);
514 return exit_status;
518 static char *
519 specific_dirname(const char *dir)
521 char dirname[1024];
523 if (0 == strcmp(".", dir))
525 /* OK, what's '.'? */
526 if (NULL != getcwd(dirname, sizeof(dirname)))
528 return strdup(dirname);
530 else
532 return strdup(dir);
535 else
537 return canonicalize_filename_mode(dir, CAN_EXISTING);
541 enum MountPointStateChange
543 MountPointRecentlyMounted,
544 MountPointRecentlyUnmounted,
545 MountPointStateUnchanged
548 static char *mount_points = NULL;
550 /* Initialise our idea of what the list of mount points is.
551 * this function is called exactly once.
553 static void
554 init_mount_point_list(void)
556 assert(NULL == mount_points);
557 mount_points = get_mounted_filesystems();
560 /* list_item_present: Search for NEEDLE in HAYSTACK.
562 * NEEDLE is a normal C string. HAYSTACK is a list of concatenated C strings,
563 * each with a terminating NUL. The last item in the list is identified by
564 * the fact that its terminating NUL is itself followed by a second NUL.
566 * This data structure does not lend itself to fast searching, but we only
567 * do this when wd_sanity_check() thinks that a filesystem might have been
568 * mounted or unmounted. That doesn't happen very often.
570 static int
571 list_item_present(const char *needle, const char *haystack)
573 if (NULL != haystack)
575 const char *s = haystack;
576 while (*s)
578 if (0 == strcmp(s, needle))
580 return 1;
582 else
584 s += strlen(s);
585 ++s; /* skip the first NUL. */
589 return 0;
593 /* Determine if a directory has recently had a filesystem
594 * mounted on it or unmounted from it.
596 static enum MountPointStateChange
597 get_mount_point_state(const char *dir)
599 int was_mounted, is_mounted;
601 was_mounted = list_item_present(dir, mount_points);
603 if (mount_points)
605 free(mount_points);
607 mount_points = get_mounted_filesystems();
609 is_mounted = list_item_present(dir, mount_points);
611 if (was_mounted == is_mounted)
612 return MountPointStateUnchanged;
613 else if (is_mounted)
614 return MountPointRecentlyMounted;
615 else
616 return MountPointRecentlyUnmounted;
620 /* Examine the results of the stat() of a directory from before we
621 * entered or left it, with the results of stat()ing it afterward. If
622 * these are different, the filesystem tree has been modified while we
623 * were traversing it. That might be an attempt to use a race
624 * condition to persuade find to do something it didn't intend
625 * (e.g. an attempt by an ordinary user to exploit the fact that root
626 * sometimes runs find on the whole filesystem). However, this can
627 * also happen if automount is running (certainly on Solaris). With
628 * automount, moving into a directory can cause a filesystem to be
629 * mounted there.
631 * To cope sensibly with this, we will raise an error if we see the
632 * device number change unless we are chdir()ing into a subdirectory,
633 * and the directory we moved into has been mounted or unmounted "recently".
634 * Here "recently" means since we started "find" or we last re-read
635 * the /etc/mnttab file.
637 * If the device number does not change but the inode does, that is a
638 * problem.
640 * If the device number and inode are both the same, we are happy.
642 * If a filesystem is (un)mounted as we chdir() into the directory, that
643 * may mean that we're now examining a section of the filesystem that might
644 * have been excluded from consideration (via -prune or -quit for example).
645 * Hence we print a warning message to indicate that the output of find
646 * might be inconsistent due to the change in the filesystem.
648 static void
649 wd_sanity_check(const char *thing_to_stat,
650 const char *program_name,
651 const char *what,
652 const struct stat *oldinfo,
653 struct stat *newinfo,
654 int parent,
655 int line_no,
656 enum TraversalDirection direction)
658 const char *fstype;
659 char *specific_what = NULL;
661 int isfatal = 1;
663 if ((*xstat) (".", newinfo) != 0)
664 error (1, errno, "%s", thing_to_stat);
666 if (oldinfo->st_dev != newinfo->st_dev)
668 specific_what = specific_dirname(what);
670 /* This condition is rare, so once we are here it is
671 * reasonable to perform an expensive computation to
672 * determine if we should continue or fail.
674 if (TraversingDown == direction)
676 /* We stat()ed a directory, chdir()ed into it (we know this
677 * since direction is TraversingDown), stat()ed it again,
678 * and noticed that the device numbers are different. Check
679 * if the filesystem was recently mounted.
681 * If it was, it looks like chdir()ing into the directory
682 * caused a filesystem to be mounted. Maybe automount is
683 * running. Anyway, that's probably OK - but it happens
684 * only when we are moving downward.
686 * We also allow for the possibility that a similar thing
687 * has happened with the unmounting of a filesystem. This
688 * is much rarer, as it relies on an automounter timeout
689 * occurring at exactly the wrong moment.
691 enum MountPointStateChange transition = get_mount_point_state(specific_what);
692 switch (transition)
694 case MountPointRecentlyUnmounted:
695 isfatal = 0;
696 error (0, 0,
697 _("Warning: filesystem %s has recently been unmounted."),
698 specific_what);
699 break;
701 case MountPointRecentlyMounted:
702 isfatal = 0;
703 error (0, 0,
704 _("Warning: filesystem %s has recently been mounted."),
705 specific_what);
706 break;
708 case MountPointStateUnchanged:
709 isfatal = 1;
710 break;
714 if (isfatal)
716 fstype = filesystem_type(thing_to_stat, ".", newinfo);
717 error (isfatal, 0,
718 _("%s%s changed during execution of %s (old device number %ld, new device number %ld, filesystem type is %s) [ref %ld]"),
719 specific_what,
720 parent ? "/.." : "",
721 program_name,
722 (long) oldinfo->st_dev,
723 (long) newinfo->st_dev,
724 fstype,
725 line_no);
727 else
729 /* Since the device has changed under us, the inode number
730 * will almost certainly also be different. However, we have
731 * already decided that this is not a problem. Hence we return
732 * without checking the inode number.
734 free(specific_what);
735 return;
739 /* Device number was the same, check if the inode has changed. */
740 if (oldinfo->st_ino != newinfo->st_ino)
742 specific_what = specific_dirname(what);
743 fstype = filesystem_type(thing_to_stat, ".", newinfo);
745 error (1, 0,
746 _("%s%s changed during execution of %s (old inode number %ld, new inode number %ld, filesystem type is %s) [ref %ld]"),
747 specific_what,
748 parent ? "/.." : "",
749 program_name,
750 (long) oldinfo->st_ino,
751 (long) newinfo->st_ino,
752 fstype,
753 line_no);
754 free(specific_what);
759 /* Safely go back to the starting directory. */
760 static void
761 chdir_back (void)
763 struct stat stat_buf;
765 if (starting_desc < 0)
767 if (chdir (starting_dir) != 0)
768 error (1, errno, "%s", starting_dir);
770 wd_sanity_check(starting_dir,
771 program_name, starting_dir,
772 &starting_stat_buf, &stat_buf, 0, __LINE__,
773 TraversingUp);
775 else
777 if (fchdir (starting_desc) != 0)
778 error (1, errno, "%s", starting_dir);
782 /* Descend PATHNAME, which is a command-line argument. */
784 static void
785 process_top_path (char *pathname)
787 struct stat stat_buf, cur_stat_buf;
789 curdepth = 0;
790 path_length = strlen (pathname);
792 /* We stat each pathname given on the command-line twice --
793 once here and once in process_path. It's not too bad, though,
794 since the kernel can read the stat information out of its inode
795 cache the second time. */
796 if ((*xstat) (pathname, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode))
798 if (chdir (pathname) < 0)
800 if (!ignore_readdir_race || (errno != ENOENT) )
802 error (0, errno, "%s", pathname);
803 exit_status = 1;
805 return;
808 /* Check that we are where we should be. */
809 wd_sanity_check(pathname, program_name,
810 ".",
811 &stat_buf, &cur_stat_buf, 0, __LINE__,
812 TraversingDown);
814 process_path (pathname, ".", false, ".");
815 chdir_back ();
817 else
818 process_path (pathname, pathname, false, ".");
821 /* Info on each directory in the current tree branch, to avoid
822 getting stuck in symbolic link loops. */
823 struct dir_id
825 ino_t ino;
826 dev_t dev;
828 static struct dir_id *dir_ids = NULL;
829 /* Entries allocated in `dir_ids'. */
830 static int dir_alloc = 0;
831 /* Index in `dir_ids' of directory currently being searched.
832 This is always the last valid entry. */
833 static int dir_curr = -1;
834 /* (Arbitrary) number of entries to grow `dir_ids' by. */
835 #define DIR_ALLOC_STEP 32
837 /* Recursively descend path PATHNAME, applying the predicates.
838 LEAF is true if PATHNAME is known to be in a directory that has no
839 more unexamined subdirectories, and therefore it is not a directory.
840 Knowing this allows us to avoid calling stat as long as possible for
841 leaf files.
843 NAME is PATHNAME relative to the current directory. We access NAME
844 but print PATHNAME.
846 PARENT is the path of the parent of NAME, relative to find's
847 starting directory.
849 Return nonzero iff PATHNAME is a directory. */
851 static int
852 process_path (char *pathname, char *name, boolean leaf, char *parent)
854 struct stat stat_buf;
855 static dev_t root_dev; /* Device ID of current argument pathname. */
856 int i;
858 /* Assume it is a non-directory initially. */
859 stat_buf.st_mode = 0;
861 rel_pathname = name;
863 if (leaf)
864 have_stat = false;
865 else
867 if ((*xstat) (name, &stat_buf) != 0)
869 if (!ignore_readdir_race || (errno != ENOENT) )
871 error (0, errno, "%s", pathname);
872 exit_status = 1;
874 return 0;
876 have_stat = true;
879 if (!S_ISDIR (stat_buf.st_mode))
881 if (curdepth >= mindepth)
882 apply_predicate (pathname, &stat_buf, eval_tree);
883 return 0;
886 /* From here on, we're working on a directory. */
888 stop_at_current_level = maxdepth >= 0 && curdepth >= maxdepth;
890 /* If we've already seen this directory on this branch,
891 don't descend it again. */
892 for (i = 0; i <= dir_curr; i++)
893 if (stat_buf.st_ino == dir_ids[i].ino &&
894 stat_buf.st_dev == dir_ids[i].dev)
895 stop_at_current_level = true;
897 if (dir_alloc <= ++dir_curr)
899 dir_alloc += DIR_ALLOC_STEP;
900 dir_ids = (struct dir_id *)
901 xrealloc ((char *) dir_ids, dir_alloc * sizeof (struct dir_id));
903 dir_ids[dir_curr].ino = stat_buf.st_ino;
904 dir_ids[dir_curr].dev = stat_buf.st_dev;
906 if (stay_on_filesystem)
908 if (curdepth == 0)
909 root_dev = stat_buf.st_dev;
910 else if (stat_buf.st_dev != root_dev)
911 stop_at_current_level = true;
914 if (do_dir_first && curdepth >= mindepth)
915 apply_predicate (pathname, &stat_buf, eval_tree);
917 #ifdef DEBUG
918 fprintf(stderr, "pathname = %s, stop_at_current_level = %d\n",
919 pathname, stop_at_current_level);
920 #endif /* DEBUG */
922 if (stop_at_current_level == false)
923 /* Scan directory on disk. */
924 process_dir (pathname, name, strlen (pathname), &stat_buf, parent);
926 if (do_dir_first == false && curdepth >= mindepth)
928 rel_pathname = name;
929 apply_predicate (pathname, &stat_buf, eval_tree);
932 dir_curr--;
934 return 1;
937 /* Scan directory PATHNAME and recurse through process_path for each entry.
939 PATHLEN is the length of PATHNAME.
941 NAME is PATHNAME relative to the current directory.
943 STATP is the results of *xstat on it.
945 PARENT is the path of the parent of NAME, relative to find's
946 starting directory. */
948 static void
949 process_dir (char *pathname, char *name, int pathlen, struct stat *statp, char *parent)
951 char *name_space; /* Names of files in PATHNAME. */
952 int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */
953 struct stat stat_buf;
955 subdirs_left = statp->st_nlink - 2; /* Account for name and ".". */
957 errno = 0;
958 name_space = savedir (name);
959 if (name_space == NULL)
961 if (errno)
963 error (0, errno, "%s", pathname);
964 exit_status = 1;
966 else
967 error (1, 0, _("virtual memory exhausted"));
969 else
971 register char *namep; /* Current point in `name_space'. */
972 char *cur_path; /* Full path of each file to process. */
973 char *cur_name; /* Base name of each file to process. */
974 unsigned cur_path_size; /* Bytes allocated for `cur_path'. */
975 register unsigned file_len; /* Length of each path to process. */
976 register unsigned pathname_len; /* PATHLEN plus trailing '/'. */
978 if (pathname[pathlen - 1] == '/')
979 pathname_len = pathlen + 1; /* For '\0'; already have '/'. */
980 else
981 pathname_len = pathlen + 2; /* For '/' and '\0'. */
982 cur_path_size = 0;
983 cur_path = NULL;
985 if (strcmp (name, ".") && chdir (name) < 0)
987 error (0, errno, "%s", pathname);
988 exit_status = 1;
989 return;
992 /* Check that we are where we should be. */
993 if (1)
995 struct stat tmp = {0};
996 tmp.st_dev = dir_ids[dir_curr].dev;
997 tmp.st_ino = dir_ids[dir_curr].ino;
998 wd_sanity_check(pathname,
999 program_name,
1000 ".",
1001 &tmp, &stat_buf, 0, __LINE__,
1002 TraversingDown);
1005 for (namep = name_space; *namep; namep += file_len - pathname_len + 1)
1007 /* Append this directory entry's name to the path being searched. */
1008 file_len = pathname_len + strlen (namep);
1009 if (file_len > cur_path_size)
1011 while (file_len > cur_path_size)
1012 cur_path_size += 1024;
1013 if (cur_path)
1014 free (cur_path);
1015 cur_path = xmalloc (cur_path_size);
1016 strcpy (cur_path, pathname);
1017 cur_path[pathname_len - 2] = '/';
1019 cur_name = cur_path + pathname_len - 1;
1020 strcpy (cur_name, namep);
1022 curdepth++;
1023 if (!no_leaf_check)
1024 /* Normal case optimization.
1025 On normal Unix filesystems, a directory that has no
1026 subdirectories has two links: its name, and ".". Any
1027 additional links are to the ".." entries of its
1028 subdirectories. Once we have processed as many
1029 subdirectories as there are additional links, we know
1030 that the rest of the entries are non-directories --
1031 in other words, leaf files. */
1032 subdirs_left -= process_path (cur_path, cur_name,
1033 subdirs_left == 0, pathname);
1034 else
1035 /* There might be weird (e.g., CD-ROM or MS-DOS) filesystems
1036 mounted, which don't have Unix-like directory link counts. */
1037 process_path (cur_path, cur_name, false, pathname);
1038 curdepth--;
1041 if (strcmp (name, "."))
1043 /* We could go back and do the next command-line arg
1044 instead, maybe using longjmp. */
1045 char const *dir;
1046 boolean deref;
1047 if (symlink_handling == SYMLINK_ALWAYS_DEREF)
1048 deref = true;
1049 else if (symlink_handling == SYMLINK_DEREF_ARGSONLY && (curdepth == 0))
1050 deref = true;
1051 else
1052 deref = false;
1054 if (!deref)
1055 dir = "..";
1056 else
1058 chdir_back ();
1059 dir = parent;
1062 if (chdir (dir) != 0)
1063 error (1, errno, "%s", parent);
1065 /* Check that we are where we should be. */
1066 if (1)
1068 struct stat tmp;
1069 int problem_is_with_parent;
1071 if (dir_curr > 0)
1073 tmp.st_dev = dir_ids[dir_curr-1].dev;
1074 tmp.st_ino = dir_ids[dir_curr-1].ino;
1076 else
1078 tmp.st_dev = starting_stat_buf.st_dev;
1079 tmp.st_ino = starting_stat_buf.st_ino;
1082 problem_is_with_parent = deref ? 1 : 0;
1083 wd_sanity_check(pathname,
1084 program_name,
1085 deref ? parent : starting_dir,
1086 &tmp, &stat_buf,
1087 problem_is_with_parent, __LINE__,
1088 TraversingUp);
1092 if (cur_path)
1093 free (cur_path);
1094 free (name_space);
1098 #if 0
1099 /* Return true if there are no side effects in any of the predicates in
1100 predicate list PRED, false if there are any. */
1102 static boolean
1103 no_side_effects (struct predicate *pred)
1105 while (pred != NULL)
1107 if (pred->side_effects)
1108 return (false);
1109 pred = pred->pred_next;
1111 return (true);
1113 #endif
1115 /* Return true if there are no predicates with no_default_print in
1116 predicate list PRED, false if there are any.
1117 Returns true if default print should be performed */
1119 static boolean
1120 default_prints (struct predicate *pred)
1122 while (pred != NULL)
1124 if (pred->no_default_print)
1125 return (false);
1126 pred = pred->pred_next;
1128 return (true);