home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume18 / undel / part05 / undelete.c
C/C++ Source or Header  |  1989-05-06  |  12KB  |  554 lines

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