home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / tar-1.11.8-src.tgz / tar.out / fsf / tar / src / gnu.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  15KB  |  692 lines

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