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.
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
[23661]12#include <math.h>
[2181]13#include <stdio.h>
[1679]14#include <sys/types.h>
15#include <sys/param.h>
[5049]16#include <dirent.h>
[3049]17#include <string.h>
[10977]18#include <time.h>
[2181]19#include <errno.h>
20#include <com_err.h>
21#include "delete_errs.h"
[4415]22#include "directories.h"
[4505]23#include "mit-copying.h"
[2181]24#include "errors.h"
[24908]25#include "util.h"
[1679]26
27static filerec root_tree;
28static filerec cwd_tree;
29
[24908]30void free_leaf(filerec *leaf);
31static int get_specs(char *path,
32                     struct mystat *specs,
33                     int follow);
[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);
[24908]110     if ((retval = get_specs(".", &cwd_tree.specs, FOLLOW_LINKS))) {
[2181]111          error("get_specs on .");
112          return retval;
[1679]113     }
[24908]114     if ((retval = get_specs("/", &root_tree.specs, FOLLOW_LINKS))) {
[2181]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     
[24908]132     if ((retval = get_specs(path, &specs, DONT_FOLLOW_LINKS))) {
[2181]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);
[24908]161          if ((retval = add_directory_to_parent(parent, next_name, False,
162                                                &parent))) {
[2181]163               error("add_directory_to_parent");
164               return retval;
165          }
166          (void) strcpy(next_name, firstpart(ptr, ptr));
[24908]167          if ((retval = get_specs(built_path, &parent->specs, FOLLOW_LINKS))) {
[2181]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
[24908]198static int get_specs(char *path,
199                     struct mystat *specs,
200                     int follow) /* follow symlinks or not? */
[1679]201{
[1732]202     int status;
[4422]203     struct stat realspecs;
[1679]204     
[1732]205     if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
206                           (strlen(path) != 1))
[1679]207          path[strlen(path) - 1] = '\0';
[1732]208     if (follow == FOLLOW_LINKS)
[4422]209          status = stat(path, &realspecs);
[1732]210     else
[4422]211          status = lstat(path, &realspecs);
[1732]212
[2181]213     if (status) {
214          set_error(errno);
215          error(path);
216          return error_code;
217     }
218
[4422]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;
[23665]223     specs->st_ctim = realspecs.st_ctime;
[4422]224
[2181]225     return 0;
[1679]226}
227
228
229
230filerec *next_leaf(leaf)
231filerec *leaf;
232{
[1684]233     filerec *new;
[1732]234
235     if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
[1684]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     }
[1679]246}
247
248
249filerec *next_specified_leaf(leaf)
250filerec *leaf;
251{
[24908]252  while ((leaf = next_leaf(leaf))) {
253    if (leaf->specified)
254      return(leaf);
255  }
256  return((filerec *) NULL);
[1679]257}
258
259
260filerec *next_directory(leaf)
261filerec *leaf;
262{
[1684]263     filerec *ret;
[1732]264     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
[1679]265          leaf = leaf->parent;
266     if (leaf)
[1684]267          ret = leaf->next;
[1679]268     else
[1684]269          ret = (filerec *) NULL;
270     if (ret) if (ret->freed)
271          ret = next_directory(ret);
272     return(ret);
[1679]273}
274
275
276filerec *next_specified_directory(leaf)
277filerec *leaf;
278{
[24908]279  while ((leaf = next_directory(leaf))) {
280    if (leaf->specified)
281      return(leaf);
282  }
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{
[24908]310  while ((leaf = next_in_directory(leaf))) {
311    if (leaf->specified)
312      return(leaf);
313  }
314  return ((filerec *) NULL);
[1679]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
[24908]353/* This is a debugging function not actually used anywhere in any program. */
[2221]354void print_paths_from(leaf)
[1679]355filerec *leaf;
356{
[6420]357     /*
358      * This is static to prevent multiple copies of it when calling
359      * recursively.
360      */
361     static char buf[MAXPATHLEN];
[1732]362
[24908]363     if (! get_leaf_path(leaf, buf)) {
364       printf("%s\n", buf);
365     }
366     else {
367       error("get_leaf_path");
368     }
[1679]369     if (leaf->dirs)
[1684]370          print_paths_from(leaf->dirs);
[1679]371     if (leaf->files)
[1684]372          print_paths_from(leaf->files);
[1679]373     if (leaf->next)
[1684]374          print_paths_from(leaf->next);
[1679]375}
376
377
[24908]378/* This is a debugging function not actually used anywhere in any program. */
[2221]379void print_specified_paths_from(leaf)
[1679]380filerec *leaf;
381{
[6420]382     /*
383      * This is static to prevent multiple copies of it when calling
384      * recursively.
385      */
386     static char buf[MAXPATHLEN];
[1732]387
[24908]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     }
[1679]396     if (leaf->dirs)
[1684]397          print_specified_paths_from(leaf->dirs);
[1679]398     if (leaf->files)
[1684]399          print_specified_paths_from(leaf->files);
[1679]400     if (leaf->next)
[1684]401          print_specified_paths_from(leaf->next);
[1679]402}
403     
404
[2181]405int add_file_to_parent(parent, name, specified, last)
406filerec *parent, **last;
[1679]407char *name;
[1684]408Boolean specified;
[1679]409{
[2181]410     filerec *files;
[1732]411
[2181]412     *last = files = (filerec *) NULL;
[1679]413     files = parent->files;
414     while (files) {
415          if (! strcmp(files->name, name))
416               break;
[2181]417          *last = files;
[1679]418          files = files->next;
419     }
420     if (files) {
421          files->specified = (files->specified || specified);
[2181]422          *last = files;
423          return 0;
[1679]424     }
[2181]425     if (*last) {
[2367]426          (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
[2181]427          if (! (*last)->next) {
428               set_error(errno);
[2367]429               error("Malloc");
[2181]430               return error_code;
431          }
432          *(*last)->next = default_file;
433          (*last)->next->previous = *last;
434          (*last)->next->parent = parent;
435          (*last) = (*last)->next;
[1679]436     }
437     else {
[2367]438          parent->files = (filerec *) Malloc(sizeof(filerec));
[2181]439          if (! parent->files) {
440               set_error(errno);
[2367]441               error("Malloc");
[2181]442               return error_code;
443          }
[1679]444          *parent->files = default_file;
445          parent->files->parent = parent;
446          parent->files->previous = (filerec *) NULL;
[2181]447          *last = parent->files;
[1679]448     }
[2181]449     (void) strcpy((*last)->name, name);
450     (*last)->specified = specified;
451     return 0;
[1679]452}
453
454
455
456
457
[2181]458int add_directory_to_parent(parent, name, specified, last)
459filerec *parent, **last;
[1679]460char *name;
[1684]461Boolean specified;
[1679]462{
[2181]463     filerec *directories;
[1732]464
[2181]465     *last = (filerec *) NULL;
[1679]466     directories = parent->dirs;
467     while (directories) {
468          if (! strcmp(directories->name, name))
469               break;
[2181]470          (*last) = directories;
[1679]471          directories = directories->next;
472     }
473     if (directories) {
474          directories->specified = (directories->specified || specified);
[2181]475          *last = directories;
476          return 0;
[1679]477     }
[2181]478     if (*last) {
[2367]479          (*last)->next = (filerec *) Malloc(sizeof(filerec));
[2181]480          if (! (*last)->next) {
481               set_error(errno);
[2367]482               error("Malloc");
[2181]483               return error_code;
484          }
485          *(*last)->next = default_directory;
486          (*last)->next->previous = *last;
487          (*last)->next->parent = parent;
488          (*last) = (*last)->next;
[1679]489     }
490     else {
[2367]491          parent->dirs = (filerec *) Malloc(sizeof(filerec));
[2181]492          if (! parent->dirs) {
493               set_error(errno);
[2367]494               error("Malloc");
[2181]495               return error_code;
496          }
[1679]497          *parent->dirs = default_directory;
498          parent->dirs->parent = parent;
499          parent->dirs->previous = (filerec *) NULL;
[2181]500          (*last) = parent->dirs;
[1679]501     }
[2181]502     (void) strcpy((*last)->name, name);
503     (*last)->specified = specified;
504     return 0;
[1679]505}
506
507
508
509
510
[24908]511void free_leaf(filerec *leaf)
[1679]512{
513     leaf->freed = True;
[1684]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;
[1752]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)
[2221]524                              free_leaf(leaf->parent);
[1752]525                    }
[1684]526               }
[1752]527               else {
528                    if (leaf->parent->files == leaf) {
529                         leaf->parent->files = leaf->next;
530                         if (leaf->parent->freed)
[2221]531                              free_leaf(leaf->parent);
[1752]532                    }
[1684]533               }
[2181]534               free((char *) leaf);
[1684]535          }
536     }
[1679]537}     
538
539
540
[2181]541int find_child(directory, name, child)
542filerec *directory, **child;
[1679]543char *name;
544{
545     filerec *ptr;
[2181]546     
547     *child = (filerec *) NULL;
[1732]548     if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
[2181]549          return DIR_NOT_DIRECTORY;
[1679]550     ptr = directory->dirs;
551     while (ptr)
552          if (strcmp(ptr->name, name))
553               ptr = ptr->next;
554          else
555               break;
[2181]556     if (ptr) {
557          *child = ptr;
558          return DIR_MATCH;
559     }
[1679]560     ptr = directory->files;
561     while (ptr)
562          if (strcmp(ptr->name, name))
563               ptr = ptr->next;
564          else
565               break;
[2181]566     if (ptr) {
567          *child = ptr;
568          return DIR_MATCH;
569     }
570     set_status(DIR_NO_MATCH);
571     return DIR_NO_MATCH;
[1679]572}
573
[1732]574
575
576
577
[2181]578int change_path(old_path, new_path)
[1679]579char *old_path, *new_path;
580{
581     char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
582     char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
[2181]583     int retval;
[1679]584     filerec *current;
[2181]585     
[1679]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;
[2181]598     
599     (void) strcpy(next_old, firstpart(old_path, rest_old));
600     (void) strcpy(next_new, firstpart(new_path, rest_new));
[1679]601     while (*next_old && *next_new) {
[2181]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));
[1679]621     }
[2181]622     return 0;
[1679]623}
624
625
[24908]626int get_leaf_path(filerec *leaf,
627                  char leaf_buf[]) /* RETURN */
[1679]628{
629     char *name_ptr;
630
[2367]631     name_ptr = Malloc(1);
[1732]632     if (! name_ptr) {
[2181]633          set_error(errno);
[2367]634          error("Malloc");
[1732]635          *leaf_buf = '\0';
[2181]636          return error_code;
[1732]637     }
[1679]638     *name_ptr = '\0';
639     do {
[2181]640          name_ptr = realloc((char *) name_ptr, (unsigned)
641                             (strlen(leaf->name) + strlen(name_ptr) + 2));
[1732]642          if (! name_ptr) {
[2181]643               set_error(errno);
[1732]644               *leaf_buf = '\0';
[2181]645               error("realloc");
646               return error_code;
[1732]647          }
[2181]648          (void) strcpy(leaf_buf, name_ptr);
[1679]649          *name_ptr = '\0';
[1713]650          if (leaf->parent) if (leaf->parent->parent)
[2181]651               (void) strcat(name_ptr, "/");
652          (void) strcat(name_ptr, leaf->name);
653          (void) strcat(name_ptr, leaf_buf);
[1679]654          leaf = leaf->parent;
655     } while (leaf);
[2181]656     (void) strcpy(leaf_buf, name_ptr);
657     return 0;
[1679]658}
[1732]659
660
661
662
663
[2181]664int accumulate_names(leaf, in_strings, num)
[1732]665filerec *leaf;
[2181]666char ***in_strings;
[1732]667int *num;
668{
[2181]669     char **strings;
670     int retval;
[1732]671     
[2181]672     strings = *in_strings;
[1732]673     if (leaf->specified) {
[6420]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
[1732]681          *num += 1;
[2181]682          strings = (char **) realloc((char *) strings, (unsigned)
683                                      (sizeof(char *) * (*num)));
[1732]684          if (! strings) {
[2181]685               set_error(errno);
686               error("realloc");
687               return error_code;
[1732]688          }
[24908]689          if ((retval = get_leaf_path(leaf, newname))) {
[2181]690               error("get_leaf_path");
691               return retval;
692          }
[2221]693          (void) convert_to_user_name(newname, newname);
[2367]694          strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
[1732]695          if (! strings[*num - 1]) {
[2181]696               set_error(errno);
[2367]697               error("Malloc");
[2181]698               return error_code;
[1732]699          }
[2181]700          (void) strcpy(strings[*num - 1], newname);
[1732]701     }
[24908]702     if (leaf->files && (retval = accumulate_names(leaf->files, &strings,
703                                                   num))) {
[2181]704          error("accumulate_names");
705          return retval;
706     }
[24908]707     if (leaf->dirs && (retval = accumulate_names(leaf->dirs, &strings,
708                                                  num))) {
[2181]709          error("accumulate_names");
710          return retval;
711     }
[24908]712     if (leaf->next && (retval = accumulate_names(leaf->next, &strings,
713                                                  num))) {
[2181]714          error("accumulate_names");
715          return retval;
716     }
[1732]717
[2181]718     *in_strings = strings;
719     return 0;
[1732]720}
[23661]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.