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

Revision 1704, 10.0 KB checked in by jik, 35 years ago (diff)
Initial revision
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.1 1989-01-27 02:57:58 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 "directories.h"
32#include "util.h"
33#include "pattern.h"
34#include "expunge.h"
35
36extern char *malloc(), *realloc();
37
38char *whoami, *error_buf;
39
40int  time,              /* minimum mod time before undeletion */
41     interactive,       /* query before each expunge */
42     recursive,         /* expunge undeleted directories recursively */
43     noop,              /* print what would be done instead of doing it */
44     verbose,           /* print a line as each file is deleted */
45     force,             /* do not ask for any confirmation */
46     listfiles;         /* list files at toplevel */
47int del_recursive = 1;  /* this tells the pattern matcher that we want */
48                        /* it always to recurse on deleted */
49                        /* directories, even when recursive is set to */
50                        /* false. */
51
52
53int directoriesonly = 0;  /* we don't use this flag, but the */
54                          /* pattern-matching routines expect it to */
55                          /* exist, so we create it and set it to */
56                          /* false, which will cause the */
57                          /* pattern-matching routines to ignore it. */
58
59
60
61
62main(argc, argv)
63int argc;
64char *argv[];
65{
66     extern char *optarg;
67     extern int optind;
68     int arg;
69     int status = 0;
70
71     whoami = lastpart(argv[0]);
72     error_buf = malloc(strlen(whoami) + MAXPATHLEN + 3);
73     if (! error_buf) {
74          perror(whoami);
75          exit(1);
76     }
77     if (*whoami == 'p') { /* we're doing a purge */
78          exit (purge());
79     }
80     time = 0;
81     interactive = recursive = noop = verbose = listfiles = force = 0;
82     while ((arg = getopt(argc, argv, "t:irfnvl")) != -1) {
83          switch (arg) {
84          case 't':
85               time = 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          default:
106               usage();
107               exit(1);
108          }
109     }
110     if (optind == argc) {
111          char *dir;
112          dir = "";
113          status = status | expunge(&dir, 1); /* current working directory */
114     }
115     else
116          status = status | expunge(&argv[optind], argc - optind);
117     exit(status & ERROR_MASK);
118}
119
120
121
122
123
124purge()
125{
126     char *home[1];
127
128     home[0] = malloc(MAXPATHLEN);
129     if (! home[0]) {
130          perror(sprintf(error_buf, "%s: purge", whoami));
131          exit(1);
132     }
133     time = interactive = noop = verbose = force = 0;
134     listfiles = recursive = 1;
135     get_home(home[0]);
136     if (! *home[0]) {
137          fprintf(stderr, "%s: purge: can't get home directory\n", whoami);
138          exit(1);
139     }
140
141     printf("Please be patient.... this may take a while.\n\n");
142     
143     return(expunge(home, 1));
144}
145
146
147
148
149usage()
150{
151     printf("Usage: %s [ options ] [ filename [ ... ]]\n", whoami);
152     printf("Options are:\n");
153     printf("     -r     recursive\n");
154     printf("     -i     interactive\n");
155     printf("     -f     force\n");
156     printf("     -t n   n-day-or-older expunge\n");
157     printf("     -n     noop\n");
158     printf("     -v     verbose\n");
159     printf("     -l     list files before expunging\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               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          free(file_re);
195          total += num_found;
196          if (num_found)
197               process_files(found_files, num_found);
198          else if (! force) {
199               fprintf(stderr, "%s: %s cannot be expunged\n",
200                       whoami, files[num - 1]);
201               status |= ERROR_MASK;
202          }
203     }
204     if (total && listfiles) {
205          list_files();
206          if (! force) if (! top_level())
207               return(NO_DELETE_MASK);
208     }
209     current = next_specified_leaf(get_root_tree());
210     if (current)
211          status = status | do_expunge(current);
212     current = next_specified_leaf(get_cwd_tree());
213     if (current)
214          status = status | do_expunge(current);
215
216     return(status);
217}
218
219
220
221
222
223process_files(files, num)
224char **files;
225int num;
226{
227     int i;
228
229     for (i = 0; i < num; i++) {
230          if (! add_path_to_tree(files[i], FtUnknown)) {
231               fprintf(stderr, "%s: error adding path to filename tree\n",
232                       whoami);
233               exit(1);
234          }
235          else
236               free(files[i]);
237     }
238     free(files);
239     return(0);
240}
241
242
243
244
245do_expunge(file_ent)
246filerec *file_ent;
247{
248     int status = 0;
249     filerec *newent;
250
251     while(file_ent) {
252          if (file_ent->ftype == FtDirectory) {
253               status |= do_directory_expunge(file_ent);
254               newent = next_specified_directory(file_ent);
255          }
256          else {
257               status |= really_do_expunge(file_ent);
258               newent = next_specified_leaf(file_ent);
259          }
260          free_leaf(file_ent);
261          file_ent = newent;
262     }
263     return(status);
264}
265
266
267
268
269
270
271
272
273
274do_directory_expunge(file_ent)
275filerec *file_ent;
276{
277     filerec *new_ent;
278     int status = 0;
279     char buf[MAXPATHLEN];
280
281     get_leaf_path(file_ent, buf);
282     convert_to_user_name(buf, buf);
283     
284     if (! timed_out(file_ent))
285          return(NO_TIMEOUT_MASK);
286     if (interactive) {
287          printf("%s: Expunge directory %s? ", whoami, buf);
288          if (! yes())
289               return(NO_DELETE_MASK);
290     }
291         
292     new_ent = first_specified_in_directory(file_ent);
293     status |= do_expunge(new_ent);
294     status |= really_do_expunge(file_ent);
295     return(status);
296}
297
298
299
300
301
302
303
304
305really_do_expunge(file_ent)
306filerec *file_ent;
307{
308     char real[MAXPATHLEN], user[MAXPATHLEN];
309     int status;
310     
311     get_leaf_path(file_ent, real);
312     convert_to_user_name(real, user);
313
314     if (! timed_out(file_ent))
315          return(NO_TIMEOUT_MASK);
316     
317     if (interactive) {
318          printf ("%s: Expunge %s? ", whoami, user);
319          if (! yes())
320               return(NO_DELETE_MASK);
321     }
322
323     if (noop) {
324          printf("%s: %s would be expunged\n", whoami, user);
325          return(0);
326     }
327
328     if (file_ent->ftype == FtDirectory)
329          status = rmdir(real);
330     else
331          status = unlink(real);
332     if (! status) {
333          if (verbose)
334               printf("%s: %s expunged\n", whoami, user);
335          return(0);
336     }
337     else {
338          if (! force)
339               fprintf(stderr, "%s: %s not expunged\n", whoami, user);
340          return(ERROR_MASK);
341     }
342}
343
344
345
346
347
348
349
350
351
352timed_out(file_ent)
353filerec *file_ent;
354{
355     char buf[MAXPATHLEN];
356     struct stat stat_buf;
357     struct timeval tm;
358     long diff;
359
360     if (time == 0) /* catch the common default case to save time */
361          return (1);
362     
363     get_leaf_path(file_ent, buf);
364     if (lstat(buf, &stat_buf))
365          return(1);
366     gettimeofday(&tm, (struct timezone *) NULL);
367     diff = (tm.tv_sec - stat_buf.st_mtime) / 86400;
368     if (diff >= time)
369          return(1);
370     else
371          return(0);
372}
373
374
375
376
377
378top_level()
379{
380     if (interactive) {
381printf("The above files, which have been marked for deletion, are about to be\n");
382printf("expunged forever!  You will be asked for confirmation before each file is\n");
383printf("deleted.  Do you wish to continue? ");
384     }
385     else {
386printf("The above files, which have been marked for deletion, are about to be\n");
387printf("expunged forever!  Make sure you don't need any of them before continuing.\n");
388printf("Do you wish to continue? ");
389     }
390     return (yes());
391}
392
393list_files()
394{
395     filerec *current;
396     char buf[MAXPATHLEN];
397     
398     printf("The following deleted files are going to be expunged: \n\n");
399
400     current = get_root_tree();
401     while (current = next_specified_leaf(current)) {
402          get_leaf_path(current, buf);
403          convert_to_user_name(buf, buf);
404          printf("     %s\n", buf);
405     }
406     current = get_cwd_tree();
407     while (current = next_specified_leaf(current)) {
408          get_leaf_path(current, buf);
409          convert_to_user_name(buf, buf);
410          printf("     %s\n", buf);
411     }
412     printf("\n");
413     return(0);
414}
415     
416
417
418
419
420char **get_the_files(base, reg_exp, num_found)
421char *base, *reg_exp;
422int *num_found;
423{
424     char **matches;
425     int num_matches;
426     char **found;
427     int num;
428     int i;
429     
430     found = (char **) malloc(0);
431     num = 0;
432     
433     matches = find_matches(base, reg_exp, &num_matches);
434     if (recursive) {
435          char **recurs_found;
436          int recurs_num;
437         
438          for (i = 0; i < num_matches; free(matches[i]), i++) {
439               if (is_deleted(lastpart(matches[i]))) {
440                    found = add_str(found, num, matches[i]);
441                    num++;
442               }
443               recurs_found = find_deleted_recurses(matches[i], &recurs_num);
444               add_arrays(&found, &num, &recurs_found, &recurs_num);
445          }
446     } 
447     else {
448          struct stat stat_buf;
449          char **contents_found;
450          int num_contents;
451         
452          for (i = 0; i < num_matches; free(matches[i]), i++) {
453               if (is_deleted(lastpart(matches[i]))) {
454                    found = add_str(found, num, matches[i]);
455                    num++;
456               }
457               if (lstat(matches[i], &stat_buf))
458                    continue;
459               if (stat_buf.st_mode & S_IFDIR) {
460                    contents_found = find_deleted_contents_recurs(matches[i],
461                                                               &num_contents);
462                    add_arrays(&found, &num, &contents_found,
463                               &num_contents);
464               }
465          }
466     }
467     free(matches);
468     *num_found = num;
469     return(found);
470}
Note: See TracBrowser for help on using the repository browser.