home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Workbench / Archivers / AmiGNUtar.lha / AmiGNUtar / src.lha / src / extract.c < prev    next >
C/C++ Source or Header  |  1996-04-19  |  25KB  |  951 lines

  1. /* Extract files from a tar archive.
  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. /*
  21.  * Extract files from a tar archive.
  22.  *
  23.  * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <errno.h>
  28. #ifndef STDC_HEADERS
  29. extern int errno;
  30. #endif
  31. #include <sys/types.h>
  32. #include <time.h>
  33. time_t time ();
  34.  
  35. #ifdef BSD42
  36. #include <sys/file.h>
  37. #else
  38. #ifndef V7
  39. #include <fcntl.h>
  40. #endif
  41. #endif
  42.  
  43. #ifdef NO_OPEN3
  44. /* We need the #define's even though we don't use them. */
  45. #include "open3.h"
  46. #endif
  47.  
  48. #ifdef EMUL_OPEN3
  49. /* Simulated 3-argument open for systems that don't have it */
  50. #include "open3.h"
  51. #endif
  52.  
  53. #include "tar.h"
  54. #include "port.h"
  55.  
  56. #if defined(_POSIX_VERSION)
  57. #include <utime.h>
  58. #else
  59. struct utimbuf
  60. {
  61.   long actime;
  62.   long modtime;
  63. };
  64.  
  65. #endif
  66.  
  67. extern FILE *msg_file;
  68.  
  69. extern union record *head;    /* Points to current tape header */
  70. extern struct stat hstat;    /* Stat struct corresponding */
  71. extern int head_standard;    /* Tape header is in ANSI format */
  72.  
  73. extern char *save_name;
  74. extern long save_totsize;
  75. extern long save_sizeleft;
  76.  
  77. int confirm ();
  78. void decode_header ();
  79. void extract_mangle ();
  80. void extract_sparse_file ();
  81. long from_oct ();
  82. void gnu_restore ();
  83. extern void print_header ();
  84. extern void skip_file ();
  85. extern void skip_extended_headers ();
  86. extern void pr_mkdir ();
  87. void saverec ();
  88.  
  89. int make_dirs ();        /* Makes required directories */
  90.  
  91. static time_t now = 0;        /* Current time */
  92. static we_are_root = 0;        /* True if our effective uid == 0 */
  93. static int notumask = ~0;    /* Masks out bits user doesn't want */
  94.  
  95. /*
  96.  * "Scratch" space to store the information about a sparse file before
  97.  * writing the info into the header or extended header
  98.  */
  99. /*struct sp_array    *sparsearray;*/
  100.  
  101. /* number of elts storable in the sparsearray */
  102. /*int    sp_array_size = 10;*/
  103.  
  104. struct saved_dir_info
  105. {
  106.   char *path;
  107.   int mode;
  108.   int atime;
  109.   int mtime;
  110.   struct saved_dir_info *next;
  111. };
  112.  
  113. struct saved_dir_info *saved_dir_info_head;
  114.  
  115. /*
  116.  * Set up to extract files.
  117.  */
  118. void
  119. extr_init ()
  120. {
  121.   int ourmask;
  122.  
  123.   now = time ((time_t *) 0);
  124.   if (geteuid () == 0)
  125.     we_are_root = 1;
  126.  
  127.   /*
  128.      * We need to know our umask.  But if f_use_protection is set,
  129.      * leave our kernel umask at 0, and our "notumask" at ~0.
  130.      */
  131.   ourmask = umask (0);        /* Read it */
  132.   if (!f_use_protection)
  133.     {
  134.       (void) umask (ourmask);    /* Set it back how it was */
  135.       notumask = ~ourmask;    /* Make umask override permissions */
  136.     }
  137. }
  138.  
  139.  
  140. /*
  141.  * Extract a file from the archive.
  142.  */
  143. void
  144. extract_archive ()
  145. {
  146.   register char *data;
  147.   int fd, check, namelen, written, openflag;
  148.   long size;
  149.   struct utimbuf acc_upd_times;
  150.   register int skipcrud;
  151.   register int i;
  152.   /*    int sparse_ind = 0;*/
  153.   union record *exhdr;
  154.   struct saved_dir_info *tmp;
  155.   /*    int end_nulls; */
  156.  
  157.   saverec (&head);        /* Make sure it sticks around */
  158.   userec (head);        /* And go past it in the archive */
  159.   decode_header (head, &hstat, &head_standard, 1);    /* Snarf fields */
  160.  
  161.   if (f_confirm && !confirm ("extract", current_file_name))
  162.     {
  163.       if (head->header.isextended)
  164.     skip_extended_headers ();
  165.       skip_file ((long) hstat.st_size);
  166.       saverec ((union record **) 0);
  167.       return;
  168.     }
  169.  
  170.   /* Print the record from 'head' and 'hstat' */
  171.   if (f_verbose)
  172.     print_header ();
  173.  
  174.   /*
  175.      * Check for fully specified pathnames and other atrocities.
  176.      *
  177.      * Note, we can't just make a pointer to the new file name,
  178.      * since saverec() might move the header and adjust "head".
  179.      * We have to start from "head" every time we want to touch
  180.      * the header record.
  181.      */
  182.   skipcrud = 0;
  183.   while (!f_absolute_paths
  184.      && '/' == current_file_name[skipcrud])
  185.     {
  186.       static int warned_once = 0;
  187.  
  188.       skipcrud++;        /* Force relative path */
  189.       if (!warned_once++)
  190.     {
  191.       msg ("Removing leading / from absolute path names in the archive.");
  192.     }
  193.     }
  194.  
  195.   switch (head->header.linkflag)
  196.     {
  197.  
  198.     default:
  199.       msg ("Unknown file type '%c' for %s, extracted as normal file",
  200.        head->header.linkflag, skipcrud + current_file_name);
  201.       /* FALL THRU */
  202.  
  203.       /*
  204.       * JK - What we want to do if the file is sparse is loop through
  205.       * the array of sparse structures in the header and read in
  206.       * and translate the character strings representing  1) the offset
  207.       * at which to write and 2) how many bytes to write into numbers,
  208.       * which we store into the scratch array, "sparsearray".  This
  209.       * array makes our life easier the same way it did in creating
  210.       * the tar file that had to deal with a sparse file.
  211.       *
  212.       * After we read in the first five (at most) sparse structures,
  213.       * we check to see if the file has an extended header, i.e.,
  214.       * if more sparse structures are needed to describe the contents
  215.       * of the new file.  If so, we read in the extended headers
  216.       * and continue to store their contents into the sparsearray.
  217.       */
  218.     case LF_SPARSE:
  219.       sp_array_size = 10;
  220.       sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
  221.       for (i = 0; i < SPARSE_IN_HDR; i++)
  222.     {
  223.       sparsearray[i].offset =
  224.         from_oct (1 + 12, head->header.sp[i].offset);
  225.       sparsearray[i].numbytes =
  226.         from_oct (1 + 12, head->header.sp[i].numbytes);
  227.       if (!sparsearray[i].numbytes)
  228.         break;
  229.     }
  230.  
  231.       /*        end_nulls = from_oct(1+12, head->header.ending_blanks);*/
  232.  
  233.       if (head->header.isextended)
  234.     {
  235.       /* read in the list of extended headers
  236.                 and translate them into the sparsearray
  237.                 as before */
  238.  
  239.       /* static */ int ind = SPARSE_IN_HDR;
  240.  
  241.       for (;;)
  242.         {
  243.  
  244.           exhdr = findrec ();
  245.           for (i = 0; i < SPARSE_EXT_HDR; i++)
  246.         {
  247.  
  248.           if (i + ind > sp_array_size - 1)
  249.             {
  250.               /*
  251.                       * realloc the scratch area
  252.                       * since we've run out of room --
  253.                       */
  254.               sparsearray = (struct sp_array *)
  255.             ck_realloc (sparsearray,
  256.                 2 * sp_array_size * (sizeof (struct sp_array)));
  257.               sp_array_size *= 2;
  258.             }
  259.           if (!exhdr->ext_hdr.sp[i].numbytes)
  260.             break;
  261.           sparsearray[i + ind].offset =
  262.             from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset);
  263.           sparsearray[i + ind].numbytes =
  264.             from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes);
  265.         }
  266.           if (!exhdr->ext_hdr.isextended)
  267.         break;
  268.           else
  269.         {
  270.           ind += SPARSE_EXT_HDR;
  271.           userec (exhdr);
  272.         }
  273.         }
  274.       userec (exhdr);
  275.     }
  276.  
  277.       /* FALL THRU */
  278.     case LF_OLDNORMAL:
  279.     case LF_NORMAL:
  280.     case LF_CONTIG:
  281.       /*
  282.           * Appears to be a file.
  283.           * See if it's really a directory.
  284.           */
  285.       namelen = strlen (skipcrud + current_file_name) - 1;
  286.       if (current_file_name[skipcrud + namelen] == '/')
  287.     goto really_dir;
  288.  
  289. #ifdef AMIGA
  290.                 {
  291.                  /* Colons may be replaced by '_' when extracting, since
  292.                     for AMIGA, we need a path description like
  293.  
  294.                          DEVICE:PATH/PATH/FILE
  295.  
  296.                     with only one ':' after the first string
  297.                     and unlimitied '/'. Also
  298.  
  299.                          /PATH/PATH
  300.  
  301.                     is relative (each '/' means 'one directory above')
  302.                     while
  303.  
  304.                         PATH/PATH
  305.  
  306.                     refers to the current directory.
  307.                     So there never can be more than two ':'
  308.                     and a ':' may never appear after the
  309.                     first '/'.
  310.                   */
  311.  
  312.                  char *filename = skipcrud + current_file_name;
  313.                  int slash_count = 0;
  314.                  
  315.                  while(*filename)
  316.                   {
  317.                    if(*filename == '/') slash_count++;
  318.  
  319.                    if(slash_count && (*filename == ':'))
  320.                     {
  321.                      *filename = '_';
  322.  
  323.                      msg ("Had to replace \42:\42 with \42_\42");
  324.                     }
  325.  
  326.                    filename++;
  327.                   }
  328.                 }
  329.  
  330. #endif /* AMIGA */
  331.  
  332.       /* FIXME, deal with protection issues */
  333.     again_file:
  334.       openflag = (f_keep ?
  335.           O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
  336.           O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
  337.     | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
  338.       /*
  339.               * JK - The last | is a kludge to solve the problem
  340.               * the O_APPEND flag  causes with files we are
  341.               * trying to make sparse:  when a file is opened
  342.               * with O_APPEND, it writes  to the last place
  343.               * that something was written, thereby ignoring
  344.               * any lseeks that we have done.  We add this
  345.               * extra condition to make it able to lseek when
  346.               * a file is sparse, i.e., we don't open the new
  347.               * file with this flag.  (Grump -- this bug caused
  348.               * me to waste a good deal of time, I might add)
  349.               */
  350.  
  351.       if (f_exstdout)
  352.     {
  353.       fd = 1;
  354.       goto extract_file;
  355.     }
  356. #ifdef O_CTG
  357.       /*
  358.           * Contiguous files (on the Masscomp) have to specify
  359.           * the size in the open call that creates them.
  360.           */
  361.       if (head->header.linkflag == LF_CONTIG)
  362.     fd = open ((longname ? longname : head->header.name)
  363.            + skipcrud,
  364.            openflag | O_CTG,
  365.            hstat.st_mode, hstat.st_size);
  366.       else
  367. #endif
  368.     {
  369. #ifdef NO_OPEN3
  370.       /*
  371.               * On raw V7 we won't let them specify -k (f_keep), but
  372.               * we just bull ahead and create the files.
  373.               */
  374.       fd = creat ((longname
  375.                ? longname
  376.                : head->header.name) + skipcrud,
  377.               hstat.st_mode);
  378. #else
  379.       /*
  380.               * With 3-arg open(), we can do this up right.
  381.               */
  382.       fd = open (skipcrud + current_file_name,
  383.              openflag, hstat.st_mode);
  384. #endif
  385.     }
  386.  
  387.       if (fd < 0)
  388.     {
  389.       if (make_dirs (skipcrud + current_file_name))
  390.         goto again_file;
  391.       msg_perror ("Could not create file %s",
  392.               skipcrud + current_file_name);
  393.       if (head->header.isextended)
  394.         skip_extended_headers ();
  395.       skip_file ((long) hstat.st_size);
  396.       goto quit;
  397.     }
  398.  
  399.     extract_file:
  400.       if (head->header.linkflag == LF_SPARSE)
  401.     {
  402.       char *name;
  403.       int namelen;
  404.  
  405.       /*
  406.               * Kludge alert.  NAME is assigned to header.name
  407.               * because during the extraction, the space that
  408.               * contains the header will get scribbled on, and
  409.               * the name will get munged, so any error messages
  410.               * that happen to contain the filename will look
  411.               * REAL interesting unless we do this.
  412.               */
  413.       namelen = strlen (skipcrud + current_file_name) + 1;
  414.       name = (char *) ck_malloc ((sizeof (char)) * namelen);
  415.       bcopy (skipcrud + current_file_name, name, namelen);
  416.       size = hstat.st_size;
  417.       extract_sparse_file (fd, &size, hstat.st_size, name);
  418.     }
  419.       else
  420.     for (size = hstat.st_size;
  421.          size > 0;
  422.          size -= written)
  423.       {
  424.  
  425.         /*            long    offset,
  426.                  numbytes;*/
  427.  
  428.         if (f_multivol)
  429.           {
  430.         save_name = current_file_name;
  431.         save_totsize = hstat.st_size;
  432.         save_sizeleft = size;
  433.           }
  434.  
  435.         /*
  436.               * Locate data, determine max length
  437.               * writeable, write it, record that
  438.               * we have used the data, then check
  439.               * if the write worked.
  440.               */
  441.         data = findrec ()->charptr;
  442.         if (data == NULL)
  443.           {            /* Check it... */
  444.         msg ("Unexpected EOF on archive file");
  445.         break;
  446.           }
  447.         /*
  448.               * JK - If the file is sparse, use the sparsearray
  449.               * that we created before to lseek into the new
  450.               * file the proper amount, and to see how many
  451.               * bytes we want to write at that position.
  452.               */
  453.         /*            if (head->header.linkflag == LF_SPARSE) {
  454.                  off_t pos;
  455.  
  456.                  pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
  457.                  printf("%d at %d\n", (int) pos, sparse_ind);
  458.                  written = sparsearray[sparse_ind++].numbytes;
  459.              } else*/
  460.         written = endofrecs ()->charptr - data;
  461.         if (written > size)
  462.           written = size;
  463.         errno = 0;
  464.         check = write (fd, data, written);
  465.         /*
  466.               * The following is in violation of strict
  467.               * typing, since the arg to userec
  468.               * should be a struct rec *.  FIXME.
  469.               */
  470.         userec ((union record *) (data + written - 1));
  471.         if (check == written)
  472.           continue;
  473.         /*
  474.               * Error in writing to file.
  475.               * Print it, skip to next file in archive.
  476.               */
  477.         if (check < 0)
  478.           msg_perror ("couldn't write to file %s",
  479.               skipcrud + current_file_name);
  480.         else
  481.           msg ("could only write %d of %d bytes to file %s",
  482.            check, written, skipcrud + current_file_name);
  483.         skip_file ((long) (size - written));
  484.         break;        /* Still do the close, mod time, chmod, etc */
  485.       }
  486.  
  487.       if (f_multivol)
  488.     save_name = 0;
  489.  
  490.       /* If writing to stdout, don't try to do anything
  491.                 to the filename; it doesn't exist, or we don't
  492.                 want to touch it anyway */
  493.       if (f_exstdout)
  494.     break;
  495.  
  496.       /*        if (head->header.isextended) {
  497.              register union record *exhdr;
  498.              register int i;
  499.  
  500.              for (i = 0; i < 21; i++) {
  501.                  long offset;
  502.  
  503.                  if (!exhdr->ext_hdr.sp[i].numbytes)
  504.                      break;
  505.                  offset = from_oct(1+12,
  506.                          exhdr->ext_hdr.sp[i].offset);
  507.                  written = from_oct(1+12,
  508.                          exhdr->ext_hdr.sp[i].numbytes);
  509.                  lseek(fd, offset, 0);
  510.                  check = write(fd, data, written);
  511.                  if (check == written) continue;
  512.  
  513.              }
  514.  
  515.  
  516.          }*/
  517.       check = close (fd);
  518.       if (check < 0)
  519.     {
  520.       msg_perror ("Error while closing %s",
  521.               skipcrud + current_file_name);
  522.     }
  523.  
  524.  
  525.     set_filestat:
  526.  
  527.       /*
  528.           * If we are root, set the owner and group of the extracted
  529.           * file.  This does what is wanted both on real Unix and on
  530.           * System V.  If we are running as a user, we extract as that
  531.           * user; if running as root, we extract as the original owner.
  532.           */
  533.       if (we_are_root || f_do_chown)
  534.     {
  535.       if (chown (skipcrud + current_file_name,
  536.              hstat.st_uid, hstat.st_gid) < 0)
  537.         {
  538.           msg_perror ("cannot chown file %s to uid %d gid %d",
  539.               skipcrud + current_file_name,
  540.               hstat.st_uid, hstat.st_gid);
  541.         }
  542.     }
  543.  
  544.       /*
  545.        * Set the modified time of the file.
  546.        *
  547.        * Note that we set the accessed time to "now", which
  548.        * is really "the time we started extracting files".
  549.        * unless f_gnudump is used, in which case .st_atime is used
  550.        */
  551.       if (!f_modified)
  552.     {
  553.       /* fixme if f_gnudump should set ctime too, but how? */
  554.       if (f_gnudump)
  555.         acc_upd_times.actime = hstat.st_atime;
  556.       else
  557.         acc_upd_times.actime = now;    /* Accessed now */
  558.       acc_upd_times.modtime = hstat.st_mtime;    /* Mod'd */
  559.       if (utime (skipcrud + current_file_name,
  560.              &acc_upd_times) < 0)
  561.         {
  562.           msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name);
  563.         }
  564.     }
  565.       /* We do the utime before the chmod because some versions of
  566.            utime are broken and trash the modes of the file.  Since
  567.            we then change the mode anyway, we don't care. . . */
  568.  
  569.       /*
  570.          * If '-k' is not set, open() or creat() could have saved
  571.          * the permission bits from a previously created file,
  572.          * ignoring the ones we specified.
  573.          * Even if -k is set, if the file has abnormal
  574.          * mode bits, we must chmod since writing or chown() has
  575.          * probably reset them.
  576.          *
  577.          * If -k is set, we know *we* created this file, so the mode
  578.          * bits were set by our open().   If the file is "normal", we
  579.          * skip the chmod.  This works because we did umask(0) if -p
  580.          * is set, so umask will have left the specified mode alone.
  581.          */
  582.       if ((!f_keep)
  583.       || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
  584.     {
  585.       if (chmod (skipcrud + current_file_name,
  586.              notumask & (int) hstat.st_mode) < 0)
  587.         {
  588.           msg_perror ("cannot change mode of file %s to %ld",
  589.               skipcrud + current_file_name,
  590.               notumask & (int) hstat.st_mode);
  591.         }
  592.     }
  593.  
  594.     quit:
  595.       break;
  596.  
  597.     case LF_LINK:
  598.     again_link:
  599.       {
  600.     struct stat st1, st2;
  601.  
  602.     check = link (current_link_name, skipcrud + current_file_name);
  603.  
  604.     if (check == 0)
  605.       break;
  606.     if (make_dirs (skipcrud + current_file_name))
  607.       goto again_link;
  608.     if (f_gnudump && errno == EEXIST)
  609.       break;
  610.     if (stat (current_link_name, &st1) == 0
  611.         && stat (current_file_name + skipcrud, &st2) == 0
  612.         && st1.st_dev == st2.st_dev
  613.         && st1.st_ino == st2.st_ino)
  614.       break;
  615.     msg_perror ("Could not link %s to %s",
  616.             skipcrud + current_file_name,
  617.             current_link_name);
  618.       }
  619.       break;
  620.  
  621. #ifdef S_ISLNK
  622.     case LF_SYMLINK:
  623.     again_symlink:
  624.       check = symlink (current_link_name,
  625.                skipcrud + current_file_name);
  626.       /* FIXME, don't worry uid, gid, etc... */
  627.       if (check == 0)
  628.     break;
  629.       if (make_dirs (current_file_name + skipcrud))
  630.     goto again_symlink;
  631.       msg_perror ("Could not create symlink to %s",
  632.           current_link_name);
  633.       break;
  634. #endif
  635.  
  636. #ifdef S_IFCHR
  637.     case LF_CHR:
  638.       hstat.st_mode |= S_IFCHR;
  639.       goto make_node;
  640. #endif
  641.  
  642. #ifdef S_IFBLK
  643.     case LF_BLK:
  644.       hstat.st_mode |= S_IFBLK;
  645. #endif
  646. #if defined(S_IFCHR) || defined(S_IFBLK)
  647.     make_node:
  648.       check = mknod (current_file_name + skipcrud,
  649.              (int) hstat.st_mode, (int) hstat.st_rdev);
  650.       if (check != 0)
  651.     {
  652.       if (make_dirs (skipcrud + current_file_name))
  653.         goto make_node;
  654.       msg_perror ("Could not make %s",
  655.               current_file_name + skipcrud);
  656.       break;
  657.     };
  658.       goto set_filestat;
  659. #endif
  660.  
  661. #ifdef S_ISFIFO
  662.       /* If local system doesn't support FIFOs, use default case */
  663.     case LF_FIFO:
  664.     make_fifo:
  665.       check = mkfifo (current_file_name + skipcrud,
  666.               (int) hstat.st_mode);
  667.       if (check != 0)
  668.     {
  669.       if (make_dirs (current_file_name + skipcrud))
  670.         goto make_fifo;
  671.       msg_perror ("Could not make %s",
  672.               skipcrud + current_file_name);
  673.       break;
  674.     };
  675.       goto set_filestat;
  676. #endif
  677.  
  678.     case LF_DIR:
  679.     case LF_DUMPDIR:
  680.       namelen = strlen (current_file_name + skipcrud) - 1;
  681.     really_dir:
  682.       /* Check for trailing /, and zap as many as we find. */
  683.       while (namelen
  684.          && current_file_name[skipcrud + namelen] == '/')
  685.     current_file_name[skipcrud + namelen--] = '\0';
  686.       if (f_gnudump)
  687.     {            /* Read the entry and delete files
  688.                        that aren't listed in the archive */
  689.       gnu_restore (skipcrud);
  690.  
  691.     }
  692.       else if (head->header.linkflag == LF_DUMPDIR)
  693.     skip_file ((long) (hstat.st_size));
  694.  
  695.  
  696.     again_dir:
  697.       check = mkdir (skipcrud + current_file_name,
  698.              (we_are_root ? 0 : 0300) | (int) hstat.st_mode);
  699.       if (check != 0)
  700.     {
  701.       struct stat st1;
  702.  
  703.       if (make_dirs (skipcrud + current_file_name))
  704.         goto again_dir;
  705.       /* If we're trying to create '.', let it be. */
  706.       if (current_file_name[skipcrud + namelen] == '.' &&
  707.           (namelen == 0 ||
  708.            current_file_name[skipcrud + namelen - 1] == '/'))
  709.         goto check_perms;
  710.       if (errno == EEXIST
  711.           && stat (skipcrud + current_file_name, &st1) == 0
  712.           && (S_ISDIR (st1.st_mode)))
  713.         break;
  714.       msg_perror ("Could not create directory %s", skipcrud + current_file_name);
  715.       break;
  716.     }
  717.  
  718.     check_perms:
  719.       if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode))
  720.     {
  721.       hstat.st_mode |= 0300;
  722.       msg ("Added write and execute permission to directory %s",
  723.            skipcrud + current_file_name);
  724.     }
  725.  
  726.       /*
  727.        * If we are root, set the owner and group of the extracted
  728.        * file.  This does what is wanted both on real Unix and on
  729.        * System V.  If we are running as a user, we extract as that
  730.        * user; if running as root, we extract as the original owner.
  731.        */
  732.       if (we_are_root || f_do_chown)
  733.     {
  734.       if (chown (skipcrud + current_file_name,
  735.              hstat.st_uid, hstat.st_gid) < 0)
  736.         {
  737.           msg_perror ("cannot chown file %s to uid %d gid %d",
  738.               skipcrud + current_file_name,
  739.               hstat.st_uid, hstat.st_gid);
  740.         }
  741.     }
  742.  
  743.       if (!f_modified)
  744.     {
  745.       tmp = ((struct saved_dir_info *) 
  746.          ck_malloc (sizeof (struct saved_dir_info)));
  747.       tmp->path = (char *) ck_malloc (strlen (skipcrud 
  748.                           + current_file_name) + 1);
  749.       strcpy (tmp->path, skipcrud + current_file_name);
  750.       tmp->mode = hstat.st_mode;
  751.       tmp->atime = hstat.st_atime;
  752.       tmp->mtime = hstat.st_mtime;
  753.       tmp->next = saved_dir_info_head;
  754.       saved_dir_info_head = tmp;
  755.     }
  756.       else
  757.     {
  758.       /* This functions exactly as the code for set_filestat above. */
  759.       if ((!f_keep)
  760.           || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
  761.         {
  762.           if (chmod (skipcrud + current_file_name,
  763.              notumask & (int) hstat.st_mode) < 0)
  764.         {
  765.           msg_perror ("cannot change mode of file %s to %ld",
  766.                   skipcrud + current_file_name,
  767.                   notumask & (int) hstat.st_mode);
  768.         }
  769.         }
  770.     }
  771.       break;
  772.  
  773.     case LF_VOLHDR:
  774.       if (f_verbose)
  775.     {
  776.       printf ("Reading %s\n", current_file_name);
  777.     }
  778.       break;
  779.  
  780.     case LF_NAMES:
  781.       extract_mangle (head);
  782.       break;
  783.  
  784.     case LF_MULTIVOL:
  785.       msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name);
  786.       skip_file ((long) hstat.st_size);
  787.       break;
  788.  
  789.     case LF_LONGNAME:
  790.     case LF_LONGLINK:
  791.       msg ("Visible long name error\n");
  792.       skip_file ((long) hstat.st_size);
  793.       break;
  794.     }
  795.  
  796.   /* We don't need to save it any longer. */
  797.   saverec ((union record **) 0);/* Unsave it */
  798. }
  799.  
  800. /*
  801.  * After a file/link/symlink/dir creation has failed, see if
  802.  * it's because some required directory was not present, and if
  803.  * so, create all required dirs.
  804.  */
  805. int
  806. make_dirs (pathname)
  807.      char *pathname;
  808. {
  809.   char *p;            /* Points into path */
  810.   int madeone = 0;        /* Did we do anything yet? */
  811.   int save_errno = errno;    /* Remember caller's errno */
  812.   int check;
  813.  
  814.   if (errno != ENOENT)
  815.     return 0;            /* Not our problem */
  816.  
  817.   for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/'))
  818.     {
  819.       /* Avoid mkdir of empty string, if leading or double '/' */
  820.       if (p == pathname || p[-1] == '/')
  821.     continue;
  822.       /* Avoid mkdir where last part of path is '.' */
  823.       if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/'))
  824.     continue;
  825.       *p = 0;            /* Truncate the path there */
  826.       check = mkdir (pathname, 0777);    /* Try to create it as a dir */
  827.       if (check == 0)
  828.     {
  829.       /* Fix ownership */
  830.       if (we_are_root)
  831.         {
  832.           if (chown (pathname, hstat.st_uid,
  833.              hstat.st_gid) < 0)
  834.         {
  835.           msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid);
  836.         }
  837.         }
  838.       pr_mkdir (pathname, p - pathname, notumask & 0777);
  839.       madeone++;        /* Remember if we made one */
  840.       *p = '/';
  841.       continue;
  842.     }
  843.       *p = '/';
  844.       if (errno == EEXIST)    /* Directory already exists */
  845.     continue;
  846.       /*
  847.          * Some other error in the mkdir.  We return to the caller.
  848.          */
  849.       break;
  850.     }
  851.  
  852.   errno = save_errno;        /* Restore caller's errno */
  853.   return madeone;        /* Tell them to retry if we made one */
  854. }
  855.  
  856. void
  857. extract_sparse_file (fd, sizeleft, totalsize, name)
  858.      int fd;
  859.      long *sizeleft, totalsize;
  860.      char *name;
  861. {
  862.   /*    register char    *data;*/
  863.   union record *datarec;
  864.   int sparse_ind = 0;
  865.   int written, count;
  866.  
  867.   /* assuming sizeleft is initially totalsize */
  868.  
  869.  
  870.   while (*sizeleft > 0)
  871.     {
  872.       datarec = findrec ();
  873.       if (datarec == NULL)
  874.     {
  875.       msg ("Unexpected EOF on archive file");
  876.       return;
  877.     }
  878.       lseek (fd, sparsearray[sparse_ind].offset, 0);
  879.       written = sparsearray[sparse_ind++].numbytes;
  880.       while (written > RECORDSIZE)
  881.     {
  882.       count = write (fd, datarec->charptr, RECORDSIZE);
  883.       if (count < 0)
  884.         msg_perror ("couldn't write to file %s", name);
  885.       written -= count;
  886.       *sizeleft -= count;
  887.       userec (datarec);
  888.       datarec = findrec ();
  889.     }
  890.  
  891.       count = write (fd, datarec->charptr, written);
  892.  
  893.       if (count < 0)
  894.     {
  895.       msg_perror ("couldn't write to file %s", name);
  896.     }
  897.       else if (count != written)
  898.     {
  899.       msg ("could only write %d of %d bytes to file %s", count, 
  900.            totalsize, name);
  901.       skip_file ((long) (*sizeleft));
  902.     }
  903.  
  904.       written -= count;
  905.       *sizeleft -= count;
  906.       userec (datarec);
  907.     }
  908.   free (sparsearray);
  909.   /*    if (end_nulls) {
  910.         register int i;
  911.  
  912.         printf("%d\n", (int) end_nulls);
  913.         for (i = 0; i < end_nulls; i++)
  914.             write(fd, "\000", 1);
  915.     }*/
  916.   userec (datarec);
  917. }
  918.  
  919. /* Set back the utime and mode for all the extracted directories. */
  920. void 
  921. restore_saved_dir_info ()
  922. {
  923.   struct utimbuf acc_upd_times;
  924.  
  925.   while (saved_dir_info_head != NULL)
  926.     {
  927.       /* fixme if f_gnudump should set ctime too, but how? */
  928.       if (f_gnudump)
  929.     acc_upd_times.actime = saved_dir_info_head->atime;
  930.       else
  931.     acc_upd_times.actime = now;    /* Accessed now */
  932.       acc_upd_times.modtime = saved_dir_info_head->mtime;    /* Mod'd */
  933.       if (utime (saved_dir_info_head->path, &acc_upd_times) < 0)
  934.     {
  935.       msg_perror ("couldn't change access and modification times of %s",
  936.               saved_dir_info_head->path);
  937.     }
  938.       if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX)))
  939.     {
  940.       if (chmod (saved_dir_info_head->path,
  941.              notumask & saved_dir_info_head->mode) < 0)
  942.         {
  943.           msg_perror ("cannot change mode of file %s to %ld",
  944.               saved_dir_info_head->path,
  945.               notumask & saved_dir_info_head->mode);
  946.         }
  947.     }
  948.       saved_dir_info_head = saved_dir_info_head->next;
  949.     }
  950. }
  951.