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

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