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

Revision 12144, 12.4 KB checked in by ghudson, 26 years ago (diff)
Source changes for autoconfiscation: AFS_MOUNTPOINTS -> HAVE_AFS, assume USE_BLOCKS, and fix qsort arguments.
Line 
1/*
2 * $Source: /afs/dev.mit.edu/source/repository/athena/bin/delete/undelete.c,v $
3 * $Author: ghudson $
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-copying.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.28 1998-11-16 16:42:34 ghudson Exp $";
15#endif
16
17#include <stdio.h>
18#include <sys/types.h>
19#include <dirent.h>
20#include <sys/param.h>
21#include <string.h>
22#include <com_err.h>
23#include <errno.h>
24#include "delete_errs.h"
25#include "pattern.h"
26#include "util.h"
27#include "directories.h"
28#include "undelete.h"
29#include "shell_regexp.h"
30#include "mit-copying.h"
31#include "errors.h"
32
33int interactive, recursive, verbose, directoriesonly, noop, force;
34
35
36main(argc, argv)
37int argc;
38char *argv[];
39{
40     extern char *optarg;
41     extern int optind;
42     int arg;
43     int retval;
44     
45     initialize_del_error_table();
46     
47     whoami = lastpart(argv[0]);
48     interactive = recursive = verbose = directoriesonly = noop = force = 0;
49
50     while ((arg = getopt(argc, argv, "firvnR")) != -1) {
51          switch (arg) {
52          case 'f':
53               force++;
54               break;
55          case 'i':
56               interactive++;
57               break;
58          case 'r':
59               recursive++;
60               if (directoriesonly) {
61                    fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
62                            whoami);
63                    usage();
64                    exit(1);
65               }
66               break;
67          case 'v':
68               verbose++;
69               break;
70          case 'n':
71               noop++;
72               break;
73          case 'R':
74               directoriesonly++;
75               if (recursive) {
76                    fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
77                            whoami);
78                    usage();
79                    exit(1);
80               }
81               break;
82          default:
83               usage();
84               exit(1);
85          }
86     }
87
88     report_errors = ! force;
89     
90     if (optind == argc) {
91          if (interactive_mode())
92               error("interactive_mode");
93     }
94     else while (optind < argc) {
95          retval = undelete(argv[optind]);
96          if (retval)
97               error(argv[optind]);
98          optind++;
99     }
100     exit(((! force) && error_occurred) ? 1 : 0);
101}
102
103
104
105interactive_mode()
106{
107     char buf[MAXPATHLEN];
108     char *ptr;
109     int status = 0;
110     int retval;
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 = strchr(buf, '\n');  /* fgets breakage */
124          if (ptr)
125               *ptr = '\0';
126          if (! *buf)
127               return status;
128          retval = undelete(buf);
129          if (retval) {
130               error(buf);
131               status = retval;
132          }
133     } while (*buf);
134     return status;
135}
136
137
138
139usage()
140{
141     fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
142     fprintf(stderr, "Options are:\n");
143     fprintf(stderr, "     -r     recursive\n");
144     fprintf(stderr, "     -i     interactive\n");
145     fprintf(stderr, "     -f     force\n");
146     fprintf(stderr, "     -v     verbose\n");
147     fprintf(stderr, "     -n     noop\n");
148     fprintf(stderr, "     -R     directories only (i.e. no recursion)\n");
149     fprintf(stderr, "     --     end options and start filenames\n");
150     fprintf(stderr, "-r and -D are mutually exclusive\n");
151}
152
153undelete(name)
154char *name;
155{
156     char **found_files;
157     int num_found;
158     int status = 0;
159     filerec *current;
160     int retval;
161     
162     if (retval =  get_the_files(name, &num_found, &found_files)) {
163          error(name);
164          return retval;
165     }
166     
167     if (num_found) {
168          if (retval = process_files(found_files, num_found)) {
169               error(name);
170               return retval;
171          }
172          if (*name == '/')
173               current = get_root_tree();
174          else
175               current = get_cwd_tree();
176
177          status = recurs_and_undelete(current);
178          if (status) {
179               error(name);
180               return status;
181          }
182     }
183     else {
184          if (no_wildcards(name)) {
185               set_error(ENOENT)
186          }
187          else
188               set_error(ENOMATCH);
189          error(name);
190          return error_code;
191     }
192
193     return status;
194}
195
196
197
198
199
200int recurs_and_undelete(leaf)
201filerec *leaf;
202{
203     int status = 0;
204     int retval;
205     
206     if (leaf->specified) {
207          retval = do_undelete(leaf);
208          if (retval) {
209               error("do_undelete");
210               status = retval;
211          }
212     }
213
214     if (! status) { /* recurse only if if top-level undelete */
215                     /* succeeded or was not requested        */
216          if (leaf->dirs) {
217               retval = recurs_and_undelete(leaf->dirs);
218               if (retval) {
219                    error("recurs_and_undelete");
220                    status = retval;
221               }
222          }
223
224          if (leaf->files) {
225               retval = recurs_and_undelete(leaf->files);
226               if (retval) {
227                    error("recurs_and_undelete");
228                    status = retval;
229               }
230          }
231     }
232
233     if (leaf->next) {
234          retval = recurs_and_undelete(leaf->next);
235          if (retval) {
236               error("recurs_and_undelete");
237               status = retval;
238          }
239     }
240
241     free_leaf(leaf);
242
243     return status;
244}
245
246
247
248
249
250
251int process_files(files, num)
252char **files;
253int num;
254{
255     int i;
256     listrec *filelist;
257     struct filrec *not_needed;
258     int retval;
259     
260     filelist = (listrec *) Malloc((unsigned) (sizeof(listrec) * num));
261     if ((! filelist) && num)
262     {
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(arg1, arg2)
421const void *arg1, *arg2;
422{
423     listrec *file1 = (listrec *) arg1, *file2 = (listrec *) arg2;
424
425     return(strcmp(file1->user_name, file2->user_name));
426}
427
428     
429     
430int sort_files(data, num_data)
431listrec *data;
432int num_data;
433{
434     qsort(data, num_data, sizeof(listrec), filecmp);
435
436     return 0;
437}
438
439
440
441
442
443int unique(the_files, number)
444listrec **the_files;
445int *number;
446{
447     int i, last;
448     int offset;
449     listrec *files;
450
451     files = *the_files;
452     for (last = 0, i = 1; i < *number; i++) {
453          if (! strcmp(files[last].user_name, files[i].user_name)) {
454               int better;
455
456               better = choose_better(files[last].real_name,
457                                      files[i].real_name);
458               if (better == 1) { /* the first one is better */
459                    free (files[i].real_name);
460                    free (files[i].user_name);
461                    files[i].real_name = (char *) NULL;
462               }
463               else {
464                    free (files[last].real_name);
465                    free (files[last].user_name);
466                    files[last].real_name = (char *) NULL;
467                    last = i;
468               }
469          }
470          else
471               last = i;
472     }
473     
474     for (offset = 0, i = 0; i + offset < *number; i++) {
475          if (! files[i].real_name)
476               offset++;
477          if (i + offset < *number)
478               files[i] = files[i + offset];
479     }
480     *number -= offset;
481     files = (listrec *) realloc((char *) files,
482                                 (unsigned) (sizeof(listrec) * *number));
483     if ((! files) && *number)
484     {
485          set_error(errno);
486          error("realloc");
487          return errno;
488     }
489
490     *the_files = files;
491     return 0;
492}
493
494
495
496
497choose_better(str1, str2)
498char *str1, *str2;
499{
500     char *pos1, *pos2;
501     
502     pos1 = strindex(str1, ".#");
503     pos2 = strindex(str2, ".#");
504     while (pos1 && pos2) {
505          if (pos1 - str1 < pos2 - str2)
506               return(2);
507          else if (pos2 - str2 < pos1 - str1)
508               return(1);
509          pos1 = strindex(pos1 + 1, ".#");
510          pos2 = strindex(pos2 + 1, ".#");
511     }
512     if (! pos1)
513          return(1);
514     else
515          return(2);
516}
517
518
519
520
521     
522unlink_completely(filename)
523char *filename;
524{
525     char buf[MAXPATHLEN];
526     struct stat stat_buf;
527     DIR *dirp;
528     struct dirent *dp;
529     int retval;
530     int status = 0;
531     
532     if (lstat(filename, &stat_buf)) {
533          set_error(errno);
534          error(filename);
535          return error_code;
536     }
537
538     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
539          dirp = Opendir(filename);
540          if (! dirp) {
541               set_error(errno);
542               error(filename);
543               return error_code;
544          }
545               
546          for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
547               if (is_dotfile(dp->d_name))
548                    continue;
549               (void) strcpy(buf, append(filename, dp->d_name));
550               if (retval = unlink_completely(buf)) {
551                    error(buf);
552                    status = retval;
553               }
554          }
555          closedir(dirp);
556          if (retval = rmdir(filename)) {
557               set_error(errno);
558               error(filename);
559               return error_code;
560          }
561     }
562     else if (retval = unlink(filename)) {
563          set_error(errno);
564          error(filename);
565          return error_code;
566     }
567
568     return status;
569}
570
571
572
573
574int get_the_files(name, num_found, found)
575char *name;
576int *num_found;
577char ***found;
578{
579     int retval;
580     int options;
581     
582     options = FIND_DELETED;
583     if (recursive)
584          options |= RECURS_DELETED;
585     if (! directoriesonly)
586          options |= FIND_CONTENTS;
587
588     retval = find_matches(name, num_found, found, options);
589     if (retval) {
590          error("find_matches");
591          return retval;
592     }
593
594     return 0;
595}
Note: See TracBrowser for help on using the repository browser.