home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume18 / undel / part04 / expunge.c next >
Encoding:
C/C++ Source or Header  |  1989-05-06  |  10.6 KB  |  473 lines

  1. /*
  2.  * $Source: /mit/jik/src/delete/RCS/expunge.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_expunge_c[] = "$Header: expunge.c,v 1.7 89/03/27 12:06:47 jik Exp $";
  15. #endif
  16.  
  17. /*
  18.  * Things that need to be fixed later:
  19.  *
  20.  * 1. The program should somehow store the sizes of deleted files and
  21.  * report the total amount of space regained after an expunge or purge.
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <sys/types.h>
  26. #include <sys/time.h>
  27. #include <sys/dir.h>
  28. #include <sys/param.h>
  29. #include <strings.h>
  30. #include <sys/stat.h>
  31. #include "col.h"
  32. #include "directories.h"
  33. #include "util.h"
  34. #include "pattern.h"
  35. #include "expunge.h"
  36. #include "mit-copyright.h"
  37.  
  38. extern char *malloc(), *realloc();
  39. extern int current_time;
  40.  
  41. char *whoami, *error_buf;
  42.  
  43. int  timev,        /* minimum mod time before undeletion */
  44.      interactive,    /* query before each expunge */
  45.      recursive,        /* expunge undeleted directories recursively */
  46.      noop,        /* print what would be done instead of doing it */
  47.      verbose,        /* print a line as each file is deleted */
  48.      force,        /* do not ask for any confirmation */
  49.      listfiles,        /* list files at toplevel */
  50.      yield;        /* print yield of expunge at end */
  51.  
  52. int blocks_removed = 0;
  53.  
  54.  
  55.  
  56.  
  57. main(argc, argv)
  58. int argc;
  59. char *argv[];
  60. {
  61.      extern char *optarg;
  62.      extern int optind;
  63.      int arg;
  64.      int status = 0;
  65.  
  66.      whoami = lastpart(argv[0]);
  67.      error_buf = malloc(strlen(whoami) + MAXPATHLEN + 3);
  68.      if (! error_buf) {
  69.       perror(whoami);
  70.       exit(1);
  71.      }
  72.      if (*whoami == 'p') { /* we're doing a purge */
  73.       exit (purge());
  74.      }
  75.      timev = 0;
  76.      yield = interactive = recursive = noop = verbose = listfiles = force = 0;
  77.      while ((arg = getopt(argc, argv, "t:irfnvly")) != -1) {
  78.       switch (arg) {
  79.       case 't':
  80.            timev = atoi(optarg);
  81.            break;
  82.       case 'i':
  83.            interactive++;
  84.            break;
  85.       case 'r':
  86.            recursive++;
  87.            break;
  88.       case 'f':
  89.            force++;
  90.            break;
  91.       case 'n':
  92.            noop++;
  93.            break;
  94.       case 'v':
  95.            verbose++;
  96.            break;
  97.       case 'l':
  98.            listfiles++;
  99.            break;
  100.       case 'y':
  101.            yield++;
  102.            break;
  103.       default:
  104.            usage();
  105.            exit(1);
  106.       }
  107.      }
  108.      if (optind == argc) {
  109.       char *dir;
  110.       dir = ".";
  111.       status = status | expunge(&dir, 1); /* current working directory */
  112.      }
  113.      else
  114.       status = status | expunge(&argv[optind], argc - optind);
  115.      exit(status & ERROR_MASK);
  116. }
  117.  
  118.  
  119.  
  120.  
  121.  
  122. purge()
  123. {
  124.      char *home[1];
  125.  
  126.      home[0] = malloc(MAXPATHLEN);
  127.      if (! home[0]) {
  128.       perror(sprintf(error_buf, "%s: purge", whoami));
  129.       exit(1);
  130.      }
  131.      timev = interactive = noop = verbose = force = 0;
  132.      yield = listfiles = recursive = 1;
  133.      get_home(home[0]);
  134.      if (! *home[0]) {
  135.       fprintf(stderr, "%s: purge: can't get home directory\n", whoami);
  136.       exit(1);
  137.      }
  138.  
  139.      printf("Please be patient.... this may take a while.\n\n");
  140.      
  141.      return(expunge(home, 1));
  142. }
  143.  
  144.  
  145.  
  146.  
  147. usage()
  148. {
  149.      printf("Usage: %s [ options ] [ filename [ ... ]]\n", whoami);
  150.      printf("Options are:\n");
  151.      printf("     -r     recursive\n");
  152.      printf("     -i     interactive\n");
  153.      printf("     -f     force\n");
  154.      printf("     -t n   n-day-or-older expunge\n");
  155.      printf("     -n     noop\n");
  156.      printf("     -v     verbose\n");
  157.      printf("     -l     list files before expunging\n");
  158.      printf("     -y     print yield of expunge\n");
  159.      printf("     --     end options and start filenames\n");
  160. }
  161.  
  162.  
  163.  
  164.  
  165.  
  166. expunge(files, num)
  167. char **files;
  168. int num;
  169. {
  170.      char *file_re;
  171.      char **found_files;
  172.      int num_found;
  173.      char *start_dir;
  174.      int status = 0;
  175.      int total = 0;
  176.      filerec *current;
  177.      
  178.      if (initialize_tree())
  179.       exit(1);
  180.  
  181.      for ( ; num ; num--) {
  182.       if (*files[num - 1] == '/') {
  183.            start_dir = "/";
  184.            file_re = parse_pattern(files[num - 1] + 1);
  185.       }
  186.       else {
  187.            start_dir = "";
  188.            file_re = parse_pattern(files[num - 1]);
  189.       }
  190.       if (! file_re)
  191.            return(ERROR_MASK);
  192.       
  193.       found_files = get_the_files(start_dir, file_re, &num_found);
  194.       if (num_found)
  195.            num_found = process_files(found_files, num_found);
  196.       total += num_found;
  197.       if (! num_found) if (! force) {
  198.            /*
  199.         * There are three different situations here.  Eiter we
  200.         * are dealing with an existing directory with no
  201.             * deleted files in it, or we are deleting with a
  202.             * non-existing deleted file with wildcards, or we are
  203.             * dealing with a non-existing deleted file without
  204.             * wildcards.  In the former case we print nothing, and
  205.             * in the latter cases we print either "no match" or
  206.             * "not found" respectively
  207.         */
  208.            if (no_wildcards(file_re)) {
  209.             if (! directory_exists(files[num - 1])) {
  210.              fprintf(stderr, "%s: %s: not found\n",
  211.                  whoami, files[num - 1]);
  212.             }
  213.            }
  214.            else {
  215.             fprintf(stderr, "%s: %s: no match\n", whoami,
  216.                 files[num - 1]);
  217.            }
  218.       }
  219.       free(file_re);
  220.      }
  221.      if (total && listfiles) {
  222.       list_files();
  223.       if (! force) if (! top_level())
  224.            return(NO_DELETE_MASK);
  225.      }
  226.      current = get_root_tree();
  227.      if (current)
  228.       status = status | expunge_specified(current);
  229.      current = get_cwd_tree();
  230.      if (current)
  231.       status = status | expunge_specified(current);
  232.  
  233.      if (yield) {
  234.       if (noop)
  235.            printf("Total that would be expunged: %dk\n",
  236.               blk_to_k(blocks_removed));
  237.       else
  238.            printf("Total expunged: %dk\n", blk_to_k(blocks_removed));
  239.      }
  240.      return(status);
  241. }
  242.  
  243.  
  244.  
  245. expunge_specified(leaf)
  246. filerec *leaf;
  247. {
  248.      int status = 0;
  249.  
  250.      if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR))
  251.       status = do_directory_expunge(leaf);
  252.      /* the "do_directory_expunge" really only asks the user if he */
  253.      /* wants to expunge the directory, it doesn't do any deleting. */
  254.      if (! status) {
  255.       if (leaf->dirs)
  256.            status |= expunge_specified(leaf->dirs);
  257.       if (leaf->files)
  258.            status |= expunge_specified(leaf->files);
  259.      }
  260.      if (leaf->specified)
  261.       status |= really_do_expunge(leaf);
  262.      if (leaf->next)
  263.       status |= expunge_specified(leaf->next);
  264.      free_leaf(leaf);
  265.      return(status);
  266. }
  267.  
  268.  
  269. process_files(files, num)
  270. char **files;
  271. int num;
  272. {
  273.      int i;
  274.      filerec *leaf;
  275.      
  276.      for (i = 0; i < num; i++) {
  277.       if (! (leaf = add_path_to_tree(files[i]))) {
  278.            fprintf(stderr, "%s: error adding path to filename tree\n",
  279.                whoami);
  280.            exit(1);
  281.       }
  282.  
  283.       free(files[i]);
  284.       if (! timed_out(leaf, current_time, timev)) {
  285.            free_leaf(leaf);
  286.            num--;
  287.       }
  288.      }
  289.      free(files);
  290.      return(num);
  291. }
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301. do_directory_expunge(file_ent)
  302. filerec *file_ent;
  303. {
  304.      char buf[MAXPATHLEN];
  305.  
  306.      get_leaf_path(file_ent, buf);
  307.      convert_to_user_name(buf, buf);
  308.      
  309.      if (interactive) {
  310.       printf("%s: Expunge directory %s? ", whoami, buf);
  311.       if (! yes())
  312.            return(NO_DELETE_MASK);
  313.      }
  314.      return(0);
  315. }
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324. really_do_expunge(file_ent)
  325. filerec *file_ent;
  326. {
  327.      char real[MAXPATHLEN], user[MAXPATHLEN];
  328.      int status;
  329.      
  330.      get_leaf_path(file_ent, real);
  331.      convert_to_user_name(real, user);
  332.  
  333.      if (interactive) {
  334.       printf ("%s: Expunge %s (%dk)? ", whoami, user,
  335.           blk_to_k(file_ent->specs.st_blocks));
  336.       if (! yes())
  337.            return(NO_DELETE_MASK);
  338.      }
  339.  
  340.      if (noop) {
  341.       blocks_removed += file_ent->specs.st_blocks;
  342.       printf("%s: %s (%dk) would be expunged (%dk total)\n", whoami, user,
  343.          blk_to_k(file_ent->specs.st_blocks),
  344.          blk_to_k(blocks_removed));
  345.       return(0);
  346.      }
  347.  
  348.      if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
  349.       status = rmdir(real);
  350.      else
  351.       status = unlink(real);
  352.      if (! status) {
  353.       blocks_removed += file_ent->specs.st_blocks;
  354.       if (verbose)
  355.            printf("%s: %s (%dk) expunged (%dk total)\n", whoami, user,
  356.               blk_to_k(file_ent->specs.st_blocks),
  357.               blk_to_k(blocks_removed));
  358.       return(0);
  359.      }
  360.      else {
  361.       if (! force)
  362.            fprintf(stderr, "%s: %s not expunged\n", whoami, user);
  363.       return(ERROR_MASK);
  364.      }
  365. }
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375. top_level()
  376. {
  377.      if (interactive) {
  378. printf("The above files, which have been marked for deletion, are about to be\n");
  379. printf("expunged forever!  You will be asked for confirmation before each file is\n");
  380. printf("deleted.  Do you wish to continue [return = no]? ");
  381.      }
  382.      else {
  383. printf("The above files, which have been marked for deletion, are about to be\n");
  384. printf("expunged forever!  Make sure you don't need any of them before continuing.\n");
  385. printf("Do you wish to continue [return = no]? ");
  386.      }
  387.      return (yes());
  388. }
  389.  
  390.  
  391.  
  392.  
  393.  
  394. list_files()
  395. {
  396.      filerec *current;
  397.      char **strings;
  398.      int num;
  399.      
  400.      strings = (char **) malloc(sizeof(char *));
  401.      num = 0;
  402.      if (! strings) {
  403.       if (! force)
  404.            perror(sprintf(error_buf, "%s: list_files", whoami));
  405.       exit(1);
  406.      }
  407.      printf("The following deleted files are going to be expunged: \n\n");
  408.  
  409.      current = get_root_tree();
  410.      strings = accumulate_names(current, strings, &num);
  411.      current = get_cwd_tree();
  412.      strings = accumulate_names(current, strings, &num);
  413.      column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0, 1, stdout);
  414.      printf("\n");
  415.      return(0);
  416. }
  417.      
  418.  
  419.  
  420.  
  421.  
  422. char **get_the_files(base, reg_exp, num_found)
  423. char *base, *reg_exp;
  424. int *num_found;
  425. {
  426.      char **matches;
  427.      int num_matches;
  428.      char **found;
  429.      int num;
  430.      int i;
  431.      
  432.      found = (char **) malloc(0);
  433.      num = 0;
  434.      
  435.      matches = find_matches(base, reg_exp, &num_matches);
  436.      if (recursive) {
  437.       char **recurs_found;
  438.       int recurs_num;
  439.       
  440.       for (i = 0; i < num_matches; free(matches[i]), i++) {
  441.            if (is_deleted(lastpart(matches[i]))) {
  442.             found = add_str(found, num, matches[i]);
  443.             num++;
  444.            }
  445.            recurs_found = find_deleted_recurses(matches[i], &recurs_num);
  446.            add_arrays(&found, &num, &recurs_found, &recurs_num);
  447.       }
  448.      }    
  449.      else {
  450.       struct stat stat_buf;
  451.       char **contents_found;
  452.       int num_contents;
  453.       
  454.       for (i = 0; i < num_matches; free(matches[i]), i++) {
  455.            if (is_deleted(lastpart(matches[i]))) {
  456.             found = add_str(found, num, matches[i]);
  457.             num++;
  458.            }
  459.            if (lstat(matches[i], &stat_buf))
  460.             continue;
  461.            if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  462.             contents_found = find_deleted_contents_recurs(matches[i],
  463.                                    &num_contents);
  464.             add_arrays(&found, &num, &contents_found,
  465.                    &num_contents);
  466.            }
  467.       }
  468.      }
  469.      free(matches);
  470.      *num_found = num;
  471.      return(found);
  472. }
  473.