home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / undel2 / part02 / undelete.c < prev    next >
C/C++ Source or Header  |  1990-06-07  |  13KB  |  593 lines

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