home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume22 / undel2 / part03 / directories.c < prev    next >
C/C++ Source or Header  |  1990-06-07  |  15KB  |  693 lines

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