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

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