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.
RevLine 
[1671]1/*
2 * $Source: /afs/dev.mit.edu/source/repository/athena/bin/delete/undelete.c,v $
[11165]3 * $Author: ghudson $
[1671]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.
[4505]10 * For copying and distribution information, see the file "mit-copying.h."
[1671]11 */
12
13#if (!defined(lint) && !defined(SABER))
[12144]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 $";
[1671]15#endif
16
[1656]17#include <stdio.h>
18#include <sys/types.h>
[5050]19#include <dirent.h>
[1656]20#include <sys/param.h>
[3049]21#include <string.h>
[2171]22#include <com_err.h>
23#include <errno.h>
24#include "delete_errs.h"
[1690]25#include "pattern.h"
26#include "util.h"
[4415]27#include "directories.h"
[1690]28#include "undelete.h"
[2171]29#include "shell_regexp.h"
[4505]30#include "mit-copying.h"
[2171]31#include "errors.h"
[1656]32
[1690]33int interactive, recursive, verbose, directoriesonly, noop, force;
[1705]34
[1684]35
[1656]36main(argc, argv)
37int argc;
38char *argv[];
39{
[1671]40     extern char *optarg;
41     extern int optind;
42     int arg;
[2171]43     int retval;
[1671]44     
[2171]45     initialize_del_error_table();
46     
[1656]47     whoami = lastpart(argv[0]);
[1674]48     interactive = recursive = verbose = directoriesonly = noop = force = 0;
[2171]49
[1674]50     while ((arg = getopt(argc, argv, "firvnR")) != -1) {
[1671]51          switch (arg) {
[1674]52          case 'f':
53               force++;
54               break;
[1671]55          case 'i':
56               interactive++;
57               break;
58          case 'r':
59               recursive++;
60               if (directoriesonly) {
[1674]61                    fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
[1671]62                            whoami);
63                    usage();
64                    exit(1);
65               }
66               break;
67          case 'v':
68               verbose++;
69               break;
70          case 'n':
71               noop++;
72               break;
[1674]73          case 'R':
[1671]74               directoriesonly++;
75               if (recursive) {
[1674]76                    fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
[1671]77                            whoami);
78                    usage();
79                    exit(1);
80               }
[2171]81               break;
[1696]82          default:
83               usage();
84               exit(1);
[1671]85          }
86     }
[2171]87
88     report_errors = ! force;
89     
90     if (optind == argc) {
91          if (interactive_mode())
92               error("interactive_mode");
93     }
[1671]94     else while (optind < argc) {
[2171]95          retval = undelete(argv[optind]);
96          if (retval)
97               error(argv[optind]);
[1671]98          optind++;
99     }
[2171]100     exit(((! force) && error_occurred) ? 1 : 0);
[1671]101}
[1656]102
[1671]103
104
105interactive_mode()
106{
[1686]107     char buf[MAXPATHLEN];
108     char *ptr;
109     int status = 0;
[2171]110     int retval;
111     
[1686]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");
[2171]121               return status;
[1686]122          }
[10977]123          ptr = strchr(buf, '\n');  /* fgets breakage */
[1686]124          if (ptr)
125               *ptr = '\0';
126          if (! *buf)
[2171]127               return status;
128          retval = undelete(buf);
129          if (retval) {
130               error(buf);
131               status = retval;
132          }
133     } while (*buf);
134     return status;
[1656]135}
136
137
138
[1671]139usage()
140{
[1684]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");
[1671]151}
[1656]152
[2221]153undelete(name)
154char *name;
[1671]155{
[1684]156     char **found_files;
157     int num_found;
158     int status = 0;
[1680]159     filerec *current;
[2171]160     int retval;
[1674]161     
[2221]162     if (retval =  get_the_files(name, &num_found, &found_files)) {
163          error(name);
[2171]164          return retval;
165     }
166     
[1674]167     if (num_found) {
[2171]168          if (retval = process_files(found_files, num_found)) {
[2221]169               error(name);
[2171]170               return retval;
171          }
[2221]172          if (*name == '/')
[1684]173               current = get_root_tree();
174          else
175               current = get_cwd_tree();
[2171]176
[1732]177          status = recurs_and_undelete(current);
[2171]178          if (status) {
[2221]179               error(name);
[2171]180               return status;
181          }
[1674]182     }
[1676]183     else {
[2221]184          if (no_wildcards(name)) {
[2171]185               set_error(ENOENT)
186          }
187          else
188               set_error(ENOMATCH);
[2221]189          error(name);
[2171]190          return error_code;
[1676]191     }
[2171]192
193     return status;
[1671]194}
195
[1674]196
197
[1680]198
[1732]199
[2171]200int recurs_and_undelete(leaf)
[1732]201filerec *leaf;
202{
203     int status = 0;
[2171]204     int retval;
205     
206     if (leaf->specified) {
207          retval = do_undelete(leaf);
208          if (retval) {
209               error("do_undelete");
[4032]210               status = retval;
[2171]211          }
212     }
[1732]213
[4032]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               }
[2171]222          }
[1732]223
[4032]224          if (leaf->files) {
225               retval = recurs_and_undelete(leaf->files);
226               if (retval) {
227                    error("recurs_and_undelete");
228                    status = retval;
229               }
[2171]230          }
231     }
[4032]232
[2171]233     if (leaf->next) {
234          retval = recurs_and_undelete(leaf->next);
235          if (retval) {
236               error("recurs_and_undelete");
237               status = retval;
238          }
[1732]239     }
[4032]240
[2221]241     free_leaf(leaf);
[2171]242
243     return status;
[1732]244}
245
246
247
248
249
[2171]250
251int process_files(files, num)
[1684]252char **files;
[1698]253int num;
[1674]254{
[1680]255     int i;
[1684]256     listrec *filelist;
[2171]257     struct filrec *not_needed;
258     int retval;
259     
[2363]260     filelist = (listrec *) Malloc((unsigned) (sizeof(listrec) * num));
[5050]261     if ((! filelist) && num)
262     {
[2171]263          set_error(errno);
264          error("process_files");
265          return error_code;
[1680]266     }
[2171]267     
[1698]268     for (i = 0; i < num; i++) {
[2363]269          filelist[i].real_name = Malloc((unsigned) (strlen(files[i]) + 1));
[2171]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]);
[2363]276          filelist[i].user_name = Malloc((unsigned) (strlen(files[i]) + 1));
[2171]277          if (! filelist[i].user_name) {
278               set_error(errno);
279               error("process_files");
280               return error_code;
281          }
[2221]282          (void) convert_to_user_name(files[i], filelist[i].user_name);
[1684]283          free(files[i]);
[1680]284     }
[2171]285     free((char *) files);
286         
287     if (retval = sort_files(filelist, num)) {
288          error("sort_files");
289          return retval;
[1680]290     }
[2171]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         
[1698]300     for (i = 0; i < num; i++) {
[2171]301          if (retval = add_path_to_tree(filelist[i].real_name, &not_needed)) {
302               error("add_path_to_tree");
303               return retval;
[1684]304          }
305          else {
[2171]306               free(filelist[i].real_name);
307               free(filelist[i].user_name);
[1684]308          }
309     }
[2171]310     free((char *) filelist);
311     return 0;
[1680]312}
[1674]313
[1680]314     
[1674]315
[1680]316
[1674]317
318
319
320     
[1732]321do_undelete(file_ent)
[1680]322filerec *file_ent;
[1674]323{
324     struct stat stat_buf;
[1684]325     char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
[2171]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     
[2221]335     (void) convert_to_user_name(real_name, user_name);
[1684]336
[1676]337     if (interactive) {
[1732]338          if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
[1684]339               printf("%s: Undelete directory %s? ", whoami, user_name);
340          else
341               printf("%s: Undelete %s? ", whoami, user_name);
[2171]342          if (! yes()) {
343               set_status(UNDEL_NOT_UNDELETED);
344               return error_code;
345          }
[1676]346     }
[1680]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? ");
[2171]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          }
[1674]358     }
359     if (noop) {
[1684]360          printf("%s: %s would be undeleted\n", whoami, user_name);
[2171]361          return 0;
[1674]362     }
363
[2171]364     if (retval = do_file_rename(real_name, user_name)) {
365          error("do_file_rename");
366          return retval;
367     }
368     else {
[1674]369          if (verbose)
[1680]370               printf("%s: %s undeleted\n", whoami, user_name);
[2171]371          return 0;
[1674]372     }
373}
374
375
376
377
[1684]378do_file_rename(real_name, user_name)
[1680]379char *real_name, *user_name;
[1674]380{
[1680]381     char *ptr;
[2171]382     int retval;
383     char error_buf[MAXPATHLEN+MAXPATHLEN+14];
[1680]384     char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
385     char buf[MAXPATHLEN];
[1674]386
[2171]387     (void) strcpy(old_name, real_name);
388     (void) strcpy(new_name, real_name);
389
[1680]390     while (ptr = strrindex(new_name, ".#")) {
[2221]391          (void) convert_to_user_name(ptr, ptr);
[2171]392          (void) strcpy(ptr, firstpart(ptr, buf));
393          (void) strcpy(&old_name[ptr - new_name],
394                        firstpart(&old_name[ptr - new_name], buf));
[1684]395          if (rename(old_name, new_name)) {
[2171]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;
[1684]401          }
[1680]402          if (ptr > new_name) {
403               *--ptr = '\0';
404               old_name[ptr - new_name] = '\0';
[1674]405          }
406     }
[2171]407     if (retval = change_path(real_name, user_name)) {
408          error("change_path");
409          return retval;
410     }
411     
412     return 0;
[1674]413}
414
415
416
[1680]417
418
419
[12144]420filecmp(arg1, arg2)
421const void *arg1, *arg2;
[1656]422{
[12144]423     listrec *file1 = (listrec *) arg1, *file2 = (listrec *) arg2;
424
[1684]425     return(strcmp(file1->user_name, file2->user_name));
[1656]426}
427
[1680]428     
429     
[2171]430int sort_files(data, num_data)
[1684]431listrec *data;
[1656]432int num_data;
433{
[12144]434     qsort(data, num_data, sizeof(listrec), filecmp);
[2171]435
436     return 0;
[1656]437}
438
439
440
441
442
[2171]443int unique(the_files, number)
444listrec **the_files;
[1671]445int *number;
446{
[1680]447     int i, last;
[1684]448     int offset;
[2171]449     listrec *files;
450
451     files = *the_files;
[1671]452     for (last = 0, i = 1; i < *number; i++) {
[1684]453          if (! strcmp(files[last].user_name, files[i].user_name)) {
[1671]454               int better;
[1680]455
[1684]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               }
[1671]463               else {
[1684]464                    free (files[last].real_name);
465                    free (files[last].user_name);
466                    files[last].real_name = (char *) NULL;
[1671]467                    last = i;
468               }
469          }
[1684]470          else
[1671]471               last = i;
472     }
[1680]473     
[1671]474     for (offset = 0, i = 0; i + offset < *number; i++) {
[1684]475          if (! files[i].real_name)
[1671]476               offset++;
477          if (i + offset < *number)
478               files[i] = files[i + offset];
479     }
480     *number -= offset;
[2171]481     files = (listrec *) realloc((char *) files,
482                                 (unsigned) (sizeof(listrec) * *number));
[5050]483     if ((! files) && *number)
484     {
[2171]485          set_error(errno);
486          error("realloc");
487          return errno;
[1671]488     }
[2171]489
490     *the_files = files;
491     return 0;
[1671]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     
[1674]522unlink_completely(filename)
523char *filename;
524{
525     char buf[MAXPATHLEN];
526     struct stat stat_buf;
527     DIR *dirp;
[5138]528     struct dirent *dp;
[2171]529     int retval;
[1674]530     int status = 0;
531     
[2171]532     if (lstat(filename, &stat_buf)) {
533          set_error(errno);
534          error(filename);
535          return error_code;
536     }
[1674]537
[1712]538     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
[2482]539          dirp = Opendir(filename);
[2171]540          if (! dirp) {
541               set_error(errno);
542               error(filename);
543               return error_code;
544          }
545               
[1674]546          for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
547               if (is_dotfile(dp->d_name))
548                    continue;
[2171]549               (void) strcpy(buf, append(filename, dp->d_name));
550               if (retval = unlink_completely(buf)) {
551                    error(buf);
552                    status = retval;
[1674]553               }
554          }
555          closedir(dirp);
[2171]556          if (retval = rmdir(filename)) {
557               set_error(errno);
558               error(filename);
559               return error_code;
560          }
[1674]561     }
[2171]562     else if (retval = unlink(filename)) {
563          set_error(errno);
564          error(filename);
565          return error_code;
566     }
567
568     return status;
[1674]569}
570
571
572
573
[2221]574int get_the_files(name, num_found, found)
575char *name;
[1705]576int *num_found;
[2171]577char ***found;
[1705]578{
[2171]579     int retval;
[2221]580     int options;
[1705]581     
[2221]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) {
[2171]590          error("find_matches");
591          return retval;
592     }
[2221]593
[2171]594     return 0;
[1705]595}
Note: See TracBrowser for help on using the repository browser.