*** empty log message ***
[debian/tar] / src / extract.c
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       /* FIXME, deal with protection issues */
290     again_file:
291       openflag = (f_keep ?
292                   O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
293                   O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
294         | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
295       /*
296                           * JK - The last | is a kludge to solve the problem
297                           * the O_APPEND flag  causes with files we are
298                           * trying to make sparse:  when a file is opened
299                           * with O_APPEND, it writes  to the last place
300                           * that something was written, thereby ignoring
301                           * any lseeks that we have done.  We add this
302                           * extra condition to make it able to lseek when
303                           * a file is sparse, i.e., we don't open the new
304                           * file with this flag.  (Grump -- this bug caused
305                           * me to waste a good deal of time, I might add)
306                           */
307
308       if (f_exstdout)
309         {
310           fd = 1;
311           goto extract_file;
312         }
313 #ifdef O_CTG
314       /*
315                   * Contiguous files (on the Masscomp) have to specify
316                   * the size in the open call that creates them.
317                   */
318       if (head->header.linkflag == LF_CONTIG)
319         fd = open ((longname ? longname : head->header.name)
320                    + skipcrud,
321                    openflag | O_CTG,
322                    hstat.st_mode, hstat.st_size);
323       else
324 #endif
325         {
326 #ifdef NO_OPEN3
327           /*
328                           * On raw V7 we won't let them specify -k (f_keep), but
329                           * we just bull ahead and create the files.
330                           */
331           fd = creat ((longname
332                        ? longname
333                        : head->header.name) + skipcrud,
334                       hstat.st_mode);
335 #else
336           /*
337                           * With 3-arg open(), we can do this up right.
338                           */
339           fd = open (skipcrud + current_file_name,
340                      openflag, hstat.st_mode);
341 #endif
342         }
343
344       if (fd < 0)
345         {
346           if (make_dirs (skipcrud + current_file_name))
347             goto again_file;
348           msg_perror ("Could not create file %s",
349                       skipcrud + current_file_name);
350           if (head->header.isextended)
351             skip_extended_headers ();
352           skip_file ((long) hstat.st_size);
353           goto quit;
354         }
355
356     extract_file:
357       if (head->header.linkflag == LF_SPARSE)
358         {
359           char *name;
360           int namelen;
361
362           /*
363                           * Kludge alert.  NAME is assigned to header.name
364                           * because during the extraction, the space that
365                           * contains the header will get scribbled on, and
366                           * the name will get munged, so any error messages
367                           * that happen to contain the filename will look
368                           * REAL interesting unless we do this.
369                           */
370           namelen = strlen (skipcrud + current_file_name) + 1;
371           name = (char *) ck_malloc ((sizeof (char)) * namelen);
372           bcopy (skipcrud + current_file_name, name, namelen);
373           size = hstat.st_size;
374           extract_sparse_file (fd, &size, hstat.st_size, name);
375         }
376       else
377         for (size = hstat.st_size;
378              size > 0;
379              size -= written)
380           {
381
382             /*                  long    offset,
383                                  numbytes;*/
384
385             if (f_multivol)
386               {
387                 save_name = current_file_name;
388                 save_totsize = hstat.st_size;
389                 save_sizeleft = size;
390               }
391
392             /*
393                           * Locate data, determine max length
394                           * writeable, write it, record that
395                           * we have used the data, then check
396                           * if the write worked.
397                           */
398             data = findrec ()->charptr;
399             if (data == NULL)
400               {                 /* Check it... */
401                 msg ("Unexpected EOF on archive file");
402                 break;
403               }
404             /*
405                           * JK - If the file is sparse, use the sparsearray
406                           * that we created before to lseek into the new
407                           * file the proper amount, and to see how many
408                           * bytes we want to write at that position.
409                           */
410             /*                  if (head->header.linkflag == LF_SPARSE) {
411                                  off_t pos;
412
413                                  pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
414                                  printf("%d at %d\n", (int) pos, sparse_ind);
415                                  written = sparsearray[sparse_ind++].numbytes;
416                          } else*/
417             written = endofrecs ()->charptr - data;
418             if (written > size)
419               written = size;
420             errno = 0;
421             check = write (fd, data, written);
422             /*
423                           * The following is in violation of strict
424                           * typing, since the arg to userec
425                           * should be a struct rec *.  FIXME.
426                           */
427             userec ((union record *) (data + written - 1));
428             if (check == written)
429               continue;
430             /*
431                           * Error in writing to file.
432                           * Print it, skip to next file in archive.
433                           */
434             if (check < 0)
435               msg_perror ("couldn't write to file %s",
436                           skipcrud + current_file_name);
437             else
438               msg ("could only write %d of %d bytes to file %s",
439                    check, written, skipcrud + current_file_name);
440             skip_file ((long) (size - written));
441             break;              /* Still do the close, mod time, chmod, etc */
442           }
443
444       if (f_multivol)
445         save_name = 0;
446
447       /* If writing to stdout, don't try to do anything
448                             to the filename; it doesn't exist, or we don't
449                             want to touch it anyway */
450       if (f_exstdout)
451         break;
452
453       /*                if (head->header.isextended) {
454                          register union record *exhdr;
455                          register int i;
456
457                          for (i = 0; i < 21; i++) {
458                                  long offset;
459
460                                  if (!exhdr->ext_hdr.sp[i].numbytes)
461                                          break;
462                                  offset = from_oct(1+12,
463                                                  exhdr->ext_hdr.sp[i].offset);
464                                  written = from_oct(1+12,
465                                                  exhdr->ext_hdr.sp[i].numbytes);
466                                  lseek(fd, offset, 0);
467                                  check = write(fd, data, written);
468                                  if (check == written) continue;
469
470                          }
471
472
473                  }*/
474       check = close (fd);
475       if (check < 0)
476         {
477           msg_perror ("Error while closing %s",
478                       skipcrud + current_file_name);
479         }
480
481
482     set_filestat:
483
484       /*
485                   * If we are root, set the owner and group of the extracted
486                   * file.  This does what is wanted both on real Unix and on
487                   * System V.  If we are running as a user, we extract as that
488                   * user; if running as root, we extract as the original owner.
489                   */
490       if (we_are_root || f_do_chown)
491         {
492           if (chown (skipcrud + current_file_name,
493                      hstat.st_uid, hstat.st_gid) < 0)
494             {
495               msg_perror ("cannot chown file %s to uid %d gid %d",
496                           skipcrud + current_file_name,
497                           hstat.st_uid, hstat.st_gid);
498             }
499         }
500
501       /*
502        * Set the modified time of the file.
503        *
504        * Note that we set the accessed time to "now", which
505        * is really "the time we started extracting files".
506        * unless f_gnudump is used, in which case .st_atime is used
507        */
508       if (!f_modified)
509         {
510           /* fixme if f_gnudump should set ctime too, but how? */
511           if (f_gnudump)
512             acc_upd_times.actime = hstat.st_atime;
513           else
514             acc_upd_times.actime = now; /* Accessed now */
515           acc_upd_times.modtime = hstat.st_mtime;       /* Mod'd */
516           if (utime (skipcrud + current_file_name,
517                      &acc_upd_times) < 0)
518             {
519               msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name);
520             }
521         }
522       /* We do the utime before the chmod because some versions of
523                    utime are broken and trash the modes of the file.  Since
524                    we then change the mode anyway, we don't care. . . */
525
526       /*
527                  * If '-k' is not set, open() or creat() could have saved
528                  * the permission bits from a previously created file,
529                  * ignoring the ones we specified.
530                  * Even if -k is set, if the file has abnormal
531                  * mode bits, we must chmod since writing or chown() has
532                  * probably reset them.
533                  *
534                  * If -k is set, we know *we* created this file, so the mode
535                  * bits were set by our open().   If the file is "normal", we
536                  * skip the chmod.  This works because we did umask(0) if -p
537                  * is set, so umask will have left the specified mode alone.
538                  */
539       if ((!f_keep)
540           || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
541         {
542           if (chmod (skipcrud + current_file_name,
543                      notumask & (int) hstat.st_mode) < 0)
544             {
545               msg_perror ("cannot change mode of file %s to %lo",
546                           skipcrud + current_file_name,
547                           notumask & (int) hstat.st_mode);
548             }
549         }
550
551     quit:
552       break;
553
554     case LF_LINK:
555     again_link:
556       {
557         struct stat st1, st2;
558
559         check = link (current_link_name, skipcrud + current_file_name);
560
561         if (check == 0)
562           break;
563         if (make_dirs (skipcrud + current_file_name))
564           goto again_link;
565         if (f_gnudump && errno == EEXIST)
566           break;
567         if (stat (current_link_name, &st1) == 0
568             && stat (current_file_name + skipcrud, &st2) == 0
569             && st1.st_dev == st2.st_dev
570             && st1.st_ino == st2.st_ino)
571           break;
572         msg_perror ("Could not link %s to %s",
573                     skipcrud + current_file_name,
574                     current_link_name);
575       }
576       break;
577
578 #ifdef S_ISLNK
579     case LF_SYMLINK:
580     again_symlink:
581       check = symlink (current_link_name,
582                        skipcrud + current_file_name);
583       /* FIXME, don't worry uid, gid, etc... */
584       if (check == 0)
585         break;
586       if (make_dirs (current_file_name + skipcrud))
587         goto again_symlink;
588       msg_perror ("Could not create symlink to %s",
589                   current_link_name);
590       break;
591 #endif
592
593 #ifdef S_IFCHR
594     case LF_CHR:
595       hstat.st_mode |= S_IFCHR;
596       goto make_node;
597 #endif
598
599 #ifdef S_IFBLK
600     case LF_BLK:
601       hstat.st_mode |= S_IFBLK;
602 #endif
603 #if defined(S_IFCHR) || defined(S_IFBLK)
604     make_node:
605       check = mknod (current_file_name + skipcrud,
606                      (int) hstat.st_mode, (int) hstat.st_rdev);
607       if (check != 0)
608         {
609           if (make_dirs (skipcrud + current_file_name))
610             goto make_node;
611           msg_perror ("Could not make %s",
612                       current_file_name + skipcrud);
613           break;
614         };
615       goto set_filestat;
616 #endif
617
618 #ifdef S_ISFIFO
619       /* If local system doesn't support FIFOs, use default case */
620     case LF_FIFO:
621     make_fifo:
622       check = mkfifo (current_file_name + skipcrud,
623                       (int) hstat.st_mode);
624       if (check != 0)
625         {
626           if (make_dirs (current_file_name + skipcrud))
627             goto make_fifo;
628           msg_perror ("Could not make %s",
629                       skipcrud + current_file_name);
630           break;
631         };
632       goto set_filestat;
633 #endif
634
635     case LF_DIR:
636     case LF_DUMPDIR:
637       namelen = strlen (current_file_name + skipcrud) - 1;
638     really_dir:
639       /* Check for trailing /, and zap as many as we find. */
640       while (namelen
641              && current_file_name[skipcrud + namelen] == '/')
642         current_file_name[skipcrud + namelen--] = '\0';
643       if (f_gnudump)
644         {                       /* Read the entry and delete files
645                                            that aren't listed in the archive */
646           gnu_restore (skipcrud);
647
648         }
649       else if (head->header.linkflag == LF_DUMPDIR)
650         skip_file ((long) (hstat.st_size));
651
652
653     again_dir:
654       check = mkdir (skipcrud + current_file_name,
655                      (we_are_root ? 0 : 0300) | (int) hstat.st_mode);
656       if (check != 0)
657         {
658           struct stat st1;
659
660           if (make_dirs (skipcrud + current_file_name))
661             goto again_dir;
662           /* If we're trying to create '.', let it be. */
663           if (current_file_name[skipcrud + namelen] == '.' &&
664               (namelen == 0 ||
665                current_file_name[skipcrud + namelen - 1] == '/'))
666             goto check_perms;
667           if (errno == EEXIST
668               && stat (skipcrud + current_file_name, &st1) == 0
669               && (S_ISDIR (st1.st_mode)))
670             break;
671           msg_perror ("Could not create directory %s", skipcrud + current_file_name);
672           break;
673         }
674
675     check_perms:
676       if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode))
677         {
678           hstat.st_mode |= 0300;
679           msg ("Added write and execute permission to directory %s",
680                skipcrud + current_file_name);
681         }
682
683       /*
684        * If we are root, set the owner and group of the extracted
685        * file.  This does what is wanted both on real Unix and on
686        * System V.  If we are running as a user, we extract as that
687        * user; if running as root, we extract as the original owner.
688        */
689       if (we_are_root || f_do_chown)
690         {
691           if (chown (skipcrud + current_file_name,
692                      hstat.st_uid, hstat.st_gid) < 0)
693             {
694               msg_perror ("cannot chown file %s to uid %d gid %d",
695                           skipcrud + current_file_name,
696                           hstat.st_uid, hstat.st_gid);
697             }
698         }
699
700       if (!f_modified)
701         {
702           tmp = ((struct saved_dir_info *) 
703                  ck_malloc (sizeof (struct saved_dir_info)));
704           tmp->path = (char *) ck_malloc (strlen (skipcrud 
705                                                   + current_file_name) + 1);
706           strcpy (tmp->path, skipcrud + current_file_name);
707           tmp->mode = hstat.st_mode;
708           tmp->atime = hstat.st_atime;
709           tmp->mtime = hstat.st_mtime;
710           tmp->next = saved_dir_info_head;
711           saved_dir_info_head = tmp;
712         }
713       else
714         {
715           /* This functions exactly as the code for set_filestat above. */
716           if ((!f_keep)
717               || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
718             {
719               if (chmod (skipcrud + current_file_name,
720                          notumask & (int) hstat.st_mode) < 0)
721                 {
722                   msg_perror ("cannot change mode of file %s to %lo",
723                               skipcrud + current_file_name,
724                               notumask & (int) hstat.st_mode);
725                 }
726             }
727         }
728       break;
729
730     case LF_VOLHDR:
731       if (f_verbose)
732         {
733           printf ("Reading %s\n", current_file_name);
734         }
735       break;
736
737     case LF_NAMES:
738       extract_mangle (head);
739       break;
740
741     case LF_MULTIVOL:
742       msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name);
743       skip_file ((long) hstat.st_size);
744       break;
745
746     case LF_LONGNAME:
747     case LF_LONGLINK:
748       msg ("Visible long name error\n");
749       skip_file ((long) hstat.st_size);
750       break;
751     }
752
753   /* We don't need to save it any longer. */
754   saverec ((union record **) 0);/* Unsave it */
755 }
756
757 /*
758  * After a file/link/symlink/dir creation has failed, see if
759  * it's because some required directory was not present, and if
760  * so, create all required dirs.
761  */
762 int
763 make_dirs (pathname)
764      char *pathname;
765 {
766   char *p;                      /* Points into path */
767   int madeone = 0;              /* Did we do anything yet? */
768   int save_errno = errno;       /* Remember caller's errno */
769   int check;
770
771   if (errno != ENOENT)
772     return 0;                   /* Not our problem */
773
774   for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/'))
775     {
776       /* Avoid mkdir of empty string, if leading or double '/' */
777       if (p == pathname || p[-1] == '/')
778         continue;
779       /* Avoid mkdir where last part of path is '.' */
780       if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/'))
781         continue;
782       *p = 0;                   /* Truncate the path there */
783       check = mkdir (pathname, 0777);   /* Try to create it as a dir */
784       if (check == 0)
785         {
786           /* Fix ownership */
787           if (we_are_root)
788             {
789               if (chown (pathname, hstat.st_uid,
790                          hstat.st_gid) < 0)
791                 {
792                   msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid);
793                 }
794             }
795           pr_mkdir (pathname, p - pathname, notumask & 0777);
796           madeone++;            /* Remember if we made one */
797           *p = '/';
798           continue;
799         }
800       *p = '/';
801       if (errno == EEXIST)      /* Directory already exists */
802         continue;
803       /*
804                  * Some other error in the mkdir.  We return to the caller.
805                  */
806       break;
807     }
808
809   errno = save_errno;           /* Restore caller's errno */
810   return madeone;               /* Tell them to retry if we made one */
811 }
812
813 void
814 extract_sparse_file (fd, sizeleft, totalsize, name)
815      int fd;
816      long *sizeleft, totalsize;
817      char *name;
818 {
819   /*    register char   *data;*/
820   union record *datarec;
821   int sparse_ind = 0;
822   int written, count;
823
824   /* assuming sizeleft is initially totalsize */
825
826
827   while (*sizeleft > 0)
828     {
829       datarec = findrec ();
830       if (datarec == NULL)
831         {
832           msg ("Unexpected EOF on archive file");
833           return;
834         }
835       lseek (fd, sparsearray[sparse_ind].offset, 0);
836       written = sparsearray[sparse_ind++].numbytes;
837       while (written > RECORDSIZE)
838         {
839           count = write (fd, datarec->charptr, RECORDSIZE);
840           if (count < 0)
841             msg_perror ("couldn't write to file %s", name);
842           written -= count;
843           *sizeleft -= count;
844           userec (datarec);
845           datarec = findrec ();
846         }
847
848       count = write (fd, datarec->charptr, written);
849
850       if (count < 0)
851         {
852           msg_perror ("couldn't write to file %s", name);
853         }
854       else if (count != written)
855         {
856           msg ("could only write %d of %d bytes to file %s", count, 
857                totalsize, name);
858           skip_file ((long) (*sizeleft));
859         }
860
861       written -= count;
862       *sizeleft -= count;
863       userec (datarec);
864     }
865   free (sparsearray);
866   /*    if (end_nulls) {
867                 register int i;
868
869                 printf("%d\n", (int) end_nulls);
870                 for (i = 0; i < end_nulls; i++)
871                         write(fd, "\000", 1);
872         }*/
873   userec (datarec);
874 }
875
876 /* Set back the utime and mode for all the extracted directories. */
877 void 
878 restore_saved_dir_info ()
879 {
880   struct utimbuf acc_upd_times;
881
882   while (saved_dir_info_head != NULL)
883     {
884       /* fixme if f_gnudump should set ctime too, but how? */
885       if (f_gnudump)
886         acc_upd_times.actime = saved_dir_info_head->atime;
887       else
888         acc_upd_times.actime = now;     /* Accessed now */
889       acc_upd_times.modtime = saved_dir_info_head->mtime;       /* Mod'd */
890       if (utime (saved_dir_info_head->path, &acc_upd_times) < 0)
891         {
892           msg_perror ("couldn't change access and modification times of %s",
893                       saved_dir_info_head->path);
894         }
895       if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX)))
896         {
897           if (chmod (saved_dir_info_head->path,
898                      notumask & saved_dir_info_head->mode) < 0)
899             {
900               msg_perror ("cannot change mode of file %s to %lo",
901                           saved_dir_info_head->path,
902                           notumask & saved_dir_info_head->mode);
903             }
904         }
905       saved_dir_info_head = saved_dir_info_head->next;
906     }
907 }