home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
f
/
find12as.zip
/
FIND.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-22
|
11KB
|
356 lines
/* find -- search for files in a directory heirarchy
Copyright (C) 1987, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* GNU find was written by Eric Decker (cire@cisco.com),
with enhancements by David MacKenzie (djm@ai.mit.edu). */
/* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
This port is also distributed under the terms of the
GNU General Public License as published by the
Free Software Foundation.
Please note that this file is not identical to the
original GNU release, you should have received this
code as patch to the official release.
$Header: e:/gnu/find/RCS/find.c 1.2.0.3 90/09/23 16:09:38 tho Exp $
*/
/* Usage: find path... [expression]
Predicates:
Numbers can be specified as
+n for greater than n, or
-n for less than n,
n for exactly n.
If none of -print, -ls, -ok, -exec are given, -print is assumed.
-atime n file last accessed n*24 hours ago
-ctime n file status last modified n*24 hours ago
-depth true; process dir contents before dir itself
-exec cmd exec cmd, true if 0 status returned
-fulldays true; from day boundaries rather than from now
-fstype type file is on a filesystem of type type
-group gname file belongs to group gname (gid allowed)
-inum n file has inode number n
-links n file has n links
-ls true; list current file in 'ls -li' format
-mtime n file data last modified n*24 hours ago
-name pattern base of path name matches glob pattern
('*' and '?' do not match '.' at start)
-newer file modtime is more recent than file's
-nouser no user corresponds to file's uid
-nogroup no group corresponds to file's gid
-ok cmd like exec but ask user first; false if not 'y'
-perm mode perm bits are exactly mode (octal or symbol)
-perm -mode perm bits mode are set (s,s,t checked)
-permmask mode true; set significant bits mask for next -perm
(allows testing for unset bits)
-print true; print current full pathname
-prune (no -depth) true; do not descend current dir
(-depth) false; no effect
-regex pattern path name matches regex pattern
-size n[c] file has n blocks (or chars)
-type c file type: b, c, d, p, f, l, s
-user uname file is owned by uname (uid allowed)
-version true; print find version number on stderr
-xdev true; don't descend dirs with different st_dev
Grouping operators (in order of decreasing precendence):
( expr ) force precedence
! expr true if expr is false
expr1 expr2 and (implied); expr2 not eval if expr1 false
expr1 -o expr2 or; expr2 not eval if expr1 true
expr1 -or expr2 same as -o
find processes files by applying each predicate in turn until the
overall expression evaluates false. The expression evaluation
continues until the outcome is known (left hand side false for and,
true for or). Once this happens no more expressions are
evaluated and find moves on to the next pathname.
Exits with status 0 if all files are processed successfully,
>0 if error occurrs. */
#include <sys/types.h>
#include <stdio.h>
#ifndef USG
#include <strings.h>
#else
#include <string.h>
#define index strchr
#define rindex strrchr
#endif
#include <sys/stat.h>
#ifndef S_IFLNK
#define lstat stat
#endif
#include "defs.h"
#define apply_predicate(pathname, stat_buf_ptr, node) \
(*(node)->pred_func)((pathname), (stat_buf_ptr), (node))
char *savedir ();
void error ();
/* Name this program was run with. */
char *program_name;
/* All predicates for each path to process. */
struct pred_struct *predicates;
/* The last predicate allocated. */
struct pred_struct *last_pred;
/* The root of the evaluation tree. */
struct pred_struct *eval_tree;
/* If true, process directory before contents. True unless -depth given. */
boolean do_dir_first;
/* Global permission mask for -perm. */
unsigned long perm_mask;
/* Seconds between 00:00 1/1/70 and either one day before now
(the default), or the start of today (if -fulldays is given). */
long cur_day_start;
/* If true, cur_day_start has been adjusted to the start of the day. */
boolean full_days;
/* If true, don't cross filesystem boundaries. */
boolean stay_on_filesystem;
/* If true, don't descend past current directory. */
boolean stop_at_current_level;
/* Status value to return to system. */
int exit_status;
void
main (argc, argv)
int argc;
char *argv[];
{
int i;
#ifdef MSDOS
PARSE_FCT parse_function;
#else
PFB parse_function; /* Pointer to who is to do the parsing. */
#endif
struct pred_struct *cur_pred;
char *predicate_name; /* Name of predicate being parsed. */
program_name = argv[0];
predicates = NULL;
last_pred = NULL;
do_dir_first = true;
cur_day_start = time ((long *) 0) - DAYSECS;
full_days = false;
stay_on_filesystem = false;
exit_status = 0;
#ifdef DEBUG
printf ("%ld %s", cur_day_start, ctime (&cur_day_start));
#endif /* DEBUG */
/* Find where in ARGV the predicates begin. */
for (i = 1; i < argc && index ("-!()", argv[i][0]) == 0; i++)
;
if (i == 1)
usage ("no paths specified");
/* Enclose the expression in `( ... )' so a default -print will
apply to the whole expression. */
parse_open (argv, &argc);
/* Build the input order list. */
while (i < argc)
{
if (index ("-!()", argv[i][0]) == 0)
usage ("paths must precede expression");
predicate_name = argv[i];
parse_function = find_parser (predicate_name);
if (parse_function == NULL)
error (1, 0, "invalid predicate `%s'", predicate_name);
i++;
if (!(*parse_function) (argv, &i))
{
if (argv[i] == NULL)
error (1, 0, "missing argument to `%s'", predicate_name);
else
error (1, 0, "invalid argument to `%s'", predicate_name);
}
}
if (predicates->pred_next == NULL)
{
/* No predicates that are entered into the tree were given.
Remove the `(', because `( ) -print' is not a valid expression. */
free (predicates);
predicates = last_pred = NULL;
}
else
parse_close (argv, &argc);
if (no_side_effects (predicates))
parse_print (argv, &argc);
#ifdef DEBUG
print_list (predicates);
#endif /* DEBUG */
/* Done parsing the predicates. Build the evaluation tree. */
cur_pred = predicates;
eval_tree = get_expr (&cur_pred, NO_PREC);
#ifdef DEBUG
print_tree (eval_tree, 0);
#endif /* DEBUG */
/* Process all of the input paths. */
for (i = 1; i < argc && index ("-!()", argv[i][0]) == 0; i++)
process_path (argv[i], true);
exit (exit_status);
}
/* Recursively descend path PATHNAME, applying the predicates.
If ROOT is true, PATHNAME is a command line argument, and
thus the root of a subtree. */
void
process_path (pathname, root)
char *pathname;
boolean root;
{
static dev_t root_dev;
struct stat stat_buf;
char *name_space;
if (lstat (pathname, &stat_buf) != 0)
{
error (0, errno, "%s", pathname);
exit_status = 1;
return;
}
if ((stat_buf.st_mode & S_IFMT) != S_IFDIR)
{
perm_mask = 07777; /* Start fresh. */
apply_predicate (pathname, &stat_buf, eval_tree);
return;
}
if (stay_on_filesystem)
{
if (root)
root_dev = stat_buf.st_dev;
else if (stat_buf.st_dev != root_dev)
return;
}
stop_at_current_level = false;
if (do_dir_first)
{
perm_mask = 07777; /* Start fresh. */
apply_predicate (pathname, &stat_buf, eval_tree);
}
if (stop_at_current_level == false)
{
errno = 0;
name_space = savedir (pathname, stat_buf.st_size);
if (name_space == NULL)
{
if (errno)
{
error (0, errno, "%s", pathname);
exit_status = 1;
}
else
error (1, 0, "virtual memory exhausted");
}
else
{
char *namep; /* Current point in `name_space'. */
char *cur_path; /* Full path of each file to process. */
unsigned cur_path_size; /* Bytes allocated for `cur_path'. */
unsigned file_len; /* Length of each path to process. */
unsigned pathname_len; /* Length of `pathname' + 2. */
if (!strcmp (pathname, "/"))
pathname_len = 2; /* Won't add a slash to this. */
#ifdef MSDOS
else if (!strcmp (pathname + 1, ":/"))
pathname_len = 4; /* Won't add a slash to this either. */
#endif /* MSDOS */
else
pathname_len = strlen (pathname) + 2; /* For '/' and '\0'. */
cur_path_size = 0;
cur_path = NULL;
for (namep = name_space; *namep;
namep += file_len - pathname_len + 1)
{
file_len = pathname_len + strlen (namep);
if (file_len > cur_path_size)
{
while (file_len > cur_path_size)
cur_path_size += 1024;
if (cur_path)
free (cur_path);
cur_path = xmalloc (cur_path_size);
strcpy (cur_path, pathname);
cur_path[pathname_len - 2] = '/';
}
strcpy (cur_path + pathname_len - 1, namep);
process_path (cur_path, false);
}
if (cur_path)
free (cur_path);
free (name_space);
}
}
if (do_dir_first == false)
{
perm_mask = 07777; /* Start fresh. */
apply_predicate (pathname, &stat_buf, eval_tree);
}
}
/* Return true if there are no side effects in any of the predicates in
predicate list PRED, false if there are any. */
boolean
no_side_effects (pred)
struct pred_struct *pred;
{
while (pred != NULL)
{
if (pred->side_effects)
return (false);
pred = pred->pred_next;
}
return (true);
}