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

Revision 1850, 11.5 KB checked in by jik, 35 years ago (diff)
fixed some bugs with handling the current working directory; added a few comments.
Line 
1/*
2 * $Source: /afs/dev.mit.edu/source/repository/athena/bin/delete/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/dev.mit.edu/source/repository/athena/bin/delete/expunge.c,v 1.9 1989-05-04 14:10:54 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
38extern char *malloc(), *realloc();
39extern int current_time;
40
41char *whoami, *error_buf;
42
43int  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
52int blocks_removed = 0;
53
54
55
56
57main(argc, argv)
58int argc;
59char *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
122purge()
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
147usage()
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
166expunge(files, num)
167char **files;
168int 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               if ((*files[num - 1] == '.') && (! *(files[num - 1] + 1)))
189                    file_re = parse_pattern("*");
190               else
191                    file_re = parse_pattern(files[num - 1]);
192          }
193          if (! file_re)
194               return(ERROR_MASK);
195         
196          found_files = get_the_files(start_dir, file_re, &num_found);
197          if (num_found)
198               num_found = process_files(found_files, num_found);
199          total += num_found;
200          if (! num_found) if (! force) {
201               /*
202                * There are three different situations here.  Eiter we
203                * are dealing with an existing directory with no
204                * deleted files in it, or we are deleting with a
205                * non-existing deleted file with wildcards, or we are
206                * dealing with a non-existing deleted file without
207                * wildcards.  In the former case we print nothing, and
208                * in the latter cases we print either "no match" or
209                * "not found" respectively
210                */
211               if (no_wildcards(file_re)) {
212                    if (! directory_exists(files[num - 1])) {
213                         fprintf(stderr, "%s: %s: not found\n",
214                                 whoami, files[num - 1]);
215                    }
216               }
217               else {
218                    fprintf(stderr, "%s: %s: no match\n", whoami,
219                            files[num - 1]);
220               }
221          }
222          free(file_re);
223     }
224     if (total && listfiles) {
225          list_files();
226          if (! force) if (! top_level())
227               return(NO_DELETE_MASK);
228     }
229     current = get_root_tree();
230     if (current)
231          status = status | expunge_specified(current);
232     current = get_cwd_tree();
233     if (current)
234          status = status | expunge_specified(current);
235
236     if (yield) {
237          if (noop)
238               printf("Total that would be expunged: %dk\n",
239                      blk_to_k(blocks_removed));
240          else
241               printf("Total expunged: %dk\n", blk_to_k(blocks_removed));
242     }
243     return(status);
244}
245
246
247
248expunge_specified(leaf)
249filerec *leaf;
250{
251     int status = 0;
252
253     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR)) {
254          status = do_directory_expunge(leaf);
255          /* the "do_directory_expunge" really only asks the user if he */
256          /* wants to expunge the directory, it doesn't do any deleting. */
257     }
258     /* "But wait," you're saying to yourself as you ponder this code, */
259     /* "Why isn't this next if statement included inside the if       */
260     /* statement above, since they both refer to directories."  Well, */
261     /* I wondered about the same thing a week after I wrote the code. */
262     /* Keep in mind that a directory passed to this function may not  */
263     /* be specified, but some of its children may be.  Therefore, we  */
264     /* have to recursively descend even unspecified directories to    */
265     /* find specified files, hence this is outside of the if          */
266     /* statement above.                                               */
267     if (! status) {
268          if (leaf->dirs)
269               status |= expunge_specified(leaf->dirs);
270          if (leaf->files)
271               status |= expunge_specified(leaf->files);
272     }
273     if ((leaf->specified) && (! status))
274          status |= really_do_expunge(leaf);
275     if (leaf->next)
276          status |= expunge_specified(leaf->next);
277     free_leaf(leaf);
278     return(status);
279}
280
281
282process_files(files, num)
283char **files;
284int num;
285{
286     int i, skipped = 0;
287     filerec *leaf;
288     
289     for (i = 0; i < num; i++) {
290          if (! (leaf = add_path_to_tree(files[i]))) {
291               fprintf(stderr, "%s: error adding path to filename tree\n",
292                       whoami);
293               exit(1);
294          }
295
296          free(files[i]);
297          if (! timed_out(leaf, current_time, timev)) {
298               free_leaf(leaf);
299               skipped++;
300          }
301     }
302     free(files);
303     return(num-skipped);
304}
305
306
307
308
309
310
311
312
313
314do_directory_expunge(file_ent)
315filerec *file_ent;
316{
317     char buf[MAXPATHLEN];
318
319     get_leaf_path(file_ent, buf);
320     convert_to_user_name(buf, buf);
321     
322     if (interactive) {
323          printf("%s: Expunge directory %s? ", whoami, buf);
324          if (! yes())
325               return(NO_DELETE_MASK);
326     }
327     return(0);
328}
329
330
331
332
333
334
335
336
337really_do_expunge(file_ent)
338filerec *file_ent;
339{
340     char real[MAXPATHLEN], user[MAXPATHLEN];
341     int status;
342     
343     get_leaf_path(file_ent, real);
344     convert_to_user_name(real, user);
345
346     if (interactive) {
347          printf ("%s: Expunge %s (%dk)? ", whoami, user,
348                  blk_to_k(file_ent->specs.st_blocks));
349          if (! yes())
350               return(NO_DELETE_MASK);
351     }
352
353     if (noop) {
354          blocks_removed += file_ent->specs.st_blocks;
355          printf("%s: %s (%dk) would be 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
361     if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
362          status = rmdir(real);
363     else
364          status = unlink(real);
365     if (! status) {
366          blocks_removed += file_ent->specs.st_blocks;
367          if (verbose)
368               printf("%s: %s (%dk) expunged (%dk total)\n", whoami, user,
369                      blk_to_k(file_ent->specs.st_blocks),
370                      blk_to_k(blocks_removed));
371          return(0);
372     }
373     else {
374          if (! force)
375               fprintf(stderr, "%s: %s not expunged\n", whoami, user);
376          return(ERROR_MASK);
377     }
378}
379
380
381
382
383
384
385
386
387
388top_level()
389{
390     if (interactive) {
391printf("The above files, which have been marked for deletion, are about to be\n");
392printf("expunged forever!  You will be asked for confirmation before each file is\n");
393printf("deleted.  Do you wish to continue [return = no]? ");
394     }
395     else {
396printf("The above files, which have been marked for deletion, are about to be\n");
397printf("expunged forever!  Make sure you don't need any of them before continuing.\n");
398printf("Do you wish to continue [return = no]? ");
399     }
400     return (yes());
401}
402
403
404
405
406
407list_files()
408{
409     filerec *current;
410     char **strings;
411     int num;
412     
413     strings = (char **) malloc(sizeof(char *));
414     num = 0;
415     if (! strings) {
416          if (! force)
417               perror(sprintf(error_buf, "%s: list_files", whoami));
418          exit(1);
419     }
420     printf("The following deleted files are going to be expunged: \n\n");
421
422     current = get_root_tree();
423     strings = accumulate_names(current, strings, &num);
424     current = get_cwd_tree();
425     strings = accumulate_names(current, strings, &num);
426     column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0, 1, stdout);
427     printf("\n");
428     return(0);
429}
430     
431
432
433
434
435char **get_the_files(base, reg_exp, num_found)
436char *base, *reg_exp;
437int *num_found;
438{
439     char **matches;
440     int num_matches;
441     char **found;
442     int num;
443     int i;
444     
445     found = (char **) malloc(0);
446     num = 0;
447     
448     matches = find_matches(base, reg_exp, &num_matches);
449     if (recursive) {
450          char **recurs_found;
451          int recurs_num;
452         
453          for (i = 0; i < num_matches; free(matches[i]), i++) {
454               if (is_deleted(lastpart(matches[i]))) {
455                    found = add_str(found, num, matches[i]);
456                    num++;
457               }
458               recurs_found = find_deleted_recurses(matches[i], &recurs_num);
459               add_arrays(&found, &num, &recurs_found, &recurs_num);
460          }
461     } 
462     else {
463          struct stat stat_buf;
464          char **contents_found;
465          int num_contents;
466         
467          for (i = 0; i < num_matches; free(matches[i]), i++) {
468               if (is_deleted(lastpart(matches[i]))) {
469                    found = add_str(found, num, matches[i]);
470                    num++;
471               }
472               if (lstat(matches[i], &stat_buf))
473                    continue;
474               if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
475                    contents_found = find_deleted_contents_recurs(matches[i],
476                                                               &num_contents);
477                    add_arrays(&found, &num, &contents_found,
478                               &num_contents);
479               }
480          }
481     }
482     free(matches);
483     *num_found = num;
484     return(found);
485}
Note: See TracBrowser for help on using the repository browser.