]>
Dogcows Code - chaz/tar/blob - src/extract.c
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 static char *longname
;
150 static char *longlink
;
152 saverec(&head
); /* Make sure it sticks around */
153 userec(head
); /* And go past it in the archive */
154 decode_header(head
, &hstat
, &head_standard
, 1); /* Snarf fields */
156 if(f_confirm
&& !confirm("extract",head
->header
.name
)) {
157 if (head
->header
.isextended
)
158 skip_extended_headers();
159 skip_file((long)hstat
.st_size
);
160 saverec((union record
**)0);
164 /* Print the record from 'head' and 'hstat' */
169 * Check for fully specified pathnames and other atrocities.
171 * Note, we can't just make a pointer to the new file name,
172 * since saverec() might move the header and adjust "head".
173 * We have to start from "head" every time we want to touch
177 while (!f_absolute_paths
&& '/' == head
->header
.name
[skipcrud
]) {
178 static int warned_once
= 0;
180 skipcrud
++; /* Force relative path */
181 if (!warned_once
++) {
182 msg("Removing leading / from absolute path names in the archive.");
186 switch (head
->header
.linkflag
) {
189 msg("Unknown file type '%c' for %s, extracted as normal file",
190 head
->header
.linkflag
, skipcrud
+head
->header
.name
);
194 * JK - What we want to do if the file is sparse is loop through
195 * the array of sparse structures in the header and read in
196 * and translate the character strings representing 1) the offset
197 * at which to write and 2) how many bytes to write into numbers,
198 * which we store into the scratch array, "sparsearray". This
199 * array makes our life easier the same way it did in creating
200 * the tar file that had to deal with a sparse file.
202 * After we read in the first five (at most) sparse structures,
203 * we check to see if the file has an extended header, i.e.,
204 * if more sparse structures are needed to describe the contents
205 * of the new file. If so, we read in the extended headers
206 * and continue to store their contents into the sparsearray.
210 sparsearray
= (struct sp_array
*) malloc(sp_array_size
* sizeof(struct sp_array
));
211 for (i
= 0; i
< SPARSE_IN_HDR
; i
++) {
212 sparsearray
[i
].offset
=
213 from_oct(1+12, head
->header
.sp
[i
].offset
);
214 sparsearray
[i
].numbytes
=
215 from_oct(1+12, head
->header
.sp
[i
].numbytes
);
216 if (!sparsearray
[i
].numbytes
)
220 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
222 if (head
->header
.isextended
) {
223 /* read in the list of extended headers
224 and translate them into the sparsearray
227 /* static */ int ind
= SPARSE_IN_HDR
;
232 for (i
= 0; i
< SPARSE_EXT_HDR
; i
++) {
234 if (i
+ind
> sp_array_size
-1) {
236 * realloc the scratch area
237 * since we've run out of room --
239 sparsearray
= (struct sp_array
*)
241 2 * sp_array_size
* (sizeof(struct sp_array
)));
244 if (!exhdr
->ext_hdr
.sp
[i
].numbytes
)
246 sparsearray
[i
+ind
].offset
=
247 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].offset
);
248 sparsearray
[i
+ind
].numbytes
=
249 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].numbytes
);
251 if (!exhdr
->ext_hdr
.isextended
)
254 ind
+= SPARSE_EXT_HDR
;
266 * Appears to be a file.
267 * See if it's really a directory.
269 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
270 if (head
->header
.name
[skipcrud
+namelen
] == '/')
273 /* FIXME, deal with protection issues */
276 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_EXCL
:
277 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_TRUNC
)
278 | ((head
->header
.linkflag
== LF_SPARSE
) ? 0 : O_APPEND
);
280 * JK - The last | is a kludge to solve the problem
281 * the O_APPEND flag causes with files we are
282 * trying to make sparse: when a file is opened
283 * with O_APPEND, it writes to the last place
284 * that something was written, thereby ignoring
285 * any lseeks that we have done. We add this
286 * extra condition to make it able to lseek when
287 * a file is sparse, i.e., we don't open the new
288 * file with this flag. (Grump -- this bug caused
289 * me to waste a good deal of time, I might add)
298 * Contiguous files (on the Masscomp) have to specify
299 * the size in the open call that creates them.
301 if (head
->header
.linkflag
== LF_CONTIG
)
302 fd
= open(skipcrud
+head
->header
.name
, openflag
| O_CTG
,
303 hstat
.st_mode
, hstat
.st_size
);
309 * On raw V7 we won't let them specify -k (f_keep), but
310 * we just bull ahead and create the files.
312 fd
= creat(skipcrud
+head
->header
.name
,
316 * With 3-arg open(), we can do this up right.
318 fd
= open(skipcrud
+head
->header
.name
, openflag
,
324 if (make_dirs(skipcrud
+head
->header
.name
))
326 msg_perror("Could not create file %s",skipcrud
+head
->header
.name
);
327 if (head
->header
.isextended
)
328 skip_extended_headers();
329 skip_file((long)hstat
.st_size
);
334 if (head
->header
.linkflag
== LF_SPARSE
) {
339 * Kludge alert. NAME is assigned to header.name
340 * because during the extraction, the space that
341 * contains the header will get scribbled on, and
342 * the name will get munged, so any error messages
343 * that happen to contain the filename will look
344 * REAL interesting unless we do this.
346 namelen
= strlen(skipcrud
+head
->header
.name
);
347 name
= (char *) malloc((sizeof(char)) * namelen
);
348 bcopy(skipcrud
+head
->header
.name
, name
, namelen
);
349 size
= hstat
.st_size
;
350 extract_sparse_file(fd
, &size
, hstat
.st_size
,
354 for (size
= hstat
.st_size
;
362 save_name
=head
->header
.name
;
363 save_totsize
=hstat
.st_size
;
368 * Locate data, determine max length
369 * writeable, write it, record that
370 * we have used the data, then check
371 * if the write worked.
373 data
= findrec()->charptr
;
374 if (data
== NULL
) { /* Check it... */
375 msg("Unexpected EOF on archive file");
379 * JK - If the file is sparse, use the sparsearray
380 * that we created before to lseek into the new
381 * file the proper amount, and to see how many
382 * bytes we want to write at that position.
384 /* if (head->header.linkflag == LF_SPARSE) {
387 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
388 printf("%d at %d\n", (int) pos, sparse_ind);
389 written = sparsearray[sparse_ind++].numbytes;
391 written
= endofrecs()->charptr
- data
;
395 check
= write(fd
, data
, written
);
397 * The following is in violation of strict
398 * typing, since the arg to userec
399 * should be a struct rec *. FIXME.
401 userec((union record
*)(data
+ written
- 1));
402 if (check
== written
) continue;
404 * Error in writing to file.
405 * Print it, skip to next file in archive.
408 msg_perror("couldn't write to file %s",skipcrud
+head
->header
.name
);
410 msg("could only write %d of %d bytes to file %s",written
,check
,skipcrud
+head
->header
.name
);
411 skip_file((long)(size
- written
));
412 break; /* Still do the close, mod time, chmod, etc */
418 /* If writing to stdout, don't try to do anything
419 to the filename; it doesn't exist, or we don't
420 want to touch it anyway */
424 /* if (head->header.isextended) {
425 register union record *exhdr;
428 for (i = 0; i < 21; i++) {
431 if (!exhdr->ext_hdr.sp[i].numbytes)
433 offset = from_oct(1+12,
434 exhdr->ext_hdr.sp[i].offset);
435 written = from_oct(1+12,
436 exhdr->ext_hdr.sp[i].numbytes);
437 lseek(fd, offset, 0);
438 check = write(fd, data, written);
439 if (check == written) continue;
447 msg_perror("Error while closing %s",skipcrud
+head
->header
.name
);
454 * If we are root, set the owner and group of the extracted
455 * file. This does what is wanted both on real Unix and on
456 * System V. If we are running as a user, we extract as that
457 * user; if running as root, we extract as the original owner.
459 if (we_are_root
|| f_do_chown
) {
460 if (chown(skipcrud
+head
->header
.name
, hstat
.st_uid
,
462 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud
+head
->header
.name
,hstat
.st_uid
,hstat
.st_gid
);
467 * Set the modified time of the file.
469 * Note that we set the accessed time to "now", which
470 * is really "the time we started extracting files".
471 * unless f_gnudump is used, in which case .st_atime is used
474 /* fixme if f_gnudump should set ctime too, but how? */
476 acc_upd_times
[0]=hstat
.st_atime
;
477 else acc_upd_times
[0] = now
; /* Accessed now */
478 acc_upd_times
[1] = hstat
.st_mtime
; /* Mod'd */
479 if (utime(skipcrud
+head
->header
.name
,
480 acc_upd_times
) < 0) {
481 msg_perror("couldn't change access and modification times of %s",skipcrud
+head
->header
.name
);
484 /* We do the utime before the chmod because some versions of
485 utime are broken and trash the modes of the file. Since
486 we then change the mode anyway, we don't care. . . */
489 * If '-k' is not set, open() or creat() could have saved
490 * the permission bits from a previously created file,
491 * ignoring the ones we specified.
492 * Even if -k is set, if the file has abnormal
493 * mode bits, we must chmod since writing or chown() has
494 * probably reset them.
496 * If -k is set, we know *we* created this file, so the mode
497 * bits were set by our open(). If the file is "normal", we
498 * skip the chmod. This works because we did umask(0) if -p
499 * is set, so umask will have left the specified mode alone.
502 || (hstat
.st_mode
& (S_ISUID
|S_ISGID
|S_ISVTX
))) {
503 if (chmod(skipcrud
+head
->header
.name
,
504 notumask
& (int)hstat
.st_mode
) < 0) {
505 msg_perror("cannot change mode of file %s to %ld",skipcrud
+head
->header
.name
,notumask
& (int)hstat
.st_mode
);
517 check
= link (head
->header
.linkname
,
518 skipcrud
+head
->header
.name
);
521 if (make_dirs(skipcrud
+head
->header
.name
))
523 if(f_gnudump
&& errno
==EEXIST
)
525 if( stat(head
->header
.linkname
, &st1
) == 0
526 && stat(skipcrud
+head
->header
.name
, &st2
)==0
527 && st1
.st_dev
==st2
.st_dev
528 && st1
.st_ino
==st2
.st_ino
)
530 msg_perror("Could not link %s to %s",
531 skipcrud
+head
->header
.name
,head
->header
.linkname
);
538 check
= symlink(head
->header
.linkname
,
539 skipcrud
+head
->header
.name
);
540 /* FIXME, don't worry uid, gid, etc... */
543 if (make_dirs(skipcrud
+head
->header
.name
))
545 msg_perror("Could not create symlink to %s",head
->header
.linkname
);
551 hstat
.st_mode
|= S_IFCHR
;
557 hstat
.st_mode
|= S_IFBLK
;
559 #if defined(S_IFCHR) || defined(S_IFBLK)
561 check
= mknod(skipcrud
+head
->header
.name
,
562 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
564 if (make_dirs(skipcrud
+head
->header
.name
))
566 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
573 /* If local system doesn't support FIFOs, use default case */
576 check
= mkfifo(skipcrud
+head
->header
.name
,
577 (int) hstat
.st_mode
);
579 if (make_dirs(skipcrud
+head
->header
.name
))
581 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
589 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
591 /* Check for trailing /, and zap as many as we find. */
592 while (namelen
&& head
->header
.name
[skipcrud
+namelen
] == '/')
593 head
->header
.name
[skipcrud
+namelen
--] = '\0';
594 if(f_gnudump
) { /* Read the entry and delete files
595 that aren't listed in the archive */
596 gnu_restore(skipcrud
);
598 } else if(head
->header
.linkflag
==LF_DUMPDIR
)
599 skip_file((long)(hstat
.st_size
));
603 check
= mkdir(skipcrud
+head
->header
.name
,
604 (we_are_root
? 0 : 0300) | (int)hstat
.st_mode
);
608 if (make_dirs(skipcrud
+head
->header
.name
))
610 /* If we're trying to create '.', let it be. */
611 if (head
->header
.name
[skipcrud
+namelen
] == '.' &&
613 head
->header
.name
[skipcrud
+namelen
-1]=='/'))
616 && stat(skipcrud
+head
->header
.name
,&st1
)==0
617 && (S_ISDIR(st1
.st_mode
)))
619 msg_perror("Could not create directory %s",skipcrud
+head
->header
.name
);
624 if (!we_are_root
&& 0300 != (0300 & (int) hstat
.st_mode
)) {
625 hstat
.st_mode
|= 0300;
626 msg("Added write and execute permission to directory %s",
627 skipcrud
+head
->header
.name
);
632 tmp
= malloc (sizeof (struct saved_dir_info
));
633 tmp
->path
= malloc (strlen (skipcrud
+ head
->header
.name
) + 1);
634 strcpy (tmp
->path
, skipcrud
+ head
->header
.name
);
635 tmp
->mode
= hstat
.st_mode
;
636 tmp
->atime
= hstat
.st_atime
;
637 tmp
->mtime
= hstat
.st_mtime
;
638 tmp
->next
= saved_dir_info_head
;
639 saved_dir_info_head
= tmp
;
642 printf("Reading %s\n",head
->header
.name
);
647 extract_mangle(head
);
651 msg("Can't extract '%s'--file is continued from another volume\n",head
->header
.name
);
652 skip_file((long)hstat
.st_size
);
665 *longp
= ck_malloc (hstat
.st_size
);
667 /* This loop is copied from the extract_file label above;
668 as a result, some of the variable names (like `written')
669 might be confusing. */
670 for (size
= hstat
.st_size
;
679 /* We don't need to save it any longer. */
680 saverec((union record
**) 0); /* Unsave it */
684 * After a file/link/symlink/dir creation has failed, see if
685 * it's because some required directory was not present, and if
686 * so, create all required dirs.
692 char *p
; /* Points into path */
693 int madeone
= 0; /* Did we do anything yet? */
694 int save_errno
= errno
; /* Remember caller's errno */
698 return 0; /* Not our problem */
700 for (p
= index(pathname
, '/'); p
!= NULL
; p
= index(p
+1, '/')) {
701 /* Avoid mkdir of empty string, if leading or double '/' */
702 if (p
== pathname
|| p
[-1] == '/')
704 /* Avoid mkdir where last part of path is '.' */
705 if (p
[-1] == '.' && (p
== pathname
+1 || p
[-2] == '/'))
707 *p
= 0; /* Truncate the path there */
708 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
712 if (chown(pathname
, hstat
.st_uid
,
714 msg_perror("cannot change owner of %s to uid %d gid %d",pathname
,hstat
.st_uid
,hstat
.st_gid
);
717 pr_mkdir(pathname
, p
-pathname
, notumask
&0777);
718 madeone
++; /* Remember if we made one */
723 if (errno
== EEXIST
) /* Directory already exists */
726 * Some other error in the mkdir. We return to the caller.
731 errno
= save_errno
; /* Restore caller's errno */
732 return madeone
; /* Tell them to retry if we made one */
736 extract_sparse_file(fd
, sizeleft
, totalsize
, name
)
742 /* register char *data;*/
743 union record
*datarec
;
748 /* assuming sizeleft is initially totalsize */
751 while (*sizeleft
> 0) {
753 if (datarec
== NULL
) {
754 msg("Unexpected EOF on archive file");
757 lseek(fd
, sparsearray
[sparse_ind
].offset
, 0);
758 written
= sparsearray
[sparse_ind
++].numbytes
;
759 while (written
> RECORDSIZE
) {
760 count
= write(fd
, datarec
->charptr
, RECORDSIZE
);
762 msg_perror("couldn't write to file %s", name
);
769 count
= write(fd
, datarec
->charptr
, written
);
772 msg_perror("couldn't write to file %s", name
);
773 } else if (count
!= written
) {
774 msg("could only write %d of %d bytes to file %s", totalsize
- *sizeleft
, totalsize
, name
);
775 skip_file((long) (*sizeleft
));
786 printf("%d\n", (int) end_nulls);
787 for (i = 0; i < end_nulls; i++)
788 write(fd, "\000", 1);
793 /* Set back the utime and mode for all the extracted directories. */
794 void restore_saved_dir_info ()
796 time_t acc_upd_times
[2];
799 while (saved_info_head
!= NULL
)
801 /* fixme if f_gnudump should set ctime too, but how? */
803 acc_upd_times
[0]=saved_info_head
-> atime
;
804 else acc_upd_times
[0] = now
; /* Accessed now */
805 acc_upd_times
[1] = saved_info_head
-> mtime
; /* Mod'd */
806 if (utime(saved_info_head
-> path
, acc_upd_times
) < 0) {
807 msg_perror("couldn't change access and modification times of %s",
808 saved_info_head
-> path
);
810 if ((!f_keep
) || (saved_info_head
-> mode
& (S_ISUID
|S_ISGID
|S_ISVTX
)))
812 if (chmod(saved_info_head
-> path
,
813 notumask
& saved_info_head
-> mode
) < 0) {
814 msg_perror("cannot change mode of file %s to %ld",
815 saved_info_head
-> path
,
816 notumask
& saved_info_head
-> mode
);
819 saved_info_head
= saved_info_head
-> next
;
This page took 0.067275 seconds and 4 git commands to generate.