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$.
RevLine 
[1679]1/*
[12350]2 * $Id: directories.c,v 1.28 1999-01-22 23:08:54 ghudson Exp $
[1706]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."
[1706]10 */
11
12#if !defined(lint) && !defined(SABER)
[12350]13     static char rcsid_directories_c[] = "$Id: directories.c,v 1.28 1999-01-22 23:08:54 ghudson Exp $";
[1706]14#endif
15
[2181]16#include <stdio.h>
[1679]17#include <sys/types.h>
18#include <sys/param.h>
[5049]19#include <dirent.h>
[3049]20#include <string.h>
[10977]21#include <time.h>
[2181]22#include <errno.h>
23#include <com_err.h>
24#include "delete_errs.h"
[1688]25#include "util.h"
[4415]26#include "directories.h"
[4505]27#include "mit-copying.h"
[2181]28#include "errors.h"
[1679]29
30static filerec root_tree;
31static filerec cwd_tree;
32
[2221]33void free_leaf();
[1679]34
[2221]35 /* These are not static because external routines need to be able to */
36 /* access them.                                                      */
37time_t current_time;
[1679]38
[2221]39
[1688]40static filerec default_cwd = {
[1713]41     "",
[1688]42     (filerec *) NULL,
43     (filerec *) NULL,
44     (filerec *) NULL,
45     (filerec *) NULL,
46     (filerec *) NULL,
47     False,
[1732]48     False,
49     {0}
[1688]50};
[1679]51
[1688]52static filerec default_root = {
[1713]53     "/",
[1688]54     (filerec *) NULL,
55     (filerec *) NULL,
56     (filerec *) NULL,
57     (filerec *) NULL,
58     (filerec *) NULL,
59     False,
[1732]60     False,
61     {0}
[1688]62};
63
64static filerec default_directory = {
65     "",
66     (filerec *) NULL,
67     (filerec *) NULL,
68     (filerec *) NULL,
69     (filerec *) NULL,
70     (filerec *) NULL,
71     False,
[1732]72     False,
73     {0}
[1688]74};
75
76static filerec default_file = {
77     "",
78     (filerec *) NULL,
79     (filerec *) NULL,
80     (filerec *) NULL,
81     (filerec *) NULL,
82     (filerec *) NULL,
83     False,
[1732]84     False,
85     {0}
[1688]86};
87
88
[1679]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
[2181]102int initialize_tree()
[1679]103{
[2181]104     int retval;
[1732]105     
[1679]106     root_tree = default_root;
107     cwd_tree = default_cwd;
[1732]108
[2181]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;
[1679]113     }
[2181]114     if (retval = get_specs("/", &root_tree.specs, FOLLOW_LINKS)) {
115          error("get_specs on /");
116          return retval;
117     }
118     return 0;
[1679]119}
120
121
[2181]122int add_path_to_tree(path, leaf)
[1679]123char *path;
[2181]124filerec **leaf;
[1679]125{
[2181]126     filerec *parent;
[1679]127     char next_name[MAXNAMLEN];
[1732]128     char lpath[MAXPATHLEN], built_path[MAXPATHLEN], *ptr;
[4422]129     struct mystat specs;
[2181]130     int retval;
131     
132     if (retval = get_specs(path, &specs, DONT_FOLLOW_LINKS)) {
133          char error_buf[MAXPATHLEN+14];
[1679]134
[2181]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;
[1679]143     if (*ptr == '/') {
144          parent = &root_tree;
145          ptr++;
[2181]146          (void) strcpy(built_path, "/");
[1679]147     }
148     else if (! strncmp(ptr, "./", 2)) {
149          parent = &cwd_tree;
150          ptr += 2;
[1732]151          *built_path = '\0';
[1679]152     }
[1732]153     else {
[1679]154          parent = &cwd_tree;
[1732]155          *built_path = '\0';
156     }
157     
[2181]158     (void) strcpy(next_name, firstpart(ptr, ptr));
[1679]159     while (*ptr) {
[2181]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, "/");
[1679]175     }
[2181]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     }         
[1679]190
[2181]191     (*leaf)->specs = specs;
192
193     return 0;
[1679]194}
195
196
197
[2181]198int get_specs(path, specs, follow)
[1679]199char *path;
[4422]200struct mystat *specs;
[2181]201int follow; /* follow symlinks or not? */
[1679]202{
[1732]203     int status;
[4422]204     struct stat realspecs;
[1679]205     
[1732]206     if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
207                           (strlen(path) != 1))
[1679]208          path[strlen(path) - 1] = '\0';
[1732]209     if (follow == FOLLOW_LINKS)
[4422]210          status = stat(path, &realspecs);
[1732]211     else
[4422]212          status = lstat(path, &realspecs);
[1732]213
[2181]214     if (status) {
215          set_error(errno);
216          error(path);
217          return error_code;
218     }
219
[4422]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;
[7980]224     specs->st_chtime = realspecs.st_ctime;
[4422]225     specs->st_blocks = realspecs.st_blocks;
226
[2181]227     return 0;
[1679]228}
229
230
231
232filerec *next_leaf(leaf)
233filerec *leaf;
234{
[1684]235     filerec *new;
[1732]236
237     if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
[1684]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     }
[1679]248}
249
250
251filerec *next_specified_leaf(leaf)
252filerec *leaf;
253{
[1684]254     while (leaf = next_leaf(leaf))
255     if (leaf->specified)
256          return(leaf);
[1679]257     return((filerec *) NULL);
258}
259
260
261filerec *next_directory(leaf)
262filerec *leaf;
263{
[1684]264     filerec *ret;
[1732]265     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
[1679]266          leaf = leaf->parent;
267     if (leaf)
[1684]268          ret = leaf->next;
[1679]269     else
[1684]270          ret = (filerec *) NULL;
271     if (ret) if (ret->freed)
272          ret = next_directory(ret);
273     return(ret);
[1679]274}
275
276
277filerec *next_specified_directory(leaf)
278filerec *leaf;
279{
[1684]280     while (leaf = next_directory(leaf))
281          if (leaf->specified)
282               return(leaf);
283     return ((filerec *) NULL);
[1679]284}
285
286
287
288filerec *next_in_directory(leaf)
289filerec *leaf;
290{
[1684]291     filerec *ret;
[1732]292
[1679]293     if (leaf->next)
[1684]294          ret = leaf->next;
[1732]295     else if (((leaf->specs.st_mode & S_IFMT) != S_IFDIR) && leaf->parent)
[1684]296          ret = leaf->parent->dirs;
[1679]297     else
[1684]298          ret = (filerec *) NULL;
299     if (ret) if (ret->freed)
300          ret = next_in_directory(ret);
301     return (ret);
[1679]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{
[1684]321     filerec *ret;
[1732]322
323     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
[1684]324          ret = (filerec *) NULL;
325     else if (leaf->files)
326          ret = leaf->files;
[1679]327     else if (leaf->dirs)
[1684]328          ret =  leaf->dirs;
[1679]329     else
[1684]330          ret = (filerec *) NULL;
331     if (ret) if (ret->freed)
332          ret = next_in_directory(ret);
333     return(ret);
[1679]334}
335
336
[1684]337filerec *first_specified_in_directory(leaf)
[1679]338filerec *leaf;
339{
340     leaf = first_in_directory(leaf);
[1700]341     if (! leaf)
342          return((filerec *) NULL);
[1679]343     
[1684]344     if (leaf->specified)
[1679]345          return(leaf);
346     else
[1684]347          leaf = next_specified_in_directory(leaf);
[1732]348     return (leaf);
[1679]349}
350
351
[2221]352void print_paths_from(leaf)
[1679]353filerec *leaf;
354{
[6420]355     /*
356      * This is static to prevent multiple copies of it when calling
357      * recursively.
358      */
359     static char buf[MAXPATHLEN];
[1732]360
[1679]361     printf("%s\n", get_leaf_path(leaf, buf));
362     if (leaf->dirs)
[1684]363          print_paths_from(leaf->dirs);
[1679]364     if (leaf->files)
[1684]365          print_paths_from(leaf->files);
[1679]366     if (leaf->next)
[1684]367          print_paths_from(leaf->next);
[1679]368}
369
370
[2221]371void print_specified_paths_from(leaf)
[1679]372filerec *leaf;
373{
[6420]374     /*
375      * This is static to prevent multiple copies of it when calling
376      * recursively.
377      */
378     static char buf[MAXPATHLEN];
[1732]379
[1679]380     if (leaf->specified)
381          printf("%s\n", get_leaf_path(leaf, buf));
382     if (leaf->dirs)
[1684]383          print_specified_paths_from(leaf->dirs);
[1679]384     if (leaf->files)
[1684]385          print_specified_paths_from(leaf->files);
[1679]386     if (leaf->next)
[1684]387          print_specified_paths_from(leaf->next);
[1679]388}
389     
390
[2181]391int add_file_to_parent(parent, name, specified, last)
392filerec *parent, **last;
[1679]393char *name;
[1684]394Boolean specified;
[1679]395{
[2181]396     filerec *files;
[1732]397
[2181]398     *last = files = (filerec *) NULL;
[1679]399     files = parent->files;
400     while (files) {
401          if (! strcmp(files->name, name))
402               break;
[2181]403          *last = files;
[1679]404          files = files->next;
405     }
406     if (files) {
407          files->specified = (files->specified || specified);
[2181]408          *last = files;
409          return 0;
[1679]410     }
[2181]411     if (*last) {
[2367]412          (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
[2181]413          if (! (*last)->next) {
414               set_error(errno);
[2367]415               error("Malloc");
[2181]416               return error_code;
417          }
418          *(*last)->next = default_file;
419          (*last)->next->previous = *last;
420          (*last)->next->parent = parent;
421          (*last) = (*last)->next;
[1679]422     }
423     else {
[2367]424          parent->files = (filerec *) Malloc(sizeof(filerec));
[2181]425          if (! parent->files) {
426               set_error(errno);
[2367]427               error("Malloc");
[2181]428               return error_code;
429          }
[1679]430          *parent->files = default_file;
431          parent->files->parent = parent;
432          parent->files->previous = (filerec *) NULL;
[2181]433          *last = parent->files;
[1679]434     }
[2181]435     (void) strcpy((*last)->name, name);
436     (*last)->specified = specified;
437     return 0;
[1679]438}
439
440
441
442
443
[2181]444int add_directory_to_parent(parent, name, specified, last)
445filerec *parent, **last;
[1679]446char *name;
[1684]447Boolean specified;
[1679]448{
[2181]449     filerec *directories;
[1732]450
[2181]451     *last = (filerec *) NULL;
[1679]452     directories = parent->dirs;
453     while (directories) {
454          if (! strcmp(directories->name, name))
455               break;
[2181]456          (*last) = directories;
[1679]457          directories = directories->next;
458     }
459     if (directories) {
460          directories->specified = (directories->specified || specified);
[2181]461          *last = directories;
462          return 0;
[1679]463     }
[2181]464     if (*last) {
[2367]465          (*last)->next = (filerec *) Malloc(sizeof(filerec));
[2181]466          if (! (*last)->next) {
467               set_error(errno);
[2367]468               error("Malloc");
[2181]469               return error_code;
470          }
471          *(*last)->next = default_directory;
472          (*last)->next->previous = *last;
473          (*last)->next->parent = parent;
474          (*last) = (*last)->next;
[1679]475     }
476     else {
[2367]477          parent->dirs = (filerec *) Malloc(sizeof(filerec));
[2181]478          if (! parent->dirs) {
479               set_error(errno);
[2367]480               error("Malloc");
[2181]481               return error_code;
482          }
[1679]483          *parent->dirs = default_directory;
484          parent->dirs->parent = parent;
485          parent->dirs->previous = (filerec *) NULL;
[2181]486          (*last) = parent->dirs;
[1679]487     }
[2181]488     (void) strcpy((*last)->name, name);
489     (*last)->specified = specified;
490     return 0;
[1679]491}
492
493
494
495
496
[2221]497void free_leaf(leaf)
[1679]498filerec *leaf;
499{
500     leaf->freed = True;
[1684]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;
[1752]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)
[2221]511                              free_leaf(leaf->parent);
[1752]512                    }
[1684]513               }
[1752]514               else {
515                    if (leaf->parent->files == leaf) {
516                         leaf->parent->files = leaf->next;
517                         if (leaf->parent->freed)
[2221]518                              free_leaf(leaf->parent);
[1752]519                    }
[1684]520               }
[2181]521               free((char *) leaf);
[1684]522          }
523     }
[1679]524}     
525
526
527
[2181]528int find_child(directory, name, child)
529filerec *directory, **child;
[1679]530char *name;
531{
532     filerec *ptr;
[2181]533     
534     *child = (filerec *) NULL;
[1732]535     if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
[2181]536          return DIR_NOT_DIRECTORY;
[1679]537     ptr = directory->dirs;
538     while (ptr)
539          if (strcmp(ptr->name, name))
540               ptr = ptr->next;
541          else
542               break;
[2181]543     if (ptr) {
544          *child = ptr;
545          return DIR_MATCH;
546     }
[1679]547     ptr = directory->files;
548     while (ptr)
549          if (strcmp(ptr->name, name))
550               ptr = ptr->next;
551          else
552               break;
[2181]553     if (ptr) {
554          *child = ptr;
555          return DIR_MATCH;
556     }
557     set_status(DIR_NO_MATCH);
558     return DIR_NO_MATCH;
[1679]559}
560
[1732]561
562
563
564
[2181]565int change_path(old_path, new_path)
[1679]566char *old_path, *new_path;
567{
568     char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
569     char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
[2181]570     int retval;
[1679]571     filerec *current;
[2181]572     
[1679]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;
[2181]585     
586     (void) strcpy(next_old, firstpart(old_path, rest_old));
587     (void) strcpy(next_new, firstpart(new_path, rest_new));
[1679]588     while (*next_old && *next_new) {
[2181]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));
[1679]608     }
[2181]609     return 0;
[1679]610}
611
612
[2181]613int get_leaf_path(leaf, leaf_buf)
[1679]614filerec *leaf;
615char leaf_buf[]; /* RETURN */
616{
617     char *name_ptr;
618
[2367]619     name_ptr = Malloc(1);
[1732]620     if (! name_ptr) {
[2181]621          set_error(errno);
[2367]622          error("Malloc");
[1732]623          *leaf_buf = '\0';
[2181]624          return error_code;
[1732]625     }
[1679]626     *name_ptr = '\0';
627     do {
[2181]628          name_ptr = realloc((char *) name_ptr, (unsigned)
629                             (strlen(leaf->name) + strlen(name_ptr) + 2));
[1732]630          if (! name_ptr) {
[2181]631               set_error(errno);
[1732]632               *leaf_buf = '\0';
[2181]633               error("realloc");
634               return error_code;
[1732]635          }
[2181]636          (void) strcpy(leaf_buf, name_ptr);
[1679]637          *name_ptr = '\0';
[1713]638          if (leaf->parent) if (leaf->parent->parent)
[2181]639               (void) strcat(name_ptr, "/");
640          (void) strcat(name_ptr, leaf->name);
641          (void) strcat(name_ptr, leaf_buf);
[1679]642          leaf = leaf->parent;
643     } while (leaf);
[2181]644     (void) strcpy(leaf_buf, name_ptr);
645     return 0;
[1679]646}
[1732]647
648
649
650
651
[2181]652int accumulate_names(leaf, in_strings, num)
[1732]653filerec *leaf;
[2181]654char ***in_strings;
[1732]655int *num;
656{
[2181]657     char **strings;
658     int retval;
[1732]659     
[2181]660     strings = *in_strings;
[1732]661     if (leaf->specified) {
[6420]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
[1732]669          *num += 1;
[2181]670          strings = (char **) realloc((char *) strings, (unsigned)
671                                      (sizeof(char *) * (*num)));
[1732]672          if (! strings) {
[2181]673               set_error(errno);
674               error("realloc");
675               return error_code;
[1732]676          }
[2181]677          if (retval = get_leaf_path(leaf, newname)) {
678               error("get_leaf_path");
679               return retval;
680          }
[2221]681          (void) convert_to_user_name(newname, newname);
[2367]682          strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
[1732]683          if (! strings[*num - 1]) {
[2181]684               set_error(errno);
[2367]685               error("Malloc");
[2181]686               return error_code;
[1732]687          }
[2181]688          (void) strcpy(strings[*num - 1], newname);
[1732]689     }
[2181]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     }
[1732]705
[2181]706     *in_strings = strings;
707     return 0;
[1732]708}
Note: See TracBrowser for help on using the repository browser.