home *** CD-ROM | disk | FTP | other *** search
/ The UNIX CD Bookshelf / OREILLY_TUCB_UNIX_CD.iso / upt / examples / SOURCES / DELETE / PART02.Z / PART02 / undelete.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-24  |  12.4 KB  |  601 lines

  1. /*
  2.  * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/undelete.c,v $
  3.  * $Author: jik $
  4.  *
  5.  * This program is part of a package including delete, undelete,
  6.  * lsdel, expunge and purge.  The software suite is meant as a
  7.  * replacement for rm which allows for file recovery.
  8.  * 
  9.  * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  10.  * For copying and distribution information, see the file "mit-copyright.h."
  11.  */
  12.  
  13. #if (!defined(lint) && !defined(SABER))
  14.      static char rcsid_undelete_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/undelete.c,v 1.22 91/02/20 17:27:38 jik Exp $";
  15. #endif
  16.  
  17. #include <stdio.h>
  18. #include <sys/types.h>
  19. #include <sys/dir.h>
  20. #include <sys/param.h>
  21. #ifdef SYSV
  22. #include <string.h>
  23. #define index strchr
  24. #define rindex strrchr
  25. #else
  26. #include <strings.h>
  27. #endif /* SYSV */
  28. #include <com_err.h>
  29. #include <errno.h>
  30. #include "delete_errs.h"
  31. #include "pattern.h"
  32. #include "util.h"
  33. #include "directories.h"
  34. #include "undelete.h"
  35. #include "shell_regexp.h"
  36. #include "mit-copyright.h"
  37. #include "errors.h"
  38.  
  39. extern char *realloc();
  40. extern int errno;
  41.  
  42. int interactive, recursive, verbose, directoriesonly, noop, force;
  43.  
  44.  
  45. main(argc, argv)
  46. int argc;
  47. char *argv[];
  48. {
  49.      extern char *optarg;
  50.      extern int optind;
  51.      int arg;
  52.      int retval;
  53.      
  54.      initialize_del_error_table();
  55.      
  56.      whoami = lastpart(argv[0]);
  57.      interactive = recursive = verbose = directoriesonly = noop = force = 0;
  58.  
  59.      while ((arg = getopt(argc, argv, "firvnR")) != -1) {
  60.       switch (arg) {
  61.       case 'f':
  62.            force++;
  63.            break;
  64.       case 'i':
  65.            interactive++;
  66.            break;
  67.       case 'r':
  68.            recursive++;
  69.            if (directoriesonly) {
  70.             fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
  71.                 whoami);
  72.             usage();
  73.             exit(1);
  74.            }
  75.            break;
  76.       case 'v':
  77.            verbose++;
  78.            break;
  79.       case 'n':
  80.            noop++;
  81.            break;
  82.       case 'R':
  83.            directoriesonly++;
  84.            if (recursive) {
  85.             fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
  86.                 whoami);
  87.             usage();
  88.             exit(1);
  89.            }
  90.            break;
  91.       default:
  92.            usage();
  93.            exit(1);
  94.       }
  95.      }
  96.  
  97.      report_errors = ! force;
  98.      
  99.      if (optind == argc) {
  100.       if (interactive_mode())
  101.            error("interactive_mode");
  102.      }
  103.      else while (optind < argc) {
  104.       retval = undelete(argv[optind]);
  105.       if (retval)
  106.            error(argv[optind]);
  107.       optind++;
  108.      }
  109.      exit(((! force) && error_occurred) ? 1 : 0);
  110. }
  111.  
  112.  
  113.  
  114. interactive_mode()
  115. {
  116.      char buf[MAXPATHLEN];
  117.      char *ptr;
  118.      int status = 0;
  119.      int retval;
  120.      
  121.      if (verbose) {
  122.       printf("Enter the files to be undeleted, one file per line.\n");
  123.       printf("Hit <RETURN> on a line by itself to exit.\n\n");
  124.      }
  125.      do {
  126.       printf("%s: ", whoami);
  127.       ptr = fgets(buf, MAXPATHLEN, stdin);
  128.       if (! ptr) {
  129.            printf("\n");
  130.            return status;
  131.       }
  132.       ptr = index(buf, '\n');  /* fgets breakage */
  133.       if (ptr)
  134.            *ptr = '\0';
  135.       if (! *buf)
  136.            return status;
  137.       retval = undelete(buf);
  138.       if (retval) {
  139.            error(buf);
  140.            status = retval;
  141.       }
  142.      } while (*buf);
  143.      return status;
  144. }
  145.  
  146.  
  147.  
  148. usage()
  149. {
  150.      fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
  151.      fprintf(stderr, "Options are:\n");
  152.      fprintf(stderr, "     -r     recursive\n");
  153.      fprintf(stderr, "     -i     interactive\n");
  154.      fprintf(stderr, "     -f     force\n");
  155.      fprintf(stderr, "     -v     verbose\n");
  156.      fprintf(stderr, "     -n     noop\n");
  157.      fprintf(stderr, "     -R     directories only (i.e. no recursion)\n");
  158.      fprintf(stderr, "     --     end options and start filenames\n");
  159.      fprintf(stderr, "-r and -D are mutually exclusive\n");
  160. }
  161.  
  162. undelete(name)
  163. char *name;
  164. {
  165.      char **found_files;
  166.      int num_found;
  167.      int status = 0;
  168.      filerec *current;
  169.      int retval;
  170.      
  171.      if (retval =  get_the_files(name, &num_found, &found_files)) {
  172.       error(name);
  173.       return retval;
  174.      }
  175.      
  176.      if (num_found) {
  177.       if (retval = process_files(found_files, num_found)) {
  178.            error(name);
  179.            return retval;
  180.       }
  181.       if (*name == '/')
  182.            current = get_root_tree();
  183.       else
  184.            current = get_cwd_tree();
  185.  
  186.       status = recurs_and_undelete(current);
  187.       if (status) {
  188.            error(name);
  189.            return status;
  190.       }
  191.      }
  192.      else {
  193.       if (no_wildcards(name)) {
  194.            set_error(ENOENT)
  195.       }
  196.       else
  197.            set_error(ENOMATCH);
  198.       error(name);
  199.       return error_code;
  200.      }
  201.  
  202.      return status;
  203. }
  204.  
  205.  
  206.  
  207.  
  208.  
  209. int recurs_and_undelete(leaf)
  210. filerec *leaf;
  211. {
  212.      int status = 0;
  213.      int retval;
  214.      
  215.      if (leaf->specified) {
  216.       retval = do_undelete(leaf);
  217.       if (retval) {
  218.            error("do_undelete");
  219.            status = retval;
  220.       }
  221.      }
  222.  
  223.      if (! status) { /* recurse only if if top-level undelete */
  224.              /* succeeded or was not requested        */
  225.       if (leaf->dirs) {
  226.            retval = recurs_and_undelete(leaf->dirs);
  227.            if (retval) {
  228.             error("recurs_and_undelete");
  229.             status = retval;
  230.            }
  231.       }
  232.  
  233.       if (leaf->files) {
  234.            retval = recurs_and_undelete(leaf->files);
  235.            if (retval) {
  236.             error("recurs_and_undelete");
  237.             status = retval;
  238.            }
  239.       }
  240.      }
  241.  
  242.      if (leaf->next) {
  243.       retval = recurs_and_undelete(leaf->next);
  244.       if (retval) {
  245.            error("recurs_and_undelete");
  246.            status = retval;
  247.       }
  248.      }
  249.  
  250.      free_leaf(leaf);
  251.  
  252.      return status;
  253. }
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260. int process_files(files, num)
  261. char **files;
  262. int num;
  263. {
  264.      int i;
  265.      listrec *filelist;
  266.      struct filrec *not_needed;
  267.      int retval;
  268.      
  269.      filelist = (listrec *) Malloc((unsigned) (sizeof(listrec) * num));
  270.      if (! filelist) {
  271.       set_error(errno);
  272.       error("process_files");
  273.       return error_code;
  274.      }
  275.      
  276.      for (i = 0; i < num; i++) {
  277.       filelist[i].real_name = Malloc((unsigned) (strlen(files[i]) + 1));
  278.       if (! filelist[i].real_name) {
  279.            set_error(errno);
  280.            error("process_files");
  281.            return error_code;
  282.       }
  283.       (void) strcpy(filelist[i].real_name, files[i]);
  284.       filelist[i].user_name = Malloc((unsigned) (strlen(files[i]) + 1));
  285.       if (! filelist[i].user_name) {
  286.            set_error(errno);
  287.            error("process_files");
  288.            return error_code;
  289.       }
  290.        (void) convert_to_user_name(files[i], filelist[i].user_name);
  291.       free(files[i]);
  292.      }
  293.      free((char *) files);
  294.       
  295.      if (retval = sort_files(filelist, num)) {
  296.       error("sort_files");
  297.       return retval;
  298.      }
  299.      if (retval = unique(&filelist, &num)) {
  300.       error("unique");
  301.       return retval;
  302.      }
  303.      if (retval = initialize_tree()) {
  304.       error("initialize_tree");
  305.       return retval;
  306.      }
  307.       
  308.      for (i = 0; i < num; i++) {
  309.       if (retval = add_path_to_tree(filelist[i].real_name, ¬_needed)) {
  310.            error("add_path_to_tree");
  311.            return retval;
  312.       }
  313.       else {
  314.            free(filelist[i].real_name);
  315.            free(filelist[i].user_name);
  316.       }
  317.      }
  318.      free((char *) filelist);
  319.      return 0;
  320. }
  321.  
  322.      
  323.  
  324.  
  325.  
  326.  
  327.  
  328.      
  329. do_undelete(file_ent)
  330. filerec *file_ent;
  331. {
  332.      struct stat stat_buf;
  333.      char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
  334.      int retval;
  335.      
  336.      if (retval = get_leaf_path(file_ent, real_name)) {
  337.       if (! force)
  338.            fprintf(stderr, "%s: %s: %s\n", whoami, "get_leaf_path",
  339.                error_message(retval));
  340.       return retval;
  341.      }
  342.      
  343.      (void) convert_to_user_name(real_name, user_name);
  344.  
  345.      if (interactive) {
  346.       if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
  347.            printf("%s: Undelete directory %s? ", whoami, user_name);
  348.       else
  349.            printf("%s: Undelete %s? ", whoami, user_name);
  350.       if (! yes()) {
  351.            set_status(UNDEL_NOT_UNDELETED);
  352.            return error_code;
  353.       }
  354.      }
  355.      if (! lstat(user_name, &stat_buf)) if (! force) {
  356.       printf("%s: An undeleted %s already exists.\n", whoami, user_name);
  357.       printf("Do you wish to continue with the undelete and overwrite that version? ");
  358.       if (! yes()) {
  359.            set_status(UNDEL_NOT_UNDELETED);
  360.            return error_code;
  361.       }
  362.       if (! noop) if (retval = unlink_completely(user_name)) {
  363.            error(user_name);
  364.            return retval;
  365.       }
  366.      }
  367.      if (noop) {
  368.       printf("%s: %s would be undeleted\n", whoami, user_name);
  369.       return 0;
  370.      }
  371.  
  372.      if (retval = do_file_rename(real_name, user_name)) {
  373.       error("do_file_rename");
  374.       return retval;
  375.      }
  376.      else {
  377.       if (verbose)
  378.            printf("%s: %s undeleted\n", whoami, user_name);
  379.       return 0;
  380.      }
  381. }
  382.  
  383.  
  384.  
  385.  
  386. do_file_rename(real_name, user_name)
  387. char *real_name, *user_name;
  388. {
  389.      char *ptr;
  390.      int retval;
  391.      char error_buf[MAXPATHLEN+MAXPATHLEN+14];
  392.      char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
  393.      char buf[MAXPATHLEN];
  394.  
  395.      (void) strcpy(old_name, real_name);
  396.      (void) strcpy(new_name, real_name);
  397.  
  398.      while (ptr = strrindex(new_name, ".#")) {
  399.       (void) convert_to_user_name(ptr, ptr);
  400.       (void) strcpy(ptr, firstpart(ptr, buf));
  401.       (void) strcpy(&old_name[ptr - new_name],
  402.             firstpart(&old_name[ptr - new_name], buf));
  403.       if (rename(old_name, new_name)) {
  404.            set_error(errno);
  405.            (void) sprintf(error_buf, "renaming %s to %s",
  406.                   old_name, new_name);
  407.            error(error_buf);
  408.            return error_code;
  409.       }
  410.       if (ptr > new_name) {
  411.            *--ptr = '\0';
  412.            old_name[ptr - new_name] = '\0';
  413.       }
  414.      }
  415.      if (retval = change_path(real_name, user_name)) {
  416.       error("change_path");
  417.       return retval;
  418.      }
  419.      
  420.      return 0;
  421. }
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428. filecmp(file1, file2)
  429. listrec *file1, *file2;
  430. {
  431.      return(strcmp(file1->user_name, file2->user_name));
  432. }
  433.  
  434.      
  435.      
  436. int sort_files(data, num_data)
  437. listrec *data;
  438. int num_data;
  439. {
  440.      qsort((char *) data, num_data, sizeof(listrec), filecmp);
  441.  
  442.      return 0;
  443. }
  444.  
  445.  
  446.  
  447.  
  448.  
  449. int unique(the_files, number)
  450. listrec **the_files;
  451. int *number;
  452. {
  453.      int i, last;
  454.      int offset;
  455.      listrec *files;
  456.  
  457.      files = *the_files;
  458.      for (last = 0, i = 1; i < *number; i++) {
  459.       if (! strcmp(files[last].user_name, files[i].user_name)) {
  460.            int better;
  461.  
  462.            better = choose_better(files[last].real_name,
  463.                       files[i].real_name);
  464.            if (better == 1) { /* the first one is better */
  465.             free (files[i].real_name);
  466.             free (files[i].user_name);
  467.             files[i].real_name = (char *) NULL;
  468.            }
  469.            else {
  470.             free (files[last].real_name);
  471.             free (files[last].user_name);
  472.             files[last].real_name = (char *) NULL;
  473.             last = i;
  474.            }
  475.       }
  476.       else
  477.            last = i;
  478.      }
  479.      
  480.      for (offset = 0, i = 0; i + offset < *number; i++) {
  481.       if (! files[i].real_name)
  482.            offset++;
  483.       if (i + offset < *number)
  484.            files[i] = files[i + offset];
  485.      }
  486.      *number -= offset;
  487.      files = (listrec *) realloc((char *) files,
  488.                  (unsigned) (sizeof(listrec) * *number));
  489.      if (! files) {
  490.       set_error(errno);
  491.       error("realloc");
  492.       return errno;
  493.      }
  494.  
  495.      *the_files = files;
  496.      return 0;
  497. }
  498.  
  499.  
  500.  
  501.  
  502. choose_better(str1, str2)
  503. char *str1, *str2;
  504. {
  505.      char *pos1, *pos2;
  506.      
  507.      pos1 = strindex(str1, ".#");
  508.      pos2 = strindex(str2, ".#");
  509.      while (pos1 && pos2) {
  510.       if (pos1 - str1 < pos2 - str2)
  511.            return(2);
  512.       else if (pos2 - str2 < pos1 - str1)
  513.            return(1);
  514.       pos1 = strindex(pos1 + 1, ".#");
  515.       pos2 = strindex(pos2 + 1, ".#");
  516.      }
  517.      if (! pos1)
  518.       return(1);
  519.      else
  520.       return(2);
  521. }
  522.  
  523.  
  524.  
  525.  
  526.      
  527. unlink_completely(filename)
  528. char *filename;
  529. {
  530.      char buf[MAXPATHLEN];
  531.      struct stat stat_buf;
  532.      DIR *dirp;
  533.      struct direct *dp;
  534.      int retval;
  535.      int status = 0;
  536.      
  537.      if (lstat(filename, &stat_buf)) {
  538.       set_error(errno);
  539.       error(filename);
  540.       return error_code;
  541.      }
  542.  
  543.      if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  544.       dirp = Opendir(filename);
  545.       if (! dirp) {
  546.            set_error(errno);
  547.            error(filename);
  548.            return error_code;
  549.       }
  550.            
  551.       for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  552.            if (is_dotfile(dp->d_name))
  553.             continue;
  554.            (void) strcpy(buf, append(filename, dp->d_name));
  555.            if (retval = unlink_completely(buf)) {
  556.             error(buf);
  557.             status = retval;
  558.            }
  559.       }
  560.       closedir(dirp);
  561.       if (retval = rmdir(filename)) {
  562.            set_error(errno);
  563.            error(filename);
  564.            return error_code;
  565.       }
  566.      }
  567.      else if (retval = unlink(filename)) {
  568.       set_error(errno);
  569.       error(filename);
  570.       return error_code;
  571.      }
  572.  
  573.      return status;
  574. }
  575.  
  576.  
  577.  
  578.  
  579. int get_the_files(name, num_found, found)
  580. char *name;
  581. int *num_found;
  582. char ***found;
  583. {
  584.      int retval;
  585.      int options;
  586.      
  587.      options = FIND_DELETED;
  588.      if (recursive)
  589.       options |= RECURS_DELETED;
  590.      if (! directoriesonly)
  591.       options |= FIND_CONTENTS;
  592.  
  593.      retval = find_matches(name, num_found, found, options);
  594.      if (retval) {
  595.       error("find_matches");
  596.       return retval;
  597.      }
  598.  
  599.      return 0;
  600. }
  601.