]>
Dogcows Code - chaz/tar/blob - src/extract.c
8aa5ba03d3cadff173253eb79f46366793629947
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)
66 extern FILE *msg_file
;
68 extern union record
*head
; /* Points to current tape header */
69 extern struct stat hstat
; /* Stat struct corresponding */
70 extern int head_standard
; /* Tape header is in ANSI format */
72 extern char *save_name
;
73 extern long save_totsize
;
74 extern long save_sizeleft
;
78 void extract_mangle();
79 void extract_sparse_file();
82 extern void print_header();
83 extern void skip_file();
84 extern void skip_extended_headers();
85 extern void pr_mkdir();
88 int make_dirs(); /* Makes required directories */
90 static time_t now
= 0; /* Current time */
91 static we_are_root
= 0; /* True if our effective uid == 0 */
92 static int notumask
= ~0; /* Masks out bits user doesn't want */
95 * "Scratch" space to store the information about a sparse file before
96 * writing the info into the header or extended header
98 /*struct sp_array *sparsearray;*/
100 /* number of elts storable in the sparsearray */
101 /*int sp_array_size = 10;*/
103 struct saved_dir_info
109 struct saved_dir_info
*next
;
112 struct saved_dir_info
*saved_dir_info_head
;
115 * Set up to extract files.
122 now
= time((time_t *)0);
127 * We need to know our umask. But if f_use_protection is set,
128 * leave our kernel umask at 0, and our "notumask" at ~0.
130 ourmask
= umask(0); /* Read it */
131 if (!f_use_protection
) {
132 (void) umask (ourmask
); /* Set it back how it was */
133 notumask
= ~ourmask
; /* Make umask override permissions */
139 * Extract a file from the archive.
145 int fd
, check
, namelen
, written
, openflag
;
147 struct utimbuf acc_upd_times
;
148 register int skipcrud
;
150 /* int sparse_ind = 0;*/
152 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
)) {
162 if (head
->header
.isextended
)
163 skip_extended_headers();
164 skip_file((long)hstat
.st_size
);
165 saverec((union record
**)0);
169 /* Print the record from 'head' and 'hstat' */
174 * Check for fully specified pathnames and other atrocities.
176 * Note, we can't just make a pointer to the new file name,
177 * since saverec() might move the header and adjust "head".
178 * We have to start from "head" every time we want to touch
182 while (!f_absolute_paths
183 && '/' == current_file_name
[skipcrud
]) {
184 static int warned_once
= 0;
186 skipcrud
++; /* Force relative path */
187 if (!warned_once
++) {
188 msg("Removing leading / from absolute path names in the archive.");
192 switch (head
->header
.linkflag
) {
195 msg("Unknown file type '%c' for %s, extracted as normal file",
196 head
->header
.linkflag
, skipcrud
+current_file_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
+current_file_name
)-1;
276 if (current_file_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.
328 fd
= open(skipcrud
+ current_file_name
,
329 openflag
, hstat
.st_mode
);
334 if (make_dirs(skipcrud
+ current_file_name
))
336 msg_perror("Could not create file %s",
337 skipcrud
+ current_file_name
);
338 if (head
->header
.isextended
)
339 skip_extended_headers();
340 skip_file((long)hstat
.st_size
);
345 if (head
->header
.linkflag
== LF_SPARSE
) {
350 * Kludge alert. NAME is assigned to header.name
351 * because during the extraction, the space that
352 * contains the header will get scribbled on, and
353 * the name will get munged, so any error messages
354 * that happen to contain the filename will look
355 * REAL interesting unless we do this.
357 namelen
= strlen(skipcrud
+ current_file_name
);
358 name
= (char *) malloc((sizeof(char)) * namelen
);
359 bcopy(skipcrud
+current_file_name
, name
, namelen
);
360 size
= hstat
.st_size
;
361 extract_sparse_file(fd
, &size
, hstat
.st_size
, name
);
364 for (size
= hstat
.st_size
;
372 save_name
=current_file_name
;
373 save_totsize
=hstat
.st_size
;
378 * Locate data, determine max length
379 * writeable, write it, record that
380 * we have used the data, then check
381 * if the write worked.
383 data
= findrec()->charptr
;
384 if (data
== NULL
) { /* Check it... */
385 msg("Unexpected EOF on archive file");
389 * JK - If the file is sparse, use the sparsearray
390 * that we created before to lseek into the new
391 * file the proper amount, and to see how many
392 * bytes we want to write at that position.
394 /* if (head->header.linkflag == LF_SPARSE) {
397 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
398 printf("%d at %d\n", (int) pos, sparse_ind);
399 written = sparsearray[sparse_ind++].numbytes;
401 written
= endofrecs()->charptr
- data
;
405 check
= write(fd
, data
, written
);
407 * The following is in violation of strict
408 * typing, since the arg to userec
409 * should be a struct rec *. FIXME.
411 userec((union record
*)(data
+ written
- 1));
412 if (check
== written
) continue;
414 * Error in writing to file.
415 * Print it, skip to next file in archive.
418 msg_perror("couldn't write to file %s",
419 skipcrud
+ current_file_name
);
421 msg("could only write %d of %d bytes to file %s",
422 written
,check
,skipcrud
+ current_file_name
);
423 skip_file((long)(size
- written
));
424 break; /* Still do the close, mod time, chmod, etc */
430 /* If writing to stdout, don't try to do anything
431 to the filename; it doesn't exist, or we don't
432 want to touch it anyway */
436 /* if (head->header.isextended) {
437 register union record *exhdr;
440 for (i = 0; i < 21; i++) {
443 if (!exhdr->ext_hdr.sp[i].numbytes)
445 offset = from_oct(1+12,
446 exhdr->ext_hdr.sp[i].offset);
447 written = from_oct(1+12,
448 exhdr->ext_hdr.sp[i].numbytes);
449 lseek(fd, offset, 0);
450 check = write(fd, data, written);
451 if (check == written) continue;
459 msg_perror("Error while closing %s",
460 skipcrud
+ current_file_name
);
467 * If we are root, set the owner and group of the extracted
468 * file. This does what is wanted both on real Unix and on
469 * System V. If we are running as a user, we extract as that
470 * user; if running as root, we extract as the original owner.
472 if (we_are_root
|| f_do_chown
) {
473 if (chown(skipcrud
+ current_file_name
,
474 hstat
.st_uid
, hstat
.st_gid
) < 0) {
475 msg_perror("cannot chown file %s to uid %d gid %d",
476 skipcrud
+ current_file_name
,
477 hstat
.st_uid
,hstat
.st_gid
);
482 * Set the modified time of the file.
484 * Note that we set the accessed time to "now", which
485 * is really "the time we started extracting files".
486 * unless f_gnudump is used, in which case .st_atime is used
489 /* fixme if f_gnudump should set ctime too, but how? */
491 acc_upd_times
.actime
=hstat
.st_atime
;
493 acc_upd_times
.actime
= now
; /* Accessed now */
494 acc_upd_times
.modtime
= hstat
.st_mtime
; /* Mod'd */
495 if (utime(skipcrud
+ current_file_name
,
496 &acc_upd_times
) < 0) {
497 msg_perror("couldn't change access and modification times of %s",skipcrud
+ current_file_name
);
500 /* We do the utime before the chmod because some versions of
501 utime are broken and trash the modes of the file. Since
502 we then change the mode anyway, we don't care. . . */
505 * If '-k' is not set, open() or creat() could have saved
506 * the permission bits from a previously created file,
507 * ignoring the ones we specified.
508 * Even if -k is set, if the file has abnormal
509 * mode bits, we must chmod since writing or chown() has
510 * probably reset them.
512 * If -k is set, we know *we* created this file, so the mode
513 * bits were set by our open(). If the file is "normal", we
514 * skip the chmod. This works because we did umask(0) if -p
515 * is set, so umask will have left the specified mode alone.
518 || (hstat
.st_mode
& (S_ISUID
|S_ISGID
|S_ISVTX
))) {
519 if (chmod(skipcrud
+ current_file_name
,
520 notumask
& (int)hstat
.st_mode
) < 0) {
521 msg_perror("cannot change mode of file %s to %ld",
522 skipcrud
+ current_file_name
,
523 notumask
& (int)hstat
.st_mode
);
535 check
= link (current_link_name
, skipcrud
+ current_file_name
);
539 if (make_dirs(skipcrud
+ current_file_name
))
541 if(f_gnudump
&& errno
==EEXIST
)
543 if(stat(current_link_name
, &st1
) == 0
544 && stat(current_file_name
+ skipcrud
, &st2
)==0
545 && st1
.st_dev
==st2
.st_dev
546 && st1
.st_ino
==st2
.st_ino
)
548 msg_perror("Could not link %s to %s",
549 skipcrud
+ current_file_name
,
557 check
= symlink(current_link_name
,
558 skipcrud
+ current_file_name
);
559 /* FIXME, don't worry uid, gid, etc... */
562 if (make_dirs(current_file_name
+ skipcrud
))
564 msg_perror("Could not create symlink to %s",
571 hstat
.st_mode
|= S_IFCHR
;
577 hstat
.st_mode
|= S_IFBLK
;
579 #if defined(S_IFCHR) || defined(S_IFBLK)
581 check
= mknod(current_file_name
+ skipcrud
,
582 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
584 if (make_dirs(skipcrud
+ current_file_name
))
586 msg_perror("Could not make %s",
587 current_file_name
+ skipcrud
);
594 /* If local system doesn't support FIFOs, use default case */
597 check
= mkfifo(current_file_name
+ skipcrud
,
598 (int) hstat
.st_mode
);
600 if (make_dirs(current_file_name
+ skipcrud
))
602 msg_perror("Could not make %s",
603 skipcrud
+ current_file_name
);
611 namelen
= strlen(current_file_name
) + skipcrud
- 1;
613 /* Check for trailing /, and zap as many as we find. */
615 && current_file_name
[skipcrud
+namelen
] == '/')
616 current_file_name
[skipcrud
+namelen
--] = '\0';
617 if(f_gnudump
) { /* Read the entry and delete files
618 that aren't listed in the archive */
619 gnu_restore(skipcrud
);
621 } else if(head
->header
.linkflag
==LF_DUMPDIR
)
622 skip_file((long)(hstat
.st_size
));
626 check
= mkdir(skipcrud
+current_file_name
,
627 (we_are_root
? 0 : 0300) | (int)hstat
.st_mode
);
631 if (make_dirs(skipcrud
+current_file_name
))
633 /* If we're trying to create '.', let it be. */
634 if (current_file_name
[skipcrud
+namelen
] == '.' &&
636 current_file_name
[skipcrud
+namelen
-1]=='/'))
639 && stat(skipcrud
+current_file_name
,&st1
)==0
640 && (S_ISDIR(st1
.st_mode
)))
642 msg_perror("Could not create directory %s",skipcrud
+current_file_name
);
647 if (!we_are_root
&& 0300 != (0300 & (int) hstat
.st_mode
)) {
648 hstat
.st_mode
|= 0300;
649 msg("Added write and execute permission to directory %s",
650 skipcrud
+current_file_name
);
655 tmp
= (struct saved_dir_info
*) malloc (sizeof (struct saved_dir_info
));
656 tmp
->path
= malloc (strlen (skipcrud
+ current_file_name
) + 1);
657 strcpy (tmp
->path
, skipcrud
+ current_file_name
);
658 tmp
->mode
= hstat
.st_mode
;
659 tmp
->atime
= hstat
.st_atime
;
660 tmp
->mtime
= hstat
.st_mtime
;
661 tmp
->next
= saved_dir_info_head
;
662 saved_dir_info_head
= tmp
;
665 printf("Reading %s\n", current_file_name
);
670 extract_mangle(head
);
674 msg("Can't extract '%s'--file is continued from another volume\n",current_file_name
);
675 skip_file((long)hstat
.st_size
);
680 msg ("Visible long name error\n");
681 skip_file ((long)hstat
.st_size
);
685 /* We don't need to save it any longer. */
686 saverec((union record
**) 0); /* Unsave it */
690 * After a file/link/symlink/dir creation has failed, see if
691 * it's because some required directory was not present, and if
692 * so, create all required dirs.
698 char *p
; /* Points into path */
699 int madeone
= 0; /* Did we do anything yet? */
700 int save_errno
= errno
; /* Remember caller's errno */
704 return 0; /* Not our problem */
706 for (p
= index(pathname
, '/'); p
!= NULL
; p
= index(p
+1, '/')) {
707 /* Avoid mkdir of empty string, if leading or double '/' */
708 if (p
== pathname
|| p
[-1] == '/')
710 /* Avoid mkdir where last part of path is '.' */
711 if (p
[-1] == '.' && (p
== pathname
+1 || p
[-2] == '/'))
713 *p
= 0; /* Truncate the path there */
714 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
718 if (chown(pathname
, hstat
.st_uid
,
720 msg_perror("cannot change owner of %s to uid %d gid %d",pathname
,hstat
.st_uid
,hstat
.st_gid
);
723 pr_mkdir(pathname
, p
-pathname
, notumask
&0777);
724 madeone
++; /* Remember if we made one */
729 if (errno
== EEXIST
) /* Directory already exists */
732 * Some other error in the mkdir. We return to the caller.
737 errno
= save_errno
; /* Restore caller's errno */
738 return madeone
; /* Tell them to retry if we made one */
742 extract_sparse_file(fd
, sizeleft
, totalsize
, name
)
748 /* register char *data;*/
749 union record
*datarec
;
754 /* assuming sizeleft is initially totalsize */
757 while (*sizeleft
> 0) {
759 if (datarec
== NULL
) {
760 msg("Unexpected EOF on archive file");
763 lseek(fd
, sparsearray
[sparse_ind
].offset
, 0);
764 written
= sparsearray
[sparse_ind
++].numbytes
;
765 while (written
> RECORDSIZE
) {
766 count
= write(fd
, datarec
->charptr
, RECORDSIZE
);
768 msg_perror("couldn't write to file %s", name
);
775 count
= write(fd
, datarec
->charptr
, written
);
778 msg_perror("couldn't write to file %s", name
);
779 } else if (count
!= written
) {
780 msg("could only write %d of %d bytes to file %s", totalsize
- *sizeleft
, totalsize
, name
);
781 skip_file((long) (*sizeleft
));
792 printf("%d\n", (int) end_nulls);
793 for (i = 0; i < end_nulls; i++)
794 write(fd, "\000", 1);
799 /* Set back the utime and mode for all the extracted directories. */
800 void restore_saved_dir_info ()
802 struct utimbuf acc_upd_times
;
803 struct saved_dir_info
*tmp
;
805 while (saved_dir_info_head
!= NULL
)
807 /* fixme if f_gnudump should set ctime too, but how? */
809 acc_upd_times
.actime
=saved_dir_info_head
-> atime
;
811 acc_upd_times
.actime
= now
; /* Accessed now */
812 acc_upd_times
.modtime
= saved_dir_info_head
-> mtime
; /* Mod'd */
813 if (utime(saved_dir_info_head
-> path
, &acc_upd_times
) < 0) {
814 msg_perror("couldn't change access and modification times of %s",
815 saved_dir_info_head
-> path
);
817 if ((!f_keep
) || (saved_dir_info_head
-> mode
& (S_ISUID
|S_ISGID
|S_ISVTX
)))
819 if (chmod(saved_dir_info_head
-> path
,
820 notumask
& saved_dir_info_head
-> mode
) < 0) {
821 msg_perror("cannot change mode of file %s to %ld",
822 saved_dir_info_head
-> path
,
823 notumask
& saved_dir_info_head
-> mode
);
826 saved_dir_info_head
= saved_dir_info_head
-> next
;
This page took 0.066131 seconds and 4 git commands to generate.