Check to see if the new directory is a transitioned mount point by
[findutils.git] / find / find.c
blob870297518ceb2f4910cfa1f9b43bf2f5c078a7da
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 <modetype.h>
39 #include "../gnulib/lib/savedir.h"
41 #ifdef HAVE_LOCALE_H
42 #include <locale.h>
43 #endif
45 #if ENABLE_NLS
46 # include <libintl.h>
47 # define _(Text) gettext (Text)
48 #else
49 # define _(Text) Text
50 #define textdomain(Domain)
51 #define bindtextdomain(Package, Directory)
52 #endif
53 #ifdef gettext_noop
54 # define N_(String) gettext_noop (String)
55 #else
56 /* See locate.c for explanation as to why not use (String) */
57 # define N_(String) String
58 #endif
60 #define apply_predicate(pathname, stat_buf_ptr, node) \
61 (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
64 static void init_mount_point_list(void);
65 static void process_top_path PARAMS((char *pathname));
66 static int process_path PARAMS((char *pathname, char *name, boolean leaf, char *parent));
67 static void process_dir PARAMS((char *pathname, char *name, int pathlen, struct stat *statp, char *parent));
68 #if 0
69 static boolean no_side_effects PARAMS((struct predicate *pred));
70 #endif
71 static boolean default_prints PARAMS((struct predicate *pred));
73 /* Name this program was run with. */
74 char *program_name;
76 /* All predicates for each path to process. */
77 struct predicate *predicates;
79 /* The last predicate allocated. */
80 struct predicate *last_pred;
82 /* The root of the evaluation tree. */
83 static struct predicate *eval_tree;
85 /* If true, process directory before contents. True unless -depth given. */
86 boolean do_dir_first;
88 /* If >=0, don't descend more than this many levels of subdirectories. */
89 int maxdepth;
91 /* If >=0, don't process files above this level. */
92 int mindepth;
94 /* Current depth; 0 means current path is a command line arg. */
95 int curdepth;
97 /* Output block size. */
98 int output_block_size;
100 /* Time at start of execution. */
101 time_t start_time;
103 /* Seconds between 00:00 1/1/70 and either one day before now
104 (the default), or the start of today (if -daystart is given). */
105 time_t cur_day_start;
107 /* If true, cur_day_start has been adjusted to the start of the day. */
108 boolean full_days;
110 /* If true, do not assume that files in directories with nlink == 2
111 are non-directories. */
112 boolean no_leaf_check;
114 /* If true, don't cross filesystem boundaries. */
115 boolean stay_on_filesystem;
117 /* If true, don't descend past current directory.
118 Can be set by -prune, -maxdepth, and -xdev/-mount. */
119 boolean stop_at_current_level;
121 /* The full path of the initial working directory, or "." if
122 STARTING_DESC is nonnegative. */
123 char const *starting_dir = ".";
125 /* A file descriptor open to the initial working directory.
126 Doing it this way allows us to work when the i.w.d. has
127 unreadable parents. */
128 int starting_desc;
130 /* The stat buffer of the initial working directory. */
131 struct stat starting_stat_buf;
133 /* If true, we have called stat on the current path. */
134 boolean have_stat;
136 /* The file being operated on, relative to the current directory.
137 Used for stat, readlink, remove, and opendir. */
138 char *rel_pathname;
140 /* Length of current path. */
141 int path_length;
143 /* true if following symlinks. Should be consistent with xstat. */
144 /* boolean dereference; */
145 enum SymlinkOption symlink_handling;
148 /* Pointer to the function used to stat files. */
149 int (*xstat) ();
151 /* Status value to return to system. */
152 int exit_status;
154 /* If true, we ignore the problem where we find that a directory entry
155 * no longer exists by the time we get around to processing it.
157 boolean ignore_readdir_race;
160 /* If true, we issue warning messages
162 boolean warnings;
165 enum TraversalDirection
167 TraversingUp,
168 TraversingDown
172 /* optionh_stat() implements the stat operation when the -H option is
173 * in effect.
175 * If the item to be examined is a command-line argument, we follow
176 * symbolic links. If the stat() call fails on the command-line item,
177 * we fall back on the properties of the symbolic link.
179 * If the item to be examined is not a command-line argument, we
180 * examine the link itself.
182 int
183 optionh_stat(const char *name, struct stat *p)
185 if (0 == curdepth)
187 /* This file is from the command line; deference the link (if it
188 * is a link).
190 if (0 == stat(name, p))
192 /* success */
193 return 0;
195 else
197 /* fallback - return the information for the link itself. */
198 return lstat(name, p);
201 else
203 /* Not a file on the command line; do not derefernce the link.
205 return lstat(name, p);
209 /* optionl_stat() implements the stat operation when the -L option is
210 * in effect. That option makes us examine the thing the symbolic
211 * link points to, not the symbolic link itself.
213 int
214 optionl_stat(const char *name, struct stat *p)
216 if (0 == stat(name, p))
218 return 0; /* normal case. */
220 else
222 return lstat(name, p); /* can't follow link, return the link itself. */
226 /* optionp_stat() implements the stat operation when the -P option is
227 * in effect (this is also the default). That option makes us examine
228 * the symbolic link itself, not the thing it points to.
230 int
231 optionp_stat(const char *name, struct stat *p)
233 return lstat(name, p);
236 #ifdef DEBUG_STAT
237 static int
238 debug_stat (const char *file, struct stat *bufp)
240 fprintf (stderr, "debug_stat (%s)\n", file);
241 switch (symlink_handling)
243 case SYMLINK_ALWAYS_DEREF:
244 return optionl_stat(file, bufp);
245 case SYMLINK_DEREF_ARGSONLY:
246 return optionh_stat(file, bufp);
247 case SYMLINK_NEVER_DEREF:
248 return optionp_stat(file, bufp);
251 #endif /* DEBUG_STAT */
253 void
254 set_follow_state(enum SymlinkOption opt)
256 switch (opt)
258 case SYMLINK_ALWAYS_DEREF: /* -L */
259 xstat = optionl_stat;
260 no_leaf_check = false;
261 break;
263 case SYMLINK_NEVER_DEREF: /* -P (default) */
264 xstat = optionp_stat;
265 /* Can't turn on no_leaf_check because the user might have specified
266 * -noleaf anyway
268 break;
270 case SYMLINK_DEREF_ARGSONLY: /* -H */
271 xstat = optionh_stat;
272 no_leaf_check = true;
275 /* For DBEUG_STAT, the choice is made at runtime within debug_stat()
276 * by checking the contents of the symlink_handling variable.
278 #if defined(DEBUG_STAT)
279 xstat = debug_stat;
280 #endif /* !DEBUG_STAT */
285 main (int argc, char **argv)
287 int i;
288 PFB parse_function; /* Pointer to the function which parses. */
289 struct predicate *cur_pred;
290 char *predicate_name; /* Name of predicate being parsed. */
291 int end_of_leading_options = 0; /* First arg after any -H/-L etc. */
292 program_name = argv[0];
294 #ifdef HAVE_SETLOCALE
295 setlocale (LC_ALL, "");
296 #endif
297 bindtextdomain (PACKAGE, LOCALEDIR);
298 textdomain (PACKAGE);
300 if (isatty(0))
302 warnings = true;
304 else
306 warnings = false;
310 predicates = NULL;
311 last_pred = NULL;
312 do_dir_first = true;
313 maxdepth = mindepth = -1;
314 start_time = time (NULL);
315 cur_day_start = start_time - DAYSECS;
316 full_days = false;
317 no_leaf_check = false;
318 stay_on_filesystem = false;
319 ignore_readdir_race = false;
320 exit_status = 0;
322 #if defined(DEBUG_STAT)
323 xstat = debug_stat;
324 #endif /* !DEBUG_STAT */
326 #if 0
327 human_block_size (getenv ("FIND_BLOCK_SIZE"), 0, &output_block_size);
328 #else
329 if (getenv("POSIXLY_CORRECT"))
330 output_block_size = 512;
331 else
332 output_block_size = 1024;
334 if (getenv("FIND_BLOCK_SIZE"))
336 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"));
339 set_follow_state(SYMLINK_NEVER_DEREF); /* The default is equivalent to -P. */
341 init_mount_point_list();
343 #endif
345 #ifdef DEBUG
346 printf ("cur_day_start = %s", ctime (&cur_day_start));
347 #endif /* DEBUG */
349 /* Check for -P, -H or -L options. */
350 for (i=1; (end_of_leading_options = i) < argc; ++i)
352 if (0 == strcmp("-H", argv[i]))
354 /* Meaning: dereference symbolic links on command line, but nowhere else. */
355 set_follow_state(SYMLINK_DEREF_ARGSONLY);
357 else if (0 == strcmp("-L", argv[i]))
359 /* Meaning: dereference all symbolic links. */
360 set_follow_state(SYMLINK_ALWAYS_DEREF);
362 else if (0 == strcmp("-P", argv[i]))
364 /* Meaning: never dereference symbolic links (default). */
365 set_follow_state(SYMLINK_NEVER_DEREF);
367 else if (0 == strcmp("--", argv[i]))
369 /* -- signifies the end of options. */
370 end_of_leading_options = i+1; /* Next time start with the next option */
371 break;
373 else
375 /* Hmm, must be one of
376 * (a) A path name
377 * (b) A predicate
379 end_of_leading_options = i; /* Next time start with this option */
380 break;
384 /* We are now processing the part of the "find" command line
385 * after the -H/-L options (if any).
388 /* fprintf(stderr, "rest: optind=%ld\n", (long)optind); */
390 /* Find where in ARGV the predicates begin. */
391 for (i = end_of_leading_options; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
393 /* fprintf(stderr, "Looks like %s is not a predicate\n", argv[i]); */
394 /* Do nothing. */ ;
397 /* Enclose the expression in `( ... )' so a default -print will
398 apply to the whole expression. */
399 parse_open (argv, &argc);
400 /* Build the input order list. */
401 while (i < argc)
403 if (strchr ("-!(),", argv[i][0]) == NULL)
404 usage (_("paths must precede expression"));
405 predicate_name = argv[i];
406 parse_function = find_parser (predicate_name);
407 if (parse_function == NULL)
408 /* Command line option not recognized */
409 error (1, 0, _("invalid predicate `%s'"), predicate_name);
410 i++;
411 if (!(*parse_function) (argv, &i))
413 if (argv[i] == NULL)
414 /* Command line option requires an argument */
415 error (1, 0, _("missing argument to `%s'"), predicate_name);
416 else
417 error (1, 0, _("invalid argument `%s' to `%s'"),
418 argv[i], predicate_name);
421 if (predicates->pred_next == NULL)
423 /* No predicates that do something other than set a global variable
424 were given; remove the unneeded initial `(' and add `-print'. */
425 cur_pred = predicates;
426 predicates = last_pred = predicates->pred_next;
427 free ((char *) cur_pred);
428 parse_print (argv, &argc);
430 else if (!default_prints (predicates->pred_next))
432 /* One or more predicates that produce output were given;
433 remove the unneeded initial `('. */
434 cur_pred = predicates;
435 predicates = predicates->pred_next;
436 free ((char *) cur_pred);
438 else
440 /* `( user-supplied-expression ) -print'. */
441 parse_close (argv, &argc);
442 parse_print (argv, &argc);
445 #ifdef DEBUG
446 printf (_("Predicate List:\n"));
447 print_list (predicates);
448 #endif /* DEBUG */
450 /* Done parsing the predicates. Build the evaluation tree. */
451 cur_pred = predicates;
452 eval_tree = get_expr (&cur_pred, NO_PREC);
454 /* Check if we have any left-over predicates (this fixes
455 * Debian bug #185202).
457 if (cur_pred != NULL)
459 error (1, 0, _("unexpected extra predicate"));
462 #ifdef DEBUG
463 printf (_("Eval Tree:\n"));
464 print_tree (eval_tree, 0);
465 #endif /* DEBUG */
467 /* Rearrange the eval tree in optimal-predicate order. */
468 opt_expr (&eval_tree);
470 /* Determine the point, if any, at which to stat the file. */
471 mark_stat (eval_tree);
473 #ifdef DEBUG
474 printf (_("Optimized Eval Tree:\n"));
475 print_tree (eval_tree, 0);
476 #endif /* DEBUG */
478 starting_desc = open (".", O_RDONLY);
479 if (0 <= starting_desc && fchdir (starting_desc) != 0)
481 close (starting_desc);
482 starting_desc = -1;
484 if (starting_desc < 0)
486 starting_dir = xgetcwd ();
487 if (! starting_dir)
488 error (1, errno, _("cannot get current directory"));
490 if ((*xstat) (".", &starting_stat_buf) != 0)
491 error (1, errno, _("cannot get current directory"));
493 /* If no paths are given, default to ".". */
494 for (i = end_of_leading_options; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
496 process_top_path (argv[i]);
499 /* If there were no path arguments, default to ".". */
500 if (i == end_of_leading_options)
503 * We use a temporary variable here because some actions modify
504 * the path temporarily. Hence if we use a string constant,
505 * we get a coredump. The best example of this is if we say
506 * "find -printf %H" (note, not "find . -printf %H").
508 char defaultpath[2] = ".";
509 process_top_path (defaultpath);
513 return exit_status;
517 static char *
518 specific_dirname(const char *dir)
520 char dirname[1024];
522 if (0 != strcmp(".", dir))
524 return strdup(dir);
527 /* OK, what's '.'? */
528 if (NULL != getcwd(dirname, sizeof(dirname)))
530 return strdup(dirname);
532 else
534 return strdup(dir);
538 enum MountPointStateChange
540 MountPointRecentlyMounted,
541 MountPointRecentlyUnmounted,
542 MountPointStateUnchanged
545 static char *mount_points = NULL;
547 /* Initialise our idea of what the list of mount points is.
548 * this function is called exactly once.
550 static void
551 init_mount_point_list(void)
553 assert(NULL == mount_points);
554 mount_points = get_mounted_filesystems();
557 /* list_item_present: Search for NEEDLE in HAYSTACK.
559 * NEEDLE is a normal C string. HAYSTACK is a list of concatenated C strings,
560 * each with a terminating NUL. The last item in the list is identified by
561 * the fact that its terminating NUL is itself followed by a second NUL.
563 * This data structure does not lend itself to fast searching, but we only
564 * do this when wd_sanity_check() thinks that a filesystem might have been
565 * mounted or unmounted. That doesn't happen very often.
567 static int
568 list_item_present(const char *needle, const char *haystack)
570 if (NULL != haystack)
572 const char *s = haystack;
573 while (*s)
575 if (0 == strcmp(s, needle))
577 return 1;
579 else
581 s += strlen(s);
582 ++s; /* skip the first NUL. */
586 return 0;
590 /* Determine if a directory has recently had a filesystem
591 * mounted on it or unmounted from it.
593 static enum MountPointStateChange
594 get_mount_point_state(const char *dir)
596 int was_mounted, is_mounted;
598 was_mounted = list_item_present(dir, mount_points);
600 if (mount_points)
602 free(mount_points);
604 mount_points = get_mounted_filesystems();
606 is_mounted = list_item_present(dir, mount_points);
608 if (was_mounted == is_mounted)
609 return MountPointStateUnchanged;
610 else if (is_mounted)
611 return MountPointRecentlyMounted;
612 else
613 return MountPointRecentlyUnmounted;
617 /* Examine the results of the stat() of a directory from before we
618 * entered or left it, with the results of stat()ing it afterward. If
619 * these are different, the filesystem tree has been modified while we
620 * were traversing it. That might be an attempt to use a race
621 * condition to persuade find to do something it didn't intend
622 * (e.g. an attempt by an ordinary user to exploit the fact that root
623 * sometimes runs find on the whole filesystem). However, this can
624 * also happen if automount is running (certainly on Solaris). With
625 * automount, moving into a directory can cause a filesystem to be
626 * mounted there.
628 * To cope sensibly with this, we will raise an error if we see the
629 * device number change unless we are chdir()ing into a subdirectory,
630 * and the directory we moved into has been mounted or unmounted "recently".
631 * Here "recently" means since we started "find" or we last re-read
632 * the /etc/mnttab file.
634 * If the device number does not change but the inode does, that is a
635 * problem.
637 * If the device number and inode are both the same, we are happy.
639 * If a filesystem is (un)mounted as we chdir() into the directory, that
640 * may mean that we're now examining a section of the filesystem that might
641 * have been excluded from consideration (via -prune or -quit for example).
642 * Hence we print a warning message to indicate that the output of find
643 * might be inconsistent due to the change in the filesystem.
645 static void
646 wd_sanity_check(const char *thing_to_stat,
647 const char *program_name,
648 const char *what,
649 const struct stat *oldinfo,
650 struct stat *newinfo,
651 int parent,
652 int line_no,
653 enum TraversalDirection direction)
655 const char *fstype;
656 char *specific_what = NULL;
658 int isfatal = 1;
660 if ((*xstat) (".", newinfo) != 0)
661 error (1, errno, "%s", thing_to_stat);
663 if (oldinfo->st_dev != newinfo->st_dev)
665 specific_what = specific_dirname(what);
667 /* This condition is rare, so once we are here it is
668 * reasonable to perform an expensive computation to
669 * determine if we should continue or fail.
671 if (TraversingDown == direction)
673 /* We stat()ed a directory, chdir()ed into it (we know this
674 * since direction is TraversingDown), stat()ed it again,
675 * and noticed that the device numbers are different. Check
676 * if the filesystem was recently mounted.
678 * If it was, it looks like chdir()ing into the directory
679 * caused a filesystem to be mounted. Maybe automount is
680 * running. Anyway, that's probably OK - but it happens
681 * only when we are moving downward.
683 * We also allow for the possibility that a similar thing
684 * has happened with the unmounting of a filesystem. This
685 * is much rarer, as it relies on an automounter timeout
686 * occurring at exactly the wrong moment.
688 enum MountPointStateChange transition = get_mount_point_state(specific_what);
689 switch (transition)
691 case MountPointRecentlyUnmounted:
692 isfatal = 0;
693 error (0, 0,
694 _("Warning: filesystem %s has recently been unmounted."),
695 specific_what);
696 break;
698 case MountPointRecentlyMounted:
699 isfatal = 0;
700 error (0, 0,
701 _("Warning: filesystem %s has recently been mounted."),
702 specific_what);
703 break;
705 case MountPointStateUnchanged:
706 isfatal = 1;
707 break;
711 if (isfatal)
713 fstype = filesystem_type(thing_to_stat, ".", newinfo);
714 error (isfatal, 0,
715 _("%s%s changed during execution of %s (old device number %ld, new device number %ld, filesystem type is %s) [ref %ld]"),
716 specific_what,
717 parent ? "/.." : "",
718 program_name,
719 (long) oldinfo->st_dev,
720 (long) newinfo->st_dev,
721 fstype,
722 line_no);
724 else
726 /* Since the device has changed under us, the inode number
727 * will almost certainly also be different. However, we have
728 * already decided that this is not a problem. Hence we return
729 * without checking the inode number.
731 free(specific_what);
732 return;
736 /* Device number was the same, check if the inode has changed. */
737 if (oldinfo->st_ino != newinfo->st_ino)
739 specific_what = specific_dirname(what);
740 fstype = filesystem_type(thing_to_stat, ".", newinfo);
742 error (1, 0,
743 _("%s%s changed during execution of %s (old inode number %ld, new inode number %ld, filesystem type is %s) [ref %ld]"),
744 specific_what,
745 parent ? "/.." : "",
746 program_name,
747 (long) oldinfo->st_ino,
748 (long) newinfo->st_ino,
749 fstype,
750 line_no);
751 free(specific_what);
756 /* Safely go back to the starting directory. */
757 static void
758 chdir_back (void)
760 struct stat stat_buf;
762 if (starting_desc < 0)
764 if (chdir (starting_dir) != 0)
765 error (1, errno, "%s", starting_dir);
767 wd_sanity_check(starting_dir,
768 program_name, starting_dir,
769 &starting_stat_buf, &stat_buf, 0, __LINE__,
770 TraversingUp);
772 else
774 if (fchdir (starting_desc) != 0)
775 error (1, errno, "%s", starting_dir);
779 /* Descend PATHNAME, which is a command-line argument. */
781 static void
782 process_top_path (char *pathname)
784 struct stat stat_buf, cur_stat_buf;
786 curdepth = 0;
787 path_length = strlen (pathname);
789 /* We stat each pathname given on the command-line twice --
790 once here and once in process_path. It's not too bad, though,
791 since the kernel can read the stat information out of its inode
792 cache the second time. */
793 if ((*xstat) (pathname, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode))
795 if (chdir (pathname) < 0)
797 if (!ignore_readdir_race || (errno != ENOENT) )
799 error (0, errno, "%s", pathname);
800 exit_status = 1;
802 return;
805 /* Check that we are where we should be. */
806 wd_sanity_check(pathname, program_name, pathname,
807 &stat_buf, &cur_stat_buf, 0, __LINE__,
808 TraversingDown);
810 process_path (pathname, ".", false, ".");
811 chdir_back ();
813 else
814 process_path (pathname, pathname, false, ".");
817 /* Info on each directory in the current tree branch, to avoid
818 getting stuck in symbolic link loops. */
819 struct dir_id
821 ino_t ino;
822 dev_t dev;
824 static struct dir_id *dir_ids = NULL;
825 /* Entries allocated in `dir_ids'. */
826 static int dir_alloc = 0;
827 /* Index in `dir_ids' of directory currently being searched.
828 This is always the last valid entry. */
829 static int dir_curr = -1;
830 /* (Arbitrary) number of entries to grow `dir_ids' by. */
831 #define DIR_ALLOC_STEP 32
833 /* Recursively descend path PATHNAME, applying the predicates.
834 LEAF is true if PATHNAME is known to be in a directory that has no
835 more unexamined subdirectories, and therefore it is not a directory.
836 Knowing this allows us to avoid calling stat as long as possible for
837 leaf files.
839 NAME is PATHNAME relative to the current directory. We access NAME
840 but print PATHNAME.
842 PARENT is the path of the parent of NAME, relative to find's
843 starting directory.
845 Return nonzero iff PATHNAME is a directory. */
847 static int
848 process_path (char *pathname, char *name, boolean leaf, char *parent)
850 struct stat stat_buf;
851 static dev_t root_dev; /* Device ID of current argument pathname. */
852 int i;
854 /* Assume it is a non-directory initially. */
855 stat_buf.st_mode = 0;
857 rel_pathname = name;
859 if (leaf)
860 have_stat = false;
861 else
863 if ((*xstat) (name, &stat_buf) != 0)
865 if (!ignore_readdir_race || (errno != ENOENT) )
867 error (0, errno, "%s", pathname);
868 exit_status = 1;
870 return 0;
872 have_stat = true;
875 if (!S_ISDIR (stat_buf.st_mode))
877 if (curdepth >= mindepth)
878 apply_predicate (pathname, &stat_buf, eval_tree);
879 return 0;
882 /* From here on, we're working on a directory. */
884 stop_at_current_level = maxdepth >= 0 && curdepth >= maxdepth;
886 /* If we've already seen this directory on this branch,
887 don't descend it again. */
888 for (i = 0; i <= dir_curr; i++)
889 if (stat_buf.st_ino == dir_ids[i].ino &&
890 stat_buf.st_dev == dir_ids[i].dev)
891 stop_at_current_level = true;
893 if (dir_alloc <= ++dir_curr)
895 dir_alloc += DIR_ALLOC_STEP;
896 dir_ids = (struct dir_id *)
897 xrealloc ((char *) dir_ids, dir_alloc * sizeof (struct dir_id));
899 dir_ids[dir_curr].ino = stat_buf.st_ino;
900 dir_ids[dir_curr].dev = stat_buf.st_dev;
902 if (stay_on_filesystem)
904 if (curdepth == 0)
905 root_dev = stat_buf.st_dev;
906 else if (stat_buf.st_dev != root_dev)
907 stop_at_current_level = true;
910 if (do_dir_first && curdepth >= mindepth)
911 apply_predicate (pathname, &stat_buf, eval_tree);
913 #ifdef DEBUG
914 fprintf(stderr, "pathname = %s, stop_at_current_level = %d\n",
915 pathname, stop_at_current_level);
916 #endif /* DEBUG */
918 if (stop_at_current_level == false)
919 /* Scan directory on disk. */
920 process_dir (pathname, name, strlen (pathname), &stat_buf, parent);
922 if (do_dir_first == false && curdepth >= mindepth)
924 rel_pathname = name;
925 apply_predicate (pathname, &stat_buf, eval_tree);
928 dir_curr--;
930 return 1;
933 /* Scan directory PATHNAME and recurse through process_path for each entry.
935 PATHLEN is the length of PATHNAME.
937 NAME is PATHNAME relative to the current directory.
939 STATP is the results of *xstat on it.
941 PARENT is the path of the parent of NAME, relative to find's
942 starting directory. */
944 static void
945 process_dir (char *pathname, char *name, int pathlen, struct stat *statp, char *parent)
947 char *name_space; /* Names of files in PATHNAME. */
948 int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */
949 struct stat stat_buf;
951 subdirs_left = statp->st_nlink - 2; /* Account for name and ".". */
953 errno = 0;
954 name_space = savedir (name);
955 if (name_space == NULL)
957 if (errno)
959 error (0, errno, "%s", pathname);
960 exit_status = 1;
962 else
963 error (1, 0, _("virtual memory exhausted"));
965 else
967 register char *namep; /* Current point in `name_space'. */
968 char *cur_path; /* Full path of each file to process. */
969 char *cur_name; /* Base name of each file to process. */
970 unsigned cur_path_size; /* Bytes allocated for `cur_path'. */
971 register unsigned file_len; /* Length of each path to process. */
972 register unsigned pathname_len; /* PATHLEN plus trailing '/'. */
974 if (pathname[pathlen - 1] == '/')
975 pathname_len = pathlen + 1; /* For '\0'; already have '/'. */
976 else
977 pathname_len = pathlen + 2; /* For '/' and '\0'. */
978 cur_path_size = 0;
979 cur_path = NULL;
981 if (strcmp (name, ".") && chdir (name) < 0)
983 error (0, errno, "%s", pathname);
984 exit_status = 1;
985 return;
988 /* Check that we are where we should be. */
989 if (1)
991 struct stat tmp = {0};
992 tmp.st_dev = dir_ids[dir_curr].dev;
993 tmp.st_ino = dir_ids[dir_curr].ino;
994 wd_sanity_check(pathname,
995 program_name, starting_dir,
996 &tmp, &stat_buf, 0, __LINE__,
997 TraversingDown);
1000 for (namep = name_space; *namep; namep += file_len - pathname_len + 1)
1002 /* Append this directory entry's name to the path being searched. */
1003 file_len = pathname_len + strlen (namep);
1004 if (file_len > cur_path_size)
1006 while (file_len > cur_path_size)
1007 cur_path_size += 1024;
1008 if (cur_path)
1009 free (cur_path);
1010 cur_path = xmalloc (cur_path_size);
1011 strcpy (cur_path, pathname);
1012 cur_path[pathname_len - 2] = '/';
1014 cur_name = cur_path + pathname_len - 1;
1015 strcpy (cur_name, namep);
1017 curdepth++;
1018 if (!no_leaf_check)
1019 /* Normal case optimization.
1020 On normal Unix filesystems, a directory that has no
1021 subdirectories has two links: its name, and ".". Any
1022 additional links are to the ".." entries of its
1023 subdirectories. Once we have processed as many
1024 subdirectories as there are additional links, we know
1025 that the rest of the entries are non-directories --
1026 in other words, leaf files. */
1027 subdirs_left -= process_path (cur_path, cur_name,
1028 subdirs_left == 0, pathname);
1029 else
1030 /* There might be weird (e.g., CD-ROM or MS-DOS) filesystems
1031 mounted, which don't have Unix-like directory link counts. */
1032 process_path (cur_path, cur_name, false, pathname);
1033 curdepth--;
1036 if (strcmp (name, "."))
1038 /* We could go back and do the next command-line arg
1039 instead, maybe using longjmp. */
1040 char const *dir;
1041 boolean deref;
1042 if (symlink_handling == SYMLINK_ALWAYS_DEREF)
1043 deref = true;
1044 else if (symlink_handling == SYMLINK_DEREF_ARGSONLY && (curdepth == 0))
1045 deref = true;
1046 else
1047 deref = false;
1049 if (!deref)
1050 dir = "..";
1051 else
1053 chdir_back ();
1054 dir = parent;
1057 if (chdir (dir) != 0)
1058 error (1, errno, "%s", parent);
1060 /* Check that we are where we should be. */
1061 if (1)
1063 struct stat tmp;
1064 int problem_is_with_parent;
1066 if (dir_curr > 0)
1068 tmp.st_dev = dir_ids[dir_curr-1].dev;
1069 tmp.st_ino = dir_ids[dir_curr-1].ino;
1071 else
1073 tmp.st_dev = starting_stat_buf.st_dev;
1074 tmp.st_ino = starting_stat_buf.st_ino;
1077 problem_is_with_parent = deref ? 1 : 0;
1078 wd_sanity_check(pathname,
1079 program_name,
1080 deref ? parent : starting_dir,
1081 &tmp, &stat_buf,
1082 problem_is_with_parent, __LINE__,
1083 TraversingUp);
1087 if (cur_path)
1088 free (cur_path);
1089 free (name_space);
1093 #if 0
1094 /* Return true if there are no side effects in any of the predicates in
1095 predicate list PRED, false if there are any. */
1097 static boolean
1098 no_side_effects (struct predicate *pred)
1100 while (pred != NULL)
1102 if (pred->side_effects)
1103 return (false);
1104 pred = pred->pred_next;
1106 return (true);
1108 #endif
1110 /* Return true if there are no predicates with no_default_print in
1111 predicate list PRED, false if there are any.
1112 Returns true if default print should be performed */
1114 static boolean
1115 default_prints (struct predicate *pred)
1117 while (pred != NULL)
1119 if (pred->no_default_print)
1120 return (false);
1121 pred = pred->pred_next;
1123 return (true);