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)
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,
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>. */
37 #include "../gnulib/lib/xalloc.h"
38 #include "../gnulib/lib/human.h"
39 #include "../gnulib/lib/canonicalize.h"
41 #include "../gnulib/lib/savedir.h"
49 # define _(Text) gettext (Text)
52 #define textdomain(Domain)
53 #define bindtextdomain(Package, Directory)
56 # define N_(String) gettext_noop (String)
58 /* See locate.c for explanation as to why not use (String) */
59 # define N_(String) String
62 #define apply_predicate(pathname, stat_buf_ptr, node) \
63 (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
66 static void init_mounted_dev_list(void);
67 static void process_top_path
PARAMS((char *pathname
));
68 static int process_path
PARAMS((char *pathname
, char *name
, boolean leaf
, char *parent
));
69 static void process_dir
PARAMS((char *pathname
, char *name
, int pathlen
, struct stat
*statp
, char *parent
));
71 static boolean no_side_effects
PARAMS((struct predicate
*pred
));
73 static boolean default_prints
PARAMS((struct predicate
*pred
));
75 /* Name this program was run with. */
78 /* All predicates for each path to process. */
79 struct predicate
*predicates
;
81 /* The last predicate allocated. */
82 struct predicate
*last_pred
;
84 /* The root of the evaluation tree. */
85 static struct predicate
*eval_tree
;
87 /* If true, process directory before contents. True unless -depth given. */
90 /* If >=0, don't descend more than this many levels of subdirectories. */
93 /* If >=0, don't process files above this level. */
96 /* Current depth; 0 means current path is a command line arg. */
99 /* Output block size. */
100 int output_block_size
;
102 /* Time at start of execution. */
105 /* Seconds between 00:00 1/1/70 and either one day before now
106 (the default), or the start of today (if -daystart is given). */
107 time_t cur_day_start
;
109 /* If true, cur_day_start has been adjusted to the start of the day. */
112 /* If true, do not assume that files in directories with nlink == 2
113 are non-directories. */
114 boolean no_leaf_check
;
116 /* If true, don't cross filesystem boundaries. */
117 boolean stay_on_filesystem
;
119 /* If true, don't descend past current directory.
120 Can be set by -prune, -maxdepth, and -xdev/-mount. */
121 boolean stop_at_current_level
;
123 /* The full path of the initial working directory, or "." if
124 STARTING_DESC is nonnegative. */
125 char const *starting_dir
= ".";
127 /* A file descriptor open to the initial working directory.
128 Doing it this way allows us to work when the i.w.d. has
129 unreadable parents. */
132 /* The stat buffer of the initial working directory. */
133 struct stat starting_stat_buf
;
135 /* If true, we have called stat on the current path. */
138 /* The file being operated on, relative to the current directory.
139 Used for stat, readlink, remove, and opendir. */
142 /* Length of current path. */
145 /* true if following symlinks. Should be consistent with xstat. */
146 /* boolean dereference; */
147 enum SymlinkOption symlink_handling
;
150 /* Pointer to the function used to stat files. */
153 /* Status value to return to system. */
156 /* If true, we ignore the problem where we find that a directory entry
157 * no longer exists by the time we get around to processing it.
159 boolean ignore_readdir_race
;
162 /* If true, we issue warning messages
167 enum TraversalDirection
175 following_links(void)
177 switch (symlink_handling
)
179 case SYMLINK_ALWAYS_DEREF
:
181 case SYMLINK_DEREF_ARGSONLY
:
182 return (curdepth
== 0);
183 case SYMLINK_NEVER_DEREF
:
190 /* optionh_stat() implements the stat operation when the -H option is
193 * If the item to be examined is a command-line argument, we follow
194 * symbolic links. If the stat() call fails on the command-line item,
195 * we fall back on the properties of the symbolic link.
197 * If the item to be examined is not a command-line argument, we
198 * examine the link itself.
201 optionh_stat(const char *name
, struct stat
*p
)
205 /* This file is from the command line; deference the link (if it
208 if (0 == stat(name
, p
))
215 /* fallback - return the information for the link itself. */
216 return lstat(name
, p
);
221 /* Not a file on the command line; do not derefernce the link.
223 return lstat(name
, p
);
227 /* optionl_stat() implements the stat operation when the -L option is
228 * in effect. That option makes us examine the thing the symbolic
229 * link points to, not the symbolic link itself.
232 optionl_stat(const char *name
, struct stat
*p
)
234 if (0 == stat(name
, p
))
236 return 0; /* normal case. */
240 return lstat(name
, p
); /* can't follow link, return the link itself. */
244 /* optionp_stat() implements the stat operation when the -P option is
245 * in effect (this is also the default). That option makes us examine
246 * the symbolic link itself, not the thing it points to.
249 optionp_stat(const char *name
, struct stat
*p
)
251 return lstat(name
, p
);
256 debug_stat (const char *file
, struct stat
*bufp
)
258 fprintf (stderr
, "debug_stat (%s)\n", file
);
259 switch (symlink_handling
)
261 case SYMLINK_ALWAYS_DEREF
:
262 return optionl_stat(file
, bufp
);
263 case SYMLINK_DEREF_ARGSONLY
:
264 return optionh_stat(file
, bufp
);
265 case SYMLINK_NEVER_DEREF
:
266 return optionp_stat(file
, bufp
);
269 #endif /* DEBUG_STAT */
272 set_follow_state(enum SymlinkOption opt
)
276 case SYMLINK_ALWAYS_DEREF
: /* -L */
277 xstat
= optionl_stat
;
278 no_leaf_check
= false;
281 case SYMLINK_NEVER_DEREF
: /* -P (default) */
282 xstat
= optionp_stat
;
283 /* Can't turn on no_leaf_check because the user might have specified
288 case SYMLINK_DEREF_ARGSONLY
: /* -H */
289 xstat
= optionh_stat
;
290 no_leaf_check
= true;
293 /* For DBEUG_STAT, the choice is made at runtime within debug_stat()
294 * by checking the contents of the symlink_handling variable.
296 #if defined(DEBUG_STAT)
298 #endif /* !DEBUG_STAT */
303 main (int argc
, char **argv
)
306 PFB parse_function
; /* Pointer to the function which parses. */
307 struct predicate
*cur_pred
;
308 char *predicate_name
; /* Name of predicate being parsed. */
309 int end_of_leading_options
= 0; /* First arg after any -H/-L etc. */
310 program_name
= argv
[0];
312 #ifdef HAVE_SETLOCALE
313 setlocale (LC_ALL
, "");
315 bindtextdomain (PACKAGE
, LOCALEDIR
);
316 textdomain (PACKAGE
);
331 maxdepth
= mindepth
= -1;
332 start_time
= time (NULL
);
333 cur_day_start
= start_time
- DAYSECS
;
335 no_leaf_check
= false;
336 stay_on_filesystem
= false;
337 ignore_readdir_race
= false;
340 #if defined(DEBUG_STAT)
342 #endif /* !DEBUG_STAT */
345 human_block_size (getenv ("FIND_BLOCK_SIZE"), 0, &output_block_size
);
347 if (getenv("POSIXLY_CORRECT"))
348 output_block_size
= 512;
350 output_block_size
= 1024;
352 if (getenv("FIND_BLOCK_SIZE"))
354 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"));
357 set_follow_state(SYMLINK_NEVER_DEREF
); /* The default is equivalent to -P. */
359 init_mounted_dev_list();
364 printf ("cur_day_start = %s", ctime (&cur_day_start
));
367 /* Check for -P, -H or -L options. */
368 for (i
=1; (end_of_leading_options
= i
) < argc
; ++i
)
370 if (0 == strcmp("-H", argv
[i
]))
372 /* Meaning: dereference symbolic links on command line, but nowhere else. */
373 set_follow_state(SYMLINK_DEREF_ARGSONLY
);
375 else if (0 == strcmp("-L", argv
[i
]))
377 /* Meaning: dereference all symbolic links. */
378 set_follow_state(SYMLINK_ALWAYS_DEREF
);
380 else if (0 == strcmp("-P", argv
[i
]))
382 /* Meaning: never dereference symbolic links (default). */
383 set_follow_state(SYMLINK_NEVER_DEREF
);
385 else if (0 == strcmp("--", argv
[i
]))
387 /* -- signifies the end of options. */
388 end_of_leading_options
= i
+1; /* Next time start with the next option */
393 /* Hmm, must be one of
397 end_of_leading_options
= i
; /* Next time start with this option */
402 /* We are now processing the part of the "find" command line
403 * after the -H/-L options (if any).
406 /* fprintf(stderr, "rest: optind=%ld\n", (long)optind); */
408 /* Find where in ARGV the predicates begin. */
409 for (i
= end_of_leading_options
; i
< argc
&& strchr ("-!(),", argv
[i
][0]) == NULL
; i
++)
411 /* fprintf(stderr, "Looks like %s is not a predicate\n", argv[i]); */
415 /* Enclose the expression in `( ... )' so a default -print will
416 apply to the whole expression. */
417 parse_open (argv
, &argc
);
418 /* Build the input order list. */
421 if (strchr ("-!(),", argv
[i
][0]) == NULL
)
422 usage (_("paths must precede expression"));
423 predicate_name
= argv
[i
];
424 parse_function
= find_parser (predicate_name
);
425 if (parse_function
== NULL
)
426 /* Command line option not recognized */
427 error (1, 0, _("invalid predicate `%s'"), predicate_name
);
429 if (!(*parse_function
) (argv
, &i
))
432 /* Command line option requires an argument */
433 error (1, 0, _("missing argument to `%s'"), predicate_name
);
435 error (1, 0, _("invalid argument `%s' to `%s'"),
436 argv
[i
], predicate_name
);
439 if (predicates
->pred_next
== NULL
)
441 /* No predicates that do something other than set a global variable
442 were given; remove the unneeded initial `(' and add `-print'. */
443 cur_pred
= predicates
;
444 predicates
= last_pred
= predicates
->pred_next
;
445 free ((char *) cur_pred
);
446 parse_print (argv
, &argc
);
448 else if (!default_prints (predicates
->pred_next
))
450 /* One or more predicates that produce output were given;
451 remove the unneeded initial `('. */
452 cur_pred
= predicates
;
453 predicates
= predicates
->pred_next
;
454 free ((char *) cur_pred
);
458 /* `( user-supplied-expression ) -print'. */
459 parse_close (argv
, &argc
);
460 parse_print (argv
, &argc
);
464 printf (_("Predicate List:\n"));
465 print_list (predicates
);
468 /* Done parsing the predicates. Build the evaluation tree. */
469 cur_pred
= predicates
;
470 eval_tree
= get_expr (&cur_pred
, NO_PREC
);
472 /* Check if we have any left-over predicates (this fixes
473 * Debian bug #185202).
475 if (cur_pred
!= NULL
)
477 error (1, 0, _("unexpected extra predicate"));
481 printf (_("Eval Tree:\n"));
482 print_tree (eval_tree
, 0);
485 /* Rearrange the eval tree in optimal-predicate order. */
486 opt_expr (&eval_tree
);
488 /* Determine the point, if any, at which to stat the file. */
489 mark_stat (eval_tree
);
492 printf (_("Optimized Eval Tree:\n"));
493 print_tree (eval_tree
, 0);
496 starting_desc
= open (".", O_RDONLY
);
497 if (0 <= starting_desc
&& fchdir (starting_desc
) != 0)
499 close (starting_desc
);
502 if (starting_desc
< 0)
504 starting_dir
= xgetcwd ();
506 error (1, errno
, _("cannot get current directory"));
508 if ((*xstat
) (".", &starting_stat_buf
) != 0)
509 error (1, errno
, _("cannot get current directory"));
511 /* If no paths are given, default to ".". */
512 for (i
= end_of_leading_options
; i
< argc
&& strchr ("-!(),", argv
[i
][0]) == NULL
; i
++)
514 process_top_path (argv
[i
]);
517 /* If there were no path arguments, default to ".". */
518 if (i
== end_of_leading_options
)
521 * We use a temporary variable here because some actions modify
522 * the path temporarily. Hence if we use a string constant,
523 * we get a coredump. The best example of this is if we say
524 * "find -printf %H" (note, not "find . -printf %H").
526 char defaultpath
[2] = ".";
527 process_top_path (defaultpath
);
536 specific_dirname(const char *dir
)
540 if (0 == strcmp(".", dir
))
542 /* OK, what's '.'? */
543 if (NULL
!= getcwd(dirname
, sizeof(dirname
)))
545 return strdup(dirname
);
554 return canonicalize_filename_mode(dir
, CAN_EXISTING
);
562 /* list_item_present: Search for NEEDLE in HAYSTACK.
564 * NEEDLE is a normal C string. HAYSTACK is a list of concatenated C strings,
565 * each with a terminating NUL. The last item in the list is identified by
566 * the fact that its terminating NUL is itself followed by a second NUL.
568 * This data structure does not lend itself to fast searching, but we only
569 * do this when wd_sanity_check() thinks that a filesystem might have been
570 * mounted or unmounted. That doesn't happen very often.
573 list_item_present(const char *needle
, const char *haystack
)
575 if (NULL
!= haystack
)
577 const char *s
= haystack
;
580 if (0 == strcmp(s
, needle
))
587 ++s
; /* skip the first NUL. */
594 static char *mount_points
= NULL
;
597 /* Initialise our idea of what the list of mount points is.
598 * this function is called exactly once.
601 init_mount_point_list(void)
603 assert(NULL
== mount_points
);
604 mount_points
= get_mounted_filesystems();
608 refresh_mount_point_list(void)
615 init_mount_point_list();
618 /* Determine if a directory has recently had a filesystem
619 * mounted on it or unmounted from it.
621 static enum MountPointStateChange
622 get_mount_point_state(const char *dir
)
624 int was_mounted
, is_mounted
;
626 was_mounted
= list_item_present(dir
, mount_points
);
627 refresh_mount_point_list();
628 is_mounted
= list_item_present(dir
, mount_points
);
630 if (was_mounted
== is_mounted
)
631 return MountPointStateUnchanged
;
633 return MountPointRecentlyMounted
;
635 return MountPointRecentlyUnmounted
;
641 static dev_t
*mounted_devices
= NULL
;
642 static size_t num_mounted_devices
= 0u;
646 init_mounted_dev_list()
648 assert(NULL
== mounted_devices
);
649 assert(0 == num_mounted_devices
);
650 mounted_devices
= get_mounted_devices(&num_mounted_devices
);
654 refresh_mounted_dev_list(void)
658 free(mounted_devices
);
661 num_mounted_devices
= 0u;
662 init_mounted_dev_list();
666 /* Search for device DEV in the array LIST, which is of size N. */
668 dev_present(dev_t dev
, const dev_t
*list
, size_t n
)
674 if ( (*list
++) == dev
)
681 enum MountPointStateChange
683 MountPointRecentlyMounted
,
684 MountPointRecentlyUnmounted
,
685 MountPointStateUnchanged
690 static enum MountPointStateChange
691 get_mount_state(dev_t newdev
)
693 int new_is_present
, new_was_present
;
695 new_was_present
= dev_present(newdev
, mounted_devices
, num_mounted_devices
);
696 refresh_mounted_dev_list();
697 new_is_present
= dev_present(newdev
, mounted_devices
, num_mounted_devices
);
699 if (new_was_present
== new_is_present
)
700 return MountPointStateUnchanged
;
701 else if (new_is_present
)
702 return MountPointRecentlyMounted
;
704 return MountPointRecentlyUnmounted
;
709 /* Examine the results of the stat() of a directory from before we
710 * entered or left it, with the results of stat()ing it afterward. If
711 * these are different, the filesystem tree has been modified while we
712 * were traversing it. That might be an attempt to use a race
713 * condition to persuade find to do something it didn't intend
714 * (e.g. an attempt by an ordinary user to exploit the fact that root
715 * sometimes runs find on the whole filesystem). However, this can
716 * also happen if automount is running (certainly on Solaris). With
717 * automount, moving into a directory can cause a filesystem to be
720 * To cope sensibly with this, we will raise an error if we see the
721 * device number change unless we are chdir()ing into a subdirectory,
722 * and the directory we moved into has been mounted or unmounted "recently".
723 * Here "recently" means since we started "find" or we last re-read
724 * the /etc/mnttab file.
726 * If the device number does not change but the inode does, that is a
729 * If the device number and inode are both the same, we are happy.
731 * If a filesystem is (un)mounted as we chdir() into the directory, that
732 * may mean that we're now examining a section of the filesystem that might
733 * have been excluded from consideration (via -prune or -quit for example).
734 * Hence we print a warning message to indicate that the output of find
735 * might be inconsistent due to the change in the filesystem.
738 wd_sanity_check(const char *thing_to_stat
,
739 const char *program_name
,
741 const struct stat
*oldinfo
,
742 struct stat
*newinfo
,
745 enum TraversalDirection direction
,
746 boolean
*changed
) /* output parameter */
749 char *specific_what
= NULL
;
754 if ((*xstat
) (".", newinfo
) != 0)
755 error (1, errno
, "%s", thing_to_stat
);
757 if (oldinfo
->st_dev
!= newinfo
->st_dev
)
760 specific_what
= specific_dirname(what
);
762 /* This condition is rare, so once we are here it is
763 * reasonable to perform an expensive computation to
764 * determine if we should continue or fail.
766 if (TraversingDown
== direction
)
768 /* We stat()ed a directory, chdir()ed into it (we know this
769 * since direction is TraversingDown), stat()ed it again,
770 * and noticed that the device numbers are different. Check
771 * if the filesystem was recently mounted.
773 * If it was, it looks like chdir()ing into the directory
774 * caused a filesystem to be mounted. Maybe automount is
775 * running. Anyway, that's probably OK - but it happens
776 * only when we are moving downward.
778 * We also allow for the possibility that a similar thing
779 * has happened with the unmounting of a filesystem. This
780 * is much rarer, as it relies on an automounter timeout
781 * occurring at exactly the wrong moment.
783 enum MountPointStateChange transition
= get_mount_state(newinfo
->st_dev
);
786 case MountPointRecentlyUnmounted
:
789 _("Warning: filesystem %s has recently been unmounted."),
793 case MountPointRecentlyMounted
:
796 _("Warning: filesystem %s has recently been mounted."),
800 case MountPointStateUnchanged
:
808 fstype
= filesystem_type(thing_to_stat
, ".", newinfo
);
810 _("%s%s changed during execution of %s (old device number %ld, new device number %ld, filesystem type is %s) [ref %ld]"),
814 (long) oldinfo
->st_dev
,
815 (long) newinfo
->st_dev
,
821 /* Since the device has changed under us, the inode number
822 * will almost certainly also be different. However, we have
823 * already decided that this is not a problem. Hence we return
824 * without checking the inode number.
831 /* Device number was the same, check if the inode has changed. */
832 if (oldinfo
->st_ino
!= newinfo
->st_ino
)
835 specific_what
= specific_dirname(what
);
836 fstype
= filesystem_type(thing_to_stat
, ".", newinfo
);
839 _("%s%s changed during execution of %s (old inode number %ld, new inode number %ld, filesystem type is %s) [ref %ld]"),
843 (long) oldinfo
->st_ino
,
844 (long) newinfo
->st_ino
,
854 SafeChdirFailSymlink
,
859 /* Safely perform a change in directory. */
861 safely_chdir(const char *dest
, enum TraversalDirection direction
)
863 struct stat statbuf_dest
, statbuf_arrived
;
864 int rv
=SafeChdirFailDefect
, dotfd
=-1;
868 dotfd
= open(".", O_RDONLY
);
871 /* Stat the directory we're going to. */
872 if (0 == (following_links() ? stat
: lstat
)(dest
, &statbuf_dest
))
875 if (!following_links() && S_ISLNK(statbuf_dest
.st_mode
))
877 rv
= SafeChdirFailSymlink
;
885 rv
= SafeChdirFailStat
;
886 name
= specific_dirname(dest
);
898 name
= specific_dirname(".");
899 error(0, errno
, "%s", name
);
914 /* Safely go back to the starting directory. */
918 struct stat stat_buf
;
921 if (starting_desc
< 0)
923 if (chdir (starting_dir
) != 0)
924 error (1, errno
, "%s", starting_dir
);
926 wd_sanity_check(starting_dir
,
927 program_name
, starting_dir
,
928 &starting_stat_buf
, &stat_buf
, 0, __LINE__
,
929 TraversingUp
, &dummy
);
933 if (fchdir (starting_desc
) != 0)
934 error (1, errno
, "%s", starting_dir
);
938 /* Descend PATHNAME, which is a command-line argument. */
941 process_top_path (char *pathname
)
943 struct stat stat_buf
, cur_stat_buf
;
947 path_length
= strlen (pathname
);
949 /* We stat each pathname given on the command-line twice --
950 once here and once in process_path. It's not too bad, though,
951 since the kernel can read the stat information out of its inode
952 cache the second time. */
953 if ((*xstat
) (pathname
, &stat_buf
) == 0 && S_ISDIR (stat_buf
.st_mode
))
955 if (chdir (pathname
) < 0)
957 if (!ignore_readdir_race
|| (errno
!= ENOENT
) )
959 error (0, errno
, "%s", pathname
);
965 /* Check that we are where we should be. */
966 wd_sanity_check(pathname
, program_name
,
968 &stat_buf
, &cur_stat_buf
, 0, __LINE__
,
969 TraversingDown
, &dummy
);
971 process_path (pathname
, ".", false, ".");
975 process_path (pathname
, pathname
, false, ".");
978 /* Info on each directory in the current tree branch, to avoid
979 getting stuck in symbolic link loops. */
985 static struct dir_id
*dir_ids
= NULL
;
986 /* Entries allocated in `dir_ids'. */
987 static int dir_alloc
= 0;
988 /* Index in `dir_ids' of directory currently being searched.
989 This is always the last valid entry. */
990 static int dir_curr
= -1;
991 /* (Arbitrary) number of entries to grow `dir_ids' by. */
992 #define DIR_ALLOC_STEP 32
994 /* Recursively descend path PATHNAME, applying the predicates.
995 LEAF is true if PATHNAME is known to be in a directory that has no
996 more unexamined subdirectories, and therefore it is not a directory.
997 Knowing this allows us to avoid calling stat as long as possible for
1000 NAME is PATHNAME relative to the current directory. We access NAME
1003 PARENT is the path of the parent of NAME, relative to find's
1006 Return nonzero iff PATHNAME is a directory. */
1009 process_path (char *pathname
, char *name
, boolean leaf
, char *parent
)
1011 struct stat stat_buf
;
1012 static dev_t root_dev
; /* Device ID of current argument pathname. */
1015 /* Assume it is a non-directory initially. */
1016 stat_buf
.st_mode
= 0;
1018 rel_pathname
= name
;
1024 if ((*xstat
) (name
, &stat_buf
) != 0)
1026 if (!ignore_readdir_race
|| (errno
!= ENOENT
) )
1028 error (0, errno
, "%s", pathname
);
1036 if (!S_ISDIR (stat_buf
.st_mode
))
1038 if (curdepth
>= mindepth
)
1039 apply_predicate (pathname
, &stat_buf
, eval_tree
);
1043 /* From here on, we're working on a directory. */
1045 stop_at_current_level
= maxdepth
>= 0 && curdepth
>= maxdepth
;
1047 /* If we've already seen this directory on this branch,
1048 don't descend it again. */
1049 for (i
= 0; i
<= dir_curr
; i
++)
1050 if (stat_buf
.st_ino
== dir_ids
[i
].ino
&&
1051 stat_buf
.st_dev
== dir_ids
[i
].dev
)
1052 stop_at_current_level
= true;
1054 if (dir_alloc
<= ++dir_curr
)
1056 dir_alloc
+= DIR_ALLOC_STEP
;
1057 dir_ids
= (struct dir_id
*)
1058 xrealloc ((char *) dir_ids
, dir_alloc
* sizeof (struct dir_id
));
1060 dir_ids
[dir_curr
].ino
= stat_buf
.st_ino
;
1061 dir_ids
[dir_curr
].dev
= stat_buf
.st_dev
;
1063 if (stay_on_filesystem
)
1066 root_dev
= stat_buf
.st_dev
;
1067 else if (stat_buf
.st_dev
!= root_dev
)
1068 stop_at_current_level
= true;
1071 if (do_dir_first
&& curdepth
>= mindepth
)
1072 apply_predicate (pathname
, &stat_buf
, eval_tree
);
1075 fprintf(stderr
, "pathname = %s, stop_at_current_level = %d\n",
1076 pathname
, stop_at_current_level
);
1079 if (stop_at_current_level
== false)
1080 /* Scan directory on disk. */
1081 process_dir (pathname
, name
, strlen (pathname
), &stat_buf
, parent
);
1083 if (do_dir_first
== false && curdepth
>= mindepth
)
1085 rel_pathname
= name
;
1086 apply_predicate (pathname
, &stat_buf
, eval_tree
);
1094 /* Scan directory PATHNAME and recurse through process_path for each entry.
1096 PATHLEN is the length of PATHNAME.
1098 NAME is PATHNAME relative to the current directory.
1100 STATP is the results of *xstat on it.
1102 PARENT is the path of the parent of NAME, relative to find's
1103 starting directory. */
1106 process_dir (char *pathname
, char *name
, int pathlen
, struct stat
*statp
, char *parent
)
1108 char *name_space
; /* Names of files in PATHNAME. */
1109 int subdirs_left
; /* Number of unexamined subdirs in PATHNAME. */
1110 struct stat stat_buf
;
1112 subdirs_left
= statp
->st_nlink
- 2; /* Account for name and ".". */
1115 name_space
= savedir (name
);
1116 if (name_space
== NULL
)
1120 error (0, errno
, "%s", pathname
);
1124 error (1, 0, _("virtual memory exhausted"));
1128 register char *namep
; /* Current point in `name_space'. */
1129 char *cur_path
; /* Full path of each file to process. */
1130 char *cur_name
; /* Base name of each file to process. */
1131 unsigned cur_path_size
; /* Bytes allocated for `cur_path'. */
1132 register unsigned file_len
; /* Length of each path to process. */
1133 register unsigned pathname_len
; /* PATHLEN plus trailing '/'. */
1135 if (pathname
[pathlen
- 1] == '/')
1136 pathname_len
= pathlen
+ 1; /* For '\0'; already have '/'. */
1138 pathname_len
= pathlen
+ 2; /* For '/' and '\0'. */
1142 if (strcmp (name
, ".") && chdir (name
) < 0)
1144 error (0, errno
, "%s", pathname
);
1149 /* Check that we are where we should be. */
1155 memset(&tmp
, 0, sizeof(tmp
));
1156 tmp
.st_dev
= dir_ids
[dir_curr
].dev
;
1157 tmp
.st_ino
= dir_ids
[dir_curr
].ino
;
1159 wd_sanity_check(pathname
,
1162 &tmp
, &stat_buf
, 0, __LINE__
,
1163 TraversingDown
, &changed
);
1166 /* If there had been a change but wd_sanity_check()
1167 * accepted it, we need to accept that on the
1168 * way back up as well, so modify our record
1169 * of what we think we should see later.
1171 dir_ids
[dir_curr
].dev
= stat_buf
.st_dev
;
1172 dir_ids
[dir_curr
].ino
= stat_buf
.st_ino
;
1176 for (namep
= name_space
; *namep
; namep
+= file_len
- pathname_len
+ 1)
1178 /* Append this directory entry's name to the path being searched. */
1179 file_len
= pathname_len
+ strlen (namep
);
1180 if (file_len
> cur_path_size
)
1182 while (file_len
> cur_path_size
)
1183 cur_path_size
+= 1024;
1186 cur_path
= xmalloc (cur_path_size
);
1187 strcpy (cur_path
, pathname
);
1188 cur_path
[pathname_len
- 2] = '/';
1190 cur_name
= cur_path
+ pathname_len
- 1;
1191 strcpy (cur_name
, namep
);
1195 /* Normal case optimization.
1196 On normal Unix filesystems, a directory that has no
1197 subdirectories has two links: its name, and ".". Any
1198 additional links are to the ".." entries of its
1199 subdirectories. Once we have processed as many
1200 subdirectories as there are additional links, we know
1201 that the rest of the entries are non-directories --
1202 in other words, leaf files. */
1203 subdirs_left
-= process_path (cur_path
, cur_name
,
1204 subdirs_left
== 0, pathname
);
1206 /* There might be weird (e.g., CD-ROM or MS-DOS) filesystems
1207 mounted, which don't have Unix-like directory link counts. */
1208 process_path (cur_path
, cur_name
, false, pathname
);
1212 if (strcmp (name
, "."))
1214 /* We could go back and do the next command-line arg
1215 instead, maybe using longjmp. */
1217 boolean deref
= following_links() ? true : false;
1227 if (chdir (dir
) != 0)
1228 error (1, errno
, "%s", parent
);
1230 /* Check that we are where we should be. */
1233 boolean changed
= false;
1235 int problem_is_with_parent
;
1237 memset(&tmp
, 0, sizeof(tmp
));
1240 tmp
.st_dev
= dir_ids
[dir_curr
-1].dev
;
1241 tmp
.st_ino
= dir_ids
[dir_curr
-1].ino
;
1245 tmp
.st_dev
= starting_stat_buf
.st_dev
;
1246 tmp
.st_ino
= starting_stat_buf
.st_ino
;
1249 problem_is_with_parent
= deref
? 1 : 0;
1250 wd_sanity_check(pathname
,
1254 problem_is_with_parent
, __LINE__
,
1255 TraversingUp
, &changed
);
1266 /* Return true if there are no side effects in any of the predicates in
1267 predicate list PRED, false if there are any. */
1270 no_side_effects (struct predicate
*pred
)
1272 while (pred
!= NULL
)
1274 if (pred
->side_effects
)
1276 pred
= pred
->pred_next
;
1282 /* Return true if there are no predicates with no_default_print in
1283 predicate list PRED, false if there are any.
1284 Returns true if default print should be performed */
1287 default_prints (struct predicate
*pred
)
1289 while (pred
!= NULL
)
1291 if (pred
->no_default_print
)
1293 pred
= pred
->pred_next
;