]>
Dogcows Code - chaz/tar/blob - src/extract.c
4a989a349a5251e84f4703324b94763304478a5b
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 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
;
149 saverec(&head
); /* Make sure it sticks around */
150 userec(head
); /* And go past it in the archive */
151 decode_header(head
, &hstat
, &head_standard
, 1); /* Snarf fields */
153 if(f_confirm
&& !confirm("extract",head
->header
.name
)) {
154 if (head
->header
.isextended
)
155 skip_extended_headers();
156 skip_file((long)hstat
.st_size
);
157 saverec((union record
**)0);
161 /* Print the record from 'head' and 'hstat' */
166 * Check for fully specified pathnames and other atrocities.
168 * Note, we can't just make a pointer to the new file name,
169 * since saverec() might move the header and adjust "head".
170 * We have to start from "head" every time we want to touch
174 while (!f_absolute_paths
&& '/' == head
->header
.name
[skipcrud
]) {
175 static int warned_once
= 0;
177 skipcrud
++; /* Force relative path */
178 if (!warned_once
++) {
179 msg("Removing leading / from absolute path names in the archive.");
183 switch (head
->header
.linkflag
) {
186 msg("Unknown file type '%c' for %s, extracted as normal file",
187 head
->header
.linkflag
, skipcrud
+head
->header
.name
);
191 * JK - What we want to do if the file is sparse is loop through
192 * the array of sparse structures in the header and read in
193 * and translate the character strings representing 1) the offset
194 * at which to write and 2) how many bytes to write into numbers,
195 * which we store into the scratch array, "sparsearray". This
196 * array makes our life easier the same way it did in creating
197 * the tar file that had to deal with a sparse file.
199 * After we read in the first five (at most) sparse structures,
200 * we check to see if the file has an extended header, i.e.,
201 * if more sparse structures are needed to describe the contents
202 * of the new file. If so, we read in the extended headers
203 * and continue to store their contents into the sparsearray.
207 sparsearray
= (struct sp_array
*) malloc(sp_array_size
* sizeof(struct sp_array
));
208 for (i
= 0; i
< SPARSE_IN_HDR
; i
++) {
209 sparsearray
[i
].offset
=
210 from_oct(1+12, head
->header
.sp
[i
].offset
);
211 sparsearray
[i
].numbytes
=
212 from_oct(1+12, head
->header
.sp
[i
].numbytes
);
213 if (!sparsearray
[i
].numbytes
)
217 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
219 if (head
->header
.isextended
) {
220 /* read in the list of extended headers
221 and translate them into the sparsearray
224 /* static */ int ind
= SPARSE_IN_HDR
;
229 for (i
= 0; i
< SPARSE_EXT_HDR
; i
++) {
231 if (i
+ind
> sp_array_size
-1) {
233 * realloc the scratch area
234 * since we've run out of room --
236 sparsearray
= (struct sp_array
*)
238 2 * sp_array_size
* (sizeof(struct sp_array
)));
241 if (!exhdr
->ext_hdr
.sp
[i
].numbytes
)
243 sparsearray
[i
+ind
].offset
=
244 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].offset
);
245 sparsearray
[i
+ind
].numbytes
=
246 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].numbytes
);
248 if (!exhdr
->ext_hdr
.isextended
)
251 ind
+= SPARSE_EXT_HDR
;
263 * Appears to be a file.
264 * See if it's really a directory.
266 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
267 if (head
->header
.name
[skipcrud
+namelen
] == '/')
270 /* FIXME, deal with protection issues */
273 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_EXCL
:
274 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_TRUNC
)
275 | ((head
->header
.linkflag
== LF_SPARSE
) ? 0 : O_APPEND
);
277 * JK - The last | is a kludge to solve the problem
278 * the O_APPEND flag causes with files we are
279 * trying to make sparse: when a file is opened
280 * with O_APPEND, it writes to the last place
281 * that something was written, thereby ignoring
282 * any lseeks that we have done. We add this
283 * extra condition to make it able to lseek when
284 * a file is sparse, i.e., we don't open the new
285 * file with this flag. (Grump -- this bug caused
286 * me to waste a good deal of time, I might add)
295 * Contiguous files (on the Masscomp) have to specify
296 * the size in the open call that creates them.
298 if (head
->header
.linkflag
== LF_CONTIG
)
299 fd
= open(skipcrud
+head
->header
.name
, openflag
| O_CTG
,
300 hstat
.st_mode
, hstat
.st_size
);
306 * On raw V7 we won't let them specify -k (f_keep), but
307 * we just bull ahead and create the files.
309 fd
= creat(skipcrud
+head
->header
.name
,
313 * With 3-arg open(), we can do this up right.
315 fd
= open(skipcrud
+head
->header
.name
, openflag
,
321 if (make_dirs(skipcrud
+head
->header
.name
))
323 msg_perror("Could not create file %s",skipcrud
+head
->header
.name
);
324 if (head
->header
.isextended
)
325 skip_extended_headers();
326 skip_file((long)hstat
.st_size
);
331 if (head
->header
.linkflag
== LF_SPARSE
) {
336 * Kludge alert. NAME is assigned to header.name
337 * because during the extraction, the space that
338 * contains the header will get scribbled on, and
339 * the name will get munged, so any error messages
340 * that happen to contain the filename will look
341 * REAL interesting unless we do this.
343 namelen
= strlen(skipcrud
+head
->header
.name
);
344 name
= (char *) malloc((sizeof(char)) * namelen
);
345 bcopy(skipcrud
+head
->header
.name
, name
, namelen
);
346 size
= hstat
.st_size
;
347 extract_sparse_file(fd
, &size
, hstat
.st_size
,
351 for (size
= hstat
.st_size
;
359 save_name
=head
->header
.name
;
360 save_totsize
=hstat
.st_size
;
365 * Locate data, determine max length
366 * writeable, write it, record that
367 * we have used the data, then check
368 * if the write worked.
370 data
= findrec()->charptr
;
371 if (data
== NULL
) { /* Check it... */
372 msg("Unexpected EOF on archive file");
376 * JK - If the file is sparse, use the sparsearray
377 * that we created before to lseek into the new
378 * file the proper amount, and to see how many
379 * bytes we want to write at that position.
381 /* if (head->header.linkflag == LF_SPARSE) {
384 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
385 printf("%d at %d\n", (int) pos, sparse_ind);
386 written = sparsearray[sparse_ind++].numbytes;
388 written
= endofrecs()->charptr
- data
;
392 check
= write(fd
, data
, written
);
394 * The following is in violation of strict
395 * typing, since the arg to userec
396 * should be a struct rec *. FIXME.
398 userec((union record
*)(data
+ written
- 1));
399 if (check
== written
) continue;
401 * Error in writing to file.
402 * Print it, skip to next file in archive.
405 msg_perror("couldn't write to file %s",skipcrud
+head
->header
.name
);
407 msg("could only write %d of %d bytes to file %s",written
,check
,skipcrud
+head
->header
.name
);
408 skip_file((long)(size
- written
));
409 break; /* Still do the close, mod time, chmod, etc */
415 /* If writing to stdout, don't try to do anything
416 to the filename; it doesn't exist, or we don't
417 want to touch it anyway */
421 /* if (head->header.isextended) {
422 register union record *exhdr;
425 for (i = 0; i < 21; i++) {
428 if (!exhdr->ext_hdr.sp[i].numbytes)
430 offset = from_oct(1+12,
431 exhdr->ext_hdr.sp[i].offset);
432 written = from_oct(1+12,
433 exhdr->ext_hdr.sp[i].numbytes);
434 lseek(fd, offset, 0);
435 check = write(fd, data, written);
436 if (check == written) continue;
444 msg_perror("Error while closing %s",skipcrud
+head
->header
.name
);
451 * If we are root, set the owner and group of the extracted
452 * file. This does what is wanted both on real Unix and on
453 * System V. If we are running as a user, we extract as that
454 * user; if running as root, we extract as the original owner.
456 if (we_are_root
|| f_do_chown
) {
457 if (chown(skipcrud
+head
->header
.name
, hstat
.st_uid
,
459 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud
+head
->header
.name
,hstat
.st_uid
,hstat
.st_gid
);
464 * Set the modified time of the file.
466 * Note that we set the accessed time to "now", which
467 * is really "the time we started extracting files".
468 * unless f_gnudump is used, in which case .st_atime is used
471 /* fixme if f_gnudump should set ctime too, but how? */
473 acc_upd_times
[0]=hstat
.st_atime
;
474 else acc_upd_times
[0] = now
; /* Accessed now */
475 acc_upd_times
[1] = hstat
.st_mtime
; /* Mod'd */
476 if (utime(skipcrud
+head
->header
.name
,
477 acc_upd_times
) < 0) {
478 msg_perror("couldn't change access and modification times of %s",skipcrud
+head
->header
.name
);
481 /* We do the utime before the chmod because some versions of
482 utime are broken and trash the modes of the file. Since
483 we then change the mode anyway, we don't care. . . */
486 * If '-k' is not set, open() or creat() could have saved
487 * the permission bits from a previously created file,
488 * ignoring the ones we specified.
489 * Even if -k is set, if the file has abnormal
490 * mode bits, we must chmod since writing or chown() has
491 * probably reset them.
493 * If -k is set, we know *we* created this file, so the mode
494 * bits were set by our open(). If the file is "normal", we
495 * skip the chmod. This works because we did umask(0) if -p
496 * is set, so umask will have left the specified mode alone.
499 || (hstat
.st_mode
& (S_ISUID
|S_ISGID
|S_ISVTX
))) {
500 if (chmod(skipcrud
+head
->header
.name
,
501 notumask
& (int)hstat
.st_mode
) < 0) {
502 msg_perror("cannot change mode of file %s to %ld",skipcrud
+head
->header
.name
,notumask
& (int)hstat
.st_mode
);
514 check
= link (head
->header
.linkname
,
515 skipcrud
+head
->header
.name
);
518 if (make_dirs(skipcrud
+head
->header
.name
))
520 if(f_gnudump
&& errno
==EEXIST
)
522 if( stat(head
->header
.linkname
, &st1
) == 0
523 && stat(skipcrud
+head
->header
.name
, &st2
)==0
524 && st1
.st_dev
==st2
.st_dev
525 && st1
.st_ino
==st2
.st_ino
)
527 msg_perror("Could not link %s to %s",
528 skipcrud
+head
->header
.name
,head
->header
.linkname
);
535 check
= symlink(head
->header
.linkname
,
536 skipcrud
+head
->header
.name
);
537 /* FIXME, don't worry uid, gid, etc... */
540 if (make_dirs(skipcrud
+head
->header
.name
))
542 msg_perror("Could not create symlink to %s",head
->header
.linkname
);
548 hstat
.st_mode
|= S_IFCHR
;
554 hstat
.st_mode
|= S_IFBLK
;
556 #if defined(S_IFCHR) || defined(S_IFBLK)
558 check
= mknod(skipcrud
+head
->header
.name
,
559 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
561 if (make_dirs(skipcrud
+head
->header
.name
))
563 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
570 /* If local system doesn't support FIFOs, use default case */
573 check
= mkfifo(skipcrud
+head
->header
.name
,
574 (int) hstat
.st_mode
);
576 if (make_dirs(skipcrud
+head
->header
.name
))
578 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
586 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
588 /* Check for trailing /, and zap as many as we find. */
589 while (namelen
&& head
->header
.name
[skipcrud
+namelen
] == '/')
590 head
->header
.name
[skipcrud
+namelen
--] = '\0';
591 if(f_gnudump
) { /* Read the entry and delete files
592 that aren't listed in the archive */
593 gnu_restore(skipcrud
);
595 } else if(head
->header
.linkflag
==LF_DUMPDIR
)
596 skip_file((long)(hstat
.st_size
));
600 check
= mkdir(skipcrud
+head
->header
.name
,
601 (we_are_root
? 0 : 0300) | (int)hstat
.st_mode
);
605 if (make_dirs(skipcrud
+head
->header
.name
))
607 /* If we're trying to create '.', let it be. */
608 if (head
->header
.name
[skipcrud
+namelen
] == '.' &&
610 head
->header
.name
[skipcrud
+namelen
-1]=='/'))
613 && stat(skipcrud
+head
->header
.name
,&st1
)==0
614 && (S_ISDIR(st1
.st_mode
)))
616 msg_perror("Could not create directory %s",skipcrud
+head
->header
.name
);
621 if (!we_are_root
&& 0300 != (0300 & (int) hstat
.st_mode
)) {
622 hstat
.st_mode
|= 0300;
623 msg("Added write and execute permission to directory %s",
624 skipcrud
+head
->header
.name
);
629 tmp
= malloc (sizeof (struct saved_dir_info
));
630 tmp
->path
= malloc (strlen (skipcrud
+ head
->header
.name
) + 1);
631 strcpy (tmp
->path
, skipcrud
+ head
->header
.name
);
632 tmp
->mode
= hstat
.st_mode
;
633 tmp
->atime
= hstat
.st_atime
;
634 tmp
->mtime
= hstat
.st_mtime
;
635 tmp
->next
= saved_dir_info_head
;
636 saved_dir_info_head
= tmp
;
639 printf("Reading %s\n",head
->header
.name
);
644 extract_mangle(head
);
648 msg("Can't extract '%s'--file is continued from another volume\n",head
->header
.name
);
649 skip_file((long)hstat
.st_size
);
654 /* We don't need to save it any longer. */
655 saverec((union record
**) 0); /* Unsave it */
659 * After a file/link/symlink/dir creation has failed, see if
660 * it's because some required directory was not present, and if
661 * so, create all required dirs.
667 char *p
; /* Points into path */
668 int madeone
= 0; /* Did we do anything yet? */
669 int save_errno
= errno
; /* Remember caller's errno */
673 return 0; /* Not our problem */
675 for (p
= index(pathname
, '/'); p
!= NULL
; p
= index(p
+1, '/')) {
676 /* Avoid mkdir of empty string, if leading or double '/' */
677 if (p
== pathname
|| p
[-1] == '/')
679 /* Avoid mkdir where last part of path is '.' */
680 if (p
[-1] == '.' && (p
== pathname
+1 || p
[-2] == '/'))
682 *p
= 0; /* Truncate the path there */
683 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
687 if (chown(pathname
, hstat
.st_uid
,
689 msg_perror("cannot change owner of %s to uid %d gid %d",pathname
,hstat
.st_uid
,hstat
.st_gid
);
692 pr_mkdir(pathname
, p
-pathname
, notumask
&0777);
693 madeone
++; /* Remember if we made one */
698 if (errno
== EEXIST
) /* Directory already exists */
701 * Some other error in the mkdir. We return to the caller.
706 errno
= save_errno
; /* Restore caller's errno */
707 return madeone
; /* Tell them to retry if we made one */
711 extract_sparse_file(fd
, sizeleft
, totalsize
, name
)
717 /* register char *data;*/
718 union record
*datarec
;
723 /* assuming sizeleft is initially totalsize */
726 while (*sizeleft
> 0) {
728 if (datarec
== NULL
) {
729 msg("Unexpected EOF on archive file");
732 lseek(fd
, sparsearray
[sparse_ind
].offset
, 0);
733 written
= sparsearray
[sparse_ind
++].numbytes
;
734 while (written
> RECORDSIZE
) {
735 count
= write(fd
, datarec
->charptr
, RECORDSIZE
);
737 msg_perror("couldn't write to file %s", name
);
744 count
= write(fd
, datarec
->charptr
, written
);
747 msg_perror("couldn't write to file %s", name
);
748 } else if (count
!= written
) {
749 msg("could only write %d of %d bytes to file %s", totalsize
- *sizeleft
, totalsize
, name
);
750 skip_file((long) (*sizeleft
));
761 printf("%d\n", (int) end_nulls);
762 for (i = 0; i < end_nulls; i++)
763 write(fd, "\000", 1);
768 /* Set back the utime and mode for all the extracted directories. */
769 void restore_saved_dir_info ()
771 time_t acc_upd_times
[2];
774 while (saved_info_head
!= NULL
)
776 /* fixme if f_gnudump should set ctime too, but how? */
778 acc_upd_times
[0]=saved_info_head
-> atime
;
779 else acc_upd_times
[0] = now
; /* Accessed now */
780 acc_upd_times
[1] = saved_info_head
-> mtime
; /* Mod'd */
781 if (utime(saved_info_head
-> path
, acc_upd_times
) < 0) {
782 msg_perror("couldn't change access and modification times of %s",
783 saved_info_head
-> path
);
785 if ((!f_keep
) || (saved_info_head
-> mode
& (S_ISUID
|S_ISGID
|S_ISVTX
)))
787 if (chmod(saved_info_head
-> path
,
788 notumask
& saved_info_head
-> mode
) < 0) {
789 msg_perror("cannot change mode of file %s to %ld",
790 saved_info_head
-> path
,
791 notumask
& saved_info_head
-> mode
);
794 saved_info_head
= saved_info_head
-> next
;
This page took 0.066422 seconds and 4 git commands to generate.