source: trunk/athena/bin/delete/undelete.c @ 1811

Revision 1811, 11.9 KB checked in by jik, 35 years ago (diff)
added mit-copyright stuff
Line 
1/*
2 * $Source: /afs/dev.mit.edu/source/repository/athena/bin/delete/undelete.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_undelete_c[] = "$Header: /afs/dev.mit.edu/source/repository/athena/bin/delete/undelete.c,v 1.15 1989-03-27 12:08:08 jik Exp $";
15#endif
16
17#include <stdio.h>
18#include <sys/types.h>
19#include <sys/dir.h>
20#include <sys/param.h>
21#include <strings.h>
22#include <sys/stat.h>
23#include "directories.h"
24#include "pattern.h"
25#include "util.h"
26#include "undelete.h"
27#include "mit-copyright.h"
28
29#define ERROR_MASK 1
30#define NO_DELETE_MASK 2
31
32char *malloc(), *realloc();
33
34int interactive, recursive, verbose, directoriesonly, noop, force;
35int del_recursive = 0; /* this tells the pattern matcher that we do */
36                       /* *not* want it to recurse deleted directories */
37                       /* when recursive is set to false. */
38
39char *whoami, *error_buf;
40
41
42
43
44main(argc, argv)
45int argc;
46char *argv[];
47{
48     extern char *optarg;
49     extern int optind;
50     int arg;
51     int status = 0;
52     
53     whoami = lastpart(argv[0]);
54     interactive = recursive = verbose = directoriesonly = noop = force = 0;
55     error_buf = malloc(MAXPATHLEN + strlen(whoami));
56     if (! error_buf) {
57          perror(whoami);
58          exit(1);
59     }
60     while ((arg = getopt(argc, argv, "firvnR")) != -1) {
61          switch (arg) {
62          case 'f':
63               force++;
64               break;
65          case 'i':
66               interactive++;
67               break;
68          case 'r':
69               recursive++;
70               if (directoriesonly) {
71                    fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
72                            whoami);
73                    usage();
74                    exit(1);
75               }
76               break;
77          case 'v':
78               verbose++;
79               break;
80          case 'n':
81               noop++;
82               break;
83          case 'R':
84               directoriesonly++;
85               if (recursive) {
86                    fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
87                            whoami);
88                    usage();
89                    exit(1);
90               }
91          default:
92               usage();
93               exit(1);
94          }
95     }
96     if (optind == argc)
97          exit(interactive_mode());
98     else while (optind < argc) {
99          status = status | undelete(argv[optind]);
100          optind++;
101     }
102     exit(status & ERROR_MASK);
103}
104
105
106
107interactive_mode()
108{
109     char buf[MAXPATHLEN];
110     char *ptr;
111     int status = 0;
112
113     if (verbose) {
114          printf("Enter the files to be undeleted, one file per line.\n");
115          printf("Hit <RETURN> on a line by itself to exit.\n\n");
116     }
117     do {
118          printf("%s: ", whoami);
119          ptr = fgets(buf, MAXPATHLEN, stdin);
120          if (! ptr) {
121               printf("\n");
122               return(status);
123          }
124          ptr = index(buf, '\n');  /* fgets breakage */
125          if (ptr)
126               *ptr = '\0';
127          if (! *buf)
128               return(status);
129          status = status | undelete(buf);
130     } while (*ptr);
131     return(status);
132}
133
134
135
136usage()
137{
138     fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
139     fprintf(stderr, "Options are:\n");
140     fprintf(stderr, "     -r     recursive\n");
141     fprintf(stderr, "     -i     interactive\n");
142     fprintf(stderr, "     -f     force\n");
143     fprintf(stderr, "     -v     verbose\n");
144     fprintf(stderr, "     -n     noop\n");
145     fprintf(stderr, "     -R     directories only (i.e. no recursion)\n");
146     fprintf(stderr, "     --     end options and start filenames\n");
147     fprintf(stderr, "-r and -D are mutually exclusive\n");
148}
149
150
151undelete(file_exp)
152char *file_exp;
153{
154     char *file_re;
155     char **found_files;
156     int num_found;
157     char *startdir;
158     int status = 0;
159     filerec *current;
160     
161     if (*file_exp == '/') {
162          startdir = "/";
163          file_re = parse_pattern(file_exp + 1);
164     }
165     else {
166          startdir = "";
167          file_re = parse_pattern(file_exp);
168     }
169     if (! file_re)
170          return(ERROR_MASK);
171     found_files = get_the_files(startdir, file_re, &num_found);
172     free(file_re);
173     if (num_found) {
174          process_files(found_files, num_found);
175          if (*file_exp == '/')
176               current = get_root_tree();
177          else
178               current = get_cwd_tree();
179          status = recurs_and_undelete(current);
180     }
181     else {
182          if (! force)
183               fprintf(stderr, "%s: %s not found\n", whoami, file_exp);
184          status = ERROR_MASK;
185     }
186     return(status);
187}
188
189
190
191
192
193recurs_and_undelete(leaf)
194filerec *leaf;
195{
196     int status = 0;
197
198     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR))
199          status = do_directory_undelete(leaf);
200     /* the "do_directory_undelete" really only asks the user if he */
201     /* wants to expunge the directory, it doesn't do any deleting. */
202     if (! status) {
203          if (leaf->dirs)
204               status |= recurs_and_undelete(leaf->dirs);
205          if (leaf->files)
206               status |= recurs_and_undelete(leaf->files);
207     }
208     if (leaf->specified)
209          status |= do_undelete(leaf);
210     if (leaf->next)
211          status |= recurs_and_undelete(leaf->next);
212     free_leaf(leaf);
213     return(status);
214}
215
216
217
218
219
220
221do_directory_undelete(file_ent)
222filerec *file_ent;
223{
224     char buf[MAXPATHLEN];
225
226     get_leaf_path(file_ent, buf);
227     convert_to_user_name(buf, buf);
228     
229     if (interactive) {
230          printf("%s: Undelete directory %s? ", whoami, buf);
231          if (! yes())
232               return(NO_DELETE_MASK);
233     }
234     return(0);
235}
236
237
238
239
240
241process_files(files, num)
242char **files;
243int num;
244{
245     int i;
246     listrec *new_files;
247     listrec *filelist;
248
249     filelist = (listrec *) malloc(sizeof(listrec) * num);
250     if (! filelist) {
251          perror(sprintf(error_buf, "%s: process_files\n", whoami));
252          exit(1);
253     }
254     for (i = 0; i < num; i++) {
255          filelist[i].real_name = malloc(strlen(files[i]) + 1);
256          strcpy(filelist[i].real_name, files[i]);
257          filelist[i].user_name = malloc(strlen(files[i]) + 1);
258          convert_to_user_name(files[i], filelist[i].user_name);
259          free(files[i]);
260     }
261     free(files);
262     
263     new_files = sort_files(filelist, num);
264     new_files = unique(new_files, &num);
265     if (initialize_tree()) {
266          exit(1);
267     }
268     for (i = 0; i < num; i++) {
269          if (!add_path_to_tree(new_files[i].real_name)) {
270               fprintf(stderr, "%s: error adding path to filename tree\n",
271                       whoami);
272               exit(1);
273          }
274          else {
275               free(new_files[i].real_name);
276               free(new_files[i].user_name);
277          }
278     }
279     free(new_files);
280     return(0);
281}
282
283     
284
285
286
287
288
289     
290do_undelete(file_ent)
291filerec *file_ent;
292{
293     struct stat stat_buf;
294     char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
295
296     get_leaf_path(file_ent, real_name);
297     convert_to_user_name(real_name, user_name);
298
299     if (interactive) {
300          if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
301               printf("%s: Undelete directory %s? ", whoami, user_name);
302          else
303               printf("%s: Undelete %s? ", whoami, user_name);
304          if (! yes())
305               return(NO_DELETE_MASK);
306     }
307     if (! lstat(user_name, &stat_buf)) if (! force) {
308          printf("%s: An undeleted %s already exists.\n", whoami, user_name);
309          printf("Do you wish to continue with the undelete and overwrite that version? ");
310          if (! yes())
311               return(NO_DELETE_MASK);
312          unlink_completely(user_name);
313     }
314     if (noop) {
315          printf("%s: %s would be undeleted\n", whoami, user_name);
316          return(0);
317     }
318
319     if (! do_file_rename(real_name, user_name)) {
320          if (verbose)
321               printf("%s: %s undeleted\n", whoami, user_name);
322          return(0);
323     }
324     else {
325          if (! force)
326               fprintf(stderr, "%s: %s not undeleted\n", whoami, user_name);
327          return(ERROR_MASK);
328     }
329}
330
331
332
333
334do_file_rename(real_name, user_name)
335char *real_name, *user_name;
336{
337     char *ptr;
338     
339     char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
340     char buf[MAXPATHLEN];
341     
342     strcpy(old_name, real_name);
343     strcpy(new_name, real_name);
344
345     while (ptr = strrindex(new_name, ".#")) {
346          convert_to_user_name(ptr, ptr);
347          strcpy(ptr, firstpart(ptr, buf));
348          strcpy(&old_name[ptr - new_name],
349                 firstpart(&old_name[ptr - new_name], buf));
350          if (rename(old_name, new_name)) {
351               return(ERROR_MASK);
352          }
353          if (ptr > new_name) {
354               *--ptr = '\0';
355               old_name[ptr - new_name] = '\0';
356          }
357     }
358     change_path(real_name, user_name);
359     return(0);
360}
361
362
363
364
365
366
367filecmp(file1, file2)
368listrec *file1, *file2;
369{
370     return(strcmp(file1->user_name, file2->user_name));
371}
372
373     
374     
375listrec *sort_files(data, num_data)
376listrec *data;
377int num_data;
378{
379     qsort(data, num_data, sizeof(listrec), filecmp);
380     return(data);
381}
382
383
384
385
386
387listrec *unique(files, number)
388listrec *files;
389int *number;
390{
391     int i, last;
392     int offset;
393     
394     for (last = 0, i = 1; i < *number; i++) {
395          if (! strcmp(files[last].user_name, files[i].user_name)) {
396               int better;
397
398               better = choose_better(files[last].real_name,
399                                      files[i].real_name);
400               if (better == 1) { /* the first one is better */
401                    free (files[i].real_name);
402                    free (files[i].user_name);
403                    files[i].real_name = (char *) NULL;
404               }
405               else {
406                    free (files[last].real_name);
407                    free (files[last].user_name);
408                    files[last].real_name = (char *) NULL;
409                    last = i;
410               }
411          }
412          else
413               last = i;
414     }
415     
416     for (offset = 0, i = 0; i + offset < *number; i++) {
417          if (! files[i].real_name)
418               offset++;
419          if (i + offset < *number)
420               files[i] = files[i + offset];
421     }
422     *number -= offset;
423     files = (listrec *) realloc(files, sizeof(listrec) * *number);
424     if (! files) {
425          perror(sprintf(error_buf, "%s: unique", whoami));
426          exit(1);
427     }
428     return(files);
429}
430
431
432
433
434choose_better(str1, str2)
435char *str1, *str2;
436{
437     char *pos1, *pos2;
438     
439     pos1 = strindex(str1, ".#");
440     pos2 = strindex(str2, ".#");
441     while (pos1 && pos2) {
442          if (pos1 - str1 < pos2 - str2)
443               return(2);
444          else if (pos2 - str2 < pos1 - str1)
445               return(1);
446          pos1 = strindex(pos1 + 1, ".#");
447          pos2 = strindex(pos2 + 1, ".#");
448     }
449     if (! pos1)
450          return(1);
451     else
452          return(2);
453}
454
455
456
457
458     
459unlink_completely(filename)
460char *filename;
461{
462     char buf[MAXPATHLEN];
463     struct stat stat_buf;
464     DIR *dirp;
465     struct direct *dp;
466     int status = 0;
467     
468     if (lstat(filename, &stat_buf))
469          return(1);
470
471     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
472          dirp = opendir(filename);
473          if (! dirp)
474               return(1);
475          for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
476               if (is_dotfile(dp->d_name))
477                    continue;
478               strcpy(buf, append(filename, dp->d_name));
479               if (! buf) {
480                    status = 1;
481                    continue;
482               }
483               status = status | unlink_completely(buf);
484          }
485          closedir(dirp);
486     }
487     else
488          return(unlink(filename) == -1);
489     return(0);
490}
491
492
493
494
495char **get_the_files(base, reg_exp, num_found)
496char *base, *reg_exp;
497int *num_found;
498{
499     char **matches;
500     int num_matches;
501     char **found;
502     int num;
503     int i;
504     
505     found = (char **) malloc(0);
506     num = 0;
507     
508     matches = find_matches(base, reg_exp, &num_matches);
509     if (recursive) {
510          char **recurs_found;
511          int recurs_num;
512         
513          for (i = 0; i < num_matches; free(matches[i]), i++) {
514               if (is_deleted(lastpart(matches[i]))) {
515                    found = add_str(found, num, matches[i]);
516                    num++;
517               }
518               recurs_found = find_deleted_recurses(matches[i], &recurs_num);
519               add_arrays(&found, &num, &recurs_found, &recurs_num);
520          }
521     }
522     else {
523          struct stat stat_buf;
524          char **contents_found;
525          int num_contents;
526         
527          for (i = 0; i < num_matches; free(matches[i]), i++) {
528               if (is_deleted(lastpart(matches[i]))) {
529                    found = add_str(found, num, matches[i]);
530                    num++;
531               }
532               else if (! directoriesonly) {
533                    if (lstat(matches[i], &stat_buf))
534                         continue;
535                    if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
536                         contents_found = find_deleted_contents(matches[i],
537                                                                &num_contents);
538                         add_arrays(&found, &num, &contents_found,
539                                    &num_contents);
540                    }
541               }
542          }
543         
544     }
545     free(matches);
546     *num_found = num;
547     return(found);
548}
549
550                         
551                   
552         
553         
Note: See TracBrowser for help on using the repository browser.