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

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