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