source: trunk/athena/bin/delete/expunge.c @ 24908

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