rsalz@uunet.uu.net (Rich Salz) (03/29/89)
Submitted-by: Jonathan I. Kamens <jik@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@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@uunet.uu.net.