]>
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;*/
107 * Set up to extract files.
114 now
= time((time_t *)0);
119 * We need to know our umask. But if f_use_protection is set,
120 * leave our kernel umask at 0, and our "notumask" at ~0.
122 ourmask
= umask(0); /* Read it */
123 if (!f_use_protection
) {
124 (void) umask (ourmask
); /* Set it back how it was */
125 notumask
= ~ourmask
; /* Make umask override permissions */
131 * Extract a file from the archive.
137 int fd
, check
, namelen
, written
, openflag
;
139 time_t acc_upd_times
[2];
140 register int skipcrud
;
142 /* int sparse_ind = 0;*/
146 saverec(&head
); /* Make sure it sticks around */
147 userec(head
); /* And go past it in the archive */
148 decode_header(head
, &hstat
, &head_standard
, 1); /* Snarf fields */
150 if(f_confirm
&& !confirm("extract",head
->header
.name
)) {
151 if (head
->header
.isextended
)
152 skip_extended_headers();
153 skip_file((long)hstat
.st_size
);
154 saverec((union record
**)0);
158 /* Print the record from 'head' and 'hstat' */
163 * Check for fully specified pathnames and other atrocities.
165 * Note, we can't just make a pointer to the new file name,
166 * since saverec() might move the header and adjust "head".
167 * We have to start from "head" every time we want to touch
171 while (!f_absolute_paths
&& '/' == head
->header
.name
[skipcrud
]) {
172 static int warned_once
= 0;
174 skipcrud
++; /* Force relative path */
175 if (!warned_once
++) {
176 msg("Removing leading / from absolute path names in the archive.");
180 switch (head
->header
.linkflag
) {
183 msg("Unknown file type '%c' for %s, extracted as normal file",
184 head
->header
.linkflag
, skipcrud
+head
->header
.name
);
188 * JK - What we want to do if the file is sparse is loop through
189 * the array of sparse structures in the header and read in
190 * and translate the character strings representing 1) the offset
191 * at which to write and 2) how many bytes to write into numbers,
192 * which we store into the scratch array, "sparsearray". This
193 * array makes our life easier the same way it did in creating
194 * the tar file that had to deal with a sparse file.
196 * After we read in the first five (at most) sparse structures,
197 * we check to see if the file has an extended header, i.e.,
198 * if more sparse structures are needed to describe the contents
199 * of the new file. If so, we read in the extended headers
200 * and continue to store their contents into the sparsearray.
204 sparsearray
= (struct sp_array
*) malloc(sp_array_size
* sizeof(struct sp_array
));
205 for (i
= 0; i
< SPARSE_IN_HDR
; i
++) {
206 sparsearray
[i
].offset
=
207 from_oct(1+12, head
->header
.sp
[i
].offset
);
208 sparsearray
[i
].numbytes
=
209 from_oct(1+12, head
->header
.sp
[i
].numbytes
);
210 if (!sparsearray
[i
].numbytes
)
214 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
216 if (head
->header
.isextended
) {
217 /* read in the list of extended headers
218 and translate them into the sparsearray
221 /* static */ int ind
= SPARSE_IN_HDR
;
226 for (i
= 0; i
< SPARSE_EXT_HDR
; i
++) {
228 if (i
+ind
> sp_array_size
-1) {
230 * realloc the scratch area
231 * since we've run out of room --
233 sparsearray
= (struct sp_array
*)
235 2 * sp_array_size
* (sizeof(struct sp_array
)));
238 if (!exhdr
->ext_hdr
.sp
[i
].numbytes
)
240 sparsearray
[i
+ind
].offset
=
241 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].offset
);
242 sparsearray
[i
+ind
].numbytes
=
243 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].numbytes
);
245 if (!exhdr
->ext_hdr
.isextended
)
248 ind
+= SPARSE_EXT_HDR
;
260 * Appears to be a file.
261 * See if it's really a directory.
263 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
264 if (head
->header
.name
[skipcrud
+namelen
] == '/')
267 /* FIXME, deal with protection issues */
270 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_EXCL
:
271 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_TRUNC
)
272 | ((head
->header
.linkflag
== LF_SPARSE
) ? 0 : O_APPEND
);
274 * JK - The last | is a kludge to solve the problem
275 * the O_APPEND flag causes with files we are
276 * trying to make sparse: when a file is opened
277 * with O_APPEND, it writes to the last place
278 * that something was written, thereby ignoring
279 * any lseeks that we have done. We add this
280 * extra condition to make it able to lseek when
281 * a file is sparse, i.e., we don't open the new
282 * file with this flag. (Grump -- this bug caused
283 * me to waste a good deal of time, I might add)
292 * Contiguous files (on the Masscomp) have to specify
293 * the size in the open call that creates them.
295 if (head
->header
.linkflag
== LF_CONTIG
)
296 fd
= open(skipcrud
+head
->header
.name
, openflag
| O_CTG
,
297 hstat
.st_mode
, hstat
.st_size
);
303 * On raw V7 we won't let them specify -k (f_keep), but
304 * we just bull ahead and create the files.
306 fd
= creat(skipcrud
+head
->header
.name
,
310 * With 3-arg open(), we can do this up right.
312 fd
= open(skipcrud
+head
->header
.name
, openflag
,
318 if (make_dirs(skipcrud
+head
->header
.name
))
320 msg_perror("Could not create file %s",skipcrud
+head
->header
.name
);
321 if (head
->header
.isextended
)
322 skip_extended_headers();
323 skip_file((long)hstat
.st_size
);
328 if (head
->header
.linkflag
== LF_SPARSE
) {
333 * Kludge alert. NAME is assigned to header.name
334 * because during the extraction, the space that
335 * contains the header will get scribbled on, and
336 * the name will get munged, so any error messages
337 * that happen to contain the filename will look
338 * REAL interesting unless we do this.
340 namelen
= strlen(skipcrud
+head
->header
.name
);
341 name
= (char *) malloc((sizeof(char)) * namelen
);
342 bcopy(skipcrud
+head
->header
.name
, name
, namelen
);
343 size
= hstat
.st_size
;
344 extract_sparse_file(fd
, &size
, hstat
.st_size
,
348 for (size
= hstat
.st_size
;
356 save_name
=head
->header
.name
;
357 save_totsize
=hstat
.st_size
;
362 * Locate data, determine max length
363 * writeable, write it, record that
364 * we have used the data, then check
365 * if the write worked.
367 data
= findrec()->charptr
;
368 if (data
== NULL
) { /* Check it... */
369 msg("Unexpected EOF on archive file");
373 * JK - If the file is sparse, use the sparsearray
374 * that we created before to lseek into the new
375 * file the proper amount, and to see how many
376 * bytes we want to write at that position.
378 /* if (head->header.linkflag == LF_SPARSE) {
381 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
382 printf("%d at %d\n", (int) pos, sparse_ind);
383 written = sparsearray[sparse_ind++].numbytes;
385 written
= endofrecs()->charptr
- data
;
389 check
= write(fd
, data
, written
);
391 * The following is in violation of strict
392 * typing, since the arg to userec
393 * should be a struct rec *. FIXME.
395 userec((union record
*)(data
+ written
- 1));
396 if (check
== written
) continue;
398 * Error in writing to file.
399 * Print it, skip to next file in archive.
402 msg_perror("couldn't write to file %s",skipcrud
+head
->header
.name
);
404 msg("could only write %d of %d bytes to file %s",written
,check
,skipcrud
+head
->header
.name
);
405 skip_file((long)(size
- written
));
406 break; /* Still do the close, mod time, chmod, etc */
412 /* If writing to stdout, don't try to do anything
413 to the filename; it doesn't exist, or we don't
414 want to touch it anyway */
418 /* if (head->header.isextended) {
419 register union record *exhdr;
422 for (i = 0; i < 21; i++) {
425 if (!exhdr->ext_hdr.sp[i].numbytes)
427 offset = from_oct(1+12,
428 exhdr->ext_hdr.sp[i].offset);
429 written = from_oct(1+12,
430 exhdr->ext_hdr.sp[i].numbytes);
431 lseek(fd, offset, 0);
432 check = write(fd, data, written);
433 if (check == written) continue;
441 msg_perror("Error while closing %s",skipcrud
+head
->header
.name
);
448 * If we are root, set the owner and group of the extracted
449 * file. This does what is wanted both on real Unix and on
450 * System V. If we are running as a user, we extract as that
451 * user; if running as root, we extract as the original owner.
453 if (we_are_root
|| f_do_chown
) {
454 if (chown(skipcrud
+head
->header
.name
, hstat
.st_uid
,
456 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud
+head
->header
.name
,hstat
.st_uid
,hstat
.st_gid
);
461 * Set the modified time of the file.
463 * Note that we set the accessed time to "now", which
464 * is really "the time we started extracting files".
465 * unless f_gnudump is used, in which case .st_atime is used
468 /* fixme if f_gnudump should set ctime too, but how? */
470 acc_upd_times
[0]=hstat
.st_atime
;
471 else acc_upd_times
[0] = now
; /* Accessed now */
472 acc_upd_times
[1] = hstat
.st_mtime
; /* Mod'd */
473 if (utime(skipcrud
+head
->header
.name
,
474 acc_upd_times
) < 0) {
475 msg_perror("couldn't change access and modification times of %s",skipcrud
+head
->header
.name
);
478 /* We do the utime before the chmod because some versions of
479 utime are broken and trash the modes of the file. Since
480 we then change the mode anyway, we don't care. . . */
483 * If '-k' is not set, open() or creat() could have saved
484 * the permission bits from a previously created file,
485 * ignoring the ones we specified.
486 * Even if -k is set, if the file has abnormal
487 * mode bits, we must chmod since writing or chown() has
488 * probably reset them.
490 * If -k is set, we know *we* created this file, so the mode
491 * bits were set by our open(). If the file is "normal", we
492 * skip the chmod. This works because we did umask(0) if -p
493 * is set, so umask will have left the specified mode alone.
496 || (hstat
.st_mode
& (S_ISUID
|S_ISGID
|S_ISVTX
))) {
497 if (chmod(skipcrud
+head
->header
.name
,
498 notumask
& (int)hstat
.st_mode
) < 0) {
499 msg_perror("cannot change mode of file %s to %ld",skipcrud
+head
->header
.name
,notumask
& (int)hstat
.st_mode
);
511 check
= link (head
->header
.linkname
,
512 skipcrud
+head
->header
.name
);
515 if (make_dirs(skipcrud
+head
->header
.name
))
517 if(f_gnudump
&& errno
==EEXIST
)
519 if( stat(head
->header
.linkname
, &st1
) == 0
520 && stat(skipcrud
+head
->header
.name
, &st2
)==0
521 && st1
.st_dev
==st2
.st_dev
522 && st1
.st_ino
==st2
.st_ino
)
524 msg_perror("Could not link %s to %s",
525 skipcrud
+head
->header
.name
,head
->header
.linkname
);
532 check
= symlink(head
->header
.linkname
,
533 skipcrud
+head
->header
.name
);
534 /* FIXME, don't worry uid, gid, etc... */
537 if (make_dirs(skipcrud
+head
->header
.name
))
539 msg_perror("Could not create symlink to %s",head
->header
.linkname
);
545 hstat
.st_mode
|= S_IFCHR
;
551 hstat
.st_mode
|= S_IFBLK
;
553 #if defined(S_IFCHR) || defined(S_IFBLK)
555 check
= mknod(skipcrud
+head
->header
.name
,
556 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
558 if (make_dirs(skipcrud
+head
->header
.name
))
560 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
567 /* If local system doesn't support FIFOs, use default case */
570 check
= mkfifo(skipcrud
+head
->header
.name
,
571 (int) hstat
.st_mode
);
573 if (make_dirs(skipcrud
+head
->header
.name
))
575 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
583 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
585 /* Check for trailing /, and zap as many as we find. */
586 while (namelen
&& head
->header
.name
[skipcrud
+namelen
] == '/')
587 head
->header
.name
[skipcrud
+namelen
--] = '\0';
588 if(f_gnudump
) { /* Read the entry and delete files
589 that aren't listed in the archive */
590 gnu_restore(skipcrud
);
592 } else if(head
->header
.linkflag
==LF_DUMPDIR
)
593 skip_file((long)(hstat
.st_size
));
597 check
= mkdir(skipcrud
+head
->header
.name
,
598 (we_are_root
? 0 : 0300) | (int)hstat
.st_mode
);
602 if (make_dirs(skipcrud
+head
->header
.name
))
604 /* If we're trying to create '.', let it be. */
605 if (head
->header
.name
[skipcrud
+namelen
] == '.' &&
607 head
->header
.name
[skipcrud
+namelen
-1]=='/'))
610 && stat(skipcrud
+head
->header
.name
,&st1
)==0
611 && (S_ISDIR(st1
.st_mode
)))
613 msg_perror("Could not create directory %s",skipcrud
+head
->header
.name
);
618 if (!we_are_root
&& 0300 != (0300 & (int) hstat
.st_mode
)) {
619 hstat
.st_mode
|= 0300;
620 msg("Added write and execute permission to directory %s",
621 skipcrud
+head
->header
.name
);
625 /* FIXME, Remember timestamps for after files created? */
626 /* FIXME, change mode after files created (if was R/O dir) */
629 printf("Reading %s\n",head
->header
.name
);
634 extract_mangle(head
);
638 msg("Can't extract '%s'--file is continued from another volume\n",head
->header
.name
);
639 skip_file((long)hstat
.st_size
);
644 /* We don't need to save it any longer. */
645 saverec((union record
**) 0); /* Unsave it */
649 * After a file/link/symlink/dir creation has failed, see if
650 * it's because some required directory was not present, and if
651 * so, create all required dirs.
657 char *p
; /* Points into path */
658 int madeone
= 0; /* Did we do anything yet? */
659 int save_errno
= errno
; /* Remember caller's errno */
663 return 0; /* Not our problem */
665 for (p
= index(pathname
, '/'); p
!= NULL
; p
= index(p
+1, '/')) {
666 /* Avoid mkdir of empty string, if leading or double '/' */
667 if (p
== pathname
|| p
[-1] == '/')
669 /* Avoid mkdir where last part of path is '.' */
670 if (p
[-1] == '.' && (p
== pathname
+1 || p
[-2] == '/'))
672 *p
= 0; /* Truncate the path there */
673 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
677 if (chown(pathname
, hstat
.st_uid
,
679 msg_perror("cannot change owner of %s to uid %d gid %d",pathname
,hstat
.st_uid
,hstat
.st_gid
);
682 pr_mkdir(pathname
, p
-pathname
, notumask
&0777);
683 madeone
++; /* Remember if we made one */
688 if (errno
== EEXIST
) /* Directory already exists */
691 * Some other error in the mkdir. We return to the caller.
696 errno
= save_errno
; /* Restore caller's errno */
697 return madeone
; /* Tell them to retry if we made one */
701 extract_sparse_file(fd
, sizeleft
, totalsize
, name
)
707 /* register char *data;*/
708 union record
*datarec
;
713 /* assuming sizeleft is initially totalsize */
716 while (*sizeleft
> 0) {
718 if (datarec
== NULL
) {
719 msg("Unexpected EOF on archive file");
722 lseek(fd
, sparsearray
[sparse_ind
].offset
, 0);
723 written
= sparsearray
[sparse_ind
++].numbytes
;
724 while (written
> RECORDSIZE
) {
725 count
= write(fd
, datarec
->charptr
, RECORDSIZE
);
727 msg_perror("couldn't write to file %s", name
);
734 count
= write(fd
, datarec
->charptr
, written
);
737 msg_perror("couldn't write to file %s", name
);
738 } else if (count
!= written
) {
739 msg("could only write %d of %d bytes to file %s", totalsize
- *sizeleft
, totalsize
, name
);
740 skip_file((long) (*sizeleft
));
751 printf("%d\n", (int) end_nulls);
752 for (i = 0; i < end_nulls; i++)
753 write(fd, "\000", 1);
This page took 0.071344 seconds and 4 git commands to generate.