v18i075: MIT Athena delete/undelete programs, Part03/06

Rich Salz rsalz at uunet.uu.net
Wed Mar 29 14:32:02 AEST 1989


Submitted-by: Jonathan I. Kamens <jik at PIT-MANAGER.MIT.EDU>
Posting-number: Volume 18, Issue 75
Archive-name: undel/part03

#! /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 3 (of 6)."
# Contents:  delete.c lsdel.c
# Wrapped by jik at pit-manager on Mon Mar 27 12:16:50 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'delete.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'delete.c'\"
else
echo shar: Extracting \"'delete.c'\" \(9801 characters\)
sed "s/^X//" >'delete.c' <<'END_OF_FILE'
X/*
X * $Source: /mit/jik/src/delete/RCS/delete.c,v $
X * $Author: jik $
X *
X * This program is a replacement for rm.  Instead of actually deleting
X * files, it marks them for deletion by prefixing them with a ".#"
X * prefix.
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_delete_c[] = "$Header: delete.c,v 1.17 89/03/27 12:05:58 jik Exp $";
X#endif
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include <strings.h>
X#include <sys/param.h>
X#include <sys/file.h>
X#include "util.h"
X#include "delete.h"
X#include "mit-copyright.h"
X
X
X
X
X/*
X * ALGORITHM:
X *
X * 1. Parse command-line arguments and set flags.
X * 2. Call the function delete() for each filename command-line argument.
X *
X * delete():
X *
X * 1. Can the file be lstat'd?
X *    no -- abort
X *    yes -- continue
X * 2. Is the file a directory?
X *    yes -- is it a dotfile?
X *           yes -- abort
X *           no -- continue
X *        -- is the filesonly option set?
X *           yes -- is the recursive option specified?
X *                  yes -- continue
X *                  no -- abort
X *           no -- is the directory empty?
X *                  yes -- remove it
X *                  no -- is the directoriesonly option set?
X * 			  yes -- abort
X * 			  no -- continue
X * 		       -- is the recursive option specified?
X * 			  yes -- continue
X * 			  no -- abort
X *    no -- is the directoriesonly option set?
X * 	    yes -- abort
X * 	    no -- continue
X * 3. If the file is a file, remove it.
X * 4. If the file is a directory, open it and pass each of its members
X *    (excluding . files) to delete().
X */
X
X
Xint force, interactive, recursive, noop, verbose, filesonly, directoriesonly;
Xchar *whoami;
Xchar *malloc();
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
X     force = interactive = recursive = noop = verbose = filesonly =
X	  directoriesonly = 0;
X     while ((arg = getopt(argc, argv, "firnvFD")) != -1) {
X	  switch (arg) {
X	  case 'r':
X	       recursive++;
X	       if (directoriesonly) {
X		    fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
X			    whoami);
X		    usage();
X		    exit(! force);
X	       }
X	       break;
X	  case 'f':
X	       force++;
X	       break;
X	  case 'i':
X	       interactive++;
X	       break;
X	  case 'n':
X	       noop++;
X	       break;
X	  case 'v':
X	       verbose++;
X	       break;
X	  case 'F':
X	       filesonly++;
X	       if (directoriesonly) {
X		    fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
X			    whoami);
X		    usage();
X		    exit(! force);
X	       }
X	       break;
X	  case 'D':
X	       directoriesonly++;
X	       if (recursive) {
X		    fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
X			    whoami);
X		    usage();
X		    exit(! force);
X	       }
X	       if (filesonly) {
X		    fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
X			    whoami);
X		    usage();
X		    exit(! force);
X	       }
X	       break;
X	  default:
X	       usage();
X	       exit(! force);
X	  }
X     }
X     if (optind == argc) {
X	  fprintf(stderr, "%s: no files specified.\n", whoami);
X	  usage();
X	  exit(! force);
X     }
X     while (optind < argc) {
X	  status = status | delete(argv[optind], 0);
X	  optind++;
X     }
X     exit((! force) && (status & ERROR_MASK));
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("     -n     noop\n");
X     printf("     -v     verbose\n");
X     printf("     -F     files only\n");
X     printf("     -D     directories only\n");
X     printf("     --     end options and start filenames\n");
X     printf("-r and -D are mutually exclusive\n");
X     printf("-F and -D are mutually exclusive\n");
X}
X
X
X
X
X
X
Xdelete(filename, recursed)
Xchar *filename;
Xint recursed;
X{
X     struct stat stat_buf;
X
X     /* can the file be lstat'd? */
X     if (lstat(filename, &stat_buf) == -1) {
X	  if (! force)
X	       fprintf(stderr, "%s: %s nonexistent\n", whoami, filename);
X	  return(ERROR_MASK);
X     }
X     
X     /* is the file a directory? */
X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X	  /* is the file a dot file? */
X	  if (is_dotfile(filename)) {
X	       if (! force)
X		    fprintf(stderr, "%s: cannot remove `.' or `..'\n",
X			    whoami);
X	       return(ERROR_MASK);
X	  }
X	  /* is the filesonly option set? */
X	  if (filesonly) {
X	       /* is the recursive option specified? */
X	       if (recursive) {
X		    return(recursive_delete(filename, stat_buf, recursed));
X	       }
X	       else {
X		    if (! force)
X			 fprintf(stderr, "%s: %s directory\n", whoami,
X				 filename);
X		    return(ERROR_MASK);
X	       }
X	  }
X	  else {
X	       /* is the directory empty? */
X	       if (empty_directory(filename)) {
X		    /* remove it */
X		    return(do_move(filename, stat_buf, 0));
X	       }
X	       else {
X		    /* is the directoriesonly option set? */
X		    if (directoriesonly) {
X			 if (! force)
X			      fprintf(stderr, "%s: %s: Directory not empty\n",
X				     whoami, filename);
X			 return(ERROR_MASK);
X		    }
X		    else {
X			 /* is the recursive option specified? */
X			 if (recursive) {
X			      return(recursive_delete(filename, stat_buf,
X						      recursed));
X			 }
X			 else {
X			      if (! force)
X				   fprintf(stderr, "%s: %s not empty\n",
X					   whoami, filename);
X			      return(ERROR_MASK);
X			 }
X		    }
X	       }
X	  }
X     }
X     else {
X	  /* is the directoriesonly option set? */
X	  if (directoriesonly) {
X	       if (! force)
X		    fprintf(stderr, "%s: %s: Not a directory\n", whoami,
X			    filename);
X	       return(ERROR_MASK);
X	  }
X	  else
X	       return(do_move(filename, stat_buf, 0));
X     }
X}
X
X		 
X			 
X	       
Xempty_directory(filename)
Xchar *filename;
X{
X     DIR *dirp;
X     struct direct *dp;
X
X     dirp = opendir(filename);
X     if (! dirp) {
X	  return(0);
X     }
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  if (is_dotfile(dp->d_name))
X	       continue;
X	  if (is_deleted(dp->d_name))
X	       continue;
X	  else {
X	       closedir(dirp);
X	       return(0);
X	  }
X     }
X     closedir(dirp);
X     return(1);
X}
X
X
X
X
Xrecursive_delete(filename, stat_buf, recursed)
Xchar *filename;
Xstruct stat stat_buf;
Xint recursed;
X{
X     DIR *dirp;
X     struct direct *dp;
X     int status = 0;
X     char newfile[MAXPATHLEN];
X     
X     if (interactive && recursed) {
X	  printf("%s: remove directory %s? ", whoami, filename);
X	  if (! yes())
X	       return(NO_DELETE_MASK);
X     }
X     dirp = opendir(filename);
X     if (! dirp) {
X	  if (! force)
X	       fprintf(stderr, "%s: %s not changed\n", whoami, filename);
X	  return(ERROR_MASK);
X     }
X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	  if (is_dotfile(dp->d_name))
X	       continue;
X	  if (is_deleted(dp->d_name))
X	       continue;
X	  else {
X	       strcpy(newfile, append(filename, dp->d_name, !force));
X	       if (*newfile)
X		    status = status | delete(newfile, 1);
X	       else
X		    status = ERROR_MASK;
X	  }
X     }
X     closedir(dirp);
X     status = status | do_move(filename, stat_buf, status);
X     return(status);
X}
X
X					 
X
X
X
X
Xdo_move(filename, stat_buf, err_mask)
Xchar *filename;
Xstruct stat stat_buf;
Xint err_mask;
X{
X     char *last;
X     char buf[MAXPATHLEN];
X     char name[MAXNAMLEN];
X     struct stat deleted_buf;
X
X     strncpy(buf, filename, MAXPATHLEN);
X     last = lastpart(buf);
X     if (strlen(last) > MAXNAMLEN) {
X	  if (! force)
X	       fprintf(stderr, "%s: %s: filename too long\n", whoami,
X		       filename);
X	  return(ERROR_MASK);
X     }
X     strcpy(name, last);
X     if (strlen(buf) + 3 > MAXPATHLEN) {
X	  if (! force)
X	       fprintf(stderr, "%s: %s: pathname too long\n", whoami,
X		       filename);
X	  return(ERROR_MASK);
X     }
X     *last = '\0';
X     strcat(buf, ".#");
X     strcat(buf, name);
X     if (err_mask) {
X	  if (! force)
X	       fprintf(stderr, "%s: %s not removed\n", whoami, filename);
X	  return(err_mask);
X     }
X     if (interactive) {
X	  printf("%s: remove %s? ", whoami, filename);
X	  if (! yes())
X	       return(NO_DELETE_MASK);
X     }
X     else if ((! force) && ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
X	      && access(filename, W_OK)) {
X	  printf("%s: override protection %o for %s? ", whoami,
X		 stat_buf.st_mode & 0777, filename);
X	  if (! yes())
X	       return(NO_DELETE_MASK);
X     }
X     if (noop) {
X	  fprintf(stderr, "%s: %s would be removed\n", whoami, filename);
X	  return(0);
X     }
X     if (! lstat(buf, &deleted_buf))
X	  unlink_completely(buf);
X     if (rename(filename, buf)) {
X	  if (! force)
X	       fprintf(stderr, "%s: %s not removed\n", whoami, filename);
X	  return(ERROR_MASK);
X     }
X     else {
X	  if (verbose)
X	       fprintf(stderr, "%s: %s removed\n", whoami, filename);
X	  return(0);
X     }
X}
X
X
X
Xunlink_completely(filename)
Xchar *filename;
X{
X     char buf[MAXPATHLEN];
X     struct stat stat_buf;
X     DIR *dirp;
X     struct direct *dp;
X     int status = 0;
X     
X     if (lstat(filename, &stat_buf))
X	  return(1);
X
X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
X	  dirp = opendir(filename);
X	  if (! dirp)
X	       return(1);
X	  readdir(dirp); readdir(dirp); /* get rid of . and .. */
X	  for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X	       strcpy(buf, append(filename, dp->d_name, 0));
X	       if (! buf) {
X		    status = 1;
X		    continue;
X	       }
X	       status = status | unlink_completely(buf);
X	  }
X	  closedir(dirp);
X	  status = status | rmdir(filename);
X	  return(status);
X     }
X     else
X	  return(unlink(filename) == -1);
X}
X
END_OF_FILE
if test 9801 -ne `wc -c <'delete.c'`; then
    echo shar: \"'delete.c'\" unpacked with wrong size!
