home *** CD-ROM | disk | FTP | other *** search
/ The UNIX CD Bookshelf / OREILLY_TUCB_UNIX_CD.iso / upt / examples / SOURCES / DELETE / PART03.Z / PART03 / directories.c < prev   
Encoding:
C/C++ Source or Header  |  1998-07-24  |  14.8 KB  |  711 lines

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