]> Dogcows Code - chaz/tar/blob - src/extract.c
*** empty log message ***
[chaz/tar] / src / extract.c
1 /* Extract files from a tar archive.
2 Copyright (C) 1988, 1992 Free Software Foundation
3
4 This file is part of GNU Tar.
5
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)
9 any later version.
10
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.
15
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. */
19
20 /*
21 * Extract files from a tar archive.
22 *
23 * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
24 */
25
26 #include <stdio.h>
27 #include <errno.h>
28 #ifndef STDC_HEADERS
29 extern int errno;
30 #endif
31 #include <sys/types.h>
32 #include <time.h>
33 time_t time();
34
35 #ifdef BSD42
36 #include <sys/file.h>
37 #else
38 #ifndef V7
39 #include <fcntl.h>
40 #endif
41 #endif
42
43 #ifdef NO_OPEN3
44 /* We need the #define's even though we don't use them. */
45 #include "open3.h"
46 #endif
47
48 #ifdef EMUL_OPEN3
49 /* Simulated 3-argument open for systems that don't have it */
50 #include "open3.h"
51 #endif
52
53 #include "tar.h"
54 #include "port.h"
55
56 #if defined(_POSIX_VERSION)
57 #include <utime.h>
58 #endif
59
60 extern FILE *msg_file;
61
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 */
65
66 extern char *save_name;
67 extern long save_totsize;
68 extern long save_sizeleft;
69
70 int confirm();
71 void decode_header();
72 void extract_mangle();
73 void extract_sparse_file();
74 long from_oct();
75 void gnu_restore();
76 extern void print_header();
77 extern void skip_file();
78 extern void skip_extended_headers();
79 extern void pr_mkdir();
80 void saverec();
81
82 int make_dirs(); /* Makes required directories */
83
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 */
87
88 /*
89 * "Scratch" space to store the information about a sparse file before
90 * writing the info into the header or extended header
91 */
92 /*struct sp_array *sparsearray;*/
93
94 /* number of elts storable in the sparsearray */
95 /*int sp_array_size = 10;*/
96
97 struct saved_info
98 {
99 char *path;
100 int mode;
101 int atime;
102 int mtime;
103 saved_info *next;
104 };
105
106 /*
107 * Set up to extract files.
108 */
109 void
110 extr_init()
111 {
112 int ourmask;
113
114 now = time((time_t *)0);
115 if (geteuid() == 0)
116 we_are_root = 1;
117
118 /*
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.
121 */
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 */
126 }
127 }
128
129
130 /*
131 * Extract a file from the archive.
132 */
133 void
134 extract_archive()
135 {
136 register char *data;
137 int fd, check, namelen, written, openflag;
138 long size;
139 time_t acc_upd_times[2];
140 register int skipcrud;
141 register int i;
142 /* int sparse_ind = 0;*/
143 union record *exhdr;
144 /* int end_nulls; */
145
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 */
149
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);
155 return;
156 }
157
158 /* Print the record from 'head' and 'hstat' */
159 if (f_verbose)
160 print_header();
161
162 /*
163 * Check for fully specified pathnames and other atrocities.
164 *
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
168 * the header record.
169 */
170 skipcrud = 0;
171 while (!f_absolute_paths && '/' == head->header.name[skipcrud]) {
172 static int warned_once = 0;
173
174 skipcrud++; /* Force relative path */
175 if (!warned_once++) {
176 msg("Removing leading / from absolute path names in the archive.");
177 }
178 }
179
180 switch (head->header.linkflag) {
181
182 default:
183 msg("Unknown file type '%c' for %s, extracted as normal file",
184 head->header.linkflag, skipcrud+head->header.name);
185 /* FALL THRU */
186
187 /*
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.
195 *
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.
201 */
202 case LF_SPARSE:
203 sp_array_size = 10;
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)
211 break;
212 }
213
214 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
215
216 if (head->header.isextended) {
217 /* read in the list of extended headers
218 and translate them into the sparsearray
219 as before */
220
221 /* static */ int ind = SPARSE_IN_HDR;
222
223 for (;;) {
224
225 exhdr = findrec();
226 for (i = 0; i < SPARSE_EXT_HDR; i++) {
227
228 if (i+ind > sp_array_size-1) {
229 /*
230 * realloc the scratch area
231 * since we've run out of room --
232 */
233 sparsearray = (struct sp_array *)
234 realloc(sparsearray,
235 2 * sp_array_size * (sizeof(struct sp_array)));
236 sp_array_size *= 2;
237 }
238 if (!exhdr->ext_hdr.sp[i].numbytes)
239 break;
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);
244 }
245 if (!exhdr->ext_hdr.isextended)
246 break;
247 else {
248 ind += SPARSE_EXT_HDR;
249 userec(exhdr);
250 }
251 }
252 userec(exhdr);
253 }
254
255 /* FALL THRU */
256 case LF_OLDNORMAL:
257 case LF_NORMAL:
258 case LF_CONTIG:
259 /*
260 * Appears to be a file.
261 * See if it's really a directory.
262 */
263 namelen = strlen(skipcrud+head->header.name)-1;
264 if (head->header.name[skipcrud+namelen] == '/')
265 goto really_dir;
266
267 /* FIXME, deal with protection issues */
268 again_file:
269 openflag = (f_keep?
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);
273 /*
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)
284 */
285
286 if(f_exstdout) {
287 fd = 1;
288 goto extract_file;
289 }
290 #ifdef O_CTG
291 /*
292 * Contiguous files (on the Masscomp) have to specify
293 * the size in the open call that creates them.
294 */
295 if (head->header.linkflag == LF_CONTIG)
296 fd = open(skipcrud+head->header.name, openflag | O_CTG,
297 hstat.st_mode, hstat.st_size);
298 else
299 #endif
300 {
301 #ifdef NO_OPEN3
302 /*
303 * On raw V7 we won't let them specify -k (f_keep), but
304 * we just bull ahead and create the files.
305 */
306 fd = creat(skipcrud+head->header.name,
307 hstat.st_mode);
308 #else
309 /*
310 * With 3-arg open(), we can do this up right.
311 */
312 fd = open(skipcrud+head->header.name, openflag,
313 hstat.st_mode);
314 #endif
315 }
316
317 if (fd < 0) {
318 if (make_dirs(skipcrud+head->header.name))
319 goto again_file;
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);
324 goto quit;
325 }
326
327 extract_file:
328 if (head->header.linkflag == LF_SPARSE) {
329 char *name;
330 int namelen;
331
332 /*
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.
339 */
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,
345 name);
346 }
347 else
348 for (size = hstat.st_size;
349 size > 0;
350 size -= written) {
351
352 /* long offset,
353 numbytes;*/
354
355 if(f_multivol) {
356 save_name=head->header.name;
357 save_totsize=hstat.st_size;
358 save_sizeleft=size;
359 }
360
361 /*
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.
366 */
367 data = findrec()->charptr;
368 if (data == NULL) { /* Check it... */
369 msg("Unexpected EOF on archive file");
370 break;
371 }
372 /*
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.
377 */
378 /* if (head->header.linkflag == LF_SPARSE) {
379 off_t pos;
380
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;
384 } else*/
385 written = endofrecs()->charptr - data;
386 if (written > size)
387 written = size;
388 errno = 0;
389 check = write(fd, data, written);
390 /*
391 * The following is in violation of strict
392 * typing, since the arg to userec
393 * should be a struct rec *. FIXME.
394 */
395 userec((union record *)(data + written - 1));
396 if (check == written) continue;
397 /*
398 * Error in writing to file.
399 * Print it, skip to next file in archive.
400 */
401 if(check<0)
402 msg_perror("couldn't write to file %s",skipcrud+head->header.name);
403 else
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 */
407 }
408
409 if(f_multivol)
410 save_name = 0;
411
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 */
415 if(f_exstdout)
416 break;
417
418 /* if (head->header.isextended) {
419 register union record *exhdr;
420 register int i;
421
422 for (i = 0; i < 21; i++) {
423 long offset;
424
425 if (!exhdr->ext_hdr.sp[i].numbytes)
426 break;
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;
434
435 }
436
437
438 }*/
439 check = close(fd);
440 if (check < 0) {
441 msg_perror("Error while closing %s",skipcrud+head->header.name);
442 }
443
444
445 set_filestat:
446
447 /*
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.
452 */
453 if (we_are_root || f_do_chown) {
454 if (chown(skipcrud+head->header.name, hstat.st_uid,
455 hstat.st_gid) < 0) {
456 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
457 }
458 }
459
460 /*
461 * Set the modified time of the file.
462 *
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
466 */
467 if (!f_modified) {
468 /* fixme if f_gnudump should set ctime too, but how? */
469 if(f_gnudump)
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);
476 }
477 }
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. . . */
481
482 /*
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.
489 *
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.
494 */
495 if ((!f_keep)
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);
500 }
501 }
502
503 quit:
504 break;
505
506 case LF_LINK:
507 again_link:
508 {
509 struct stat st1,st2;
510
511 check = link (head->header.linkname,
512 skipcrud+head->header.name);
513 if (check == 0)
514 break;
515 if (make_dirs(skipcrud+head->header.name))
516 goto again_link;
517 if(f_gnudump && errno==EEXIST)
518 break;
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)
523 break;
524 msg_perror("Could not link %s to %s",
525 skipcrud+head->header.name,head->header.linkname);
526 }
527 break;
528
529 #ifdef S_ISLNK
530 case LF_SYMLINK:
531 again_symlink:
532 check = symlink(head->header.linkname,
533 skipcrud+head->header.name);
534 /* FIXME, don't worry uid, gid, etc... */
535 if (check == 0)
536 break;
537 if (make_dirs(skipcrud+head->header.name))
538 goto again_symlink;
539 msg_perror("Could not create symlink to %s",head->header.linkname);
540 break;
541 #endif
542
543 #ifdef S_IFCHR
544 case LF_CHR:
545 hstat.st_mode |= S_IFCHR;
546 goto make_node;
547 #endif
548
549 #ifdef S_IFBLK
550 case LF_BLK:
551 hstat.st_mode |= S_IFBLK;
552 #endif
553 #if defined(S_IFCHR) || defined(S_IFBLK)
554 make_node:
555 check = mknod(skipcrud+head->header.name,
556 (int) hstat.st_mode, (int) hstat.st_rdev);
557 if (check != 0) {
558 if (make_dirs(skipcrud+head->header.name))
559 goto make_node;
560 msg_perror("Could not make %s",skipcrud+head->header.name);
561 break;
562 };
563 goto set_filestat;
564 #endif
565
566 #ifdef S_ISFIFO
567 /* If local system doesn't support FIFOs, use default case */
568 case LF_FIFO:
569 make_fifo:
570 check = mkfifo(skipcrud+head->header.name,
571 (int) hstat.st_mode);
572 if (check != 0) {
573 if (make_dirs(skipcrud+head->header.name))
574 goto make_fifo;
575 msg_perror("Could not make %s",skipcrud+head->header.name);
576 break;
577 };
578 goto set_filestat;
579 #endif
580
581 case LF_DIR:
582 case LF_DUMPDIR:
583 namelen = strlen(skipcrud+head->header.name)-1;
584 really_dir:
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);
591
592 } else if(head->header.linkflag==LF_DUMPDIR)
593 skip_file((long)(hstat.st_size));
594
595
596 again_dir:
597 check = mkdir(skipcrud+head->header.name,
598 (we_are_root ? 0 : 0300) | (int)hstat.st_mode);
599 if (check != 0) {
600 struct stat st1;
601
602 if (make_dirs(skipcrud+head->header.name))
603 goto again_dir;
604 /* If we're trying to create '.', let it be. */
605 if (head->header.name[skipcrud+namelen] == '.' &&
606 (namelen==0 ||
607 head->header.name[skipcrud+namelen-1]=='/'))
608 goto check_perms;
609 if( errno==EEXIST
610 && stat(skipcrud+head->header.name,&st1)==0
611 && (S_ISDIR(st1.st_mode)))
612 break;
613 msg_perror("Could not create directory %s",skipcrud+head->header.name);
614 break;
615 }
616
617 check_perms:
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);
622 }
623
624 goto set_filestat;
625 /* FIXME, Remember timestamps for after files created? */
626 /* FIXME, change mode after files created (if was R/O dir) */
627 case LF_VOLHDR:
628 if(f_verbose) {
629 printf("Reading %s\n",head->header.name);
630 }
631 break;
632
633 case LF_NAMES:
634 extract_mangle(head);
635 break;
636
637 case LF_MULTIVOL:
638 msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
639 skip_file((long)hstat.st_size);
640 break;
641
642 }
643
644 /* We don't need to save it any longer. */
645 saverec((union record **) 0); /* Unsave it */
646 }
647
648 /*
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.
652 */
653 int
654 make_dirs(pathname)
655 char *pathname;
656 {
657 char *p; /* Points into path */
658 int madeone = 0; /* Did we do anything yet? */
659 int save_errno = errno; /* Remember caller's errno */
660 int check;
661
662 if (errno != ENOENT)
663 return 0; /* Not our problem */
664
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] == '/')
668 continue;
669 /* Avoid mkdir where last part of path is '.' */
670 if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
671 continue;
672 *p = 0; /* Truncate the path there */
673 check = mkdir (pathname, 0777); /* Try to create it as a dir */
674 if (check == 0) {
675 /* Fix ownership */
676 if (we_are_root) {
677 if (chown(pathname, hstat.st_uid,
678 hstat.st_gid) < 0) {
679 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
680 }
681 }
682 pr_mkdir(pathname, p-pathname, notumask&0777);
683 madeone++; /* Remember if we made one */
684 *p = '/';
685 continue;
686 }
687 *p = '/';
688 if (errno == EEXIST) /* Directory already exists */
689 continue;
690 /*
691 * Some other error in the mkdir. We return to the caller.
692 */
693 break;
694 }
695
696 errno = save_errno; /* Restore caller's errno */
697 return madeone; /* Tell them to retry if we made one */
698 }
699
700 void
701 extract_sparse_file(fd, sizeleft, totalsize, name)
702 int fd;
703 long *sizeleft,
704 totalsize;
705 char *name;
706 {
707 /* register char *data;*/
708 union record *datarec;
709 int sparse_ind = 0;
710 int written,
711 count;
712
713 /* assuming sizeleft is initially totalsize */
714
715
716 while (*sizeleft > 0) {
717 datarec = findrec();
718 if (datarec == NULL) {
719 msg("Unexpected EOF on archive file");
720 return;
721 }
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);
726 if (count < 0)
727 msg_perror("couldn't write to file %s", name);
728 written -= count;
729 *sizeleft -= count;
730 userec(datarec);
731 datarec = findrec();
732 }
733
734 count = write(fd, datarec->charptr, written);
735
736 if (count < 0) {
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));
741 }
742
743 written -= count;
744 *sizeleft -= count;
745 userec(datarec);
746 }
747 free(sparsearray);
748 /* if (end_nulls) {
749 register int i;
750
751 printf("%d\n", (int) end_nulls);
752 for (i = 0; i < end_nulls; i++)
753 write(fd, "\000", 1);
754 }*/
755 userec(datarec);
756 }
This page took 0.065919 seconds and 5 git commands to generate.