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

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