v17i026: delete - MIT Athena delete/undelete programs, Part04/04
Jonathan I. Kamens
jik at pit-manager.MIT.EDU
Tue Feb 26 05:08:00 AEST 1991
Submitted-by: Jonathan I. Kamens <jik at pit-manager.MIT.EDU>
Posting-number: Volume 17, Issue 26
Archive-name: delete/part04
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 4)."
# Contents: pattern.c
# Wrapped by jik at pit-manager on Fri Feb 22 08:14:28 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'pattern.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'pattern.c'\"
else
echo shar: Extracting \"'pattern.c'\" \(25764 characters\)
sed "s/^X//" >'pattern.c' <<'END_OF_FILE'
X/*
X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/pattern.c,v $
X * $Author: jik $
X *
X * This program is part of a package including delete, undelete,
X * lsdel, expunge and purge. The software suite is meant as a
X * replacement for rm which allows for file recovery.
X *
X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
X * For copying and distribution information, see the file "mit-copyright.h."
X */
X
X#if (!defined(lint) && !defined(SABER))
X static char rcsid_pattern_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/pattern.c,v 1.21 91/02/20 17:27:03 jik Exp $";
X#endif
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/param.h>
X#ifdef SYSV
X#include <string.h>
X#define index strchr
X#define rindex strrchr
X#else
X#include <strings.h>
X#endif /* SYSV */
X#include <errno.h>
X#include <com_err.h>
X#include "pattern.h"
X#include "util.h"
X#include "directories.h"
X#include "undelete.h"
X#include "shell_regexp.h"
X#include "mit-copyright.h"
X#include "delete_errs.h"
X#include "errors.h"
X#include "stack.h"
X
Xextern char *realloc();
Xextern int errno;
Xextern char *whoami;
X
Xvoid free_list();
X
X
X/*
X * add_arrays() takes pointers to two arrays of char **'s and their
X * lengths, merges the two into the first by realloc'ing the first and
X * then free's the second's memory usage.
X */
Xint add_arrays(array1, num1, array2, num2)
Xchar ***array1, ***array2;
Xint *num1, *num2;
X{
X int counter;
X
X *array1 = (char **) realloc((char *) *array1, (unsigned)
X (sizeof(char *) * (*num1 + *num2)));
X if (! *array1) {
X set_error(errno);
X error("realloc");
X return error_code;
X }
X for (counter = *num1; counter < *num1 + *num2; counter++)
X *(*array1 + counter) = *(*array2 + counter - *num1);
X free ((char *) *array2);
X *num1 += *num2;
X return 0;
X}
X
X
X
X
X
X
X/*
X * Add a string to a list of strings.
X */
Xint add_str(strs, num, str)
Xchar ***strs;
Xint num;
Xchar *str;
X{
X char **ary;
X
X ary = *strs = (char **) realloc((char *) *strs, (unsigned)
X (sizeof(char *) * (num + 1)));
X if (! *strs) {
X set_error(errno);
X error("realloc");
X return error_code;
X }
X ary[num] = Malloc((unsigned) (strlen(str) + 1));
X if (! ary[num]) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X (void) strcpy(ary[num], str);
X return 0;
X}
X
X
X
X
X
X/*
X * Find_matches will behave unpredictably if you try to use it to find
X * very strange combinations of file types, for example only searching
X * for undeleted files in the top-level directory, while searching
X * recursively for deleted files. Basically, there are some conflicts
X * between options that I don't list here because I don't think I'll
X * ever need to use those combinations.
X */
X/*
X * Function: find_matches(char *name, int *num_found, char ***found,
X * int options)
X *
X * Requires: name points to a NULL-terminated string, representing a
X * filename pattern with regular filename characters, path
X * separators and shell wildcard characters []*?; num_found points
X * to a valid int memory storage location; found points to a valid
X * char ** memory storage location.
X *
X * Effects: Returns a list of all the files in the file hierarchy that
X * match the options specified in options and that match name.
X * Options are:
X *
X * FIND_UNDELETED search for and return undeleted files
X *
X * FIND_DELETED search for and return deleted files
X *
X * FIND_CONTENTS means that if matches are directories (or links to
X * directories), the contents of the directory should be matched
X * in addition to the directory itself
X *
X * RECURS_FIND_DELETED to search all undeleted subdirectories
X * recursively of matched directories looking for deleted files
X *
X * RECURS_FIND_UNDELETED to search all undeleted subdirectories
X * recursively of matched directories looking for undeleted files
X *
X * RECURS_DELETED to recursively return all contents of deleted
X * directories in addition to the directories themselves
X *
X * FOLLW_LINKS to pursue symlinks to directories and continue down
X * the referenced directories when searching recursively (if the
X * initial string is an undeleted symlink it is always traversed;
X * deleted symlinks are never traversed)
X *
X * FOLLW_MOUNTPOINTS to traverse mount points when searching
X * recursively (if the initial string is a mountpoint it is always
X * traversed)
X *
X * FIND_DOTFILES forces the system to recognize dot files instead of
X * discarding them when looking for files
X *
X * If the first character of name is '/', the search is conducted
X * absolutely from the root of the hierarchy; else, it is conducted
X * relative to the current working directory. The number of
X * matching files is returned in *num_found, and a list of file
X * names is returned in *found. If there are no errors, the return
X * value is 0; else the return value represents the error code of
X * the error which occurred. No matter how many file names are
X * returned, the memory location addressed in *found is a valid
X * pointer according to Malloc() and can be released using free()
X * safely. However, if an error value is returned, the caller
X * should not attempt to use the values stored in *num_found or
X * *found.
X *
X * Modifies: *num_found, *found.
X */
Xint find_matches(name, num_found, found, options)
Xchar *name;
Xint *num_found;
Xchar ***found;
Xint options;
X{
X char **matched_files, **return_files, **recurs_files;
X int num_matched_files = 0, num_return_files = 0,
X num_recurs_files = 0;
X int retval;
X int i;
X#ifdef DEBUG
X int j;
X#endif
X int match_options = 0;
X
X#ifdef DEBUG
X fprintf(stderr, "Entering find_matches, name = %s, options = %d.\n",
X name, options);
X#endif
X
X match_options = options & (FIND_DELETED | FIND_UNDELETED);
X if (options & (RECURS_FIND_DELETED | RECURS_FIND_UNDELETED |
X FIND_CONTENTS))
X match_options |= FIND_UNDELETED;
X
X if (! match_options) {
X set_error(PAT_NO_FILES_REQUESTED);
X error("find_matches");
X return error_code;
X }
X
X retval = do_match(name, &num_matched_files, &matched_files,
X match_options & FIND_UNDELETED,
X match_options & FIND_DELETED);
X if (retval) {
X error(name);
X return retval;
X }
X if (num_matched_files == 0) {
X *num_found = num_matched_files;
X *found = matched_files;
X#ifdef DEBUG
X fprintf(stderr, "No matches found, returning.\n");
X#endif
X return 0;
X }
X
X#ifdef DEBUG
X fprintf(stderr, "The following matches were found:\n");
X for (i = 0; i < num_matched_files; i++)
X fprintf(stderr, " %s\n", matched_files[i]);
X#endif
X
X if (options & RECURS) {
X return_files = (char **) Malloc(0);
X if (! return_files) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X num_return_files = 0;
X
X for (i = 0; i < num_matched_files; i++) {
X
X retval = do_recurs(matched_files[i], &num_recurs_files,
X &recurs_files, options);
X if (retval) {
X error(matched_files[i]);
X return retval;
X }
X
X if (num_recurs_files) {
X retval = add_arrays(&return_files, &num_return_files,
X &recurs_files, &num_recurs_files);
X if (retval) {
X error("add_arrays");
X return retval;
X }
X#ifdef DEBUG
X fprintf(stderr,
X "Just added the following to return_files:\n");
X for (j = num_return_files - num_recurs_files;
X j < num_return_files; j++)
X fprintf(stderr, " %s\n", return_files[j]);
X#endif
X }
X
X if (is_deleted(lastpart(matched_files[i]))) {
X if (options & FIND_DELETED) {
X retval = add_str(&return_files, num_return_files,
X matched_files[i]);
X if (retval) {
X error("add_str");
X return retval;
X }
X num_return_files++;
X#ifdef DEBUG
X fprintf(stderr, "Just added %s to return_files.\n",
X return_files[num_return_files-1]);
X#endif
X }
X }
X else if (options & FIND_UNDELETED) {
X retval = add_str(&return_files, num_return_files,
X matched_files[i]);
X if (retval) {
X error("add_str");
X return retval;
X }
X num_return_files++;
X#ifdef DEBUG
X fprintf(stderr, "Just added %s to return_files.\n",
X return_files[num_return_files-1]);
X#endif
X }
X }
X free_list(matched_files, num_matched_files);
X *num_found = num_return_files;
X *found = return_files;
X }
X else {
X *num_found = num_matched_files;
X *found = matched_files;
X }
X
X return 0;
X}
X
X
X
X
X
X
X
X
X#define string_push(str)\
X strsize = strlen(str);\
X retval = push(str, strsize);\
X if (! retval)\
X retval |= push(&strsize, sizeof(int));\
X if (retval) {\
X error("push");\
X (void) popall();\
X return retval;\
X }
X#define string_pop(str)\
X retval = pop(&strsize, sizeof(int));\
X if (! retval)\
X retval = pop(str, strsize);\
X if (! retval)\
X str[strsize] = '\0'
X
X
X
X
X
X
X/*
X * Function: do_match(char *name, int *num_found, char ***found,
X * Boolean match_undeleted, Boolean match_deleted)
X *
X * Requires: name points to a NULL-terminated string, representing a
X * filename pattern with regular filename characters, path
X * separators and shell wildcard characters []*?; num_found points
X * to a valid int memory storage location; found points to a valid
X * char ** memory storage location.
X *
X * Effects: Returns a list of all the files in the file hierarchy that
X * match name. If match_undeleted is true, will return undeleted
X * files that match; if match_deleted is true, will return
X * deleted_files that match. If the first character of name is '/',
X * the search is conducted absolutely from the root of the
X * hierarchy; else, it is conducted relative to the current working
X * directory. The number of matching files is returned in
X * *num_found, and a list of file names is returned in *found. If
X * there are no errors, the return value is 0; else the return value
X * represents the error code of the error which occurred. No matter
X * how many file names are returned, the memory location addressed
X * in *found is a valid pointer according to Malloc() and can be
X * released using free() safely. However, if an error value is
X * returned, the caller should not attempt to use the values stored
X * in *num_found or *found.
X *
X * Modifies: *num_found, *found.
X *
X * Algorithm:
X *
X * start:
X * base = "" or "/",
X * name = name or name + 1
X * initialze found and num_found
X * dirp = Opendir(base)
X * first = firstpart(name, rest) (assigns rest as side-effect)
X * if (! *first) {
X * add string to list if appropriate
X * return
X *
X * loop:
X * dp = readdir(dirp)
X * if (! dp) goto updir
X * compare dp->d_name to first -- match?
X * yes - goto downdir
X * no - are we looking for deleted and is dp->d_name deleted?
X * yes - compare undeleted dp->d_name to first -- match?
X * yes - goto downdir
X * no - goto loop
X * no - goto loop
X *
X * downdir:
X * save dirp, rest, first and base on stack
X * first = firstpart(rest, rest)
X * base = dp->d_name appended to base
X * is first an empty string?
X * yes - put back dirp, rest, first, base
X * goto loop
X * try to open dir base - opens?
X * yes - goto loop
X * no - is the error ENOTDIR?
X * yes - don't worry about it
X * no - report the error
X * restore dirp, rest, first, base from stack
X * goto loop
X *
X * updir:
X * close dirp
X * restore base, rest, first from stack
X * STACK_EMPTY?
X * yes - return from procedure with results
X * restore dirp from stack
X * goto loop
X */
Xint do_match(name, num_found, found, match_undeleted, match_deleted)
Xchar *name;
Xint *num_found;
Xchar ***found;
XBoolean match_undeleted, match_deleted;
X{
X char base[MAXPATHLEN];
X struct direct *dp;
X DIR *dirp;
X char first[MAXNAMLEN], rest[MAXPATHLEN];
X int retval;
X int strsize;
X struct stat statbuf;
X#ifdef PATTERN_DEBUG
X int j;
X#endif
X
X#ifdef DEBUG
X printf("do_match: looking for %s\n", name);
X#endif
X
X /* start: */
X
X if (*name == '/') {
X *base = '/';
X *(base + 1) = '\0';
X name++;
X }
X else
X *base = '\0';
X
X *found = (char **) Malloc(0);
X if (! *found) {
X set_error(errno);
X error("Malloc");
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 1.\n");
X#endif
X return error_code;
X }
X *num_found = 0;
X
X dirp = Opendir(base);
X if (! dirp) {
X set_error(errno);
X error(base);
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 2.\n");
X#endif
X return error_code;
X }
X (void) strcpy(first, firstpart(name, rest));
X if ((! *first) && (match_undeleted)) {
X retval = add_str(found, *num_found, base);
X if (retval) {
X error("add_str");
X (void) popall();
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 3.\n");
X#endif
X return retval;
X }
X (*num_found)++;
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 4.\n");
X#endif
X return 0;
X }
X
X while (1) {
X dp = readdir(dirp);
X if (! dp) goto updir;
X
X retval = reg_cmp(first, dp->d_name);
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: comparing %s to %s returns %d.\n",
X first, dp->d_name, retval);
X#endif
X if (retval < 0) {
X error("reg_cmp");
X goto updir;
X }
X
X if (retval == REGEXP_MATCH) goto downdir;
X
X if (is_deleted(dp->d_name) && match_deleted) {
X retval = reg_cmp(first, &dp->d_name[2]);
X#ifdef PATTERN_DEBUG
X fprintf(stderr,
X "do_match: deleted compare of %s to %s returns %d.\n",
X first, &dp->d_name[2], retval);
X#endif
X if (retval < 0) {
X error("reg_cmp");
X goto updir;
X }
X
X if (retval == REGEXP_MATCH)
X goto downdir;
X else
X continue;
X }
X else
X continue;
X
X downdir:
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: downdir\n");
X#endif
X retval = push(&dirp, sizeof(DIR *));
X if (retval) {
X error("push");
X (void) popall();
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 5.\n");
X#endif
X return retval;
X }
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: pushing %s, %s, %s\n", first, rest, base);
X#endif
X string_push(first);
X string_push(rest);
X string_push(base);
X (void) strcpy(base, append(base, dp->d_name));
X (void) strcpy(first, firstpart(rest, rest));
X if (! *first) {
X if (is_deleted(lastpart(base))) {
X if (match_deleted) {
X retval = add_str(found, *num_found, base);
X if (retval) {
X error("add_str");
X (void) popall();
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 6.\n");
X#endif
X return retval;
X }
X (*num_found)++;
X }
X }
X else if (match_undeleted) {
X retval = add_str(found, *num_found, base);
X if (retval) {
X error("add_str");
X (void) popall();
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 7.\n");
X#endif
X return retval;
X }
X (*num_found)++;
X }
X string_pop(base);
X string_pop(rest);
X string_pop(first);
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: popped %s, %s, %s\n", first,
X rest, base);
X#endif
X (void) pop(&dirp, sizeof(DIR *));
X continue;
X }
X
X if (! stat(base, &statbuf)) {
X if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
X dirp = Opendir(base);
X }
X else {
X dirp = NULL;
X }
X if (! dirp) {
X set_error(errno);
X error(base);
X string_pop(base);
X string_pop(rest);
X string_pop(first);
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: popped %s, %s, %s\n", first,
X rest, base);
X#endif
X (void) pop(&dirp, sizeof(DIR *));
X continue;
X }
X else
X continue;
X
X updir:
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: updir\n");
X#endif
X closedir(dirp);
X string_pop(base);
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: popped %s\n", base);
X#endif
X if (retval) {
X if (retval != STACK_EMPTY) {
X error("pop");
X (void) popall();
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 8.\n");
X#endif
X return retval;
X }
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "Returning %d word%s from do_match:\n",
X *num_found,
X *num_found == 1 ? "" : "s");
X for (j = 0; j < *num_found; j++)
X fprintf(stderr, "\t%s\n", (*found)[j]);
X fprintf(stderr, "do_match: return 9.\n");
X#endif
X return 0;
X }
X string_pop(rest);
X string_pop(first);
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: popped %s, %s\n", rest, first);
X#endif
X retval = pop(&dirp, sizeof(DIR *));
X if (retval) {
X error("pop");
X (void) popall();
X#ifdef PATTERN_DEBUG
X fprintf(stderr, "do_match: return 10.\n");
X#endif
X return retval;
X }
X continue;
X }
X}
X
X
X
X
X
X
X/*
X * Function: do_recurs(char *name, int *num_found, char ***found,
X * int options)
X *
X * Requires: name points to a NULL-terminated string, representing a
X * filename; points to a valid int memory storage location; found
X * points to a valid char ** memory storage location.
X *
X * Effects: Returns a list of all the files in the file hierarchy that
X * are underneath the specified file, governed by the options set in
X * options. Options are as described in the find_matches() description.
X * RECURS_FIND_DELETED and RECURS_DELETED imply FIND_DELETED.
X * RECURS_FIND_UNDELETED implies FIND_UNDELETED.
X *
X * Modifies: *num_found, *found.
X *
X * Algorithm:
X *
X * start:
X * initialze found and num_found
X * strcopy(base, name)
X * check if we just opened a deleted symlink and return if we did
X * dirp = Opendir(base)
X * check RECURS options and set FIND options as appropriate
X *
X * loop:
X * dp = readdir(dirp)
X * if (! dp) goto updir
X * is dp deleted?
X * yes - is FIND_DELETED set?
X * yes - add to list
X * is RECURS_DELETED set?
X * yes - goto downdir
X * no - goto loop
X * no - goto loop
X * no - is FIND_UNDELETED set?
X * yes - is the file a dotfile?
X * yes - is FIND_DOTFILES set?
X * yes - add to list
X * goto loop
X * no - add to list
X * are RECURS_FIND_DELETED and FIND_DELETED set?
X * yes - goto downdir
X * is RECURS_FIND_UNDELETED set?
X * yes - goto downdir
X * no - goto loop
X * no - goto loop
X *
X * downdir:
X * save dirp, base on stack
X * base = dp->d_name appended to base
X * try to open base -- opens?
X * yes - is FOLLW_LINKS set?
X * yes - is it deleted?
X * yes - is it a link?
X * yes - close the directory
X * restore base and dirp
X * goto loop
X * no - is it a link?
X * yes - close the directory
X * restore base and dirp
X * goto loop
X * is FOLLW_MOUNTPOINTS set?
X * no - is it a mountpoint?
X * yes - close the directory
X * restore base and dirp
X * goto loop
X * no - is the error ENOTDIR?
X * yes - don't worry about it
X * no - report the error
X * restore base and dirp
X * goto loop
X *
X * updir:
X * close dirp
X * restore base from stack
X * STACK_EMPTY?
X * yes - return from procedure with results
X * restore dirp from stack
X * goto loop
X */
Xint do_recurs(name, num_found, found, options)
Xchar *name;
Xint *num_found;
Xchar ***found;
Xint options;
X{
X char base[MAXPATHLEN];
X struct direct *dp;
X DIR *dirp;
X int retval;
X int strsize;
X struct stat statbuf;
X int use_stat;
X
X#ifdef DEBUG
X fprintf(stderr, "do_recurs: opening %s\n", name);
X#endif
X
X /* start: */
X
X *found = (char **) Malloc(0);
X if (! *found) {
X set_error(errno);
X error("Malloc");
X return error_code;
X }
X *num_found = 0;
X strcpy(base, name);
X
X if (lstat(base, &statbuf)) {
X set_error(errno);
X error(base);
X return error_code;
X }
X
X if (is_link(base, &statbuf)) {
X /* Never follow deleted symlinks */
X if (is_deleted(lastpart(base))) {
X return 0;
X }
X if (stat(base, &statbuf)) {
X if (errno == ENOENT) {
X extern int readlink();
X char pathbuf[MAXPATHLEN];
X int cc;
X
X /* What the link is pointing to does not exist; */
X /* this is a warning, not an error. */
X set_warning(errno);
X cc = readlink(base, pathbuf, MAXPATHLEN);
X if (cc > 0) {
X char error_buf[2*MAXPATHLEN+20];
X
X pathbuf[(cc == MAXPATHLEN) ? (cc - 1) : cc] = '\0';
X sprintf(error_buf, "%s (pointed to by %s)", pathbuf,
X base);
X error(error_buf);
X }
X else {
X error(base);
X }
X
X return 0;
X }
X else {
X set_error(errno);
X error(base);
X return error_code;
X }
X }
X }
X
X if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
X return 0;
X
X dirp = Opendir(base);
X if (! dirp) {
X#ifdef DEBUG
X fprintf(stderr, "Couldn't open %s.\n", base);
X#endif
X set_error(errno);
X error(base);
X return error_code;
X }
X
X if (options & (RECURS_FIND_DELETED | RECURS_DELETED))
X options |= FIND_DELETED;
X if (options & RECURS_FIND_UNDELETED)
X options |= FIND_UNDELETED;
X
X while (1) {
X dp = readdir(dirp);
X if (! dp) goto updir;
X
X if (is_deleted(dp->d_name)) {
X if (options & FIND_DELETED) {
X retval = add_str(found, *num_found,
X append(base, dp->d_name));
X if (retval) {
X error("add_str");
X (void) popall();
X return retval;
X }
X (*num_found)++;
X if (options & RECURS_DELETED)
X goto downdir;
X else
X continue;
X }
X else
X continue;
X }
X
X if (options & FIND_UNDELETED) {
X if (is_dotfile(dp->d_name)) {
X if (options & FIND_DOTFILES) {
X retval = add_str(found, *num_found,
X append(base, dp->d_name));
X if (retval) {
X error("add_str");
X (void) popall();
X return retval;
X }
X }
X continue;
X }
X else {
X retval = add_str(found, *num_found,
X append(base, dp->d_name));
X if (retval) {
X error("add_str");
X (void) popall();
X return retval;
X }
X (*num_found)++;
X }
X }
X
X if (! is_dotfile(dp->d_name)) {
X if (options & RECURS_FIND_DELETED)
X goto downdir;
X if (options & RECURS_FIND_UNDELETED)
X goto downdir;
X }
X
X continue;
X
X
X downdir:
X retval = push(&dirp, sizeof(DIR *));
X if (retval) {
X error("push");
X (void) popall();
X return retval;
X }
X string_push(base);
X (void) strcpy(base, append(base, dp->d_name));
X
X /*
X * Originally, I did an Opendir() right at the start and
X * then only checked things if the Opendir resulted in an
X * error. However, this is inefficient, because the
X * Opendir() procedure works by first calling open() on the
X * file, and *then* calling fstat on the file descriptor
X * that is returned. since most of the time we will be
X * trying to open things that are not directory, it is much
X * more effecient to do the stat first here and to do the
X * Opendir only if the stat results are satisfactory.
X */
X use_stat = (options & FOLLW_LINKS) && (! is_deleted(lastpart(base)));
X if (use_stat)
X retval = stat(base, &statbuf);
X else
X retval = lstat(base, &statbuf);
X if (retval == -1) {
X set_error(errno);
X error(base);
X string_pop(base);
X (void) pop(&dirp, sizeof(DIR *));
X continue;
X }
X /* It's not a directory, so punt it and continue. */
X if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
X string_pop(base);
X (void) pop(&dirp, sizeof(DIR *));
X continue;
X }
X
X /* Actually try to open it. */
X dirp = Opendir(base);
X if (! dirp) {
X set_error(errno);
X error(base);
X string_pop(base);
X (void) pop(&dirp, sizeof(DIR *));
X continue;
X }
X
X if (! (options & FOLLW_MOUNTPOINTS)) {
X if (is_mountpoint(base, use_stat ? (struct stat *) NULL :
X &statbuf)) {
X closedir(dirp);
X set_warning(PAT_IS_MOUNT);
X error(base);
X string_pop(base);
X (void) pop(&dirp, sizeof(DIR *));
X continue;
X }
X#ifdef DEBUG
X else {
X fprintf(stderr,
X "do_recurs: %s isn't a mountpoint, following.\n",
X base);
X }
X#endif
X }
X#ifdef DEBUG
X printf("do_recurs: opening %s\n", base);
X#endif
X continue;
X
X updir:
X closedir(dirp);
X string_pop(base);
X if (retval) {
X if (retval != STACK_EMPTY) {
X error("pop");
X (void) popall();
X return retval;
X }
X return 0;
X }
X retval = pop(&dirp, sizeof(DIR *));
X if (retval) {
X error("pop");
X (void) popall();
X return retval;
X }
X continue;
X }
X}
X
X
Xvoid free_list(list, num)
Xchar **list;
Xint num;
X{
X int i;
X
X for (i = 0; i < num; i++)
X free(list[i]);
X
X free((char *) list);
X}
X
X
X
X
X
X
X/*
X * returns true if the filename has no globbing wildcards in it. That
X * means no non-quoted question marks, asterisks, or open square
X * braces. Assumes a null-terminated string, and a valid globbing
X */
Xint no_wildcards(name)
Xchar *name;
X{
X do {
X switch (*name) {
X case '\\':
X name++;
X break;
X case '?':
X return(0);
X case '*':
X return(0);
X case '[':
X return(0);
X }
X } while (*++name);
X return(1);
X}
END_OF_FILE
if test 25764 -ne `wc -c <'pattern.c'`; then
echo shar: \"'pattern.c'\" unpacked with wrong size!
fi
# end of 'pattern.c'
fi
echo shar: End of archive 4 \(of 4\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 4 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.
More information about the Comp.sources.misc
mailing list