[comp.sources.unix] v18i076: MIT Athena delete/undelete programs, Part04/06

rsalz@uunet.uu.net (Rich Salz) (03/29/89)

Submitted-by: Jonathan I. Kamens <jik@PIT-MANAGER.MIT.EDU>
Posting-number: Volume 18, Issue 76
Archive-name: undel/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 6)."
# Contents:  expunge.c pattern.c
# Wrapped by jik@pit-manager on Mon Mar 27 12:16:51 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'expunge.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'expunge.c'\"
else
echo shar: Extracting \"'expunge.c'\" \(10893 characters\)
sed "s/^X//" >'expunge.c' <<'END_OF_FILE'
X/*
X * $Source: /mit/jik/src/delete/RCS/expunge.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_expunge_c[] = "$Header: expunge.c,v 1.7 89/03/27 12:06:47 jik Exp $";
X#endif
X
X/*
X * Things that need to be fixed later:
X *
X * 1. The program should somehow store the sizes of deleted files and
X * report the total amount of space regained after an expunge or purge.
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/dir.h>
X#include <sys/param.h>
X#include <strings.h>
X#include <sys/stat.h>
X#include "col.h"
X#include "directories.h"
X#include "util.h"
X#include "pattern.h"
X#include "expunge.h"
X#include "mit-copyright.h"
X
Xextern char *malloc(), *realloc();
Xextern int current_time;
X
Xchar *whoami, *error_buf;
X
Xint  timev,		/* minimum mod time before undeletion */
X     interactive,	/* query before each expunge */
X     recursive,		/* expunge undeleted directories recursively */
X     noop,		/* print what would be done instead of doing it */
X     verbose,		/* print a line as each file is deleted */
X     force,		/* do not ask for any confirmation */
X     listfiles,		/* list files at toplevel */
X     yield;		/* print yield of expunge at end */
X
Xint blocks_removed = 0;
X
X
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X     extern char *optarg;
X     extern int optind;
X     int arg;
X     int status = 0;
X
X     whoami = lastpart(argv[0]);
X     error_buf = malloc(strlen(whoami) + MAXPATHLEN + 3);
X     if (! error_buf) {
X	  perror(whoami);
X	  exit(1);
X     }
X     if (*whoami == 'p') { /* we're doing a purge */
X	  exit (purge());
X     }
X     timev = 0;
X     yield = interactive = recursive = noop = verbose = listfiles = force = 0;
X     while ((arg = getopt(argc, argv, "t:irfnvly")) != -1) {
X	  switch (arg) {
X	  case 't':
X	       timev = atoi(optarg);
X	       break;
X	  case 'i':
X	       interactive++;
X	       break;
X	  case 'r':
X	       recursive++;
X	       break;
X	  case 'f':
X	       force++;
X	       break;
X	  case 'n':
X	       noop++;
X	       break;
X	  case 'v':
X	       verbose++;
X	       break;
X	  case 'l':
X	       listfiles++;
X	       break;
X	  case 'y':
X	       yield++;
X	       break;
X	  default:
X	       usage();
X	       exit(1);
X	  }
X     }
X     if (optind == argc) {
X	  char *dir;
X	  dir = ".";
X	  status = status | expunge(&dir, 1); /* current working directory */
X     }
X     else
X	  status = status | expunge(&argv[optind], argc - optind);
X     exit(status & ERROR_MASK);
X}
X
X
X
X
X
Xpurge()
X{
X     char *home[1];
X
X     home[0] = malloc(MAXPATHLEN);
X     if (! home[0]) {
X	  perror(sprintf(error_buf, "%s: purge", whoami));
X	  exit(1);
X     }
X     timev = interactive = noop = verbose = force = 0;
X     yield = listfiles = recursive = 1;
X     get_home(home[0]);
X     if (! *home[0]) {
X	  fprintf(stderr, "%s: purge: can't get home directory\n", whoami);
X	  exit(1);
X     }
X
X     printf("Please be patient.... this may take a while.\n\n");
X     
X     return(expunge(home, 1));
X}
X
X
X
X
Xusage()
X{
X     printf("Usage: %s [ options ] [ filename [ ... ]]\n", whoami);
X     printf("Options are:\n");
X     printf("     -r     recursive\n");
X     printf("     -i     interactive\n");
X     printf("     -f     force\n");
X     printf("     -t n   n-day-or-older expunge\n");
X     printf("     -n     noop\n");
X     printf("     -v     verbose\n");
X     printf("     -l     list files before expunging\n");
X     printf("     -y     print yield of expunge\n");
X     printf("     --     end options and start filenames\n");
X}
X
X
X
X
X
Xexpunge(files, num)
Xchar **files;
Xint num;
X{
X     char *file_re;
X     char **found_files;
X     int num_found;
X     char *start_dir;
X     int status = 0;
X     int total = 0;
X     filerec *current;
X     
X     if (initialize_tree())
X	  exit(1);
X
X     for ( ; num ; num--) {
X	  if (*files[num - 1] == '/') {
X	       start_dir = "/";
X	       file_re = parse_pattern(files[num - 1] + 1);
X	  }
X	  else {
X	       start_dir = "";
X	       file_re = parse_pattern(files[num - 1]);
X	  }
X	  if (! file_re)
X	       return(ERROR_MASK);
X	  
X	  found_files = get_the_files(start_dir, file_re, &num_found);
X	  if (num_found)
X	       num_found = process_files(found_files, num_found);
X	  total += num_found;
X	  if (! num_found) if (! force) {
X	       /*
X		* There are three different situations here.  Eiter we
X		* are dealing with an existing directory with no
X	        * deleted files in it, or we are deleting with a
X	        * non-existing deleted file with wildcards, or we are
X	        * dealing with a non-existing deleted file without
X	        * wildcards.  In the former case we print nothing, and
X	        * in the latter cases we print either "no match" or
X	        * "not found" respectively
X		*/
X	       if (no_wildcards(file_re)) {
X		    if (! directory_exists(files[num - 1])) {
X			 fprintf(stderr, "%s: %s: not found\n",
X				 whoami, files[num - 1]);
X		    }
X	       }
X	       else {
X		    fprintf(stderr, "%s: %s: no match\n", whoami,
X			    files[num - 1]);
X	       }
X	  }
X	  free(file_re);
X     }
X     if (total && listfiles) {
X	  list_files();
X	  if (! force) if (! top_level())
X	       return(NO_DELETE_MASK);
X     }
X     current = get_root_tree();
X     if (current)
X	  status = status | expunge_specified(current);
X     current = get_cwd_tree();
X     if (current)
X	  status = status | expunge_specified(current);
X
X     if (yield) {
X	  if (noop)
X	       printf("Total that would be expunged: %dk\n",
X		      blk_to_k(blocks_removed));
X	  else
X	       printf("Total expunged: %dk\n", blk_to_k(blocks_removed));
X     }
X     return(status);
X}
X
X
X
Xexpunge_specified(leaf)
Xfilerec *leaf;
X{
X     int status = 0;
X
X     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR))
X	  status = do_directory_expunge(leaf);
X     /* the "do_directory_expunge" really only asks the user if he */
X     /* wants to expunge the directory, it doesn't do any deleting. */
X     if (! status) {
X	  if (leaf->dirs)
X	       status |= expunge_specified(leaf->dirs);
X	  if (leaf->files)
X	       status |= expunge_specified(leaf->files);
X     }
X     if (leaf->specified)
X	  status |= really_do_expunge(leaf);
X     if (leaf->next)
X	  status |= expunge_specified(leaf->next);
X     free_leaf(leaf);
X     return(status);
X}
X
X
Xprocess_files(files, num)
Xchar **files;
Xint num;
X{
X     int i;
X     filerec *leaf;
X     
X     for (i = 0; i < num; i++) {
X	  if (! (leaf = add_path_to_tree(files[i]))) {
X	       fprintf(stderr, "%s: error adding path to filename tree\n",
X		       whoami);
X	       exit(1);
X	  }
X
X	  free(files[i]);
X	  if (! timed_out(leaf, current_time, timev)) {
X	       free_leaf(leaf);
X	       num--;
X	  }
X     }
X     free(files);
X     return(num);
X}
X
X
X
X
X
X
X
X
X
Xdo_directory_expunge(file_ent)
Xfilerec *file_ent;
X{
X     char buf[MAXPATHLEN];
X
X     get_leaf_path(file_ent, buf);
X     convert_to_user_name(buf, buf);
X     
X     if (interactive) {
X	  printf("%s: Expunge directory %s? ", whoami, buf);
X	  if (! yes())
X	       return(NO_DELETE_MASK);
X     }
X     return(0);
X}
X
X
X
X
X
X
X
X
Xreally_do_expunge(file_ent)
Xfilerec *file_ent;
X{
X     char real[MAXPATHLEN], user[MAXPATHLEN];
X     int status;
X     
X     get_leaf_path(file_ent, real);
X     convert_to_user_name(real, user);
X
X     if (interactive) {
X	  printf ("%s: Expunge %s (%dk)? ", whoami, user,
X		  blk_to_k(file_ent->specs.st_blocks));
X	  if (! yes())
X	       return(NO_DELETE_MASK);
X     }
X
X     if (noop) {
X	  blocks_removed += file_ent->specs.st_blocks;
X	  printf("%s: %s (%dk) would be expunged (%dk total)\n", whoami, user,
X		 blk_to_k(file_ent->specs.st_blocks),
X		 blk_to_k(blocks_removed));
X	  return(0);
X     }
X
X     if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
X	  status = rmdir(real);
X     else
X	  status = unlink(real);
X     if (! status) {
X	  blocks_removed += file_ent->specs.st_blocks;
X	  if (verbose)
X	       printf("%s: %s (%dk) expunged (%dk total)\n", whoami, user,
X		      blk_to_k(file_ent->specs.st_blocks),
X		      blk_to_k(blocks_removed));
X	  return(0);
X     }
X     else {
X	  if (! force)
X	       fprintf(stderr, "%s: %s not expunged\n", whoami, user);
X	  return(ERROR_MASK);
X     }
X}
X
X
X
X
X
X
X
X
X
Xtop_level()
X{
X     if (interactive) {
Xprintf("The above files, which have been marked for deletion, are about to be\n");
Xprintf("expunged forever!  You will be asked for confirmation before each file is\n");
Xprintf("deleted.  Do you wish to continue [return = no]? ");
X     }
X     else {
Xprintf("The above files, which have been marked for deletion, are about to be\n");
Xprintf("expunged forever!  Make sure you don't need any of them before continuing.\n");
Xprintf("Do you wish to continue [return = no]? ");
X     }
X     return (yes());
X}
X
X
X
X
X
Xlist_files()
X{
X     filerec *current;
X     char **strings;
X     int num;
X     
X     strings = (char **) malloc(sizeof(char *));
X     num = 0;
X     if (! strings) {
X	  if (! force)
X	       perror(sprintf(error_buf, "%s: list_files", whoami));
X	  exit(1);
X     }
X     printf("The following deleted files are going to be expunged: \n\n");
X
X     current = get_root_tree();
X     strings = accumulate_names(current, strings, &num);
X     current = get_cwd_tree();
X     strings = accumulate_names(current, strings, &num);
X     column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0, 1, stdout);
X     printf("\n");
X     return(0);
X}
X     
X
X
X
X
Xchar **get_the_files(base, reg_exp, num_found)
Xchar *base, *reg_exp;
Xint *num_found;
X{
X     char **matches;
X     int num_matches;
X     char **found;
X     int num;
X     int i;
X     
X     found = (char **) malloc(0);
X     num = 0;
X     
X     matches = find_matches(base, reg_exp, &num_matches);
X     if (recursive) {
X	  char **recurs_found;
X	  int recurs_num;
X	  
X	  for (i = 0; i < num_matches; free(matches[i]), i++) {
X	       if (is_deleted(lastpart(matches[i]))) {
X		    found = add_str(found, num, matches[i]);
X		    num++;
X	       }
X	       recurs_found = find_deleted_recurses(matches[i], &recurs_num);
X	       add_arrays(&found, &num, &recurs_found, &recurs_num);
X	  }
X     }	
X     else {
X	  struct stat stat_buf;
X	  char **contents_found;
X	  int num_contents;
X	  
X	  for (i = 0; i < num_matches; free(matches[i]), i++) {
X	       if (is_deleted(lastpart(matches[i]))) {
X		    found = add_str(found, num, matches[i]);
X		    num++;
X	       }
X	       if (lstat(matches[i], &stat_buf))
X		    continue;
X	       if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X		    contents_found = find_deleted_contents_recurs(matches[i],
X							       &num_contents);
X		    add_arrays(&found, &num, &contents_found,
X			       &num_contents);
X	       }
X	  }
X     }
X     free(matches);
X     *num_found = num;
X     return(found);
X}
END_OF_FILE
if test 10893 -ne `wc -c <'expunge.c'`; then
    echo shar: \"'expunge.c'\" unpacked with wrong size!
