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

Revision 12350, 14.9 KB checked in by ghudson, 26 years ago (diff)
Some RCS ID cleanup: delete $Log$ and replace other RCS keywords with $Id$.
Line 
1/*
2 * $Id: directories.c,v 1.28 1999-01-22 23:08:54 ghudson Exp $
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.
9 * For copying and distribution information, see the file "mit-copying.h."
10 */
11
12#if !defined(lint) && !defined(SABER)
13     static char rcsid_directories_c[] = "$Id: directories.c,v 1.28 1999-01-22 23:08:54 ghudson Exp $";
14#endif
15
16#include <stdio.h>
17#include <sys/types.h>
18#include <sys/param.h>
19#include <dirent.h>
20#include <string.h>
21#include <time.h>
22#include <errno.h>
23#include <com_err.h>
24#include "delete_errs.h"
25#include "util.h"
26#include "directories.h"
27#include "mit-copying.h"
28#include "errors.h"
29
30static filerec root_tree;
31static filerec cwd_tree;
32
33void free_leaf();
34
35 /* These are not static because external routines need to be able to */
36 /* access them.                                                      */
37time_t current_time;
38
39
40static filerec default_cwd = {
41     "",
42     (filerec *) NULL,
43     (filerec *) NULL,
44     (filerec *) NULL,
45     (filerec *) NULL,
46     (filerec *) NULL,
47     False,
48     False,
49     {0}
50};
51
52static filerec default_root = {
53     "/",
54     (filerec *) NULL,
55     (filerec *) NULL,
56     (filerec *) NULL,
57     (filerec *) NULL,
58     (filerec *) NULL,
59     False,
60     False,
61     {0}
62};
63
64static filerec default_directory = {
65     "",
66     (filerec *) NULL,
67     (filerec *) NULL,
68     (filerec *) NULL,
69     (filerec *) NULL,
70     (filerec *) NULL,
71     False,
72     False,
73     {0}
74};
75
76static filerec default_file = {
77     "",
78     (filerec *) NULL,
79     (filerec *) NULL,
80     (filerec *) NULL,
81     (filerec *) NULL,
82     (filerec *) NULL,
83     False,
84     False,
85     {0}
86};
87
88
89filerec *get_root_tree()
90{
91     return(&root_tree);
92}
93
94
95
96filerec *get_cwd_tree()
97{
98     return(&cwd_tree);
99}
100
101
102int initialize_tree()
103{
104     int retval;
105     
106     root_tree = default_root;
107     cwd_tree = default_cwd;
108
109     current_time = time((time_t *)0);
110     if (retval = get_specs(".", &cwd_tree.specs, FOLLOW_LINKS)) {
111          error("get_specs on .");
112          return retval;
113     }
114     if (retval = get_specs("/", &root_tree.specs, FOLLOW_LINKS)) {
115          error("get_specs on /");
116          return retval;
117     }
118     return 0;
119}
120
121
122int add_path_to_tree(path, leaf)
123char *path;
124filerec **leaf;
125{
126     filerec *parent;
127     char next_name[MAXNAMLEN];
128     char lpath[MAXPATHLEN], built_path[MAXPATHLEN], *ptr;
129     struct mystat specs;
130     int retval;
131     
132     if (retval = get_specs(path, &specs, DONT_FOLLOW_LINKS)) {
133          char error_buf[MAXPATHLEN+14];
134
135          (void) sprintf(error_buf, "get_specs on %s", path);
136          error(error_buf);
137          return retval;
138     }
139     
140     (void) strcpy(lpath, path); /* we don't want to damage the user's */
141                                 /* string */
142     ptr = lpath;
143     if (*ptr == '/') {
144          parent = &root_tree;
145          ptr++;
146          (void) strcpy(built_path, "/");
147     }
148     else if (! strncmp(ptr, "./", 2)) {
149          parent = &cwd_tree;
150          ptr += 2;
151          *built_path = '\0';
152     }
153     else {
154          parent = &cwd_tree;
155          *built_path = '\0';
156     }
157     
158     (void) strcpy(next_name, firstpart(ptr, ptr));
159     while (*ptr) {
160          (void) strcat(built_path, next_name);
161          if (retval = add_directory_to_parent(parent, next_name, False,
162                                               &parent)) {
163               error("add_directory_to_parent");
164               return retval;
165          }
166          (void) strcpy(next_name, firstpart(ptr, ptr));
167          if (retval = get_specs(built_path, &parent->specs, FOLLOW_LINKS)) {
168               char error_buf[MAXPATHLEN+14];
169
170               (void) sprintf(error_buf, "get_specs on %s", built_path);
171               error(error_buf);
172               return retval;
173          }
174          (void) strcat(built_path, "/");
175     }
176     if ((specs.st_mode & S_IFMT) == S_IFDIR) {
177          retval = add_directory_to_parent(parent, next_name, True, leaf);
178          if (retval) {
179               error("add_directory_to_parent");
180               return retval;
181          }
182     }
183     else {
184          retval = add_file_to_parent(parent, next_name, True, leaf);
185          if (retval) {
186               error("add_file_to_parent");
187               return retval;
188          }
189     }         
190
191     (*leaf)->specs = specs;
192
193     return 0;
194}
195
196
197
198int get_specs(path, specs, follow)
199char *path;
200struct mystat *specs;
201int follow; /* follow symlinks or not? */
202{
203     int status;
204     struct stat realspecs;
205     
206     if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
207                           (strlen(path) != 1))
208          path[strlen(path) - 1] = '\0';
209     if (follow == FOLLOW_LINKS)
210          status = stat(path, &realspecs);
211     else
212          status = lstat(path, &realspecs);
213
214     if (status) {
215          set_error(errno);
216          error(path);
217          return error_code;
218     }
219
220     specs->st_dev = realspecs.st_dev;
221     specs->st_ino = realspecs.st_ino;
222     specs->st_mode = realspecs.st_mode;
223     specs->st_size = realspecs.st_size;
224     specs->st_chtime = realspecs.st_ctime;
225     specs->st_blocks = realspecs.st_blocks;
226
227     return 0;
228}
229
230
231
232filerec *next_leaf(leaf)
233filerec *leaf;
234{
235     filerec *new;
236
237     if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
238          new = first_in_directory(leaf);
239          if (new)
240               return(new);
241          new = next_directory(leaf);
242          return(new);
243     }
244     else {
245          new = next_in_directory(leaf);
246          return(new);
247     }
248}
249
250
251filerec *next_specified_leaf(leaf)
252filerec *leaf;
253{
254     while (leaf = next_leaf(leaf))
255     if (leaf->specified)
256          return(leaf);
257     return((filerec *) NULL);
258}
259
260
261filerec *next_directory(leaf)
262filerec *leaf;
263{
264     filerec *ret;
265     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
266          leaf = leaf->parent;
267     if (leaf)
268          ret = leaf->next;
269     else
270          ret = (filerec *) NULL;
271     if (ret) if (ret->freed)
272          ret = next_directory(ret);
273     return(ret);
274}
275
276
277filerec *next_specified_directory(leaf)
278filerec *leaf;
279{
280     while (leaf = next_directory(leaf))
281          if (leaf->specified)
282               return(leaf);
283     return ((filerec *) NULL);
284}
285
286
287
288filerec *next_in_directory(leaf)
289filerec *leaf;
290{
291     filerec *ret;
292
293     if (leaf->next)
294          ret = leaf->next;
295     else if (((leaf->specs.st_mode & S_IFMT) != S_IFDIR) && leaf->parent)
296          ret = leaf->parent->dirs;
297     else
298          ret = (filerec *) NULL;
299     if (ret) if (ret->freed)
300          ret = next_in_directory(ret);
301     return (ret);
302}
303
304
305
306
307filerec *next_specified_in_directory(leaf)
308filerec *leaf;
309{
310     while (leaf = next_in_directory(leaf))
311          if (leaf->specified)
312               return(leaf);
313     return ((filerec *) NULL);
314}
315
316
317
318filerec *first_in_directory(leaf)
319filerec *leaf;
320{
321     filerec *ret;
322
323     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
324          ret = (filerec *) NULL;
325     else if (leaf->files)
326          ret = leaf->files;
327     else if (leaf->dirs)
328          ret =  leaf->dirs;
329     else
330          ret = (filerec *) NULL;
331     if (ret) if (ret->freed)
332          ret = next_in_directory(ret);
333     return(ret);
334}
335
336
337filerec *first_specified_in_directory(leaf)
338filerec *leaf;
339{
340     leaf = first_in_directory(leaf);
341     if (! leaf)
342          return((filerec *) NULL);
343     
344     if (leaf->specified)
345          return(leaf);
346     else
347          leaf = next_specified_in_directory(leaf);
348     return (leaf);
349}
350
351
352void print_paths_from(leaf)
353filerec *leaf;
354{
355     /*
356      * This is static to prevent multiple copies of it when calling
357      * recursively.
358      */
359     static char buf[MAXPATHLEN];
360
361     printf("%s\n", get_leaf_path(leaf, buf));
362     if (leaf->dirs)
363          print_paths_from(leaf->dirs);
364     if (leaf->files)
365          print_paths_from(leaf->files);
366     if (leaf->next)
367          print_paths_from(leaf->next);
368}
369
370
371void print_specified_paths_from(leaf)
372filerec *leaf;
373{
374     /*
375      * This is static to prevent multiple copies of it when calling
376      * recursively.
377      */
378     static char buf[MAXPATHLEN];
379
380     if (leaf->specified)
381          printf("%s\n", get_leaf_path(leaf, buf));
382     if (leaf->dirs)
383          print_specified_paths_from(leaf->dirs);
384     if (leaf->files)
385          print_specified_paths_from(leaf->files);
386     if (leaf->next)
387          print_specified_paths_from(leaf->next);
388}
389     
390
391int add_file_to_parent(parent, name, specified, last)
392filerec *parent, **last;
393char *name;
394Boolean specified;
395{
396     filerec *files;
397
398     *last = files = (filerec *) NULL;
399     files = parent->files;
400     while (files) {
401          if (! strcmp(files->name, name))
402               break;
403          *last = files;
404          files = files->next;
405     }
406     if (files) {
407          files->specified = (files->specified || specified);
408          *last = files;
409          return 0;
410     }
411     if (*last) {
412          (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
413          if (! (*last)->next) {
414               set_error(errno);
415               error("Malloc");
416               return error_code;
417          }
418          *(*last)->next = default_file;
419          (*last)->next->previous = *last;
420          (*last)->next->parent = parent;
421          (*last) = (*last)->next;
422     }
423     else {
424          parent->files = (filerec *) Malloc(sizeof(filerec));
425          if (! parent->files) {
426               set_error(errno);
427               error("Malloc");
428               return error_code;
429          }
430          *parent->files = default_file;
431          parent->files->parent = parent;
432          parent->files->previous = (filerec *) NULL;
433          *last = parent->files;
434     }
435     (void) strcpy((*last)->name, name);
436     (*last)->specified = specified;
437     return 0;
438}
439
440
441
442
443
444int add_directory_to_parent(parent, name, specified, last)
445filerec *parent, **last;
446char *name;
447Boolean specified;
448{
449     filerec *directories;
450
451     *last = (filerec *) NULL;
452     directories = parent->dirs;
453     while (directories) {
454          if (! strcmp(directories->name, name))
455               break;
456          (*last) = directories;
457          directories = directories->next;
458     }
459     if (directories) {
460          directories->specified = (directories->specified || specified);
461          *last = directories;
462          return 0;
463     }
464     if (*last) {
465          (*last)->next = (filerec *) Malloc(sizeof(filerec));
466          if (! (*last)->next) {
467               set_error(errno);
468               error("Malloc");
469               return error_code;
470          }
471          *(*last)->next = default_directory;
472          (*last)->next->previous = *last;
473          (*last)->next->parent = parent;
474          (*last) = (*last)->next;
475     }
476     else {
477          parent->dirs = (filerec *) Malloc(sizeof(filerec));
478          if (! parent->dirs) {
479               set_error(errno);
480               error("Malloc");
481               return error_code;
482          }
483          *parent->dirs = default_directory;
484          parent->dirs->parent = parent;
485          parent->dirs->previous = (filerec *) NULL;
486          (*last) = parent->dirs;
487     }
488     (void) strcpy((*last)->name, name);
489     (*last)->specified = specified;
490     return 0;
491}
492
493
494
495
496
497void free_leaf(leaf)
498filerec *leaf;
499{
500     leaf->freed = True;
501     if (! (leaf->dirs || leaf->files)) {
502          if (leaf->previous)
503               leaf->previous->next = leaf->next;
504          if (leaf->next)
505               leaf->next->previous = leaf->previous;
506          if (leaf->parent) {
507               if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
508                    if (leaf->parent->dirs == leaf) {
509                         leaf->parent->dirs = leaf->next;
510                         if (leaf->parent->freed)
511                              free_leaf(leaf->parent);
512                    }
513               }
514               else {
515                    if (leaf->parent->files == leaf) {
516                         leaf->parent->files = leaf->next;
517                         if (leaf->parent->freed)
518                              free_leaf(leaf->parent);
519                    }
520               }
521               free((char *) leaf);
522          }
523     }
524}     
525
526
527
528int find_child(directory, name, child)
529filerec *directory, **child;
530char *name;
531{
532     filerec *ptr;
533     
534     *child = (filerec *) NULL;
535     if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
536          return DIR_NOT_DIRECTORY;
537     ptr = directory->dirs;
538     while (ptr)
539          if (strcmp(ptr->name, name))
540               ptr = ptr->next;
541          else
542               break;
543     if (ptr) {
544          *child = ptr;
545          return DIR_MATCH;
546     }
547     ptr = directory->files;
548     while (ptr)
549          if (strcmp(ptr->name, name))
550               ptr = ptr->next;
551          else
552               break;
553     if (ptr) {
554          *child = ptr;
555          return DIR_MATCH;
556     }
557     set_status(DIR_NO_MATCH);
558     return DIR_NO_MATCH;
559}
560
561
562
563
564
565int change_path(old_path, new_path)
566char *old_path, *new_path;
567{
568     char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
569     char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
570     int retval;
571     filerec *current;
572     
573     if (*old_path == '/') {
574          current = &root_tree;
575          old_path++;
576          new_path++;
577     }
578     else if (! strncmp(old_path, "./", 2)) {
579          current = &cwd_tree;
580          old_path += 2;
581          new_path += 2;
582     }
583     else
584          current = &cwd_tree;
585     
586     (void) strcpy(next_old, firstpart(old_path, rest_old));
587     (void) strcpy(next_new, firstpart(new_path, rest_new));
588     while (*next_old && *next_new) {
589          retval = find_child(current, next_old, &current);
590          if (retval == DIR_MATCH) {
591               if (current) {
592                    (void) strcpy(current->name, next_new);
593                    current->specified = False;
594               }
595               else {
596                    set_error(INTERNAL_ERROR);
597                    error("change_path");
598                    return error_code;
599               }
600          }
601          else {
602               error("change_path");
603               return retval;
604          }
605         
606          (void) strcpy(next_old, firstpart(rest_old, rest_old));
607          (void) strcpy(next_new, firstpart(rest_new, rest_new));
608     }
609     return 0;
610}
611
612
613int get_leaf_path(leaf, leaf_buf)
614filerec *leaf;
615char leaf_buf[]; /* RETURN */
616{
617     char *name_ptr;
618
619     name_ptr = Malloc(1);
620     if (! name_ptr) {
621          set_error(errno);
622          error("Malloc");
623          *leaf_buf = '\0';
624          return error_code;
625     }
626     *name_ptr = '\0';
627     do {
628          name_ptr = realloc((char *) name_ptr, (unsigned)
629                             (strlen(leaf->name) + strlen(name_ptr) + 2));
630          if (! name_ptr) {
631               set_error(errno);
632               *leaf_buf = '\0';
633               error("realloc");
634               return error_code;
635          }
636          (void) strcpy(leaf_buf, name_ptr);
637          *name_ptr = '\0';
638          if (leaf->parent) if (leaf->parent->parent)
639               (void) strcat(name_ptr, "/");
640          (void) strcat(name_ptr, leaf->name);
641          (void) strcat(name_ptr, leaf_buf);
642          leaf = leaf->parent;
643     } while (leaf);
644     (void) strcpy(leaf_buf, name_ptr);
645     return 0;
646}
647
648
649
650
651
652int accumulate_names(leaf, in_strings, num)
653filerec *leaf;
654char ***in_strings;
655int *num;
656{
657     char **strings;
658     int retval;
659     
660     strings = *in_strings;
661     if (leaf->specified) {
662          /*
663           * This array is static so that only one copy of it is allocated,
664           * rather than one copy on the stack for each recursive
665           * invocation of accumulate_names.
666           */
667          static char newname[MAXPATHLEN];
668
669          *num += 1;
670          strings = (char **) realloc((char *) strings, (unsigned)
671                                      (sizeof(char *) * (*num)));
672          if (! strings) {
673               set_error(errno);
674               error("realloc");
675               return error_code;
676          }
677          if (retval = get_leaf_path(leaf, newname)) {
678               error("get_leaf_path");
679               return retval;
680          }
681          (void) convert_to_user_name(newname, newname);
682          strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
683          if (! strings[*num - 1]) {
684               set_error(errno);
685               error("Malloc");
686               return error_code;
687          }
688          (void) strcpy(strings[*num - 1], newname);
689     }
690     if (leaf->files) if (retval = accumulate_names(leaf->files, &strings,
691                                                    num)) {
692          error("accumulate_names");
693          return retval;
694     }
695     if (leaf->dirs) if (retval = accumulate_names(leaf->dirs, &strings,
696                                                   num)) {
697          error("accumulate_names");
698          return retval;
699     }
700     if (leaf->next) if (retval = accumulate_names(leaf->next, &strings,
701                                                   num)) {
702          error("accumulate_names");
703          return retval;
704     }
705
706     *in_strings = strings;
707     return 0;
708}
Note: See TracBrowser for help on using the repository browser.