]>
Dogcows Code - chaz/tar/blob - src/extract.c
d6cdc3c553d80824178ddbc89db0692788a804c9
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
;
151 saverec(&head
); /* Make sure it sticks around */
152 userec(head
); /* And go past it in the archive */
153 decode_header(head
, &hstat
, &head_standard
, 1); /* Snarf fields */
155 if(f_confirm
&& !confirm("extract",current_file_name
)) {
156 if (head
->header
.isextended
)
157 skip_extended_headers();
158 skip_file((long)hstat
.st_size
);
159 saverec((union record
**)0);
163 /* Print the record from 'head' and 'hstat' */
168 * Check for fully specified pathnames and other atrocities.
170 * Note, we can't just make a pointer to the new file name,
171 * since saverec() might move the header and adjust "head".
172 * We have to start from "head" every time we want to touch
176 while (!f_absolute_paths
177 && '/' == current_file_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
+current_file_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
+current_file_name
)-1;
270 if (current_file_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((longname
? longname
: head
->header
.name
)
305 hstat
.st_mode
, hstat
.st_size
);
311 * On raw V7 we won't let them specify -k (f_keep), but
312 * we just bull ahead and create the files.
316 : head
->header
.name
) + skipcrud
,
320 * With 3-arg open(), we can do this up right.
322 fd
= open(skipcrud
+ current_file_name
,
323 openflag
, hstat
.st_mode
);
328 if (make_dirs(skipcrud
+ current_file_name
))
330 msg_perror("Could not create file %s",
331 skipcrud
+ current_file_name
);
332 if (head
->header
.isextended
)
333 skip_extended_headers();
334 skip_file((long)hstat
.st_size
);
339 if (head
->header
.linkflag
== LF_SPARSE
) {
344 * Kludge alert. NAME is assigned to header.name
345 * because during the extraction, the space that
346 * contains the header will get scribbled on, and
347 * the name will get munged, so any error messages
348 * that happen to contain the filename will look
349 * REAL interesting unless we do this.
351 namelen
= strlen(skipcrud
+ current_file_name
);
352 name
= (char *) malloc((sizeof(char)) * namelen
);
353 bcopy(skipcrud
+current_file_name
, name
, namelen
);
354 size
= hstat
.st_size
;
355 extract_sparse_file(fd
, &size
, hstat
.st_size
, name
);
358 for (size
= hstat
.st_size
;
366 save_name
=current_file_name
;
367 save_totsize
=hstat
.st_size
;
372 * Locate data, determine max length
373 * writeable, write it, record that
374 * we have used the data, then check
375 * if the write worked.
377 data
= findrec()->charptr
;
378 if (data
== NULL
) { /* Check it... */
379 msg("Unexpected EOF on archive file");
383 * JK - If the file is sparse, use the sparsearray
384 * that we created before to lseek into the new
385 * file the proper amount, and to see how many
386 * bytes we want to write at that position.
388 /* if (head->header.linkflag == LF_SPARSE) {
391 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
392 printf("%d at %d\n", (int) pos, sparse_ind);
393 written = sparsearray[sparse_ind++].numbytes;
395 written
= endofrecs()->charptr
- data
;
399 check
= write(fd
, data
, written
);
401 * The following is in violation of strict
402 * typing, since the arg to userec
403 * should be a struct rec *. FIXME.
405 userec((union record
*)(data
+ written
- 1));
406 if (check
== written
) continue;
408 * Error in writing to file.
409 * Print it, skip to next file in archive.
412 msg_perror("couldn't write to file %s",
413 skipcrud
+ current_file_name
);
415 msg("could only write %d of %d bytes to file %s",
416 written
,check
,skipcrud
+ current_file_name
);
417 skip_file((long)(size
- written
));
418 break; /* Still do the close, mod time, chmod, etc */
424 /* If writing to stdout, don't try to do anything
425 to the filename; it doesn't exist, or we don't
426 want to touch it anyway */
430 /* if (head->header.isextended) {
431 register union record *exhdr;
434 for (i = 0; i < 21; i++) {
437 if (!exhdr->ext_hdr.sp[i].numbytes)
439 offset = from_oct(1+12,
440 exhdr->ext_hdr.sp[i].offset);
441 written = from_oct(1+12,
442 exhdr->ext_hdr.sp[i].numbytes);
443 lseek(fd, offset, 0);
444 check = write(fd, data, written);
445 if (check == written) continue;
453 msg_perror("Error while closing %s",
454 skipcrud
+ current_file_name
);
461 * If we are root, set the owner and group of the extracted
462 * file. This does what is wanted both on real Unix and on
463 * System V. If we are running as a user, we extract as that
464 * user; if running as root, we extract as the original owner.
466 if (we_are_root
|| f_do_chown
) {
467 if (chown(skipcrud
+ current_file_name
,
468 hstat
.st_uid
, hstat
.st_gid
) < 0) {
469 msg_perror("cannot chown file %s to uid %d gid %d",
470 skipcrud
+ current_file_name
,
471 hstat
.st_uid
,hstat
.st_gid
);
476 * Set the modified time of the file.
478 * Note that we set the accessed time to "now", which
479 * is really "the time we started extracting files".
480 * unless f_gnudump is used, in which case .st_atime is used
483 /* fixme if f_gnudump should set ctime too, but how? */
485 acc_upd_times
[0]=hstat
.st_atime
;
486 else acc_upd_times
[0] = now
; /* Accessed now */
487 acc_upd_times
[1] = hstat
.st_mtime
; /* Mod'd */
488 if (utime(skipcrud
+ current_file_name
,
489 acc_upd_times
) < 0) {
490 msg_perror("couldn't change access and modification times of %s",skipcrud
+ current_file_name
);
493 /* We do the utime before the chmod because some versions of
494 utime are broken and trash the modes of the file. Since
495 we then change the mode anyway, we don't care. . . */
498 * If '-k' is not set, open() or creat() could have saved
499 * the permission bits from a previously created file,
500 * ignoring the ones we specified.
501 * Even if -k is set, if the file has abnormal
502 * mode bits, we must chmod since writing or chown() has
503 * probably reset them.
505 * If -k is set, we know *we* created this file, so the mode
506 * bits were set by our open(). If the file is "normal", we
507 * skip the chmod. This works because we did umask(0) if -p
508 * is set, so umask will have left the specified mode alone.
511 || (hstat
.st_mode
& (S_ISUID
|S_ISGID
|S_ISVTX
))) {
512 if (chmod(skipcrud
+ current_file_name
,
513 notumask
& (int)hstat
.st_mode
) < 0) {
514 msg_perror("cannot change mode of file %s to %ld",
515 skipcrud
+ current_file_name
,
516 notumask
& (int)hstat
.st_mode
);
528 check
= link (current_link_name
, skipcrud
+ current_file_name
);
532 if (make_dirs(skipcrud
+ current_file_name
))
534 if(f_gnudump
&& errno
==EEXIST
)
536 if(stat(current_link_name
, &st1
) == 0
537 && stat(current_file_name
+ skipcrud
, &st2
)==0
538 && st1
.st_dev
==st2
.st_dev
539 && st1
.st_ino
==st2
.st_ino
)
541 msg_perror("Could not link %s to %s",
542 skipcrud
+ current_file_name
,
550 check
= symlink(current_link_name
,
551 skipcrud
+ current_file_name
);
552 /* FIXME, don't worry uid, gid, etc... */
555 if (make_dirs(current_file_name
+ skipcrud
))
557 msg_perror("Could not create symlink to %s",
564 hstat
.st_mode
|= S_IFCHR
;
570 hstat
.st_mode
|= S_IFBLK
;
572 #if defined(S_IFCHR) || defined(S_IFBLK)
574 check
= mknod(current_file_name
+ skipcrud
,
575 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
577 if (make_dirs(skipcrud
+ current_file_name
))
579 msg_perror("Could not make %s",
580 current_file_name
+ skipcrud
);
587 /* If local system doesn't support FIFOs, use default case */
590 check
= mkfifo(current_file_name
+ skipcrud
,
591 (int) hstat
.st_mode
);
593 if (make_dirs(current_file_name
+ skipcrud
))
595 msg_perror("Could not make %s",
596 skipcrud
+ current_file_name
);
604 namelen
= strlen(current_file_name
) + skipcrud
- 1;
606 /* Check for trailing /, and zap as many as we find. */
608 && current_file_name
[skipcrud
+namelen
] == '/')
609 current_file_name
[skipcrud
+namelen
--] = '\0';
610 if(f_gnudump
) { /* Read the entry and delete files
611 that aren't listed in the archive */
612 gnu_restore(skipcrud
);
614 } else if(head
->header
.linkflag
==LF_DUMPDIR
)
615 skip_file((long)(hstat
.st_size
));
619 check
= mkdir(skipcrud
+current_file_name
,
620 (we_are_root
? 0 : 0300) | (int)hstat
.st_mode
);
624 if (make_dirs(skipcrud
+current_file_name
))
626 /* If we're trying to create '.', let it be. */
627 if (current_file_name
[skipcrud
+namelen
] == '.' &&
629 current_file_name
[skipcrud
+namelen
-1]=='/'))
632 && stat(skipcrud
+current_file_name
,&st1
)==0
633 && (S_ISDIR(st1
.st_mode
)))
635 msg_perror("Could not create directory %s",skipcrud
+current_file_name
);
640 if (!we_are_root
&& 0300 != (0300 & (int) hstat
.st_mode
)) {
641 hstat
.st_mode
|= 0300;
642 msg("Added write and execute permission to directory %s",
643 skipcrud
+current_file_name
);
648 tmp
= (struct saved_dir_info
*) malloc (sizeof (struct saved_dir_info
));
649 tmp
->path
= malloc (strlen (skipcrud
+ current_file_name
) + 1);
650 strcpy (tmp
->path
, skipcrud
+ current_file_name
);
651 tmp
->mode
= hstat
.st_mode
;
652 tmp
->atime
= hstat
.st_atime
;
653 tmp
->mtime
= hstat
.st_mtime
;
654 tmp
->next
= saved_dir_info_head
;
655 saved_dir_info_head
= tmp
;
658 printf("Reading %s\n", current_file_name
);
663 extract_mangle(head
);
667 msg("Can't extract '%s'--file is continued from another volume\n",current_file_name
);
668 skip_file((long)hstat
.st_size
);
673 msg ("Visible long name error\n");
674 skip_file ((long)hstat
.st_size
);
678 /* We don't need to save it any longer. */
679 saverec((union record
**) 0); /* Unsave it */
683 * After a file/link/symlink/dir creation has failed, see if
684 * it's because some required directory was not present, and if
685 * so, create all required dirs.
691 char *p
; /* Points into path */
692 int madeone
= 0; /* Did we do anything yet? */
693 int save_errno
= errno
; /* Remember caller's errno */
697 return 0; /* Not our problem */
699 for (p
= index(pathname
, '/'); p
!= NULL
; p
= index(p
+1, '/')) {
700 /* Avoid mkdir of empty string, if leading or double '/' */
701 if (p
== pathname
|| p
[-1] == '/')
703 /* Avoid mkdir where last part of path is '.' */
704 if (p
[-1] == '.' && (p
== pathname
+1 || p
[-2] == '/'))
706 *p
= 0; /* Truncate the path there */
707 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
711 if (chown(pathname
, hstat
.st_uid
,
713 msg_perror("cannot change owner of %s to uid %d gid %d",pathname
,hstat
.st_uid
,hstat
.st_gid
);
716 pr_mkdir(pathname
, p
-pathname
, notumask
&0777);
717 madeone
++; /* Remember if we made one */
722 if (errno
== EEXIST
) /* Directory already exists */
725 * Some other error in the mkdir. We return to the caller.
730 errno
= save_errno
; /* Restore caller's errno */
731 return madeone
; /* Tell them to retry if we made one */
735 extract_sparse_file(fd
, sizeleft
, totalsize
, name
)
741 /* register char *data;*/
742 union record
*datarec
;
747 /* assuming sizeleft is initially totalsize */
750 while (*sizeleft
> 0) {
752 if (datarec
== NULL
) {
753 msg("Unexpected EOF on archive file");
756 lseek(fd
, sparsearray
[sparse_ind
].offset
, 0);
757 written
= sparsearray
[sparse_ind
++].numbytes
;
758 while (written
> RECORDSIZE
) {
759 count
= write(fd
, datarec
->charptr
, RECORDSIZE
);
761 msg_perror("couldn't write to file %s", name
);
768 count
= write(fd
, datarec
->charptr
, written
);
771 msg_perror("couldn't write to file %s", name
);
772 } else if (count
!= written
) {
773 msg("could only write %d of %d bytes to file %s", totalsize
- *sizeleft
, totalsize
, name
);
774 skip_file((long) (*sizeleft
));
785 printf("%d\n", (int) end_nulls);
786 for (i = 0; i < end_nulls; i++)
787 write(fd, "\000", 1);
792 /* Set back the utime and mode for all the extracted directories. */
793 void restore_saved_dir_info ()
795 time_t acc_upd_times
[2];
796 struct saved_dir_info
*tmp
;
798 while (saved_dir_info_head
!= NULL
)
800 /* fixme if f_gnudump should set ctime too, but how? */
802 acc_upd_times
[0]=saved_dir_info_head
-> atime
;
803 else acc_upd_times
[0] = now
; /* Accessed now */
804 acc_upd_times
[1] = saved_dir_info_head
-> mtime
; /* Mod'd */
805 if (utime(saved_dir_info_head
-> path
, acc_upd_times
) < 0) {
806 msg_perror("couldn't change access and modification times of %s",
807 saved_dir_info_head
-> path
);
809 if ((!f_keep
) || (saved_dir_info_head
-> mode
& (S_ISUID
|S_ISGID
|S_ISVTX
)))
811 if (chmod(saved_dir_info_head
-> path
,
812 notumask
& saved_dir_info_head
-> mode
) < 0) {
813 msg_perror("cannot change mode of file %s to %ld",
814 saved_dir_info_head
-> path
,
815 notumask
& saved_dir_info_head
-> mode
);
818 saved_dir_info_head
= saved_dir_info_head
-> next
;
This page took 0.074742 seconds and 4 git commands to generate.