fi
# end of 'expunge.c'
fi
if test -f 'pattern.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pattern.c'\"
else
echo shar: Extracting \"'pattern.c'\" \(12106 characters\)
sed "s/^X//" >'pattern.c' <<'END_OF_FILE'
X/*
X * $Source: /mit/jik/src/delete/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: pattern.c,v 1.8 89/03/27 12:07:48 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#include <strings.h>
X#include <sys/stat.h>
X#include "directories.h"
X#include "pattern.h"
X#include "util.h"
X#include "undelete.h"
X#include "mit-copyright.h"
X
Xstatic char *add_char();
X
Xextern char *malloc(), *realloc();
X
Xextern char *whoami, *error_buf;
X
X/*
X * parse_pattern returns an area of memory allocated by malloc when it
X * is successful.  Therefore, other procedures calling parse_pattern
X * should use free() to free the region of memory when they are done
X * with it.
X */
Xchar *parse_pattern(file_pattern)
Xchar *file_pattern;
X{
X     char *re_pattern, *cur_ptr, *re_ptr;
X     int guess_length;
X     
X     guess_length = strlen(file_pattern) + 5;
X     re_ptr = re_pattern = malloc(guess_length);
X     if (! re_ptr) {
X	  perror(sprintf(error_buf, "%s: parse_pattern", whoami));
X	  exit(1);
X     }
X     
X     for (cur_ptr = file_pattern, re_ptr = re_pattern; *cur_ptr != NULL;
X	  cur_ptr++) {
X	  if (*cur_ptr == '\\') {
X	       if (! cur_ptr[1]) {
X		    fprintf(stderr,
X			    "%s: parse_pattern: incomplete expression\n",
X			    whoami);
X		    return((char *) NULL);
X	       }
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, '\\'))
X		    return ((char *) NULL);
X	       cur_ptr++;
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, *cur_ptr))
X		    return ((char *) NULL);
X	       continue;
X	  }
X	  else if (*cur_ptr == '*') {
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, '.'))
X		    return ((char *) NULL);
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, '*'))
X		    return ((char *) NULL);
X	       continue;
X	  }
X	  else if (*cur_ptr == '?') {
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, '.'))
X		    return ((char *) NULL);
X	       continue;
X	  }
X	  else if (*cur_ptr == '.') {
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, '\\'))
X		    return ((char *) NULL);
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, '.'))
X		    return ((char *) NULL);
X	  }
X	  else {
X	       if (! add_char(&re_pattern, &re_ptr, &guess_length, *cur_ptr))
X		    return ((char *) NULL);
X	  }
X     }
X     if (! add_char(&re_pattern, &re_ptr, &guess_length, '\0'))
X	  return ((char *) NULL);
X     return (re_pattern);
X}
X
X
X
X
X
X
X/*
X * add_char() takes two char **, a length which is the current amount
X * of space implemented for the string pointed to by the first *(char **),
X * and a character to add to the string.  It reallocs extra space if
X * necessary, adds the character, and messes with the pointers if necessary.
X */
Xstatic char *add_char(start, finish, length, chr)
Xchar **start, **finish;
Xint *length;
Xchar chr;
X{
X     if (*finish - *start == *length) {
X	  *start = realloc(*start, *length + 5);
X	  if (! *start) {
X	       perror(sprintf(error_buf, "%s: add_char", whoami));
X	       exit(1);
X	  }
X	  *finish = *start + *length - 1;
X	  *length += 5;
X     }
X     **finish = chr;
X     (*finish)++;
X     return(*start);
X}
X
X	  
X
X
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 */  
Xadd_arrays(array1, num1, array2, num2)
Xchar ***array1, ***array2;
Xint *num1, *num2;
X{
X     int counter;
X     
X     *array1 = (char **) realloc(*array1, sizeof(char *) * (*num1 + *num2));
X     if (! *array1) {
X	  perror(sprintf(error_buf, "%s: add_arrays", whoami));
X	  exit(1);
X     }
X     for (counter = *num1; counter < *num1 + *num2; counter++)
X	  *(*array1 + counter) = *(*array2 + counter - *num1);
X     free (*array2);
X     *num1 += *num2;
X     return(0);
X}
X
X
X
X
X
X
X
Xchar **add_str(strs, num, str)
Xchar **strs;
Xint num;
Xchar *str;
X{
X     strs = (char **) realloc(strs, sizeof(char *) * (num + 1));
X     if (! strs) {
X	  perror(sprintf(error_buf, "%s: add_str", whoami));
X	  exit(1);
X     }
X     strs[num] = malloc(strlen(str) + 1);
X     if (! strs[num]) {
X	  perror(sprintf(error_buf, "%s: add_str", whoami));
X	  exit(1);
X     }
X     strcpy(strs[num], str);
X     return(strs);
X}
X
X
X
X
X
X
X
Xchar **find_deleted_matches(base, expression, num_found)
Xchar *base, *expression;
Xint *num_found;
X{
X     struct direct *dp;
X     DIR *dirp;
X     char **found;
X     int num;
X     char **next;
X     int num_next;
X     char first[MAXNAMLEN], rest[MAXPATHLEN];
X     char new[MAXPATHLEN];
X
X#ifdef DEBUG
X     printf("Looking for %s in %s\n", expression, base);
X#endif
X     found = (char **) malloc(0);
X     *num_found = num = 0;
X
X     dirp = opendir(base);
X     if (! dirp)
X	  return(found);
X
X     readdir(dirp); readdir(dirp); /* get rid of . and .. */
X     
X     strcpy(first, reg_firstpart(expression, rest));
X     re_comp(first);
X
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  if (re_exec(dp->d_name) && *rest) {
X	       strcpy(new, append(base, dp->d_name));
X	       next = find_deleted_matches(new, rest, &num_next);
X	       add_arrays(&found, &num, &next, &num_next);
X	  }
X	  else if (is_deleted(dp->d_name)) if (re_exec(&dp->d_name[2])) {
X	       if (*rest) {
X		    strcpy(new, append(base, dp->d_name));
X		    next = find_deleted_matches(new, rest, &num_next);
X		    add_arrays(&found, &num, &next, &num_next);
X	       }
X	       else {
X		    found = add_str(found, num, append(base, dp->d_name));
X		    num++;
X	       }
X	  }
X     }
X     closedir(dirp);
X     *num_found = num;
X     return(found);
X}
X
X
X
X
X
Xchar **find_matches(base, expression, num_found)
Xchar *base, *expression;
Xint *num_found;
X{
X     struct direct *dp;
X     DIR *dirp;
X     char **found;
X     int num;
X     char **next;
X     int num_next;
X     char first[MAXNAMLEN], rest[MAXPATHLEN];
X     char new[MAXPATHLEN];
X     
X#ifdef DEBUG
X     printf("Looking for %s in %s\n", expression, base);
X#endif
X     found = (char **) malloc(0);
X     *num_found = num = 0;
X
X     dirp = opendir(base);
X     if (! dirp)
X	  return(found);
X
X     strcpy(first, reg_firstpart(expression, rest));
X
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  re_comp(first);
X	  if (re_exec(dp->d_name)) {
X	       if (*rest) {
X		    strcpy(new, append(base, dp->d_name));
X		    next = find_matches(new, rest, &num_next);
X		    add_arrays(&found, &num, &next, &num_next);
X	       }
X	       else {
X		    found = add_str(found, num, append(base, dp->d_name));
X		    num++;
X	       }
X	  }
X	  else if (is_deleted(dp->d_name)) if (re_exec(&dp->d_name[2])) {
X	       if (*rest) {
X		    strcpy(new, append(base, dp->d_name));
X		    next = find_matches(new, rest, &num_next);
X		    add_arrays(&found, &num, &next, &num_next);
X	       }
X	       else {
X		    found = add_str(found, num, append(base, dp->d_name));
X		    num++;
X	       }
X	  }
X     }
X     closedir(dirp);
X     *num_found = num;
X     return(found);
X}
X
X
X
X
X
X
X
Xchar **find_recurses(base, num_found)
Xchar *base;
Xint *num_found;
X{
X     DIR *dirp;
X     struct direct *dp;
X     char newname[MAXPATHLEN];
X     char **found, **new_found;
X     int found_num, new_found_num;
X     struct stat stat_buf;
X     
X#ifdef DEBUG
X     printf("Looking for subs of %s\n", base);
X#endif
X     found = (char **) malloc(0);
X     *num_found = found_num = 0;
X     
X     dirp = opendir(base);
X     if (! dirp)
X	  return(found);
X
X     readdir(dirp); readdir(dirp); /* get rid of . and .. */
X
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  strcpy(newname, append(base, dp->d_name));
X	  found = add_str(found, found_num, newname);
X	  found_num++;
X	  if (lstat(newname, &stat_buf))
X	       continue;
X	  if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X	       new_found = find_recurses(newname, &new_found_num);
X	       add_arrays(&found, &found_num, &new_found, &new_found_num);
X	  }
X     }
X     closedir(dirp);
X     *num_found = found_num;
X     return(found);
X}
X
X
X
X
X
X
Xchar **find_deleted_recurses(base, num_found)
Xchar *base;
Xint *num_found;
X{
X     DIR *dirp;
X     struct direct *dp;
X     char newname[MAXPATHLEN];
X     char **found, **new_found;
X     int found_num, new_found_num;
X     struct stat stat_buf;
X     
X     found = (char **) malloc(0);
X     *num_found = found_num = 0;
X     
X     dirp = opendir(base);
X     if (! dirp)
X	  return(found);
X
X     readdir(dirp); readdir(dirp); /* get rid of . and .. */
X
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  strcpy(newname, append(base, dp->d_name));
X	  
X	  if (is_deleted(dp->d_name)) {
X	       found = add_str(found, found_num, newname);
X	       found_num++;
X	  }
X	  if (lstat(newname, &stat_buf)) {
X	       continue;
X	  }
X	  if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X	       new_found = find_deleted_recurses(newname, &new_found_num);
X	       add_arrays(&found, &found_num, &new_found, &new_found_num);
X	  }
X     }
X     closedir(dirp);
X     *num_found = found_num;
X     return(found);
X}
X
X
X
X
X
X
Xchar **find_contents(base, num_found)
Xchar *base;
Xint *num_found;
X{
X     DIR *dirp;
X     struct direct *dp;
X     char **found;
X     int num;
X
X#ifdef DEBUG
X     printf("Looking for contents of %s\n", base);
X#endif
X     found = (char **) malloc(0);
X     *num_found = num = 0;
X   
X     dirp = opendir(base);
X     if (! dirp)
X	  return(found);
X
X     readdir(dirp); readdir(dirp); /* get rid of . and .. */
X
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  found = add_str(found, num, append(base, dp->d_name));
X	  num += 1;
X     }
X     closedir(dirp);
X     *num_found = num;
X     return(found);
X}
X
X
X     
Xchar **find_deleted_contents(base, num_found)
Xchar *base;
Xint *num_found;
X{
X     DIR *dirp;
X     struct direct *dp;
X     char **found;
X     int num;
X
X#ifdef DEBUG
X     printf("Looking for deleted contents of %s\n", base);
X#endif
X     found = (char **) malloc(0);
X     *num_found = num = 0;
X   
X     dirp = opendir(base);
X     if (! dirp)
X	  return(found);
X
X     readdir(dirp); readdir(dirp); /* get rid of . and .. */
X
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  if (is_deleted(dp->d_name)) {
X	       found = add_str(found, num, append(base, dp->d_name));
X	       num += 1;
X	  }
X     }
X     closedir(dirp);
X     *num_found = num;
X     return(found);
X}
X
X
X
X
Xchar **find_deleted_contents_recurs(base, num_found)
Xchar *base;
Xint *num_found;
X{
X     DIR *dirp;
X     struct direct *dp;
X     char **found;
X     int num;
X     struct stat stat_buf;
X     char newname[MAXPATHLEN];
X     char **new_found;
X     int new_found_num;
X     
X#ifdef DEBUG
X     printf("Looking for recursive deleted contents of %s\n", base);
X#endif
X     found = (char **) malloc(0);
X     *num_found = num = 0;
X   
X     dirp = opendir(base);
X     if (! dirp)
X	  return(found);
X
X     readdir(dirp); readdir(dirp); /* get rid of . and .. */
X
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  if (is_deleted(dp->d_name)) {
X	       strcpy(newname, append(base, dp->d_name));
X	       found = add_str(found, num, newname);
X	       num += 1;
X	       if (lstat(newname, &stat_buf))
X		    continue;
X	       if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X		    new_found = find_recurses(newname, &new_found_num);
X		    add_arrays(&found, &num, &new_found, &new_found_num);
X	       }
X	  }
X     }
X     closedir(dirp);
X     *num_found = num;
X     return(found);
X}
X     
X
X
X/*
X * returns true if the filename has no regular expression wildcards in
X * it.  That means no non-quoted dots or asterisks.  Assumes a
X * null-terminated string, and a valid regular expression.
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	  }
X     } while (*++name);
X     return(1);
X}
END_OF_FILE
if test 12106 -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 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 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

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.