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

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