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

Revision 2171, 13.9 KB checked in by jik, 35 years ago (diff)
changes to deal with the new error-handling.
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.16 1989-10-23 13:10:32 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 <com_err.h>
24#include <errno.h>
25#include "delete_errs.h"
26#include "directories.h"
27#include "pattern.h"
28#include "util.h"
29#include "undelete.h"
30#include "shell_regexp.h"
31#include "mit-copyright.h"
32#include "errors.h"
33
34extern char *malloc(), *realloc();
35extern int errno;
36
37int interactive, recursive, verbose, directoriesonly, noop, force;
38
39
40
41main(argc, argv)
42int argc;
43char *argv[];
44{
45     extern char *optarg;
46     extern int optind;
47     int arg;
48     int retval;
49     
50     initialize_del_error_table();
51     
52     whoami = lastpart(argv[0]);
53     interactive = recursive = verbose = directoriesonly = noop = force = 0;
54
55     while ((arg = getopt(argc, argv, "firvnR")) != -1) {
56          switch (arg) {
57          case 'f':
58               force++;
59               break;
60          case 'i':
61               interactive++;
62               break;
63          case 'r':
64               recursive++;
65               if (directoriesonly) {
66                    fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
67                            whoami);
68                    usage();
69                    exit(1);
70               }
71               break;
72          case 'v':
73               verbose++;
74               break;
75          case 'n':
76               noop++;
77               break;
78          case 'R':
79               directoriesonly++;
80               if (recursive) {
81                    fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
82                            whoami);
83                    usage();
84                    exit(1);
85               }
86               break;
87          default:
88               usage();
89               exit(1);
90          }
91     }
92
93     report_errors = ! force;
94     
95     if (optind == argc) {
96          if (interactive_mode())
97               error("interactive_mode");
98     }
99     else while (optind < argc) {
100          retval = undelete(argv[optind]);
101          if (retval)
102               error(argv[optind]);
103          optind++;
104     }
105     exit(((! force) && error_occurred) ? 1 : 0);
106}
107
108
109
110interactive_mode()
111{
112     char buf[MAXPATHLEN];
113     char *ptr;
114     int status = 0;
115     int retval;
116     
117     if (verbose) {
118          printf("Enter the files to be undeleted, one file per line.\n");
119          printf("Hit <RETURN> on a line by itself to exit.\n\n");
120     }
121     do {
122          printf("%s: ", whoami);
123          ptr = fgets(buf, MAXPATHLEN, stdin);
124          if (! ptr) {
125               printf("\n");
126               return status;
127          }
128          ptr = index(buf, '\n');  /* fgets breakage */
129          if (ptr)
130               *ptr = '\0';
131          if (! *buf)
132               return status;
133          retval = undelete(buf);
134          if (retval) {
135               error(buf);
136               status = retval;
137          }
138     } while (*buf);
139     return status;
140}
141
142
143
144usage()
145{
146     fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
147     fprintf(stderr, "Options are:\n");
148     fprintf(stderr, "     -r     recursive\n");
149     fprintf(stderr, "     -i     interactive\n");
150     fprintf(stderr, "     -f     force\n");
151     fprintf(stderr, "     -v     verbose\n");
152     fprintf(stderr, "     -n     noop\n");
153     fprintf(stderr, "     -R     directories only (i.e. no recursion)\n");
154     fprintf(stderr, "     --     end options and start filenames\n");
155     fprintf(stderr, "-r and -D are mutually exclusive\n");
156}
157
158undelete(file_exp)
159char *file_exp;
160{
161     char *file_re;
162     char **found_files;
163     int num_found;
164     char *startdir;
165     int status = 0;
166     filerec *current;
167     int retval;
168     
169     if (*file_exp == '/') {
170          startdir = "/";
171          file_re = file_exp + 1;
172     }
173     else {
174          startdir = "";
175          file_re = file_exp;
176     }
177
178     if (retval =  get_the_files(startdir, file_re, &num_found,
179                                 &found_files)) {
180          error(file_exp);
181          return retval;
182     }
183     
184     if (num_found) {
185          if (retval = process_files(found_files, num_found)) {
186               error(file_exp);
187               return retval;
188          }
189          if (*file_exp == '/')
190               current = get_root_tree();
191          else
192               current = get_cwd_tree();
193
194          status = recurs_and_undelete(current);
195          if (status) {
196               error(file_exp);
197               return status;
198          }
199     }
200     else {
201          if (no_wildcards(file_exp)) {
202               set_error(ENOENT)
203          }
204          else
205               set_error(ENOMATCH);
206          error(file_exp);
207          return error_code;
208     }
209
210     return status;
211}
212
213
214
215
216
217int recurs_and_undelete(leaf)
218filerec *leaf;
219{
220     int status = 0;
221     int retval;
222     
223     if (leaf->specified) {
224          retval = do_undelete(leaf);
225          if (retval) {
226               error("do_undelete");
227               return retval;
228          }
229     }
230
231     if (leaf->dirs) {
232          retval = recurs_and_undelete(leaf->dirs);
233          if (retval) {
234               error("recurs_and_undelete");
235               status = retval;
236          }
237     }
238
239     if (leaf->files) {
240          retval = recurs_and_undelete(leaf->files);
241          if (retval) {
242               error("recurs_and_undelete");
243               status = retval;
244          }
245     }
246     
247     if (leaf->next) {
248          retval = recurs_and_undelete(leaf->next);
249          if (retval) {
250               error("recurs_and_undelete");
251               status = retval;
252          }
253     }
254     
255     if (retval = free_leaf(leaf)) {
256          error("free_leaf");
257          status = retval;
258     }
259
260     return status;
261}
262
263
264
265
266
267
268int process_files(files, num)
269char **files;
270int num;
271{
272     int i;
273     listrec *filelist;
274     struct filrec *not_needed;
275     int retval;
276     
277     filelist = (listrec *) malloc((unsigned) (sizeof(listrec) * num));
278     if (! filelist) {
279          set_error(errno);
280          error("process_files");
281          return error_code;
282     }
283     
284     for (i = 0; i < num; i++) {
285          filelist[i].real_name = malloc((unsigned) (strlen(files[i]) + 1));
286          if (! filelist[i].real_name) {
287               set_error(errno);
288               error("process_files");
289               return error_code;
290          }
291          (void) strcpy(filelist[i].real_name, files[i]);
292          filelist[i].user_name = malloc((unsigned) (strlen(files[i]) + 1));
293          if (! filelist[i].user_name) {
294               set_error(errno);
295               error("process_files");
296               return error_code;
297          }
298          convert_to_user_name(files[i], filelist[i].user_name);
299          free(files[i]);
300     }
301     free((char *) files);
302         
303     if (retval = sort_files(filelist, num)) {
304          error("sort_files");
305          return retval;
306     }
307     if (retval = unique(&filelist, &num)) {
308          error("unique");
309          return retval;
310     }
311     if (retval = initialize_tree()) {
312          error("initialize_tree");
313          return retval;
314     }
315         
316     for (i = 0; i < num; i++) {
317          if (retval = add_path_to_tree(filelist[i].real_name, &not_needed)) {
318               error("add_path_to_tree");
319               return retval;
320          }
321          else {
322               free(filelist[i].real_name);
323               free(filelist[i].user_name);
324          }
325     }
326     free((char *) filelist);
327     return 0;
328}
329
330     
331
332
333
334
335
336     
337do_undelete(file_ent)
338filerec *file_ent;
339{
340     struct stat stat_buf;
341     char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
342     int retval;
343     
344     if (retval = get_leaf_path(file_ent, real_name)) {
345          if (! force)
346               fprintf(stderr, "%s: %s: %s\n", whoami, "get_leaf_path",
347                       error_message(retval));
348          return retval;
349     }
350     
351     convert_to_user_name(real_name, user_name);
352
353     if (interactive) {
354          if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
355               printf("%s: Undelete directory %s? ", whoami, user_name);
356          else
357               printf("%s: Undelete %s? ", whoami, user_name);
358          if (! yes()) {
359               set_status(UNDEL_NOT_UNDELETED);
360               return error_code;
361          }
362     }
363     if (! lstat(user_name, &stat_buf)) if (! force) {
364          printf("%s: An undeleted %s already exists.\n", whoami, user_name);
365          printf("Do you wish to continue with the undelete and overwrite that version? ");
366          if (! yes()) {
367               set_status(UNDEL_NOT_UNDELETED);
368               return error_code;
369          }
370          if (! noop) if (retval = unlink_completely(user_name)) {
371               error(user_name);
372               return retval;
373          }
374     }
375     if (noop) {
376          printf("%s: %s would be undeleted\n", whoami, user_name);
377          return 0;
378     }
379
380     if (retval = do_file_rename(real_name, user_name)) {
381          error("do_file_rename");
382          return retval;
383     }
384     else {
385          if (verbose)
386               printf("%s: %s undeleted\n", whoami, user_name);
387          return 0;
388     }
389}
390
391
392
393
394do_file_rename(real_name, user_name)
395char *real_name, *user_name;
396{
397     char *ptr;
398     int retval;
399     char error_buf[MAXPATHLEN+MAXPATHLEN+14];
400     char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
401     char buf[MAXPATHLEN];
402
403     (void) strcpy(old_name, real_name);
404     (void) strcpy(new_name, real_name);
405
406     while (ptr = strrindex(new_name, ".#")) {
407          convert_to_user_name(ptr, ptr);
408          (void) strcpy(ptr, firstpart(ptr, buf));
409          (void) strcpy(&old_name[ptr - new_name],
410                        firstpart(&old_name[ptr - new_name], buf));
411          if (rename(old_name, new_name)) {
412               set_error(errno);
413               (void) sprintf(error_buf, "renaming %s to %s",
414                              old_name, new_name);
415               error(error_buf);
416               return error_code;
417          }
418          if (ptr > new_name) {
419               *--ptr = '\0';
420               old_name[ptr - new_name] = '\0';
421          }
422     }
423     if (retval = change_path(real_name, user_name)) {
424          error("change_path");
425          return retval;
426     }
427     
428     return 0;
429}
430
431
432
433
434
435
436filecmp(file1, file2)
437listrec *file1, *file2;
438{
439     return(strcmp(file1->user_name, file2->user_name));
440}
441
442     
443     
444int sort_files(data, num_data)
445listrec *data;
446int num_data;
447{
448     qsort((char *) data, num_data, sizeof(listrec), filecmp);
449
450     return 0;
451}
452
453
454
455
456
457int unique(the_files, number)
458listrec **the_files;
459int *number;
460{
461     int i, last;
462     int offset;
463     listrec *files;
464
465     files = *the_files;
466     for (last = 0, i = 1; i < *number; i++) {
467          if (! strcmp(files[last].user_name, files[i].user_name)) {
468               int better;
469
470               better = choose_better(files[last].real_name,
471                                      files[i].real_name);
472               if (better == 1) { /* the first one is better */
473                    free (files[i].real_name);
474                    free (files[i].user_name);
475                    files[i].real_name = (char *) NULL;
476               }
477               else {
478                    free (files[last].real_name);
479                    free (files[last].user_name);
480                    files[last].real_name = (char *) NULL;
481                    last = i;
482               }
483          }
484          else
485               last = i;
486     }
487     
488     for (offset = 0, i = 0; i + offset < *number; i++) {
489          if (! files[i].real_name)
490               offset++;
491          if (i + offset < *number)
492               files[i] = files[i + offset];
493     }
494     *number -= offset;
495     files = (listrec *) realloc((char *) files,
496                                 (unsigned) (sizeof(listrec) * *number));
497     if (! files) {
498          set_error(errno);
499          error("realloc");
500          return errno;
501     }
502
503     *the_files = files;
504     return 0;
505}
506
507
508
509
510choose_better(str1, str2)
511char *str1, *str2;
512{
513     char *pos1, *pos2;
514     
515     pos1 = strindex(str1, ".#");
516     pos2 = strindex(str2, ".#");
517     while (pos1 && pos2) {
518          if (pos1 - str1 < pos2 - str2)
519               return(2);
520          else if (pos2 - str2 < pos1 - str1)
521               return(1);
522          pos1 = strindex(pos1 + 1, ".#");
523          pos2 = strindex(pos2 + 1, ".#");
524     }
525     if (! pos1)
526          return(1);
527     else
528          return(2);
529}
530
531
532
533
534     
535unlink_completely(filename)
536char *filename;
537{
538     char buf[MAXPATHLEN];
539     struct stat stat_buf;
540     DIR *dirp;
541     struct direct *dp;
542     int retval;
543     int status = 0;
544     
545     if (lstat(filename, &stat_buf)) {
546          set_error(errno);
547          error(filename);
548          return error_code;
549     }
550
551     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
552          dirp = opendir(filename);
553          if (! dirp) {
554               set_error(errno);
555               error(filename);
556               return error_code;
557          }
558               
559          for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
560               if (is_dotfile(dp->d_name))
561                    continue;
562               (void) strcpy(buf, append(filename, dp->d_name));
563               if (retval = unlink_completely(buf)) {
564                    error(buf);
565                    status = retval;
566               }
567          }
568          closedir(dirp);
569          if (retval = rmdir(filename)) {
570               set_error(errno);
571               error(filename);
572               return error_code;
573          }
574     }
575     else if (retval = unlink(filename)) {
576          set_error(errno);
577          error(filename);
578          return error_code;
579     }
580
581     return status;
582}
583
584
585
586
587int get_the_files(base, reg_exp, num_found, found)
588char *base, *reg_exp;
589int *num_found;
590char ***found;
591{
592     char **matches;
593     int num_matches;
594     int num;
595     int i;
596     int retval;
597     
598     *found = (char **) malloc(0);
599     num = 0;
600     
601     if (retval = find_matches(base, reg_exp, &num_matches, &matches)) {
602          error("find_matches");
603          return retval;
604     }
605     if (recursive) {
606          char **recurs_found;
607          int recurs_num;
608         
609          for (i = 0; i < num_matches; free(matches[i]), i++) {
610               if (is_deleted(lastpart(matches[i]))) {
611                    if (retval = add_str(found, num, matches[i])) {
612                         error("add_str");
613                         return retval;
614                    }
615                    num++;
616               }
617               if (retval = find_deleted_recurses(matches[i], &recurs_num,
618                                                  &recurs_found)) {
619                    error(matches[i]);
620                    return retval;
621               }
622               if (retval = add_arrays(found, &num, &recurs_found,
623                                       &recurs_num)) {
624                    error("add_arrays");
625                    return retval;
626               }
627          }
628     }
629     else {
630          struct stat stat_buf;
631          char **contents_found;
632          int num_contents;
633         
634          for (i = 0; i < num_matches; free(matches[i]), i++) {
635               if (is_deleted(lastpart(matches[i]))) {
636                    if (retval = add_str(found, num, matches[i])) {
637                         error("add_str");
638                         return retval;
639                    }
640                    num++;
641               }
642               else if (! directoriesonly) {
643                    if (lstat(matches[i], &stat_buf))
644                         continue;
645                    if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
646                         if (retval =
647                             find_deleted_contents(matches[i], &num_contents,
648                                                   &contents_found)) {
649                              error(matches[i]);
650                              return retval;
651                         }
652                         if (retval = add_arrays(found, &num, &contents_found,
653                                                 &num_contents)) {
654                              error("add_arrays");
655                              return retval;
656                         }
657                    }
658               }
659          }
660         
661     }
662     free((char *) matches);
663     *num_found = num;
664     return 0;
665}
Note: See TracBrowser for help on using the repository browser.