1 /* find -- search for files in a directory hierarchy
2 Copyright (C) 1990, 91, 92, 93, 94 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* GNU find was written by Eric Decker <cire@cisco.com>,
19 with enhancements by David MacKenzie <djm@gnu.ai.mit.edu>,
20 Jay Plett <jay@silence.princeton.nj.us>,
21 and Tim Wood <axolotl!tim@toad.com>.
22 The idea for -print0 and xargs -0 came from
23 Dan Bernstein <brnstnd@kramden.acf.nyu.edu>. */
26 #include <sys/types.h>
44 #define apply_predicate(pathname, stat_buf_ptr, node) \
45 (*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
47 static void process_top_path
P_((char *pathname
));
48 static int process_path
P_((char *pathname
, char *name
, boolean leaf
, char *parent
));
49 static void process_dir
P_((char *pathname
, char *name
, int pathlen
, struct stat
*statp
, char *parent
));
50 static boolean no_side_effects
P_((struct predicate
*pred
));
52 /* Name this program was run with. */
55 /* All predicates for each path to process. */
56 struct predicate
*predicates
;
58 /* The last predicate allocated. */
59 struct predicate
*last_pred
;
61 /* The root of the evaluation tree. */
62 static struct predicate
*eval_tree
;
64 /* If true, process directory before contents. True unless -depth given. */
67 /* If >=0, don't descend more than this many levels of subdirectories. */
70 /* If >=0, don't process files above this level. */
73 /* Current depth; 0 means current path is a command line arg. */
76 /* Seconds between 00:00 1/1/70 and either one day before now
77 (the default), or the start of today (if -daystart is given). */
80 /* If true, cur_day_start has been adjusted to the start of the day. */
83 /* If true, do not assume that files in directories with nlink == 2
84 are non-directories. */
85 boolean no_leaf_check
;
87 /* If true, don't cross filesystem boundaries. */
88 boolean stay_on_filesystem
;
90 /* If true, don't descend past current directory.
91 Can be set by -prune, -maxdepth, and -xdev/-mount. */
92 boolean stop_at_current_level
;
95 /* The full path of the initial working directory. */
98 /* A file descriptor open to the initial working directory.
99 Doing it this way allows us to work when the i.w.d. has
100 unreadable parents. */
104 /* If true, we have called stat on the current path. */
107 /* The file being operated on, relative to the current directory.
108 Used for stat, readlink, and opendir. */
111 /* Length of current path. */
114 /* true if following symlinks. Should be consistent with xstat. */
117 /* Pointer to the function used to stat files. */
120 /* Status value to return to system. */
125 debug_stat (file
, bufp
)
129 fprintf (stderr
, "debug_stat (%s)\n", file
);
130 return lstat (file
, bufp
);
132 #endif /* DEBUG_STAT */
140 PFB parse_function
; /* Pointer to who is to do the parsing. */
141 struct predicate
*cur_pred
;
142 char *predicate_name
; /* Name of predicate being parsed. */
144 program_name
= argv
[0];
149 maxdepth
= mindepth
= -1;
150 cur_day_start
= time ((time_t *) 0) - DAYSECS
;
152 no_leaf_check
= false;
153 stay_on_filesystem
= false;
158 #else /* !DEBUG_STAT */
160 #endif /* !DEBUG_STAT */
163 printf ("cur_day_start = %s", ctime (&cur_day_start
));
166 /* Find where in ARGV the predicates begin. */
167 for (i
= 1; i
< argc
&& strchr ("-!(),", argv
[i
][0]) == NULL
; i
++)
170 /* Enclose the expression in `( ... )' so a default -print will
171 apply to the whole expression. */
172 parse_open (argv
, &argc
);
173 /* Build the input order list. */
176 if (strchr ("-!(),", argv
[i
][0]) == NULL
)
177 usage ("paths must precede expression");
178 predicate_name
= argv
[i
];
179 parse_function
= find_parser (predicate_name
);
180 if (parse_function
== NULL
)
181 error (1, 0, "invalid predicate `%s'", predicate_name
);
183 if (!(*parse_function
) (argv
, &i
))
186 error (1, 0, "missing argument to `%s'", predicate_name
);
188 error (1, 0, "invalid argument `%s' to `%s'",
189 argv
[i
], predicate_name
);
192 if (predicates
->pred_next
== NULL
)
194 /* No predicates that do something other than set a global variable
195 were given; remove the unneeded initial `(' and add `-print'. */
196 cur_pred
= predicates
;
197 predicates
= last_pred
= predicates
->pred_next
;
198 free ((char *) cur_pred
);
199 parse_print (argv
, &argc
);
201 else if (!no_side_effects (predicates
->pred_next
))
203 /* One or more predicates that produce output were given;
204 remove the unneeded initial `('. */
205 cur_pred
= predicates
;
206 predicates
= predicates
->pred_next
;
207 free ((char *) cur_pred
);
211 /* `( user-supplied-expression ) -print'. */
212 parse_close (argv
, &argc
);
213 parse_print (argv
, &argc
);
217 printf ("Predicate List:\n");
218 print_list (predicates
);
221 /* Done parsing the predicates. Build the evaluation tree. */
222 cur_pred
= predicates
;
223 eval_tree
= get_expr (&cur_pred
, NO_PREC
);
225 printf ("Eval Tree:\n");
226 print_tree (eval_tree
, 0);
229 /* Rearrange the eval tree in optimal-predicate order. */
230 opt_expr (&eval_tree
);
232 /* Determine the point, if any, at which to stat the file. */
233 mark_stat (eval_tree
);
236 printf ("Optimized Eval Tree:\n");
237 print_tree (eval_tree
, 0);
241 starting_dir
= xgetcwd ();
242 if (starting_dir
== NULL
)
243 error (1, errno
, "cannot get current directory");
245 starting_desc
= open (".", O_RDONLY
);
246 if (starting_desc
< 0)
247 error (1, errno
, "cannot open current directory");
250 /* If no paths are given, default to ".". */
251 for (i
= 1; i
< argc
&& strchr ("-!(),", argv
[i
][0]) == NULL
; i
++)
252 process_top_path (argv
[i
]);
254 process_top_path (".");
259 /* Descend PATHNAME, which is a command-line argument. */
262 process_top_path (pathname
)
265 struct stat stat_buf
;
268 path_length
= strlen (pathname
);
270 /* We stat each pathname given on the command-line twice --
271 once here and once in process_path. It's not too bad, though,
272 since the kernel can read the stat information out of its inode
273 cache the second time. */
274 if ((*xstat
) (pathname
, &stat_buf
) == 0 && S_ISDIR (stat_buf
.st_mode
))
276 if (chdir (pathname
) < 0)
278 error (0, errno
, "%s", pathname
);
282 process_path (pathname
, ".", false, ".");
284 if (chdir (starting_dir
) < 0)
285 error (1, errno
, "%s", starting_dir
);
287 if (fchdir (starting_desc
))
288 error (1, errno
, "cannot return to starting directory");
292 process_path (pathname
, pathname
, false, ".");
295 /* Info on each directory in the current tree branch, to avoid
296 getting stuck in symbolic link loops. */
302 static struct dir_id
*dir_ids
= NULL
;
303 /* Entries allocated in `dir_ids'. */
304 static int dir_alloc
= 0;
305 /* Index in `dir_ids' of directory currently being searched.
306 This is always the last valid entry. */
307 static int dir_curr
= -1;
308 /* (Arbitrary) number of entries to grow `dir_ids' by. */
309 #define DIR_ALLOC_STEP 32
311 /* Recursively descend path PATHNAME, applying the predicates.
312 LEAF is true if PATHNAME is known to be in a directory that has no
313 more unexamined subdirectories, and therefore it is not a directory.
314 Knowing this allows us to avoid calling stat as long as possible for
317 NAME is PATHNAME relative to the current directory. We access NAME
320 PARENT is the path of the parent of NAME, relative to find's
323 Return nonzero iff PATHNAME is a directory. */
326 process_path (pathname
, name
, leaf
, parent
)
332 struct stat stat_buf
;
333 static dev_t root_dev
; /* Device ID of current argument pathname. */
336 /* Assume it is a non-directory initially. */
337 stat_buf
.st_mode
= 0;
345 if ((*xstat
) (name
, &stat_buf
) != 0)
347 error (0, errno
, "%s", pathname
);
354 if (!S_ISDIR (stat_buf
.st_mode
))
356 if (curdepth
>= mindepth
)
357 apply_predicate (pathname
, &stat_buf
, eval_tree
);
361 /* From here on, we're working on a directory. */
363 stop_at_current_level
= maxdepth
>= 0 && curdepth
>= maxdepth
;
365 /* If we've already seen this directory on this branch,
366 don't descend it again. */
367 for (i
= 0; i
<= dir_curr
; i
++)
368 if (stat_buf
.st_ino
== dir_ids
[i
].ino
&&
369 stat_buf
.st_dev
== dir_ids
[i
].dev
)
370 stop_at_current_level
= true;
372 if (dir_alloc
<= ++dir_curr
)
374 dir_alloc
+= DIR_ALLOC_STEP
;
375 dir_ids
= (struct dir_id
*)
376 xrealloc ((char *) dir_ids
, dir_alloc
* sizeof (struct dir_id
));
378 dir_ids
[dir_curr
].ino
= stat_buf
.st_ino
;
379 dir_ids
[dir_curr
].dev
= stat_buf
.st_dev
;
381 if (stay_on_filesystem
)
384 root_dev
= stat_buf
.st_dev
;
385 else if (stat_buf
.st_dev
!= root_dev
)
386 stop_at_current_level
= true;
389 if (do_dir_first
&& curdepth
>= mindepth
)
390 apply_predicate (pathname
, &stat_buf
, eval_tree
);
392 if (stop_at_current_level
== false)
393 /* Scan directory on disk. */
394 process_dir (pathname
, name
, strlen (pathname
), &stat_buf
, parent
);
396 if (do_dir_first
== false && curdepth
>= mindepth
)
397 apply_predicate (pathname
, &stat_buf
, eval_tree
);
404 /* Scan directory PATHNAME and recurse through process_path for each entry.
406 PATHLEN is the length of PATHNAME.
408 NAME is PATHNAME relative to the current directory.
410 STATP is the results of *xstat on it.
412 PARENT is the path of the parent of NAME, relative to find's
413 starting directory. */
416 process_dir (pathname
, name
, pathlen
, statp
, parent
)
423 char *name_space
; /* Names of files in PATHNAME. */
424 int subdirs_left
; /* Number of unexamined subdirs in PATHNAME. */
426 subdirs_left
= statp
->st_nlink
- 2; /* Account for name and ".". */
429 /* On some systems (VAX 4.3BSD+NFS), NFS mount points have st_size < 0. */
430 name_space
= savedir (name
, statp
->st_size
> 0 ? statp
->st_size
: 512);
431 if (name_space
== NULL
)
435 error (0, errno
, "%s", pathname
);
439 error (1, 0, "virtual memory exhausted");
443 register char *namep
; /* Current point in `name_space'. */
444 char *cur_path
; /* Full path of each file to process. */
445 char *cur_name
; /* Base name of each file to process. */
446 unsigned cur_path_size
; /* Bytes allocated for `cur_path'. */
447 register unsigned file_len
; /* Length of each path to process. */
448 register unsigned pathname_len
; /* PATHLEN plus trailing '/'. */
450 if (pathname
[pathlen
- 1] == '/')
451 pathname_len
= pathlen
+ 1; /* For '\0'; already have '/'. */
453 pathname_len
= pathlen
+ 2; /* For '/' and '\0'. */
457 if (strcmp (name
, ".") && chdir (name
) < 0)
459 error (0, errno
, "%s", pathname
);
464 for (namep
= name_space
; *namep
; namep
+= file_len
- pathname_len
+ 1)
466 /* Append this directory entry's name to the path being searched. */
467 file_len
= pathname_len
+ strlen (namep
);
468 if (file_len
> cur_path_size
)
470 while (file_len
> cur_path_size
)
471 cur_path_size
+= 1024;
474 cur_path
= xmalloc (cur_path_size
);
475 strcpy (cur_path
, pathname
);
476 cur_path
[pathname_len
- 2] = '/';
478 cur_name
= cur_path
+ pathname_len
- 1;
479 strcpy (cur_name
, namep
);
483 /* Normal case optimization.
484 On normal Unix filesystems, a directory that has no
485 subdirectories has two links: its name, and ".". Any
486 additional links are to the ".." entries of its
487 subdirectories. Once we have processed as many
488 subdirectories as there are additional links, we know
489 that the rest of the entries are non-directories --
490 in other words, leaf files. */
491 subdirs_left
-= process_path (cur_path
, cur_name
,
492 subdirs_left
== 0, pathname
);
494 /* There might be weird (e.g., CD-ROM or MS-DOS) filesystems
495 mounted, which don't have Unix-like directory link counts. */
496 process_path (cur_path
, cur_name
, false, pathname
);
500 if (strcmp (name
, "."))
504 if (chdir ("..") < 0)
505 /* We could go back and do the next command-line arg instead,
506 maybe using longjmp. */
507 error (1, errno
, "%s", parent
);
512 if (chdir (starting_dir
) || chdir (parent
))
513 error (1, errno
, "%s", parent
);
515 if (fchdir (starting_desc
) || chdir (parent
))
516 error (1, errno
, "%s", parent
);
527 /* Return true if there are no side effects in any of the predicates in
528 predicate list PRED, false if there are any. */
531 no_side_effects (pred
)
532 struct predicate
*pred
;
536 if (pred
->side_effects
)
538 pred
= pred
->pred_next
;