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

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