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

Revision 24908, 15.8 KB checked in by ghudson, 14 years ago (diff)
In delete: * Patches from Jonathan Kamens: - The "-f" flag to delete should suppress nonexistent file errors but not other errors. - When the "-v" flag is specified to expunge, the correct totals should be reported. Previously, the totals were incorrect. - Code cleanup.
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#include <math.h>
13#include <stdio.h>
14#include <sys/types.h>
15#include <sys/param.h>
16#include <dirent.h>
17#include <string.h>
18#include <time.h>
19#include <errno.h>
20#include <com_err.h>
21#include "delete_errs.h"
22#include "directories.h"
23#include "mit-copying.h"
24#include "errors.h"
25#include "util.h"
26
27static filerec root_tree;
28static filerec cwd_tree;
29
30void free_leaf(filerec *leaf);
31static int get_specs(char *path,
32                     struct mystat *specs,
33                     int follow);
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
198static int get_specs(char *path,
199                     struct mystat *specs,
200                     int follow) /* follow symlinks or not? */
201{
202     int status;
203     struct stat realspecs;
204     
205     if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
206                           (strlen(path) != 1))
207          path[strlen(path) - 1] = '\0';
208     if (follow == FOLLOW_LINKS)
209          status = stat(path, &realspecs);
210     else
211          status = lstat(path, &realspecs);
212
213     if (status) {
214          set_error(errno);
215          error(path);
216          return error_code;
217     }
218
219     specs->st_dev = realspecs.st_dev;
220     specs->st_ino = realspecs.st_ino;
221     specs->st_mode = realspecs.st_mode;
222     specs->st_size = realspecs.st_size;
223     specs->st_ctim = realspecs.st_ctime;
224
225     return 0;
226}
227
228
229
230filerec *next_leaf(leaf)
231filerec *leaf;
232{
233     filerec *new;
234
235     if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
236          new = first_in_directory(leaf);
237          if (new)
238               return(new);
239          new = next_directory(leaf);
240          return(new);
241     }
242     else {
243          new = next_in_directory(leaf);
244          return(new);
245     }
246}
247
248
249filerec *next_specified_leaf(leaf)
250filerec *leaf;
251{
252  while ((leaf = next_leaf(leaf))) {
253    if (leaf->specified)
254      return(leaf);
255  }
256  return((filerec *) NULL);
257}
258
259
260filerec *next_directory(leaf)
261filerec *leaf;
262{
263     filerec *ret;
264     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
265          leaf = leaf->parent;
266     if (leaf)
267          ret = leaf->next;
268     else
269          ret = (filerec *) NULL;
270     if (ret) if (ret->freed)
271          ret = next_directory(ret);
272     return(ret);
273}
274
275
276filerec *next_specified_directory(leaf)
277filerec *leaf;
278{
279  while ((leaf = next_directory(leaf))) {
280    if (leaf->specified)
281      return(leaf);
282  }
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  }
314  return ((filerec *) NULL);
315}
316
317
318
319filerec *first_in_directory(leaf)
320filerec *leaf;
321{
322     filerec *ret;
323
324     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
325          ret = (filerec *) NULL;
326     else if (leaf->files)
327          ret = leaf->files;
328     else if (leaf->dirs)
329          ret =  leaf->dirs;
330     else
331          ret = (filerec *) NULL;
332     if (ret) if (ret->freed)
333          ret = next_in_directory(ret);
334     return(ret);
335}
336
337
338filerec *first_specified_in_directory(leaf)
339filerec *leaf;
340{
341     leaf = first_in_directory(leaf);
342     if (! leaf)
343          return((filerec *) NULL);
344     
345     if (leaf->specified)
346          return(leaf);
347     else
348          leaf = next_specified_in_directory(leaf);
349     return (leaf);
350}
351
352
353/* This is a debugging function not actually used anywhere in any program. */
354void print_paths_from(leaf)
355filerec *leaf;
356{
357     /*
358      * This is static to prevent multiple copies of it when calling
359      * recursively.
360      */
361     static char buf[MAXPATHLEN];
362
363     if (! get_leaf_path(leaf, buf)) {
364       printf("%s\n", buf);
365     }
366     else {
367       error("get_leaf_path");
368     }
369     if (leaf->dirs)
370          print_paths_from(leaf->dirs);
371     if (leaf->files)
372          print_paths_from(leaf->files);
373     if (leaf->next)
374          print_paths_from(leaf->next);
375}
376
377
378/* This is a debugging function not actually used anywhere in any program. */
379void print_specified_paths_from(leaf)
380filerec *leaf;
381{
382     /*
383      * This is static to prevent multiple copies of it when calling
384      * recursively.
385      */
386     static char buf[MAXPATHLEN];
387
388     if (leaf->specified) {
389       if (! get_leaf_path(leaf, buf)) {
390         printf("%s\n", buf);
391       }
392       else {
393         error("get_leaf_path");
394       }
395     }
396     if (leaf->dirs)
397          print_specified_paths_from(leaf->dirs);
398     if (leaf->files)
399          print_specified_paths_from(leaf->files);
400     if (leaf->next)
401          print_specified_paths_from(leaf->next);
402}
403     
404
405int add_file_to_parent(parent, name, specified, last)
406filerec *parent, **last;
407char *name;
408Boolean specified;
409{
410     filerec *files;
411
412     *last = files = (filerec *) NULL;
413     files = parent->files;
414     while (files) {
415          if (! strcmp(files->name, name))
416               break;
417          *last = files;
418          files = files->next;
419     }
420     if (files) {
421          files->specified = (files->specified || specified);
422          *last = files;
423          return 0;
424     }
425     if (*last) {
426          (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
427          if (! (*last)->next) {
428               set_error(errno);
429               error("Malloc");
430               return error_code;
431          }
432          *(*last)->next = default_file;
433          (*last)->next->previous = *last;
434          (*last)->next->parent = parent;
435          (*last) = (*last)->next;
436     }
437     else {
438          parent->files = (filerec *) Malloc(sizeof(filerec));
439          if (! parent->files) {
440               set_error(errno);
441               error("Malloc");
442               return error_code;
443          }
444          *parent->files = default_file;
445          parent->files->parent = parent;
446          parent->files->previous = (filerec *) NULL;
447          *last = parent->files;
448     }
449     (void) strcpy((*last)->name, name);
450     (*last)->specified = specified;
451     return 0;
452}
453
454
455
456
457
458int add_directory_to_parent(parent, name, specified, last)
459filerec *parent, **last;
460char *name;
461Boolean specified;
462{
463     filerec *directories;
464
465     *last = (filerec *) NULL;
466     directories = parent->dirs;
467     while (directories) {
468          if (! strcmp(directories->name, name))
469               break;
470          (*last) = directories;
471          directories = directories->next;
472     }
473     if (directories) {
474          directories->specified = (directories->specified || specified);
475          *last = directories;
476          return 0;
477     }
478     if (*last) {
479          (*last)->next = (filerec *) Malloc(sizeof(filerec));
480          if (! (*last)->next) {
481               set_error(errno);
482               error("Malloc");
483               return error_code;
484          }
485          *(*last)->next = default_directory;
486          (*last)->next->previous = *last;
487          (*last)->next->parent = parent;
488          (*last) = (*last)->next;
489     }
490     else {
491          parent->dirs = (filerec *) Malloc(sizeof(filerec));
492          if (! parent->dirs) {
493               set_error(errno);
494               error("Malloc");
495               return error_code;
496          }
497          *parent->dirs = default_directory;
498          parent->dirs->parent = parent;
499          parent->dirs->previous = (filerec *) NULL;
500          (*last) = parent->dirs;
501     }
502     (void) strcpy((*last)->name, name);
503     (*last)->specified = specified;
504     return 0;
505}
506
507
508
509
510
511void free_leaf(filerec *leaf)
512{
513     leaf->freed = True;
514     if (! (leaf->dirs || leaf->files)) {
515          if (leaf->previous)
516               leaf->previous->next = leaf->next;
517          if (leaf->next)
518               leaf->next->previous = leaf->previous;
519          if (leaf->parent) {
520               if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
521                    if (leaf->parent->dirs == leaf) {
522                         leaf->parent->dirs = leaf->next;
523                         if (leaf->parent->freed)
524                              free_leaf(leaf->parent);
525                    }
526               }
527               else {
528                    if (leaf->parent->files == leaf) {
529                         leaf->parent->files = leaf->next;
530                         if (leaf->parent->freed)
531                              free_leaf(leaf->parent);
532                    }
533               }
534               free((char *) leaf);
535          }
536     }
537}     
538
539
540
541int find_child(directory, name, child)
542filerec *directory, **child;
543char *name;
544{
545     filerec *ptr;
546     
547     *child = (filerec *) NULL;
548     if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
549          return DIR_NOT_DIRECTORY;
550     ptr = directory->dirs;
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     ptr = directory->files;
561     while (ptr)
562          if (strcmp(ptr->name, name))
563               ptr = ptr->next;
564          else
565               break;
566     if (ptr) {
567          *child = ptr;
568          return DIR_MATCH;
569     }
570     set_status(DIR_NO_MATCH);
571     return DIR_NO_MATCH;
572}
573
574
575
576
577
578int change_path(old_path, new_path)
579char *old_path, *new_path;
580{
581     char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
582     char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
583     int retval;
584     filerec *current;
585     
586     if (*old_path == '/') {
587          current = &root_tree;
588          old_path++;
589          new_path++;
590     }
591     else if (! strncmp(old_path, "./", 2)) {
592          current = &cwd_tree;
593          old_path += 2;
594          new_path += 2;
595     }
596     else
597          current = &cwd_tree;
598     
599     (void) strcpy(next_old, firstpart(old_path, rest_old));
600     (void) strcpy(next_new, firstpart(new_path, rest_new));
601     while (*next_old && *next_new) {
602          retval = find_child(current, next_old, &current);
603          if (retval == DIR_MATCH) {
604               if (current) {
605                    (void) strcpy(current->name, next_new);
606                    current->specified = False;
607               }
608               else {
609                    set_error(INTERNAL_ERROR);
610                    error("change_path");
611                    return error_code;
612               }
613          }
614          else {
615               error("change_path");
616               return retval;
617          }
618         
619          (void) strcpy(next_old, firstpart(rest_old, rest_old));
620          (void) strcpy(next_new, firstpart(rest_new, rest_new));
621     }
622     return 0;
623}
624
625
626int get_leaf_path(filerec *leaf,
627                  char leaf_buf[]) /* RETURN */
628{
629     char *name_ptr;
630
631     name_ptr = Malloc(1);
632     if (! name_ptr) {
633          set_error(errno);
634          error("Malloc");
635          *leaf_buf = '\0';
636          return error_code;
637     }
638     *name_ptr = '\0';
639     do {
640          name_ptr = realloc((char *) name_ptr, (unsigned)
641                             (strlen(leaf->name) + strlen(name_ptr) + 2));
642          if (! name_ptr) {
643               set_error(errno);
644               *leaf_buf = '\0';
645               error("realloc");
646               return error_code;
647          }
648          (void) strcpy(leaf_buf, name_ptr);
649          *name_ptr = '\0';
650          if (leaf->parent) if (leaf->parent->parent)
651               (void) strcat(name_ptr, "/");
652          (void) strcat(name_ptr, leaf->name);
653          (void) strcat(name_ptr, leaf_buf);
654          leaf = leaf->parent;
655     } while (leaf);
656     (void) strcpy(leaf_buf, name_ptr);
657     return 0;
658}
659
660
661
662
663
664int accumulate_names(leaf, in_strings, num)
665filerec *leaf;
666char ***in_strings;
667int *num;
668{
669     char **strings;
670     int retval;
671     
672     strings = *in_strings;
673     if (leaf->specified) {
674          /*
675           * This array is static so that only one copy of it is allocated,
676           * rather than one copy on the stack for each recursive
677           * invocation of accumulate_names.
678           */
679          static char newname[MAXPATHLEN];
680
681          *num += 1;
682          strings = (char **) realloc((char *) strings, (unsigned)
683                                      (sizeof(char *) * (*num)));
684          if (! strings) {
685               set_error(errno);
686               error("realloc");
687               return error_code;
688          }
689          if ((retval = get_leaf_path(leaf, newname))) {
690               error("get_leaf_path");
691               return retval;
692          }
693          (void) convert_to_user_name(newname, newname);
694          strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
695          if (! strings[*num - 1]) {
696               set_error(errno);
697               error("Malloc");
698               return error_code;
699          }
700          (void) strcpy(strings[*num - 1], newname);
701     }
702     if (leaf->files && (retval = accumulate_names(leaf->files, &strings,
703                                                   num))) {
704          error("accumulate_names");
705          return retval;
706     }
707     if (leaf->dirs && (retval = accumulate_names(leaf->dirs, &strings,
708                                                  num))) {
709          error("accumulate_names");
710          return retval;
711     }
712     if (leaf->next && (retval = accumulate_names(leaf->next, &strings,
713                                                  num))) {
714          error("accumulate_names");
715          return retval;
716     }
717
718     *in_strings = strings;
719     return 0;
720}
721
722char *bytes_to_friendly(off_t bytes)
723{
724  double size = bytes;
725  char *output;
726
727  size /= 1024;
728  if (size < 1024) {
729    if (! (output = malloc(7))) {
730      set_error(errno);
731      error("malloc");
732      return "";
733    }
734    sprintf(output, "%.0fKB", ceil(size));
735    return(output);
736  }
737  size /= 1024;
738  if (size < 1024) {
739    if (! (output = malloc(9))) {
740      set_error(errno);
741      error("malloc");
742      return "";
743    }
744    sprintf(output, "%.1fMB", size);
745    return(output);
746  }
747  size /= 1024;
748  if (! (output = malloc((int)log10(size)+6))) {
749    set_error(errno);
750    error("malloc");
751    return "";
752  }
753  sprintf(output, "%.2fGB", size);
754  return(output);
755}
Note: See TracBrowser for help on using the repository browser.