home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / unix / unixports / tarsrc / tar1112 / c / gnu < prev    next >
Text File  |  1994-02-07  |  14KB  |  682 lines

  1. /* GNU dump extensions to tar.
  2.    Copyright (C) 1988, 1992, 1993 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <stdio.h>
  21. #include <sys/types.h>
  22. #include <ctype.h>
  23. #include <errno.h>
  24. #ifndef STDC_HEADERS
  25. extern int errno;
  26. #endif
  27. #include <time.h>
  28. time_t time ();
  29.  
  30. #include "tar.h"
  31. #include "port.h"
  32.  
  33. #ifndef S_ISLNK
  34. #define lstat stat
  35. #endif
  36.  
  37. extern time_t new_time;
  38. extern FILE *msg_file;
  39.  
  40. void addname ();
  41. int check_exclude ();
  42. extern PTR ck_malloc ();
  43. extern PTR ck_realloc ();
  44. int confirm ();
  45. extern PTR init_buffer ();
  46. extern char *get_buffer ();
  47. int is_dot_or_dotdot ();
  48. extern void add_buffer ();
  49. extern void flush_buffer ();
  50. void name_gather ();
  51. int recursively_delete ();
  52. void skip_file ();
  53. char *un_quote_string ();
  54.  
  55. extern char *new_name ();
  56.  
  57. static void add_dir_name ();
  58.  
  59. struct dirname
  60.   {
  61.     struct dirname *next;
  62.     char *name;
  63.     char *dir_text;
  64.     int dev;
  65.     int ino;
  66.     int allnew;
  67.   };
  68. static struct dirname *dir_list;
  69. static time_t this_time;
  70.  
  71. void
  72. add_dir (name, dev, ino, text)
  73.      char *name;
  74.      char *text;
  75.      dev_t dev;
  76.      ino_t ino;
  77. {
  78.   struct dirname *dp;
  79.  
  80.   dp = (struct dirname *) ck_malloc (sizeof (struct dirname));
  81.   if (!dp)
  82.     abort ();
  83.   dp->next = dir_list;
  84.   dir_list = dp;
  85.   dp->dev = dev;
  86.   dp->ino = ino;
  87.   dp->name = ck_malloc (strlen (name) + 1);
  88.   strcpy (dp->name, name);
  89.   dp->dir_text = text;
  90.   dp->allnew = 0;
  91. }
  92.  
  93. void
  94. read_dir_file ()
  95. {
  96.   int dev;
  97.   int ino;
  98.   char *strp;
  99.   FILE *fp;
  100.   char buf[512];
  101.   static char *path = 0;
  102.  
  103.   if (path == 0)
  104.     path = ck_malloc (PATH_MAX);
  105.   time (&this_time);
  106.   if (gnu_dumpfile[0] != '/')
  107.     {
  108. #if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
  109.       if (!getcwd (path, PATH_MAX))
  110.     {
  111.       msg ("Couldn't get current directory.");
  112.       exit (EX_SYSTEM);
  113.     }
  114. #else
  115.       char *getwd ();
  116.  
  117.       if (!getwd (path))
  118.     {
  119.       msg ("Couldn't get current directory: %s", path);
  120.       exit (EX_SYSTEM);
  121.     }
  122. #endif
  123.       /* If this doesn't fit, we're in serious trouble */
  124.       strcat (path, "/");
  125.       strcat (path, gnu_dumpfile);
  126.       gnu_dumpfile = path;
  127.     }
  128.   fp = fopen (gnu_dumpfile, "r");
  129.   if (fp == 0 && errno != ENOENT)
  130.     {
  131.       msg_perror ("Can't open %s", gnu_dumpfile);
  132.       return;
  133.     }
  134.   if (!fp)
  135.     return;
  136.   fgets (buf, sizeof (buf), fp);
  137.   if (!f_new_files)
  138.     {
  139.       f_new_files++;
  140.       new_time = atol (buf);
  141.     }
  142.   while (fgets (buf, sizeof (buf), fp))
  143.     {
  144.       strp = &buf[strlen (buf)];
  145.       if (strp[-1] == '\n')
  146.     strp[-1] = '\0';
  147.       strp = buf;
  148.       dev = atol (strp);
  149.       while (isdigit (*strp))
  150.     strp++;
  151.       ino = atol (strp);
  152.       while (isspace (*strp))
  153.     strp++;
  154.       while (isdigit (*strp))
  155.     strp++;
  156.       strp++;
  157.       add_dir (un_quote_string (strp), dev, ino, (char *) 0);
  158.     }
  159.   fclose (fp);
  160. }
  161.  
  162. void
  163. write_dir_file ()
  164. {
  165.   FILE *fp;
  166.   struct dirname *dp;
  167.   char *str;
  168.   extern char *quote_copy_string ();
  169.  
  170.   fp = fopen (gnu_dumpfile, "w");
  171.   if (fp == 0)
  172.     {
  173.       msg_perror ("Can't write to %s", gnu_dumpfile);
  174.       return;
  175.     }
  176.   fprintf (fp, "%lu\n", this_time);
  177.   for (dp = dir_list; dp; dp = dp->next)
  178.     {
  179.       if (!dp->dir_text)
  180.     continue;
  181.       str = quote_copy_string (dp->name);
  182.       if (str)
  183.     {
  184.       fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str);
  185.       free (str);
  186.     }
  187.       else
  188.     fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name);
  189.     }
  190.   fclose (fp);
  191. }
  192.  
  193. struct dirname *
  194. get_dir (name)
  195.      char *name;
  196. {
  197.   struct dirname *dp;
  198.  
  199.   for (dp = dir_list; dp; dp = dp->next)
  200.     {
  201.       if (!strcmp (dp->name, name))
  202.     return dp;
  203.     }
  204.   return 0;
  205. }
  206.  
  207.  
  208. /* Collect all the names from argv[] (or whatever), then expand them into
  209.    a directory tree, and put all the directories at the beginning. */
  210. void
  211. collect_and_sort_names ()
  212. {
  213.   struct name *n, *n_next;
  214.   int num_names;
  215.   struct stat statbuf;
  216.   int name_cmp ();
  217.   char *merge_sort ();
  218.  
  219.   name_gather ();
  220.  
  221.   if (gnu_dumpfile)
  222.     read_dir_file ();
  223.   if (!namelist)
  224.     addname (".");
  225.   for (n = namelist; n; n = n_next)
  226.     {
  227.       n_next = n->next;
  228.       if (n->found || n->dir_contents)
  229.     continue;
  230.       if (n->regexp)        /* FIXME just skip regexps for now */
  231.     continue;
  232.       if (n->change_dir)
  233.     if (chdir (n->change_dir) < 0)
  234.       {
  235.         msg_perror ("can't chdir to %s", n->change_dir);
  236.         continue;
  237.       }
  238.  
  239. #ifdef AIX
  240.       if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK))
  241. #else
  242.       if (lstat (n->name, &statbuf) < 0)
  243. #endif /* AIX */
  244.     {
  245.       msg_perror ("can't stat %s", n->name);
  246.       continue;
  247.     }
  248.       if (S_ISDIR (statbuf.st_mode))
  249.     {
  250.       n->found++;
  251.       add_dir_name (n->name, statbuf.st_dev);
  252.     }
  253.     }
  254.  
  255.   num_names = 0;
  256.   for (n = namelist; n; n = n->next)
  257.     num_names++;
  258.   namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp);
  259.  
  260.   for (n = namelist; n; n = n->next)
  261.     {
  262.       n->found = 0;
  263.     }
  264.   if (gnu_dumpfile)
  265.     write_dir_file ();
  266. }
  267.  
  268. int
  269. name_cmp (n1, n2)
  270.      struct name *n1, *n2;
  271. {
  272.   if (n1->found)
  273.     {
  274.       if (n2->found)
  275.     return strcmp (n1->name, n2->name);
  276.       else
  277.     return -1;
  278.     }
  279.   else if (n2->found)
  280.     return 1;
  281.   else
  282.     return strcmp (n1->name, n2->name);
  283. }
  284.  
  285. int
  286. dirent_cmp (p1, p2)
  287.      const PTR p1;
  288.      const PTR p2;
  289. {
  290.   char *frst, *scnd;
  291.  
  292.   frst = (*(char **) p1) + 1;
  293.   scnd = (*(char **) p2) + 1;
  294.  
  295.   return strcmp (frst, scnd);
  296. }
  297.  
  298. char *
  299. get_dir_contents (p, device)
  300.      char *p;
  301.      int device;
  302. {
  303.   DIR *dirp;
  304.   register struct dirent *d;
  305.   char *new_buf;
  306.   char *namebuf;
  307.   int bufsiz;
  308.   int len;
  309.   PTR the_buffer;
  310.   char *buf;
  311.   size_t n_strs;
  312.   /*    int n_size;*/
  313.   char *p_buf;
  314.   char **vec, **p_vec;
  315.  
  316. #ifdef ARCH
  317.   extern volatile int errno;
  318. #else
  319.   extern int errno;
  320. #endif
  321.  
  322.   errno = 0;
  323.   dirp = opendir (p);
  324.   bufsiz = strlen (p) + NAMSIZ;
  325.   namebuf = ck_malloc (bufsiz + 2);
  326.   if (!dirp)
  327.     {
  328.       if (errno)
  329.     msg_perror ("can't open directory %s", p);
  330.       else
  331.     msg ("error opening directory %s", p);
  332.       new_buf = NULL;
  333.     }
  334.   else
  335.     {
  336.       struct dirname *dp;
  337.       int all_children;
  338.  
  339.       dp = get_dir (p);
  340.       all_children = dp ? dp->allnew : 0;
  341.       (void) strcpy (namebuf, p);
  342.       if (p[strlen (p) - 1] != '/')
  343.     (void) strcat (namebuf, "/");
  344.       len = strlen (namebuf);
  345.  
  346.       the_buffer = init_buffer ();
  347.       while (d = readdir (dirp))
  348.     {
  349.       struct stat hs;
  350.  
  351.       /* Skip . and .. */
  352.       if (is_dot_or_dotdot (d->d_name))
  353.         continue;
  354.       if (NLENGTH (d) + len >= bufsiz)
  355.         {
  356.           bufsiz += NAMSIZ;
  357.           namebuf = ck_realloc (namebuf, bufsiz + 2);
  358.         }
  359.       (void) strcpy (namebuf + len, d->d_name);
  360. #ifdef AIX
  361.       if (0 != f_follow_links ?
  362.           statx (namebuf, &hs, STATSIZE, STX_HIDDEN) :
  363.           statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK))
  364. #else
  365.       if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs))
  366. #endif
  367.         {
  368.           msg_perror ("can't stat %s", namebuf);
  369.           continue;
  370.         }
  371.       if ((f_local_filesys && device != hs.st_dev)
  372.           || (f_exclude && check_exclude (namebuf)))
  373.         add_buffer (the_buffer, "N", 1);
  374. #ifdef AIX
  375.       else if (S_ISHIDDEN (hs.st_mode))
  376.         {
  377.           add_buffer (the_buffer, "D", 1);
  378.           strcat (d->d_name, "A");
  379.           d->d_namlen++;
  380.         }
  381. #endif /* AIX */
  382.       else if (S_ISDIR (hs.st_mode))
  383.         {
  384.           if (dp = get_dir (namebuf))
  385.         {
  386.           if (dp->dev != hs.st_dev
  387.               || dp->ino != hs.st_ino)
  388.             {
  389.               if (f_verbose)
  390.             msg ("directory %s has been renamed.", namebuf);
  391.               dp->allnew = 1;
  392.               dp->dev = hs.st_dev;
  393.               dp->ino = hs.st_ino;
  394.             }
  395.           dp->dir_text = "";
  396.         }
  397.           else
  398.         {
  399.           if (f_verbose)
  400.             msg ("Directory %s is new", namebuf);
  401.           add_dir (namebuf, hs.st_dev, hs.st_ino, "");
  402.           dp = get_dir (namebuf);
  403.           dp->allnew = 1;
  404.         }
  405.           if (all_children)
  406.         dp->allnew = 1;
  407.  
  408.           add_buffer (the_buffer, "D", 1);
  409.         }
  410.       else if (!all_children
  411.            && f_new_files
  412.            && new_time > hs.st_mtime
  413.            && (f_new_files > 1
  414.                || new_time > hs.st_ctime))
  415.         add_buffer (the_buffer, "N", 1);
  416.       else
  417.         add_buffer (the_buffer, "Y", 1);
  418.       add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  419.     }
  420.       add_buffer (the_buffer, "\000\000", 2);
  421.       closedir (dirp);
  422.  
  423.       /* Well, we've read in the contents of the dir, now sort them */
  424.       buf = get_buffer (the_buffer);
  425.       if (buf[0] == '\0')
  426.     {
  427.       flush_buffer (the_buffer);
  428.       new_buf = NULL;
  429.     }
  430.       else
  431.     {
  432.       n_strs = 0;
  433.       for (p_buf = buf; *p_buf;)
  434.         {
  435.           int tmp;
  436.  
  437.           tmp = strlen (p_buf) + 1;
  438.           n_strs++;
  439.           p_buf += tmp;
  440.         }
  441.       vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1));
  442.       for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1)
  443.         *p_vec++ = p_buf;
  444.       *p_vec = 0;
  445.       qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp);
  446.       new_buf = (char *) ck_malloc (p_buf - buf + 2);
  447.       for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++)
  448.         {
  449.           char *p_tmp;
  450.  
  451.           for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;)
  452.         ;
  453.         }
  454.       *p_buf++ = '\0';
  455.       free (vec);
  456.       flush_buffer (the_buffer);
  457.     }
  458.     }
  459.   free (namebuf);
  460.   return new_buf;
  461. }
  462.  
  463. /* p is a directory.  Add all the files in P to the namelist.  If any of the
  464.    files is a directory, recurse on the subdirectory. . . */
  465. static void
  466. add_dir_name (p, device)
  467.      char *p;
  468.      int device;
  469. {
  470.   char *new_buf;
  471.   char *p_buf;
  472.  
  473.   char *namebuf;
  474.   int buflen;
  475.   register int len;
  476.   int sublen;
  477.  
  478.   /*    PTR the_buffer;*/
  479.  
  480.   /*    char *buf;*/
  481.   /*    char **vec,**p_vec;*/
  482.   /*    int n_strs,n_size;*/
  483.  
  484.   struct name *n;
  485.  
  486.   int dirent_cmp ();
  487.  
  488.   new_buf = get_dir_contents (p, device);
  489.  
  490.   for (n = namelist; n; n = n->next)
  491.     {
  492.       if (!strcmp (n->name, p))
  493.     {
  494.       n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
  495.       break;
  496.     }
  497.     }
  498.  
  499.   if (new_buf)
  500.     {
  501.       len = strlen (p);
  502.       buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ;
  503.       namebuf = ck_malloc (buflen + 1);
  504.  
  505.       (void) strcpy (namebuf, p);
  506.       if (namebuf[len - 1] != '/')
  507.     {
  508.       namebuf[len++] = '/';
  509.       namebuf[len] = '\0';
  510.     }
  511.       for (p_buf = new_buf; *p_buf; p_buf += sublen + 1)
  512.     {
  513.       sublen = strlen (p_buf);
  514.       if (*p_buf == 'D')
  515.         {
  516.           if (len + sublen >= buflen)
  517.         {
  518.           buflen += NAMSIZ;
  519.           namebuf = ck_realloc (namebuf, buflen + 1);
  520.         }
  521.           (void) strcpy (namebuf + len, p_buf + 1);
  522.           addname (namebuf);
  523.           add_dir_name (namebuf, device);
  524.         }
  525.     }
  526.       free (namebuf);
  527.     }
  528. }
  529.  
  530. /* Returns non-zero if p is . or ..   This could be a macro for speed. */
  531. int
  532. is_dot_or_dotdot (p)
  533.      char *p;
  534. {
  535.   return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')));
  536. }
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543. void
  544. gnu_restore (skipcrud)
  545.      int skipcrud;
  546. {
  547.   char *current_dir;
  548.   /*    int current_dir_length; */
  549.  
  550.   char *archive_dir;
  551.   /*    int archive_dir_length; */
  552.   PTR the_buffer;
  553.   char *p;
  554.   DIR *dirp;
  555.   struct dirent *d;
  556.   char *cur, *arc;
  557.   extern struct stat hstat;    /* Stat struct corresponding */
  558.   long size, copied;
  559.   char *from, *to;
  560.   extern union record *head;
  561.  
  562.   dirp = opendir (skipcrud + current_file_name);
  563.  
  564.   if (!dirp)
  565.     {
  566.       /* The directory doesn't exist now.  It'll be created.
  567.                In any case, we don't have to delete any files out
  568.                of it */
  569.       skip_file ((long) hstat.st_size);
  570.       return;
  571.     }
  572.  
  573.   the_buffer = init_buffer ();
  574.   while (d = readdir (dirp))
  575.     {
  576.       if (is_dot_or_dotdot (d->d_name))
  577.     continue;
  578.  
  579.       add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  580.     }
  581.   closedir (dirp);
  582.   add_buffer (the_buffer, "", 1);
  583.  
  584.   current_dir = get_buffer (the_buffer);
  585.   archive_dir = (char *) ck_malloc (hstat.st_size);
  586.   if (archive_dir == 0)
  587.     {
  588.       msg ("Can't allocate %d bytes for restore", hstat.st_size);
  589.       skip_file ((long) hstat.st_size);
  590.       return;
  591.     }
  592.   to = archive_dir;
  593.   for (size = hstat.st_size; size > 0; size -= copied)
  594.     {
  595.       from = findrec ()->charptr;
  596.       if (!from)
  597.     {
  598.       msg ("Unexpected EOF in archive\n");
  599.       break;
  600.     }
  601.       copied = endofrecs ()->charptr - from;
  602.       if (copied > size)
  603.     copied = size;
  604.       bcopy ((PTR) from, (PTR) to, (int) copied);
  605.       to += copied;
  606.       userec ((union record *) (from + copied - 1));
  607.     }
  608.  
  609.   for (cur = current_dir; *cur; cur += strlen (cur) + 1)
  610.     {
  611.       for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
  612.     {
  613.       arc++;
  614.       if (!strcmp (arc, cur))
  615.         break;
  616.     }
  617.       if (*arc == '\0')
  618.     {
  619.       p = new_name (skipcrud + current_file_name, cur);
  620.       if (f_confirm && !confirm ("delete", p))
  621.         {
  622.           free (p);
  623.           continue;
  624.         }
  625.       if (f_verbose)
  626.         fprintf (msg_file, "%s: deleting %s\n", tar, p);
  627.       if (recursively_delete (p))
  628.         {
  629.           msg ("%s: Error while deleting %s\n", tar, p);
  630.         }
  631.       free (p);
  632.     }
  633.  
  634.     }
  635.   flush_buffer (the_buffer);
  636.   free (archive_dir);
  637. }
  638.  
  639. int
  640. recursively_delete (path)
  641.      char *path;
  642. {
  643.   struct stat sbuf;
  644.   DIR *dirp;
  645.   struct dirent *dp;
  646.   char *path_buf;
  647.   /* int path_len; */
  648.  
  649.  
  650.   if (lstat (path, &sbuf) < 0)
  651.     return 1;
  652.   if (S_ISDIR (sbuf.st_mode))
  653.     {
  654.  
  655.       /* path_len=strlen(path); */
  656.       dirp = opendir (path);
  657.       if (dirp == 0)
  658.     return 1;
  659.       while (dp = readdir (dirp))
  660.     {
  661.       if (is_dot_or_dotdot (dp->d_name))
  662.         continue;
  663.       path_buf = new_name (path, dp->d_name);
  664.       if (recursively_delete (path_buf))
  665.         {
  666.           free (path_buf);
  667.           closedir (dirp);
  668.           return 1;
  669.         }
  670.       free (path_buf);
  671.     }
  672.       closedir (dirp);
  673.  
  674.       if (rmdir (path) < 0)
  675.     return 1;
  676.       return 0;
  677.     }
  678.   if (unlink (path) < 0)
  679.     return 1;
  680.   return 0;
  681. }
  682.