]>
Dogcows Code - chaz/tar/blob - src/extract.c
1 /* Extract files from a tar archive.
2 Copyright (C) 1988, 1992, 1993 Free Software Foundation
4 This file is part of GNU Tar.
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)
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.
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. */
21 * Extract files from a tar archive.
23 * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
31 #include <sys/types.h>
44 /* We need the #define's even though we don't use them. */
49 /* Simulated 3-argument open for systems that don't have it */
56 #if defined(_POSIX_VERSION)
67 extern FILE *msg_file
;
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 */
73 extern char *save_name
;
74 extern long save_totsize
;
75 extern long save_sizeleft
;
78 void decode_header ();
79 void extract_mangle ();
80 void extract_sparse_file ();
83 extern void print_header ();
84 extern void skip_file ();
85 extern void skip_extended_headers ();
86 extern void pr_mkdir ();
89 int make_dirs (); /* Makes required directories */
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 */
96 * "Scratch" space to store the information about a sparse file before
97 * writing the info into the header or extended header
99 /*struct sp_array *sparsearray;*/
101 /* number of elts storable in the sparsearray */
102 /*int sp_array_size = 10;*/
104 struct saved_dir_info
110 struct saved_dir_info
*next
;
113 struct saved_dir_info
*saved_dir_info_head
;
116 * Set up to extract files.
123 now
= time ((time_t *) 0);
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.
131 ourmask
= umask (0); /* Read it */
132 if (!f_use_protection
)
134 (void) umask (ourmask
); /* Set it back how it was */
135 notumask
= ~ourmask
; /* Make umask override permissions */
141 * Extract a file from the archive.
147 int fd
, check
, namelen
, written
, openflag
;
149 struct utimbuf acc_upd_times
;
150 register int skipcrud
;
152 /* int sparse_ind = 0;*/
154 struct saved_dir_info
*tmp
;
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 */
161 if (f_confirm
&& !confirm ("extract", current_file_name
))
163 if (head
->header
.isextended
)
164 skip_extended_headers ();
165 skip_file ((long) hstat
.st_size
);
166 saverec ((union record
**) 0);
170 /* Print the record from 'head' and 'hstat' */
175 * Check for fully specified pathnames and other atrocities.
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
183 while (!f_absolute_paths
184 && '/' == current_file_name
[skipcrud
])
186 static int warned_once
= 0;
188 skipcrud
++; /* Force relative path */
191 msg ("Removing leading / from absolute path names in the archive.");
195 switch (head
->header
.linkflag
)
199 msg ("Unknown file type '%c' for %s, extracted as normal file",
200 head
->header
.linkflag
, skipcrud
+ current_file_name
);
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.
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.
220 sparsearray
= (struct sp_array
*) ck_malloc (sp_array_size
* sizeof (struct sp_array
));
221 for (i
= 0; i
< SPARSE_IN_HDR
; i
++)
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
)
231 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
233 if (head
->header
.isextended
)
235 /* read in the list of extended headers
236 and translate them into the sparsearray
239 /* static */ int ind
= SPARSE_IN_HDR
;
245 for (i
= 0; i
< SPARSE_EXT_HDR
; i
++)
248 if (i
+ ind
> sp_array_size
- 1)
251 * realloc the scratch area
252 * since we've run out of room --
254 sparsearray
= (struct sp_array
*)
255 ck_realloc (sparsearray
,
256 2 * sp_array_size
* (sizeof (struct sp_array
)));
259 if (!exhdr
->ext_hdr
.sp
[i
].numbytes
)
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
);
266 if (!exhdr
->ext_hdr
.isextended
)
270 ind
+= SPARSE_EXT_HDR
;
282 * Appears to be a file.
283 * See if it's really a directory.
285 namelen
= strlen (skipcrud
+ current_file_name
) - 1;
286 if (current_file_name
[skipcrud
+ namelen
] == '/')
289 /* FIXME, deal with protection issues */
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
);
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)
315 * Contiguous files (on the Masscomp) have to specify
316 * the size in the open call that creates them.
318 if (head
->header
.linkflag
== LF_CONTIG
)
319 fd
= open ((longname
? longname
: head
->header
.name
)
322 hstat
.st_mode
, hstat
.st_size
);
328 * On raw V7 we won't let them specify -k (f_keep), but
329 * we just bull ahead and create the files.
331 fd
= creat ((longname
333 : head
->header
.name
) + skipcrud
,
337 * With 3-arg open(), we can do this up right.
339 fd
= open (skipcrud
+ current_file_name
,
340 openflag
, hstat
.st_mode
);
346 if (make_dirs (skipcrud
+ current_file_name
))
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
);
357 if (head
->header
.linkflag
== LF_SPARSE
)
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.
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
);
377 for (size
= hstat
.st_size
;
387 save_name
= current_file_name
;
388 save_totsize
= hstat
.st_size
;
389 save_sizeleft
= size
;
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.
398 data
= findrec ()->charptr
;
401 msg ("Unexpected EOF on archive file");
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.
410 /* if (head->header.linkflag == LF_SPARSE) {
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;
417 written
= endofrecs ()->charptr
- data
;
421 check
= write (fd
, data
, written
);
423 * The following is in violation of strict
424 * typing, since the arg to userec
425 * should be a struct rec *. FIXME.
427 userec ((union record
*) (data
+ written
- 1));
428 if (check
== written
)
431 * Error in writing to file.
432 * Print it, skip to next file in archive.
435 msg_perror ("couldn't write to file %s",
436 skipcrud
+ current_file_name
);
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 */
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 */
453 /* if (head->header.isextended) {
454 register union record *exhdr;
457 for (i = 0; i < 21; i++) {
460 if (!exhdr->ext_hdr.sp[i].numbytes)
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;
477 msg_perror ("Error while closing %s",
478 skipcrud
+ current_file_name
);
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.
490 if (we_are_root
|| f_do_chown
)
492 if (chown (skipcrud
+ current_file_name
,
493 hstat
.st_uid
, hstat
.st_gid
) < 0)
495 msg_perror ("cannot chown file %s to uid %d gid %d",
496 skipcrud
+ current_file_name
,
497 hstat
.st_uid
, hstat
.st_gid
);
502 * Set the modified time of the file.
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
510 /* fixme if f_gnudump should set ctime too, but how? */
512 acc_upd_times
.actime
= hstat
.st_atime
;
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
,
519 msg_perror ("couldn't change access and modification times of %s", skipcrud
+ current_file_name
);
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. . . */
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.
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.
540 || (hstat
.st_mode
& (S_ISUID
| S_ISGID
| S_ISVTX
)))
542 if (chmod (skipcrud
+ current_file_name
,
543 notumask
& (int) hstat
.st_mode
) < 0)
545 msg_perror ("cannot change mode of file %s to %lo",
546 skipcrud
+ current_file_name
,
547 notumask
& (int) hstat
.st_mode
);
557 struct stat st1
, st2
;
559 check
= link (current_link_name
, skipcrud
+ current_file_name
);
563 if (make_dirs (skipcrud
+ current_file_name
))
565 if (f_gnudump
&& errno
== EEXIST
)
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
)
572 msg_perror ("Could not link %s to %s",
573 skipcrud
+ current_file_name
,
581 check
= symlink (current_link_name
,
582 skipcrud
+ current_file_name
);
583 /* FIXME, don't worry uid, gid, etc... */
586 if (make_dirs (current_file_name
+ skipcrud
))
588 msg_perror ("Could not create symlink to %s",
595 hstat
.st_mode
|= S_IFCHR
;
601 hstat
.st_mode
|= S_IFBLK
;
603 #if defined(S_IFCHR) || defined(S_IFBLK)
605 check
= mknod (current_file_name
+ skipcrud
,
606 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
609 if (make_dirs (skipcrud
+ current_file_name
))
611 msg_perror ("Could not make %s",
612 current_file_name
+ skipcrud
);
619 /* If local system doesn't support FIFOs, use default case */
622 check
= mkfifo (current_file_name
+ skipcrud
,
623 (int) hstat
.st_mode
);
626 if (make_dirs (current_file_name
+ skipcrud
))
628 msg_perror ("Could not make %s",
629 skipcrud
+ current_file_name
);
637 namelen
= strlen (current_file_name
+ skipcrud
) - 1;
639 /* Check for trailing /, and zap as many as we find. */
641 && current_file_name
[skipcrud
+ namelen
] == '/')
642 current_file_name
[skipcrud
+ namelen
--] = '\0';
644 { /* Read the entry and delete files
645 that aren't listed in the archive */
646 gnu_restore (skipcrud
);
649 else if (head
->header
.linkflag
== LF_DUMPDIR
)
650 skip_file ((long) (hstat
.st_size
));
654 check
= mkdir (skipcrud
+ current_file_name
,
655 (we_are_root
? 0 : 0300) | (int) hstat
.st_mode
);
660 if (make_dirs (skipcrud
+ current_file_name
))
662 /* If we're trying to create '.', let it be. */
663 if (current_file_name
[skipcrud
+ namelen
] == '.' &&
665 current_file_name
[skipcrud
+ namelen
- 1] == '/'))
668 && stat (skipcrud
+ current_file_name
, &st1
) == 0
669 && (S_ISDIR (st1
.st_mode
)))
671 msg_perror ("Could not create directory %s", skipcrud
+ current_file_name
);
676 if (!we_are_root
&& 0300 != (0300 & (int) hstat
.st_mode
))
678 hstat
.st_mode
|= 0300;
679 msg ("Added write and execute permission to directory %s",
680 skipcrud
+ current_file_name
);
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.
689 if (we_are_root
|| f_do_chown
)
691 if (chown (skipcrud
+ current_file_name
,
692 hstat
.st_uid
, hstat
.st_gid
) < 0)
694 msg_perror ("cannot chown file %s to uid %d gid %d",
695 skipcrud
+ current_file_name
,
696 hstat
.st_uid
, hstat
.st_gid
);
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
;
715 /* This functions exactly as the code for set_filestat above. */
717 || (hstat
.st_mode
& (S_ISUID
| S_ISGID
| S_ISVTX
)))
719 if (chmod (skipcrud
+ current_file_name
,
720 notumask
& (int) hstat
.st_mode
) < 0)
722 msg_perror ("cannot change mode of file %s to %lo",
723 skipcrud
+ current_file_name
,
724 notumask
& (int) hstat
.st_mode
);
733 printf ("Reading %s\n", current_file_name
);
738 extract_mangle (head
);
742 msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name
);
743 skip_file ((long) hstat
.st_size
);
748 msg ("Visible long name error\n");
749 skip_file ((long) hstat
.st_size
);
753 /* We don't need to save it any longer. */
754 saverec ((union record
**) 0);/* Unsave it */
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.
766 char *p
; /* Points into path */
767 int madeone
= 0; /* Did we do anything yet? */
768 int save_errno
= errno
; /* Remember caller's errno */
772 return 0; /* Not our problem */
774 for (p
= index (pathname
, '/'); p
!= NULL
; p
= index (p
+ 1, '/'))
776 /* Avoid mkdir of empty string, if leading or double '/' */
777 if (p
== pathname
|| p
[-1] == '/')
779 /* Avoid mkdir where last part of path is '.' */
780 if (p
[-1] == '.' && (p
== pathname
+ 1 || p
[-2] == '/'))
782 *p
= 0; /* Truncate the path there */
783 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
789 if (chown (pathname
, hstat
.st_uid
,
792 msg_perror ("cannot change owner of %s to uid %d gid %d", pathname
, hstat
.st_uid
, hstat
.st_gid
);
795 pr_mkdir (pathname
, p
- pathname
, notumask
& 0777);
796 madeone
++; /* Remember if we made one */
801 if (errno
== EEXIST
) /* Directory already exists */
804 * Some other error in the mkdir. We return to the caller.
809 errno
= save_errno
; /* Restore caller's errno */
810 return madeone
; /* Tell them to retry if we made one */
814 extract_sparse_file (fd
, sizeleft
, totalsize
, name
)
816 long *sizeleft
, totalsize
;
819 /* register char *data;*/
820 union record
*datarec
;
824 /* assuming sizeleft is initially totalsize */
827 while (*sizeleft
> 0)
829 datarec
= findrec ();
832 msg ("Unexpected EOF on archive file");
835 lseek (fd
, sparsearray
[sparse_ind
].offset
, 0);
836 written
= sparsearray
[sparse_ind
++].numbytes
;
837 while (written
> RECORDSIZE
)
839 count
= write (fd
, datarec
->charptr
, RECORDSIZE
);
841 msg_perror ("couldn't write to file %s", name
);
845 datarec
= findrec ();
848 count
= write (fd
, datarec
->charptr
, written
);
852 msg_perror ("couldn't write to file %s", name
);
854 else if (count
!= written
)
856 msg ("could only write %d of %d bytes to file %s", count
,
858 skip_file ((long) (*sizeleft
));
869 printf("%d\n", (int) end_nulls);
870 for (i = 0; i < end_nulls; i++)
871 write(fd, "\000", 1);
876 /* Set back the utime and mode for all the extracted directories. */
878 restore_saved_dir_info ()
880 struct utimbuf acc_upd_times
;
882 while (saved_dir_info_head
!= NULL
)
884 /* fixme if f_gnudump should set ctime too, but how? */
886 acc_upd_times
.actime
= saved_dir_info_head
->atime
;
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)
892 msg_perror ("couldn't change access and modification times of %s",
893 saved_dir_info_head
->path
);
895 if ((!f_keep
) || (saved_dir_info_head
->mode
& (S_ISUID
| S_ISGID
| S_ISVTX
)))
897 if (chmod (saved_dir_info_head
->path
,
898 notumask
& saved_dir_info_head
->mode
) < 0)
900 msg_perror ("cannot change mode of file %s to %lo",
901 saved_dir_info_head
->path
,
902 notumask
& saved_dir_info_head
->mode
);
905 saved_dir_info_head
= saved_dir_info_head
->next
;
This page took 0.079417 seconds and 4 git commands to generate.