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

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