]>
Dogcows Code - chaz/tar/blob - src/extract.c
aedd24e312132055835ed007c6ea36f852966154
1 /* Extract files from a tar archive.
2 Copyright (C) 1988 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>
48 /* We need the #define's even though we don't use them. */
53 /* Simulated 3-argument open for systems that don't have it */
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;*/
98 * Set up to extract files.
105 now
= time((time_t *)0);
110 * We need to know our umask. But if f_use_protection is set,
111 * leave our kernel umask at 0, and our "notumask" at ~0.
113 ourmask
= umask(0); /* Read it */
114 if (!f_use_protection
) {
115 (void) umask (ourmask
); /* Set it back how it was */
116 notumask
= ~ourmask
; /* Make umask override permissions */
122 * Extract a file from the archive.
128 int fd
, check
, namelen
, written
, openflag
;
130 time_t acc_upd_times
[2];
131 register int skipcrud
;
133 /* int sparse_ind = 0;*/
137 saverec(&head
); /* Make sure it sticks around */
138 userec(head
); /* And go past it in the archive */
139 decode_header(head
, &hstat
, &head_standard
, 1); /* Snarf fields */
141 if(f_confirm
&& !confirm("extract",head
->header
.name
)) {
142 if (head
->header
.isextended
)
143 skip_extended_headers();
144 skip_file((long)hstat
.st_size
);
145 saverec((union record
**)0);
149 /* Print the record from 'head' and 'hstat' */
154 * Check for fully specified pathnames and other atrocities.
156 * Note, we can't just make a pointer to the new file name,
157 * since saverec() might move the header and adjust "head".
158 * We have to start from "head" every time we want to touch
162 while (!f_absolute_paths
&& '/' == head
->header
.name
[skipcrud
]) {
163 static int warned_once
= 0;
165 skipcrud
++; /* Force relative path */
166 if (!warned_once
++) {
167 msg("Removing leading / from absolute path names in the archive.");
171 switch (head
->header
.linkflag
) {
174 msg("Unknown file type '%c' for %s, extracted as normal file",
175 head
->header
.linkflag
, skipcrud
+head
->header
.name
);
179 * JK - What we want to do if the file is sparse is loop through
180 * the array of sparse structures in the header and read in
181 * and translate the character strings representing 1) the offset
182 * at which to write and 2) how many bytes to write into numbers,
183 * which we store into the scratch array, "sparsearray". This
184 * array makes our life easier the same way it did in creating
185 * the tar file that had to deal with a sparse file.
187 * After we read in the first five (at most) sparse structures,
188 * we check to see if the file has an extended header, i.e.,
189 * if more sparse structures are needed to describe the contents
190 * of the new file. If so, we read in the extended headers
191 * and continue to store their contents into the sparsearray.
195 sparsearray
= (struct sp_array
*) malloc(sp_array_size
* sizeof(struct sp_array
));
196 for (i
= 0; i
< SPARSE_IN_HDR
; i
++) {
197 sparsearray
[i
].offset
=
198 from_oct(1+12, head
->header
.sp
[i
].offset
);
199 sparsearray
[i
].numbytes
=
200 from_oct(1+12, head
->header
.sp
[i
].numbytes
);
201 if (!sparsearray
[i
].numbytes
)
205 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
207 if (head
->header
.isextended
) {
208 /* read in the list of extended headers
209 and translate them into the sparsearray
212 /* static */ int ind
= SPARSE_IN_HDR
;
217 for (i
= 0; i
< SPARSE_EXT_HDR
; i
++) {
219 if (i
+ind
> sp_array_size
-1) {
221 * realloc the scratch area
222 * since we've run out of room --
224 sparsearray
= (struct sp_array
*)
226 2 * sp_array_size
* (sizeof(struct sp_array
)));
229 if (!exhdr
->ext_hdr
.sp
[i
].numbytes
)
231 sparsearray
[i
+ind
].offset
=
232 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].offset
);
233 sparsearray
[i
+ind
].numbytes
=
234 from_oct(1+12, exhdr
->ext_hdr
.sp
[i
].numbytes
);
236 if (!exhdr
->ext_hdr
.isextended
)
239 ind
+= SPARSE_EXT_HDR
;
251 * Appears to be a file.
252 * See if it's really a directory.
254 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
255 if (head
->header
.name
[skipcrud
+namelen
] == '/')
258 /* FIXME, deal with protection issues */
261 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_EXCL
:
262 O_BINARY
|O_NDELAY
|O_WRONLY
|O_CREAT
|O_TRUNC
)
263 | ((head
->header
.linkflag
== LF_SPARSE
) ? 0 : O_APPEND
);
265 * JK - The last | is a kludge to solve the problem
266 * the O_APPEND flag causes with files we are
267 * trying to make sparse: when a file is opened
268 * with O_APPEND, it writes to the last place
269 * that something was written, thereby ignoring
270 * any lseeks that we have done. We add this
271 * extra condition to make it able to lseek when
272 * a file is sparse, i.e., we don't open the new
273 * file with this flag. (Grump -- this bug caused
274 * me to waste a good deal of time, I might add)
283 * Contiguous files (on the Masscomp) have to specify
284 * the size in the open call that creates them.
286 if (head
->header
.linkflag
== LF_CONTIG
)
287 fd
= open(skipcrud
+head
->header
.name
, openflag
| O_CTG
,
288 hstat
.st_mode
, hstat
.st_size
);
294 * On raw V7 we won't let them specify -k (f_keep), but
295 * we just bull ahead and create the files.
297 fd
= creat(skipcrud
+head
->header
.name
,
301 * With 3-arg open(), we can do this up right.
303 fd
= open(skipcrud
+head
->header
.name
, openflag
,
309 if (make_dirs(skipcrud
+head
->header
.name
))
311 msg_perror("Could not create file %s",skipcrud
+head
->header
.name
);
312 if (head
->header
.isextended
)
313 skip_extended_headers();
314 skip_file((long)hstat
.st_size
);
319 if (head
->header
.linkflag
== LF_SPARSE
) {
324 * Kludge alert. NAME is assigned to header.name
325 * because during the extraction, the space that
326 * contains the header will get scribbled on, and
327 * the name will get munged, so any error messages
328 * that happen to contain the filename will look
329 * REAL interesting unless we do this.
331 namelen
= strlen(skipcrud
+head
->header
.name
);
332 name
= (char *) malloc((sizeof(char)) * namelen
);
333 bcopy(skipcrud
+head
->header
.name
, name
, namelen
);
334 size
= hstat
.st_size
;
335 extract_sparse_file(fd
, &size
, hstat
.st_size
,
339 for (size
= hstat
.st_size
;
347 save_name
=head
->header
.name
;
348 save_totsize
=hstat
.st_size
;
353 * Locate data, determine max length
354 * writeable, write it, record that
355 * we have used the data, then check
356 * if the write worked.
358 data
= findrec()->charptr
;
359 if (data
== NULL
) { /* Check it... */
360 msg("Unexpected EOF on archive file");
364 * JK - If the file is sparse, use the sparsearray
365 * that we created before to lseek into the new
366 * file the proper amount, and to see how many
367 * bytes we want to write at that position.
369 /* if (head->header.linkflag == LF_SPARSE) {
372 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
373 printf("%d at %d\n", (int) pos, sparse_ind);
374 written = sparsearray[sparse_ind++].numbytes;
376 written
= endofrecs()->charptr
- data
;
380 check
= write(fd
, data
, written
);
382 * The following is in violation of strict
383 * typing, since the arg to userec
384 * should be a struct rec *. FIXME.
386 userec((union record
*)(data
+ written
- 1));
387 if (check
== written
) continue;
389 * Error in writing to file.
390 * Print it, skip to next file in archive.
393 msg_perror("couldn't write to file %s",skipcrud
+head
->header
.name
);
395 msg("could only write %d of %d bytes to file %s",written
,check
,skipcrud
+head
->header
.name
);
396 skip_file((long)(size
- written
));
397 break; /* Still do the close, mod time, chmod, etc */
403 /* If writing to stdout, don't try to do anything
404 to the filename; it doesn't exist, or we don't
405 want to touch it anyway */
409 /* if (head->header.isextended) {
410 register union record *exhdr;
413 for (i = 0; i < 21; i++) {
416 if (!exhdr->ext_hdr.sp[i].numbytes)
418 offset = from_oct(1+12,
419 exhdr->ext_hdr.sp[i].offset);
420 written = from_oct(1+12,
421 exhdr->ext_hdr.sp[i].numbytes);
422 lseek(fd, offset, 0);
423 check = write(fd, data, written);
424 if (check == written) continue;
432 msg_perror("Error while closing %s",skipcrud
+head
->header
.name
);
439 * If we are root, set the owner and group of the extracted
440 * file. This does what is wanted both on real Unix and on
441 * System V. If we are running as a user, we extract as that
442 * user; if running as root, we extract as the original owner.
444 if (we_are_root
|| f_do_chown
) {
445 if (chown(skipcrud
+head
->header
.name
, hstat
.st_uid
,
447 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud
+head
->header
.name
,hstat
.st_uid
,hstat
.st_gid
);
452 * Set the modified time of the file.
454 * Note that we set the accessed time to "now", which
455 * is really "the time we started extracting files".
456 * unless f_gnudump is used, in which case .st_atime is used
459 /* fixme if f_gnudump should set ctime too, but how? */
461 acc_upd_times
[0]=hstat
.st_atime
;
462 else acc_upd_times
[0] = now
; /* Accessed now */
463 acc_upd_times
[1] = hstat
.st_mtime
; /* Mod'd */
464 if (utime(skipcrud
+head
->header
.name
,
465 acc_upd_times
) < 0) {
466 msg_perror("couldn't change access and modification times of %s",skipcrud
+head
->header
.name
);
469 /* We do the utime before the chmod because some versions of
470 utime are broken and trash the modes of the file. Since
471 we then change the mode anyway, we don't care. . . */
474 * If '-k' is not set, open() or creat() could have saved
475 * the permission bits from a previously created file,
476 * ignoring the ones we specified.
477 * Even if -k is set, if the file has abnormal
478 * mode bits, we must chmod since writing or chown() has
479 * probably reset them.
481 * If -k is set, we know *we* created this file, so the mode
482 * bits were set by our open(). If the file is "normal", we
483 * skip the chmod. This works because we did umask(0) if -p
484 * is set, so umask will have left the specified mode alone.
487 || (hstat
.st_mode
& (S_ISUID
|S_ISGID
|S_ISVTX
))) {
488 if (chmod(skipcrud
+head
->header
.name
,
489 notumask
& (int)hstat
.st_mode
) < 0) {
490 msg_perror("cannot change mode of file %s to %ld",skipcrud
+head
->header
.name
,notumask
& (int)hstat
.st_mode
);
502 check
= link (head
->header
.linkname
,
503 skipcrud
+head
->header
.name
);
506 if (make_dirs(skipcrud
+head
->header
.name
))
508 if(f_gnudump
&& errno
==EEXIST
)
510 if( stat(head
->header
.linkname
, &st1
) == 0
511 && stat(skipcrud
+head
->header
.name
, &st2
)==0
512 && st1
.st_dev
==st2
.st_dev
513 && st1
.st_ino
==st2
.st_ino
)
515 msg_perror("Could not link %s to %s",
516 skipcrud
+head
->header
.name
,head
->header
.linkname
);
523 check
= symlink(head
->header
.linkname
,
524 skipcrud
+head
->header
.name
);
525 /* FIXME, don't worry uid, gid, etc... */
528 if (make_dirs(skipcrud
+head
->header
.name
))
530 msg_perror("Could not create symlink to %s",head
->header
.linkname
);
536 hstat
.st_mode
|= S_IFCHR
;
542 hstat
.st_mode
|= S_IFBLK
;
544 #if defined(S_IFCHR) || defined(S_IFBLK)
546 check
= mknod(skipcrud
+head
->header
.name
,
547 (int) hstat
.st_mode
, (int) hstat
.st_rdev
);
549 if (make_dirs(skipcrud
+head
->header
.name
))
551 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
558 /* If local system doesn't support FIFOs, use default case */
561 check
= mkfifo(skipcrud
+head
->header
.name
,
562 (int) hstat
.st_mode
);
564 if (make_dirs(skipcrud
+head
->header
.name
))
566 msg_perror("Could not make %s",skipcrud
+head
->header
.name
);
574 namelen
= strlen(skipcrud
+head
->header
.name
)-1;
576 /* Check for trailing /, and zap as many as we find. */
577 while (namelen
&& head
->header
.name
[skipcrud
+namelen
] == '/')
578 head
->header
.name
[skipcrud
+namelen
--] = '\0';
579 if(f_gnudump
) { /* Read the entry and delete files
580 that aren't listed in the archive */
581 gnu_restore(skipcrud
);
583 } else if(head
->header
.linkflag
==LF_DUMPDIR
)
584 skip_file((long)(hstat
.st_size
));
588 check
= mkdir(skipcrud
+head
->header
.name
,
589 (we_are_root
? 0 : 0300) | (int)hstat
.st_mode
);
593 if (make_dirs(skipcrud
+head
->header
.name
))
595 /* If we're trying to create '.', let it be. */
596 if (head
->header
.name
[skipcrud
+namelen
] == '.' &&
598 head
->header
.name
[skipcrud
+namelen
-1]=='/'))
601 && stat(skipcrud
+head
->header
.name
,&st1
)==0
602 && (S_ISDIR(st1
.st_mode
)))
604 msg_perror("Could not create directory %s",skipcrud
+head
->header
.name
);
609 if (!we_are_root
&& 0300 != (0300 & (int) hstat
.st_mode
)) {
610 hstat
.st_mode
|= 0300;
611 msg("Added write and execute permission to directory %s",
612 skipcrud
+head
->header
.name
);
616 /* FIXME, Remember timestamps for after files created? */
617 /* FIXME, change mode after files created (if was R/O dir) */
620 printf("Reading %s\n",head
->header
.name
);
625 extract_mangle(head
);
629 msg("Can't extract '%s'--file is continued from another volume\n",head
->header
.name
);
630 skip_file((long)hstat
.st_size
);
635 /* We don't need to save it any longer. */
636 saverec((union record
**) 0); /* Unsave it */
640 * After a file/link/symlink/dir creation has failed, see if
641 * it's because some required directory was not present, and if
642 * so, create all required dirs.
648 char *p
; /* Points into path */
649 int madeone
= 0; /* Did we do anything yet? */
650 int save_errno
= errno
; /* Remember caller's errno */
654 return 0; /* Not our problem */
656 for (p
= index(pathname
, '/'); p
!= NULL
; p
= index(p
+1, '/')) {
657 /* Avoid mkdir of empty string, if leading or double '/' */
658 if (p
== pathname
|| p
[-1] == '/')
660 /* Avoid mkdir where last part of path is '.' */
661 if (p
[-1] == '.' && (p
== pathname
+1 || p
[-2] == '/'))
663 *p
= 0; /* Truncate the path there */
664 check
= mkdir (pathname
, 0777); /* Try to create it as a dir */
668 if (chown(pathname
, hstat
.st_uid
,
670 msg_perror("cannot change owner of %s to uid %d gid %d",pathname
,hstat
.st_uid
,hstat
.st_gid
);
673 pr_mkdir(pathname
, p
-pathname
, notumask
&0777);
674 madeone
++; /* Remember if we made one */
679 if (errno
== EEXIST
) /* Directory already exists */
682 * Some other error in the mkdir. We return to the caller.
687 errno
= save_errno
; /* Restore caller's errno */
688 return madeone
; /* Tell them to retry if we made one */
692 extract_sparse_file(fd
, sizeleft
, totalsize
, name
)
698 /* register char *data;*/
699 union record
*datarec
;
704 /* assuming sizeleft is initially totalsize */
707 while (*sizeleft
> 0) {
709 if (datarec
== NULL
) {
710 msg("Unexpected EOF on archive file");
713 lseek(fd
, sparsearray
[sparse_ind
].offset
, 0);
714 written
= sparsearray
[sparse_ind
++].numbytes
;
715 while (written
> RECORDSIZE
) {
716 count
= write(fd
, datarec
->charptr
, RECORDSIZE
);
718 msg_perror("couldn't write to file %s", name
);
725 count
= write(fd
, datarec
->charptr
, written
);
728 msg_perror("couldn't write to file %s", name
);
729 } else if (count
!= written
) {
730 msg("could only write %d of %d bytes to file %s", totalsize
- *sizeleft
, totalsize
, name
);
731 skip_file((long) (*sizeleft
));
742 printf("%d\n", (int) end_nulls);
743 for (i = 0; i < end_nulls; i++)
744 write(fd, "\000", 1);
This page took 0.063584 seconds and 4 git commands to generate.