v18i077: MIT Athena delete/undelete programs, Part05/06
Rich Salz
rsalz at uunet.uu.net
Wed Mar 29 14:33:15 AEST 1989
Submitted-by: Jonathan I. Kamens <jik at PIT-MANAGER.MIT.EDU>
Posting-number: Volume 18, Issue 77
Archive-name: undel/part05
#! /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 5 (of 6)."
# Contents: undelete.c
# Wrapped by jik at pit-manager on Mon Mar 27 12:16:54 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'undelete.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'undelete.c'\"
else
echo shar: Extracting \"'undelete.c'\" \(12143 characters\)
sed "s/^X//" >'undelete.c' <<'END_OF_FILE'
X/*
X * $Source: /mit/jik/src/delete/RCS/undelete.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_undelete_c[] = "$Header: undelete.c,v 1.15 89/03/27 12:08:08 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
X#define ERROR_MASK 1
X#define NO_DELETE_MASK 2
X
Xchar *malloc(), *realloc();
X
Xint interactive, recursive, verbose, directoriesonly, noop, force;
Xint del_recursive = 0; /* this tells the pattern matcher that we do */
X /* *not* want it to recurse deleted directories */
X /* when recursive is set to false. */
X
Xchar *whoami, *error_buf;
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 interactive = recursive = verbose = directoriesonly = noop = force = 0;
X error_buf = malloc(MAXPATHLEN + strlen(whoami));
X if (! error_buf) {
X perror(whoami);
X exit(1);
X }
X while ((arg = getopt(argc, argv, "firvnR")) != -1) {
X switch (arg) {
X case 'f':
X force++;
X break;
X case 'i':
X interactive++;
X break;
X case 'r':
X recursive++;
X if (directoriesonly) {
X fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
X whoami);
X usage();
X exit(1);
X }
X break;
X case 'v':
X verbose++;
X break;
X case 'n':
X noop++;
X break;
X case 'R':
X directoriesonly++;
X if (recursive) {
X fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
X whoami);
X usage();
X exit(1);
X }
X default:
X usage();
X exit(1);
X }
X }
X if (optind == argc)
X exit(interactive_mode());
X else while (optind < argc) {
X status = status | undelete(argv[optind]);
X optind++;
X }
X exit(status & ERROR_MASK);
X}
X
X
X
Xinteractive_mode()
X{
X char buf[MAXPATHLEN];
X char *ptr;
X int status = 0;
X
X if (verbose) {
X printf("Enter the files to be undeleted, one file per line.\n");
X printf("Hit <RETURN> on a line by itself to exit.\n\n");
X }
X do {
X printf("%s: ", whoami);
X ptr = fgets(buf, MAXPATHLEN, stdin);
X if (! ptr) {
X printf("\n");
X return(status);
X }
X ptr = index(buf, '\n'); /* fgets breakage */
X if (ptr)
X *ptr = '\0';
X if (! *buf)
X return(status);
X status = status | undelete(buf);
X } while (*ptr);
X return(status);
X}
X
X
X
Xusage()
X{
X fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
X fprintf(stderr, "Options are:\n");
X fprintf(stderr, " -r recursive\n");
X fprintf(stderr, " -i interactive\n");
X fprintf(stderr, " -f force\n");
X fprintf(stderr, " -v verbose\n");
X fprintf(stderr, " -n noop\n");
X fprintf(stderr, " -R directories only (i.e. no recursion)\n");
X fprintf(stderr, " -- end options and start filenames\n");
X fprintf(stderr, "-r and -D are mutually exclusive\n");
X}
X
X
Xundelete(file_exp)
Xchar *file_exp;
X{
X char *file_re;
X char **found_files;
X int num_found;
X char *startdir;
X int status = 0;
X filerec *current;
X
X if (*file_exp == '/') {
X startdir = "/";
X file_re = parse_pattern(file_exp + 1);
X }
X else {
X startdir = "";
X file_re = parse_pattern(file_exp);
X }
X if (! file_re)
X return(ERROR_MASK);
X found_files = get_the_files(startdir, file_re, &num_found);
X free(file_re);
X if (num_found) {
X process_files(found_files, num_found);
X if (*file_exp == '/')
X current = get_root_tree();
X else
X current = get_cwd_tree();
X status = recurs_and_undelete(current);
X }
X else {
X if (! force)
X fprintf(stderr, "%s: %s not found\n", whoami, file_exp);
X status = ERROR_MASK;
X }
X return(status);
X}
X
X
X
X
X
Xrecurs_and_undelete(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_undelete(leaf);
X /* the "do_directory_undelete" 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 |= recurs_and_undelete(leaf->dirs);
X if (leaf->files)
X status |= recurs_and_undelete(leaf->files);
X }
X if (leaf->specified)
X status |= do_undelete(leaf);
X if (leaf->next)
X status |= recurs_and_undelete(leaf->next);
X free_leaf(leaf);
X return(status);
X}
X
X
X
X
X
X
Xdo_directory_undelete(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: Undelete directory %s? ", whoami, buf);
X if (! yes())
X return(NO_DELETE_MASK);
X }
X return(0);
X}
X
X
X
X
X
Xprocess_files(files, num)
Xchar **files;
Xint num;
X{
X int i;
X listrec *new_files;
X listrec *filelist;
X
X filelist = (listrec *) malloc(sizeof(listrec) * num);
X if (! filelist) {
X perror(sprintf(error_buf, "%s: process_files\n", whoami));
X exit(1);
X }
X for (i = 0; i < num; i++) {
X filelist[i].real_name = malloc(strlen(files[i]) + 1);
X strcpy(filelist[i].real_name, files[i]);
X filelist[i].user_name = malloc(strlen(files[i]) + 1);
X convert_to_user_name(files[i], filelist[i].user_name);
X free(files[i]);
X }
X free(files);
X
X new_files = sort_files(filelist, num);
X new_files = unique(new_files, &num);
X if (initialize_tree()) {
X exit(1);
X }
X for (i = 0; i < num; i++) {
X if (!add_path_to_tree(new_files[i].real_name)) {
X fprintf(stderr, "%s: error adding path to filename tree\n",
X whoami);
X exit(1);
X }
X else {
X free(new_files[i].real_name);
X free(new_files[i].user_name);
X }
X }
X free(new_files);
X return(0);
X}
X
X
X
X
X
X
X
X
Xdo_undelete(file_ent)
Xfilerec *file_ent;
X{
X struct stat stat_buf;
X char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
X
X get_leaf_path(file_ent, real_name);
X convert_to_user_name(real_name, user_name);
X
X if (interactive) {
X if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
X printf("%s: Undelete directory %s? ", whoami, user_name);
X else
X printf("%s: Undelete %s? ", whoami, user_name);
X if (! yes())
X return(NO_DELETE_MASK);
X }
X if (! lstat(user_name, &stat_buf)) if (! force) {
X printf("%s: An undeleted %s already exists.\n", whoami, user_name);
X printf("Do you wish to continue with the undelete and overwrite that version? ");
X if (! yes())
X return(NO_DELETE_MASK);
X unlink_completely(user_name);
X }
X if (noop) {
X printf("%s: %s would be undeleted\n", whoami, user_name);
X return(0);
X }
X
X if (! do_file_rename(real_name, user_name)) {
X if (verbose)
X printf("%s: %s undeleted\n", whoami, user_name);
X return(0);
X }
X else {
X if (! force)
X fprintf(stderr, "%s: %s not undeleted\n", whoami, user_name);
X return(ERROR_MASK);
X }
X}
X
X
X
X
Xdo_file_rename(real_name, user_name)
Xchar *real_name, *user_name;
X{
X char *ptr;
X
X char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
X char buf[MAXPATHLEN];
X
X strcpy(old_name, real_name);
X strcpy(new_name, real_name);
X
X while (ptr = strrindex(new_name, ".#")) {
X convert_to_user_name(ptr, ptr);
X strcpy(ptr, firstpart(ptr, buf));
X strcpy(&old_name[ptr - new_name],
X firstpart(&old_name[ptr - new_name], buf));
X if (rename(old_name, new_name)) {
X return(ERROR_MASK);
X }
X if (ptr > new_name) {
X *--ptr = '\0';
X old_name[ptr - new_name] = '\0';
X }
X }
X change_path(real_name, user_name);
X return(0);
X}
X
X
X
X
X
X
Xfilecmp(file1, file2)
Xlistrec *file1, *file2;
X{
X return(strcmp(file1->user_name, file2->user_name));
X}
X
X
X
Xlistrec *sort_files(data, num_data)
Xlistrec *data;
Xint num_data;
X{
X qsort(data, num_data, sizeof(listrec), filecmp);
X return(data);
X}
X
X
X
X
X
Xlistrec *unique(files, number)
Xlistrec *files;
Xint *number;
X{
X int i, last;
X int offset;
X
X for (last = 0, i = 1; i < *number; i++) {
X if (! strcmp(files[last].user_name, files[i].user_name)) {
X int better;
X
X better = choose_better(files[last].real_name,
X files[i].real_name);
X if (better == 1) { /* the first one is better */
X free (files[i].real_name);
X free (files[i].user_name);
X files[i].real_name = (char *) NULL;
X }
X else {
X free (files[last].real_name);
X free (files[last].user_name);
X files[last].real_name = (char *) NULL;
X last = i;
X }
X }
X else
X last = i;
X }
X
X for (offset = 0, i = 0; i + offset < *number; i++) {
X if (! files[i].real_name)
X offset++;
X if (i + offset < *number)
X files[i] = files[i + offset];
X }
X *number -= offset;
X files = (listrec *) realloc(files, sizeof(listrec) * *number);
X if (! files) {
X perror(sprintf(error_buf, "%s: unique", whoami));
X exit(1);
X }
X return(files);
X}
X
X
X
X
Xchoose_better(str1, str2)
Xchar *str1, *str2;
X{
X char *pos1, *pos2;
X
X pos1 = strindex(str1, ".#");
X pos2 = strindex(str2, ".#");
X while (pos1 && pos2) {
X if (pos1 - str1 < pos2 - str2)
X return(2);
X else if (pos2 - str2 < pos1 - str1)
X return(1);
X pos1 = strindex(pos1 + 1, ".#");
X pos2 = strindex(pos2 + 1, ".#");
X }
X if (! pos1)
X return(1);
X else
X return(2);
X}
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 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
X if (is_dotfile(dp->d_name))
X continue;
X strcpy(buf, append(filename, dp->d_name));
X if (! buf) {
X status = 1;
X continue;
X }
X status = status | unlink_completely(buf);
X }
X closedir(dirp);
X }
X else
X return(unlink(filename) == -1);
X return(0);
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 else if (! directoriesonly) {
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(matches[i],
X &num_contents);
X add_arrays(&found, &num, &contents_found,
X &num_contents);
X }
X }
X }
X
X }
X free(matches);
X *num_found = num;
X return(found);
X}
X
X
X
X
X
END_OF_FILE
if test 12143 -ne `wc -c <'undelete.c'`; then
echo shar: \"'undelete.c'\" unpacked with wrong size!
fi
# end of 'undelete.c'
fi
echo shar: End of archive 5 \(of 6\).
cp /dev/null ark5isdone
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