fi
# end of 'delete.c'
fi
if test -f 'lsdel.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lsdel.c'\"
else
echo shar: Extracting \"'lsdel.c'\" \(6087 characters\)
sed "s/^X//" >'lsdel.c' <<'END_OF_FILE'
X/*
X * $Source: /mit/jik/src/delete/RCS/lsdel.c,v $
X * $Author: jik $
X *
X * This program is a replacement for rm.  Instead of actually deleting
X * files, it marks them for deletion by prefixing them with a ".#"
X * prefix.
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_lsdel_c[] = "$Header: lsdel.c,v 1.4 89/03/27 12:07:13 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 <sys/stat.h>
X#include <strings.h>
X#include "col.h"
X#include "util.h"
X#include "directories.h"
X#include "pattern.h"
X#include "lsdel.h"
X#include "mit-copyright.h"
X
Xchar *malloc(), *realloc();
Xextern int current_time;
X
Xint block_total = 0;
Xint dirsonly, recursive, timev, yield;
Xchar *whoami, *error_buf;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X     extern char *optarg;
X     extern int optind;
X     int arg;
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     dirsonly = recursive = timev = yield = 0;
X     while ((arg = getopt(argc, argv, "drt:y")) != -1) {
X	  switch (arg) {
X	  case 'd':
X	       dirsonly++;
X	       break;
X	  case 'r':
X	       recursive++;
X	       break;
X	  case 't':
X	       timev = atoi(optarg);
X	       break;
X	  case 'y':
X	       yield++;
X	       break;
X	  default:
X	       usage();
X	       exit(1);
X	  }
X     }
X     if (optind == argc) {
X	  char *cwd;
X
X	  cwd = ".";
X	  exit(ls(&cwd, 1));
X     }
X     exit(ls(&argv[optind], argc - optind));
X}
X
X
X
X
X
X
Xusage()
X{
X     printf("Usage: %s [ options ] [ filename [ ...]]\n", whoami);
X     printf("Options are:\n");
X     printf("     -d     list directory names, not contents\n");
X     printf("     -r     recursive\n");
X     printf("     -t n   list n-day-or-older files only\n");
X     printf("     -y     report total space taken up by files\n");
X}
X
X
X
X
Xls(args, num)
Xchar **args;
Xint num;
X{
X     char *start_dir;
X     char **found_files;
X     int num_found, total = 0;
X     char *file_re;
X     int status = 0;
X     
X     if (initialize_tree())
X	  exit(1);
X     
X     for ( ; num; num--) {
X	  if (*args[num - 1] == '/') {
X	       start_dir = "/";
X	       file_re = parse_pattern(args[num - 1] + 1);
X	  }
X	  else {
X	       start_dir = "";
X	       file_re = parse_pattern(args[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	  free(file_re);
X	  total += num_found;
X	  if (num_found)
X	       num_found = process_files(found_files, num_found);
X	  else {
X	       /* What we do at this point depends on exactly what the
X	        * file_re is.  There are three possible conditions:
X		* 1. It's an existing directory.  Print nothing.
X		* 2. It doesn't exist in deleted form, and there are
X		*    no wildcards in it.  Then we print "not found."
X		* 3. It does't exist, but there are wildcards in it.
X		*    Then we print "no match."
X		* None of these are considered error conditions, so we
X		* don't set the error flag.
X		*/
X	       if (no_wildcards(file_re)) {
X		    if (! directory_exists(args[num - 1])) {
X			 fprintf(stderr, "%s: %s: not found\n",
X				 whoami, args[num - 1]);
X		    }
X	       }
X	       else {
X		    fprintf(stderr, "%s: %s: no match\n",
X			    whoami, args[num-1]);
X	       }
X	  }
X     }
X     if (total) {
X	  list_files();
X     }
X     if (yield)
X	  printf("\nTotal space taken up by file%s: %dk\n",
X		 (total == 1 ? "" : "s"), blk_to_k(block_total));
X     return(status);
X}
X
X
X
X
Xchar **get_the_files(start_dir, file_re, number_found)
Xchar *start_dir, *file_re;
Xint *number_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(start_dir, file_re, &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 (dirsonly)
X		    continue;
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, &num_contents);
X		    
X	       }
X	  }
X     }
X     free(matches);
X     *number_found = num;
X     return(found);
X}
X
X
X
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	       continue;
X	  }
X	  block_total += leaf->specs.st_blocks;
X     }
X     free(files);
X     return(num);
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	  perror(sprintf(error_buf, "%s: list_files", whoami));
X	  exit(1);
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     for ( ; num; num--)
X	  free(strings[num - 1]);
X     free(strings);
X     return(0);
X}
END_OF_FILE
if test 6087 -ne `wc -c <'lsdel.c'`; then
    echo shar: \"'lsdel.c'\" unpacked with wrong size!
fi
# end of 'lsdel.c'
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
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 at uunet.uu.net.



More information about the Comp.sources.unix mailing list