]> Dogcows Code - chaz/tar/blob - src/extract.c
Initial revision
[chaz/tar] / src / extract.c
1 /* Extract files from a tar archive.
2 Copyright (C) 1988 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 #if defined(POSIX)
44 #include <utime.h>
45 #endif
46
47 #ifdef NO_OPEN3
48 /* We need the #define's even though we don't use them. */
49 #include "open3.h"
50 #endif
51
52 #ifdef EMUL_OPEN3
53 /* Simulated 3-argument open for systems that don't have it */
54 #include "open3.h"
55 #endif
56
57 #include "tar.h"
58 #include "port.h"
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 /*
98 * Set up to extract files.
99 */
100 void
101 extr_init()
102 {
103 int ourmask;
104
105 now = time((time_t *)0);
106 if (geteuid() == 0)
107 we_are_root = 1;
108
109 /*
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.
112 */
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 */
117 }
118 }
119
120
121 /*
122 * Extract a file from the archive.
123 */
124 void
125 extract_archive()
126 {
127 register char *data;
128 int fd, check, namelen, written, openflag;
129 long size;
130 time_t acc_upd_times[2];
131 register int skipcrud;
132 register int i;
133 /* int sparse_ind = 0;*/
134 union record *exhdr;
135 /* int end_nulls; */
136
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 */
140
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);
146 return;
147 }
148
149 /* Print the record from 'head' and 'hstat' */
150 if (f_verbose)
151 print_header();
152
153 /*
154 * Check for fully specified pathnames and other atrocities.
155 *
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
159 * the header record.
160 */
161 skipcrud = 0;
162 while (!f_absolute_paths && '/' == head->header.name[skipcrud]) {
163 static int warned_once = 0;
164
165 skipcrud++; /* Force relative path */
166 if (!warned_once++) {
167 msg("Removing leading / from absolute path names in the archive.");
168 }
169 }
170
171 switch (head->header.linkflag) {
172
173 default:
174 msg("Unknown file type '%c' for %s, extracted as normal file",
175 head->header.linkflag, skipcrud+head->header.name);
176 /* FALL THRU */
177
178 /*
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.
186 *
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.
192 */
193 case LF_SPARSE:
194 sp_array_size = 10;
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)
202 break;
203 }
204
205 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
206
207 if (head->header.isextended) {
208 /* read in the list of extended headers
209 and translate them into the sparsearray
210 as before */
211
212 /* static */ int ind = SPARSE_IN_HDR;
213
214 for (;;) {
215
216 exhdr = findrec();
217 for (i = 0; i < SPARSE_EXT_HDR; i++) {
218
219 if (i+ind > sp_array_size-1) {
220 /*
221 * realloc the scratch area
222 * since we've run out of room --
223 */
224 sparsearray = (struct sp_array *)
225 realloc(sparsearray,
226 2 * sp_array_size * (sizeof(struct sp_array)));
227 sp_array_size *= 2;
228 }
229 if (!exhdr->ext_hdr.sp[i].numbytes)
230 break;
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);
235 }
236 if (!exhdr->ext_hdr.isextended)
237 break;
238 else {
239 ind += SPARSE_EXT_HDR;
240 userec(exhdr);
241 }
242 }
243 userec(exhdr);
244 }
245
246 /* FALL THRU */
247 case LF_OLDNORMAL:
248 case LF_NORMAL:
249 case LF_CONTIG:
250 /*
251 * Appears to be a file.
252 * See if it's really a directory.
253 */
254 namelen = strlen(skipcrud+head->header.name)-1;
255 if (head->header.name[skipcrud+namelen] == '/')
256 goto really_dir;
257
258 /* FIXME, deal with protection issues */
259 again_file:
260 openflag = (f_keep?
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);
264 /*
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)
275 */
276
277 if(f_exstdout) {
278 fd = 1;
279 goto extract_file;
280 }
281 #ifdef O_CTG
282 /*
283 * Contiguous files (on the Masscomp) have to specify
284 * the size in the open call that creates them.
285 */
286 if (head->header.linkflag == LF_CONTIG)
287 fd = open(skipcrud+head->header.name, openflag | O_CTG,
288 hstat.st_mode, hstat.st_size);
289 else
290 #endif
291 {
292 #ifdef NO_OPEN3
293 /*
294 * On raw V7 we won't let them specify -k (f_keep), but
295 * we just bull ahead and create the files.
296 */
297 fd = creat(skipcrud+head->header.name,
298 hstat.st_mode);
299 #else
300 /*
301 * With 3-arg open(), we can do this up right.
302 */
303 fd = open(skipcrud+head->header.name, openflag,
304 hstat.st_mode);
305 #endif
306 }
307
308 if (fd < 0) {
309 if (make_dirs(skipcrud+head->header.name))
310 goto again_file;
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);
315 goto quit;
316 }
317
318 extract_file:
319 if (head->header.linkflag == LF_SPARSE) {
320 char *name;
321 int namelen;
322
323 /*
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.
330 */
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,
336 name);
337 }
338 else
339 for (size = hstat.st_size;
340 size > 0;
341 size -= written) {
342
343 /* long offset,
344 numbytes;*/
345
346 if(f_multivol) {
347 save_name=head->header.name;
348 save_totsize=hstat.st_size;
349 save_sizeleft=size;
350 }
351
352 /*
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.
357 */
358 data = findrec()->charptr;
359 if (data == NULL) { /* Check it... */
360 msg("Unexpected EOF on archive file");
361 break;
362 }
363 /*
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.
368 */
369 /* if (head->header.linkflag == LF_SPARSE) {
370 off_t pos;
371
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;
375 } else*/
376 written = endofrecs()->charptr - data;
377 if (written > size)
378 written = size;
379 errno = 0;
380 check = write(fd, data, written);
381 /*
382 * The following is in violation of strict
383 * typing, since the arg to userec
384 * should be a struct rec *. FIXME.
385 */
386 userec((union record *)(data + written - 1));
387 if (check == written) continue;
388 /*
389 * Error in writing to file.
390 * Print it, skip to next file in archive.
391 */
392 if(check<0)
393 msg_perror("couldn't write to file %s",skipcrud+head->header.name);
394 else
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 */
398 }
399
400 if(f_multivol)
401 save_name = 0;
402
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 */
406 if(f_exstdout)
407 break;
408
409 /* if (head->header.isextended) {
410 register union record *exhdr;
411 register int i;
412
413 for (i = 0; i < 21; i++) {
414 long offset;
415
416 if (!exhdr->ext_hdr.sp[i].numbytes)
417 break;
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;
425
426 }
427
428
429 }*/
430 check = close(fd);
431 if (check < 0) {
432 msg_perror("Error while closing %s",skipcrud+head->header.name);
433 }
434
435
436 set_filestat:
437
438 /*
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.
443 */
444 if (we_are_root || f_do_chown) {
445 if (chown(skipcrud+head->header.name, hstat.st_uid,
446 hstat.st_gid) < 0) {
447 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
448 }
449 }
450
451 /*
452 * Set the modified time of the file.
453 *
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
457 */
458 if (!f_modified) {
459 /* fixme if f_gnudump should set ctime too, but how? */
460 if(f_gnudump)
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);
467 }
468 }
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. . . */
472
473 /*
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.
480 *
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.
485 */
486 if ((!f_keep)
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);
491 }
492 }
493
494 quit:
495 break;
496
497 case LF_LINK:
498 again_link:
499 {
500 struct stat st1,st2;
501
502 check = link (head->header.linkname,
503 skipcrud+head->header.name);
504 if (check == 0)
505 break;
506 if (make_dirs(skipcrud+head->header.name))
507 goto again_link;
508 if(f_gnudump && errno==EEXIST)
509 break;
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)
514 break;
515 msg_perror("Could not link %s to %s",
516 skipcrud+head->header.name,head->header.linkname);
517 }
518 break;
519
520 #ifdef S_ISLNK
521 case LF_SYMLINK:
522 again_symlink:
523 check = symlink(head->header.linkname,
524 skipcrud+head->header.name);
525 /* FIXME, don't worry uid, gid, etc... */
526 if (check == 0)
527 break;
528 if (make_dirs(skipcrud+head->header.name))
529 goto again_symlink;
530 msg_perror("Could not create symlink to %s",head->header.linkname);
531 break;
532 #endif
533
534 #ifdef S_IFCHR
535 case LF_CHR:
536 hstat.st_mode |= S_IFCHR;
537 goto make_node;
538 #endif
539
540 #ifdef S_IFBLK
541 case LF_BLK:
542 hstat.st_mode |= S_IFBLK;
543 #endif
544 #if defined(S_IFCHR) || defined(S_IFBLK)
545 make_node:
546 check = mknod(skipcrud+head->header.name,
547 (int) hstat.st_mode, (int) hstat.st_rdev);
548 if (check != 0) {
549 if (make_dirs(skipcrud+head->header.name))
550 goto make_node;
551 msg_perror("Could not make %s",skipcrud+head->header.name);
552 break;
553 };
554 goto set_filestat;
555 #endif
556
557 #ifdef S_ISFIFO
558 /* If local system doesn't support FIFOs, use default case */
559 case LF_FIFO:
560 make_fifo:
561 check = mkfifo(skipcrud+head->header.name,
562 (int) hstat.st_mode);
563 if (check != 0) {
564 if (make_dirs(skipcrud+head->header.name))
565 goto make_fifo;
566 msg_perror("Could not make %s",skipcrud+head->header.name);
567 break;
568 };
569 goto set_filestat;
570 #endif
571
572 case LF_DIR:
573 case LF_DUMPDIR:
574 namelen = strlen(skipcrud+head->header.name)-1;
575 really_dir:
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);
582
583 } else if(head->header.linkflag==LF_DUMPDIR)
584 skip_file((long)(hstat.st_size));
585
586
587 again_dir:
588 check = mkdir(skipcrud+head->header.name,
589 (we_are_root ? 0 : 0300) | (int)hstat.st_mode);
590 if (check != 0) {
591 struct stat st1;
592
593 if (make_dirs(skipcrud+head->header.name))
594 goto again_dir;
595 /* If we're trying to create '.', let it be. */
596 if (head->header.name[skipcrud+namelen] == '.' &&
597 (namelen==0 ||
598 head->header.name[skipcrud+namelen-1]=='/'))
599 goto check_perms;
600 if( errno==EEXIST
601 && stat(skipcrud+head->header.name,&st1)==0
602 && (S_ISDIR(st1.st_mode)))
603 break;
604 msg_perror("Could not create directory %s",skipcrud+head->header.name);
605 break;
606 }
607
608 check_perms:
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);
613 }
614
615 goto set_filestat;
616 /* FIXME, Remember timestamps for after files created? */
617 /* FIXME, change mode after files created (if was R/O dir) */
618 case LF_VOLHDR:
619 if(f_verbose) {
620 printf("Reading %s\n",head->header.name);
621 }
622 break;
623
624 case LF_NAMES:
625 extract_mangle(head);
626 break;
627
628 case LF_MULTIVOL:
629 msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
630 skip_file((long)hstat.st_size);
631 break;
632
633 }
634
635 /* We don't need to save it any longer. */
636 saverec((union record **) 0); /* Unsave it */
637 }
638
639 /*
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.
643 */
644 int
645 make_dirs(pathname)
646 char *pathname;
647 {
648 char *p; /* Points into path */
649 int madeone = 0; /* Did we do anything yet? */
650 int save_errno = errno; /* Remember caller's errno */
651 int check;
652
653 if (errno != ENOENT)
654 return 0; /* Not our problem */
655
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] == '/')
659 continue;
660 /* Avoid mkdir where last part of path is '.' */
661 if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
662 continue;
663 *p = 0; /* Truncate the path there */
664 check = mkdir (pathname, 0777); /* Try to create it as a dir */
665 if (check == 0) {
666 /* Fix ownership */
667 if (we_are_root) {
668 if (chown(pathname, hstat.st_uid,
669 hstat.st_gid) < 0) {
670 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
671 }
672 }
673 pr_mkdir(pathname, p-pathname, notumask&0777);
674 madeone++; /* Remember if we made one */
675 *p = '/';
676 continue;
677 }
678 *p = '/';
679 if (errno == EEXIST) /* Directory already exists */
680 continue;
681 /*
682 * Some other error in the mkdir. We return to the caller.
683 */
684 break;
685 }
686
687 errno = save_errno; /* Restore caller's errno */
688 return madeone; /* Tell them to retry if we made one */
689 }
690
691 void
692 extract_sparse_file(fd, sizeleft, totalsize, name)
693 int fd;
694 long *sizeleft,
695 totalsize;
696 char *name;
697 {
698 /* register char *data;*/
699 union record *datarec;
700 int sparse_ind = 0;
701 int written,
702 count;
703
704 /* assuming sizeleft is initially totalsize */
705
706
707 while (*sizeleft > 0) {
708 datarec = findrec();
709 if (datarec == NULL) {
710 msg("Unexpected EOF on archive file");
711 return;
712 }
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);
717 if (count < 0)
718 msg_perror("couldn't write to file %s", name);
719 written -= count;
720 *sizeleft -= count;
721 userec(datarec);
722 datarec = findrec();
723 }
724
725 count = write(fd, datarec->charptr, written);
726
727 if (count < 0) {
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));
732 }
733
734 written -= count;
735 *sizeleft -= count;
736 userec(datarec);
737 }
738 free(sparsearray);
739 /* if (end_nulls) {
740 register int i;
741
742 printf("%d\n", (int) end_nulls);
743 for (i = 0; i < end_nulls; i++)
744 write(fd, "\000", 1);
745 }*/
746 userec(datarec);
747 }
This page took 0.06985 seconds and 5 git commands to generate.