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

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