home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / g / gtak212.zip / 1.10 / extract.c < prev    next >
C/C++ Source or Header  |  1993-02-24  |  27KB  |  982 lines

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