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

Revision 1732, 11.9 KB checked in by jik, 35 years ago (diff)
*** empty log message ***
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.14 1989-02-01 03:42:21 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          status = recurs_and_undelete(current);
179     }
180     else {
181          if (! force)
182               fprintf(stderr, "%s: %s not found\n", whoami, file_exp);
183          status = ERROR_MASK;
184     }
185     return(status);
186}
187
188
189
190
191
192recurs_and_undelete(leaf)
193filerec *leaf;
194{
195     int status = 0;
196
197     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR))
198          status = do_directory_undelete(leaf);
199     /* the "do_directory_undelete" really only asks the user if he */
200     /* wants to expunge the directory, it doesn't do any deleting. */
201     if (! status) {
202          if (leaf->dirs)
203               status |= recurs_and_undelete(leaf->dirs);
204          if (leaf->files)
205               status |= recurs_and_undelete(leaf->files);
206     }
207     if (leaf->specified)
208          status |= do_undelete(leaf);
209     if (leaf->next)
210          status |= recurs_and_undelete(leaf->next);
211     free_leaf(leaf);
212     return(status);
213}
214
215
216
217
218
219
220do_directory_undelete(file_ent)
221filerec *file_ent;
222{
223     char buf[MAXPATHLEN];
224
225     get_leaf_path(file_ent, buf);
226     convert_to_user_name(buf, buf);
227     
228     if (interactive) {
229          printf("%s: Undelete directory %s? ", whoami, buf);
230          if (! yes())
231               return(NO_DELETE_MASK);
232     }
233     return(0);
234}
235
236
237
238
239
240process_files(files, num)
241char **files;
242int num;
243{
244     int i;
245     listrec *new_files;
246     listrec *filelist;
247
248     filelist = (listrec *) malloc(sizeof(listrec) * num);
249     if (! filelist) {
250          perror(sprintf(error_buf, "%s: process_files\n", whoami));
251          exit(1);
252     }
253     for (i = 0; i < num; i++) {
254          filelist[i].real_name = malloc(strlen(files[i]) + 1);
255          strcpy(filelist[i].real_name, files[i]);
256          filelist[i].user_name = malloc(strlen(files[i]) + 1);
257          convert_to_user_name(files[i], filelist[i].user_name);
258          free(files[i]);
259     }
260     free(files);
261     
262     new_files = sort_files(filelist, num);
263     new_files = unique(new_files, &num);
264     if (initialize_tree()) {
265          exit(1);
266     }
267     for (i = 0; i < num; i++) {
268          if (!add_path_to_tree(new_files[i].real_name)) {
269               fprintf(stderr, "%s: error adding path to filename tree\n",
270                       whoami);
271               exit(1);
272          }
273          else {
274               free(new_files[i].real_name);
275               free(new_files[i].user_name);
276          }
277     }
278     free(new_files);
279     return(0);
280}
281
282     
283
284
285
286
287
288     
289do_undelete(file_ent)
290filerec *file_ent;
291{
292     struct stat stat_buf;
293     char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
294
295     get_leaf_path(file_ent, real_name);
296     convert_to_user_name(real_name, user_name);
297
298     if (interactive) {
299          if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
300               printf("%s: Undelete directory %s? ", whoami, user_name);
301          else
302               printf("%s: Undelete %s? ", whoami, user_name);
303          if (! yes())
304               return(NO_DELETE_MASK);
305     }
306     if (! lstat(user_name, &stat_buf)) if (! force) {
307          printf("%s: An undeleted %s already exists.\n", whoami, user_name);
308          printf("Do you wish to continue with the undelete and overwrite that version? ");
309          if (! yes())
310               return(NO_DELETE_MASK);
311          unlink_completely(user_name);
312     }
313     if (noop) {
314          printf("%s: %s would be undeleted\n", whoami, user_name);
315          return(0);
316     }
317
318     if (! do_file_rename(real_name, user_name)) {
319          if (verbose)
320               printf("%s: %s undeleted\n", whoami, user_name);
321          return(0);
322     }
323     else {
324          if (! force)
325               fprintf(stderr, "%s: %s not undeleted\n", whoami, user_name);
326          return(ERROR_MASK);
327     }
328}
329
330
331
332
333do_file_rename(real_name, user_name)
334char *real_name, *user_name;
335{
336     char *ptr;
337     
338     char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
339     char buf[MAXPATHLEN];
340     
341     strcpy(old_name, real_name);
342     strcpy(new_name, real_name);
343
344     while (ptr = strrindex(new_name, ".#")) {
345          convert_to_user_name(ptr, ptr);
346          strcpy(ptr, firstpart(ptr, buf));
347          strcpy(&old_name[ptr - new_name],
348                 firstpart(&old_name[ptr - new_name], buf));
349          if (rename(old_name, new_name)) {
350               return(ERROR_MASK);
351          }
352          if (ptr > new_name) {
353               *--ptr = '\0';
354               old_name[ptr - new_name] = '\0';
355          }
356     }
357     change_path(real_name, user_name);
358     return(0);
359}
360
361
362
363
364
365
366filecmp(file1, file2)
367listrec *file1, *file2;
368{
369     return(strcmp(file1->user_name, file2->user_name));
370}
371
372     
373     
374listrec *sort_files(data, num_data)
375listrec *data;
376int num_data;
377{
378     qsort(data, num_data, sizeof(listrec), filecmp);
379     return(data);
380}
381
382
383
384
385
386listrec *unique(files, number)
387listrec *files;
388int *number;
389{
390     int i, last;
391     int offset;
392     
393     for (last = 0, i = 1; i < *number; i++) {
394          if (! strcmp(files[last].user_name, files[i].user_name)) {
395               int better;
396
397               better = choose_better(files[last].real_name,
398                                      files[i].real_name);
399               if (better == 1) { /* the first one is better */
400                    free (files[i].real_name);
401                    free (files[i].user_name);
402                    files[i].real_name = (char *) NULL;
403               }
404               else {
405                    free (files[last].real_name);
406                    free (files[last].user_name);
407                    files[last].real_name = (char *) NULL;
408                    last = i;
409               }
410          }
411          else
412               last = i;
413     }
414     
415     for (offset = 0, i = 0; i + offset < *number; i++) {
416          if (! files[i].real_name)
417               offset++;
418          if (i + offset < *number)
419               files[i] = files[i + offset];
420     }
421     *number -= offset;
422     files = (listrec *) realloc(files, sizeof(listrec) * *number);
423     if (! files) {
424          perror(sprintf(error_buf, "%s: unique", whoami));
425          exit(1);
426     }
427     return(files);
428}
429
430
431
432
433choose_better(str1, str2)
434char *str1, *str2;
435{
436     char *pos1, *pos2;
437     
438     pos1 = strindex(str1, ".#");
439     pos2 = strindex(str2, ".#");
440     while (pos1 && pos2) {
441          if (pos1 - str1 < pos2 - str2)
442               return(2);
443          else if (pos2 - str2 < pos1 - str1)
444               return(1);
445          pos1 = strindex(pos1 + 1, ".#");
446          pos2 = strindex(pos2 + 1, ".#");
447     }
448     if (! pos1)
449          return(1);
450     else
451          return(2);
452}
453
454
455
456
457     
458unlink_completely(filename)
459char *filename;
460{
461     char buf[MAXPATHLEN];
462     struct stat stat_buf;
463     DIR *dirp;
464     struct direct *dp;
465     int status = 0;
466     
467     if (lstat(filename, &stat_buf))
468          return(1);
469
470     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
471          dirp = opendir(filename);
472          if (! dirp)
473               return(1);
474          for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
475               if (is_dotfile(dp->d_name))
476                    continue;
477               strcpy(buf, append(filename, dp->d_name));
478               if (! buf) {
479                    status = 1;
480                    continue;
481               }
482               status = status | unlink_completely(buf);
483          }
484          closedir(dirp);
485     }
486     else
487          return(unlink(filename) == -1);
488     return(0);
489}
490
491
492
493
494char **get_the_files(base, reg_exp, num_found)
495char *base, *reg_exp;
496int *num_found;
497{
498     char **matches;
499     int num_matches;
500     char **found;
501     int num;
502     int i;
503     
504     found = (char **) malloc(0);
505     num = 0;
506     
507     matches = find_matches(base, reg_exp, &num_matches);
508     if (recursive) {
509          char **recurs_found;
510          int recurs_num;
511         
512          for (i = 0; i < num_matches; free(matches[i]), i++) {
513               if (is_deleted(lastpart(matches[i]))) {
514                    found = add_str(found, num, matches[i]);
515                    num++;
516               }
517               recurs_found = find_deleted_recurses(matches[i], &recurs_num);
518               add_arrays(&found, &num, &recurs_found, &recurs_num);
519          }
520     }
521     else {
522          struct stat stat_buf;
523          char **contents_found;
524          int num_contents;
525         
526          for (i = 0; i < num_matches; free(matches[i]), i++) {
527               if (is_deleted(lastpart(matches[i]))) {
528                    found = add_str(found, num, matches[i]);
529                    num++;
530               }
531               else if (! directoriesonly) {
532                    if (lstat(matches[i], &stat_buf))
533                         continue;
534                    if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
535                         contents_found = find_deleted_contents(matches[i],
536                                                                &num_contents);
537                         add_arrays(&found, &num, &contents_found,
538                                    &num_contents);
539                    }
540               }
541          }
542         
543     }
544     free(matches);
545     *num_found = num;
546     return(found);
547}
548
549                         
550                   
551         
552         
Note: See TracBrowser for help on using the repository browser.