]>
Dogcows Code - chaz/tar/blob - src/extract.c
f3f7380671567ba320bca06bc9090cfc17f71b08
1 /* Extract files from a tar archive.
2 Copyright (C) 1988, 1992 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)
60 extern FILE *msg_file
;
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 */
66 extern char *save_name
;
67 extern long save_totsize
;
68 extern long save_sizeleft
;
72 void extract_mangle();
73 void extract_sparse_file();
76 extern void print_header();
77 extern void skip_file();
78 extern void skip_extended_headers();
79 extern void pr_mkdir();
82 int make_dirs(); /* Makes required directories */
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 */
89 * "Scratch" space to store the information about a sparse file before
90 * writing the info into the header or extended header
92 /*struct sp_array *sparsearray;*/
94 /* number of elts storable in the sparsearray */
95 /*int sp_array_size = 10;*/
103 struct saved_dir_info
*next
;
106 struct saved_dir_info
*saved_dir_info_head
;
109 * Set up to extract files.
116 now
= time((time_t *)0);
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.
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 */
133 * Extract a file from the archive.
139 int fd
, check
, namelen
, written
, openflag
;
141 time_t acc_upd_times
[2];
142 register int skipcrud
;
144 /* int sparse_ind = 0;*/
146 struct saved_dir_info
*tmp
;
150 static char *longname
;
151 static char *longlink
;
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 */
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);
166 /* Print the record from 'head' and 'hstat' */
171 * Check for fully specified pathnames and other atrocities.
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
179 while (!f_absolute_paths
180 && '/' == (longname
? longname
: head
->header
.name
)[skipcrud
]) {
181 static int warned_once
= 0;
183 skipcrud
++; /* Force relative path */
184 if (!warned_once
++) {
185 msg("Removing leading / from absolute path names in the archive.");
189 bumplongs
= (head
->header
.linkflag
!= LF_LONGNAME
190 && head
->header
.linkflag
!= LF_LONGLINK
);
192 switch (head
->header
.linkflag
) {
195 msg("Unknown file type '%c' for %s, extracted as normal file",
196 head
->header
.linkflag
, skipcrud
+head
->header
.name
);
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.
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.
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
)
226 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
228 if (head
->header
.isextended
) {
229 /* read in the list of extended headers
230 and translate them into the sparsearray
233 /* static */ int ind
= SPARSE_IN_HDR
;
238 for (i
= 0; i
< SPARSE_EXT_HDR
; i
++) {
240 if (i
+ind
> sp_array_size
-1) {
242 * realloc the scratch area
243 * since we've run out of room --
245 sparsearray
= (struct sp_array
*)
247 2 * sp_array_size
* (sizeof(struct sp_array
)));
250 if (!exhdr
->ext_hdr
.sp
[i
].numbytes
)
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
);
257 if (!exhdr
->ext_hdr
.isextended
)
260 ind
+= SPARSE_EXT_HDR
;
272 * Appears to be a file.
273 * See if it's really a directory.
275 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
276 if (head
->header
.name
[skipcrud
+namelen
] == '/')
279 /* FIXME, deal with protection issues */
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
);
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)
304 * Contiguous files (on the Masscomp) have to specify
305 * the size in the open call that creates them.
307 if (head
->header
.linkflag
== LF_CONTIG
)
308 fd
= open((longname
? longname
: head
->header
.name
)
311 hstat
.st_mode
, hstat
.st_size
);
317 * On raw V7 we won't let them specify -k (f_keep), but
318 * we just bull ahead and create the files.
322 : head
->header
.name
) + skipcrud
,
326 * With 3-arg open(), we can do this up right.
330 : head
->header
.name
) + skipcrud
,
331 openflag
, hstat
.st_mode
);
336 if (make_dirs(longname
338 : head
->header
.name
) + skipcrud
)
340 msg_perror("Could not create file %s",
342 +(longname
? longname
: head
->header
.name
));
343 if (head
->header
.isextended
)
344 skip_extended_headers();
345 skip_file((long)hstat
.st_size
);
350 if (head
->header
.linkflag
== LF_SPARSE
) {
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.
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
);
370 for (size
= hstat
.st_size
;
380 : head
->header
.name
);
381 save_totsize
=hstat
.st_size
;
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.
391 data
= findrec()->charptr
;
392 if (data
== NULL
) { /* Check it... */
393 msg("Unexpected EOF on archive file");
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.
402 /* if (head->header.linkflag == LF_SPARSE) {
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;
409 written
= endofrecs()->charptr
- data
;
413 check
= write(fd
, data
, written
);
415 * The following is in violation of strict
416 * typing, since the arg to userec
417 * should be a struct rec *. FIXME.
419 userec((union record
*)(data
+ written
- 1));
420 if (check
== written
) continue;
422 * Error in writing to file.
423 * Print it, skip to next file in archive.
426 msg_perror("couldn't write to file %s",
429 : head
->header
.name
) + skipcrud
);
431 msg("could only write %d of %d bytes to file %s",
432 written
,check
,(longname
434 : head
->header
.name
) + skipcrud
);
435 skip_file((long)(size
- written
));
436 break; /* Still do the close, mod time, chmod, etc */
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 */
448 /* if (head->header.isextended) {
449 register union record *exhdr;
452 for (i = 0; i < 21; i++) {
455 if (!exhdr->ext_hdr.sp[i].numbytes)
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;
471 msg_perror("Error while closing %s",
474 : head
->header
.name
) + skipcrud
);
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.
486 if (we_are_root
|| f_do_chown
) {
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",
494 : head
->header
.name
) + skipcrud
,
495 hstat
.st_uid
,hstat
.st_gid
);
500 * Set the modified time of the file.
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
507 /* fixme if f_gnudump should set ctime too, but how? */
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 */
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
);
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. . . */
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.
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.
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
);
554 check
= link (longlink
? longlink
: head
->header
.linkname
,
555 (longname
? longname
: head
->header
.name
) + skipcrud
);
558 if (make_dirs((longname
? longname
: head
->header
.name
) + skipcrud
))
560 if(f_gnudump
&& errno
==EEXIST
)
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
)
567 msg_perror("Could not link %s to %s",
568 (longname
? longname
: head
->header
.name
) + skipcrud
,
569 longlink
? longlink
: longlink
,
570 head
->header
.linkname
);
577 check
= symlink(longlink
? longlink
: head
->header
.linkname
,
578 (longname
? longname
: head
->header
.name
) + skipcrud
);
579 /* FIXME, don't worry uid, gid, etc... */
582 if (make_dirs((longname
? longname
: head
->header
.name
) + skipcrud
))
584 msg_perror("Could not create symlink to %s",
585 longlink
? longlink
: head
->header
.linkname
);
591 hstat
.st_mode
|= S_IFCHR
;
597 hstat
.st_mode
|= S_IFBLK
;
599 #if defined(S_IFCHR) || defined(S_IFBLK)
601 check
= mknod((longname
? longname
: head
->header
.name
) + skipcrud
,
602 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
604 if (make_dirs((longname
606 : head
->header
.name
) + skipcrud
))
608 msg_perror("Could not make %s",
609 (longname
? longname
: head
->header
.name
)
617 /* If local system doesn't support FIFOs, use default case */
620 check
= mkfifo((longname
? longname
: head
->header
.name
) + skipcrud
,
621 (int) hstat
.st_mode
);
623 if (make_dirs((longname
? longname
: head
->header
.name
) + skipcrud
))
625 msg_perror("Could not make %s",
626 (longname
? longname
: head
->header
.name
) + skipcrud
);
634 namelen
= strlen(longname
? longname
: head
->header
.name
)
637 /* Check for trailing /, and zap as many as we find. */
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
);
647 } else if(head
->header
.linkflag
==LF_DUMPDIR
)
648 skip_file((long)(hstat
.st_size
));
652 check
= mkdir(skipcrud
+(longname
? longname
: head
->header
.name
),
653 (we_are_root
? 0 : 0300) | (int)hstat
.st_mode
);
657 if (make_dirs(skipcrud
+(longname
? longname
: head
->header
.name
)))
659 /* If we're trying to create '.', let it be. */
660 if ((longname
? longname
: head
->header
.name
)[skipcrud
+namelen
] == '.' &&
662 (longname
? longname
: head
->header
.name
)[skipcrud
+namelen
-1]=='/'))
665 && stat(skipcrud
+(longname
? longname
: head
->header
.name
),&st1
)==0
666 && (S_ISDIR(st1
.st_mode
)))
668 msg_perror("Could not create directory %s",skipcrud
+(longname
? longname
: head
->header
.name
));
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
));
681 tmp
= (struct saved_dir_info
*) 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
;
691 printf("Reading %s\n",longname
? longname
: head
->header
.name
);
696 extract_mangle(head
);
700 msg("Can't extract '%s'--file is continued from another volume\n",head
->header
.name
);
701 skip_file((long)hstat
.st_size
);
714 bp
= *longp
= (char *) ck_malloc (hstat
.st_size
);
716 for (size
= hstat
.st_size
;
720 data
= findrec ()->charptr
;
723 msg ("Unexpected EOF on archive file");
726 written
= endofrecs () ->charptr
- data
;
730 bcopy (data
, bp
, written
);
732 userec ((union record
*) (data
+ written
- 1));
742 /* We don't need to save it any longer. */
743 saverec((union record
**) 0); /* Unsave it */
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.
755 char *p
; /* Points into path */
756 int madeone
= 0; /* Did we do anything yet? */
757 int save_errno
= errno
; /* Remember caller's errno */
761 return 0; /* Not our problem */
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] == '/')
767 /* Avoid mkdir where last part of path is '.' */
768 if (p
[-1] == '.' && (p
== pathname
+1 || p
[-2] == '/'))
770 *p
= 0; /* Truncate the path there */
771 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
775 if (chown(pathname
, hstat
.st_uid
,
777 msg_perror("cannot change owner of %s to uid %d gid %d",pathname
,hstat
.st_uid
,hstat
.st_gid
);
780 pr_mkdir(pathname
, p
-pathname
, notumask
&0777);
781 madeone
++; /* Remember if we made one */
786 if (errno
== EEXIST
) /* Directory already exists */
789 * Some other error in the mkdir. We return to the caller.
794 errno
= save_errno
; /* Restore caller's errno */
795 return madeone
; /* Tell them to retry if we made one */
799 extract_sparse_file(fd
, sizeleft
, totalsize
, name
)
805 /* register char *data;*/
806 union record
*datarec
;
811 /* assuming sizeleft is initially totalsize */
814 while (*sizeleft
> 0) {
816 if (datarec
== NULL
) {
817 msg("Unexpected EOF on archive file");
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
);
825 msg_perror("couldn't write to file %s", name
);
832 count
= write(fd
, datarec
->charptr
, written
);
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
));
849 printf("%d\n", (int) end_nulls);
850 for (i = 0; i < end_nulls; i++)
851 write(fd, "\000", 1);
856 /* Set back the utime and mode for all the extracted directories. */
857 void restore_saved_dir_info ()
859 time_t acc_upd_times
[2];
860 struct saved_dir_info
*tmp
;
862 while (saved_dir_info_head
!= NULL
)
864 /* fixme if f_gnudump should set ctime too, but how? */
866 acc_upd_times
[0]=saved_dir_info_head
-> atime
;
867 else acc_upd_times
[0] = now
; /* Accessed now */
868 acc_upd_times
[1] = saved_dir_info_head
-> mtime
; /* Mod'd */
869 if (utime(saved_dir_info_head
-> path
, acc_upd_times
) < 0) {
870 msg_perror("couldn't change access and modification times of %s",
871 saved_dir_info_head
-> path
);
873 if ((!f_keep
) || (saved_dir_info_head
-> mode
& (S_ISUID
|S_ISGID
|S_ISVTX
)))
875 if (chmod(saved_dir_info_head
-> path
,
876 notumask
& saved_dir_info_head
-> mode
) < 0) {
877 msg_perror("cannot change mode of file %s to %ld",
878 saved_dir_info_head
-> path
,
879 notumask
& saved_dir_info_head
-> mode
);
882 saved_dir_info_head
= saved_dir_info_head
-> next
;
This page took 0.080171 seconds and 4 git commands to generate.