386BSD 0.1 development
[unix-history] / usr / src / usr.bin / tar / extract.c
CommitLineData
f87489ac
WJ
1/* Extract files from a tar archive.
2 Copyright (C) 1988 Free Software Foundation
3
4This file is part of GNU Tar.
5
6GNU Tar is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Tar is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Tar; see the file COPYING. If not, write to
18the 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 * @(#) extract.c 1.32 87/11/11 - gnu
26 */
27
28#include <stdio.h>
29#include <errno.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#ifdef BSD42
34#include <sys/file.h>
35#endif
36
37#ifdef USG
38#include <fcntl.h>
39#endif
40
41#ifdef MSDOS
42#include <fcntl.h>
43#endif /* MSDOS */
44
45/*
46 * Some people don't have a #define for these.
47 */
48#ifndef O_BINARY
49#define O_BINARY 0
50#endif
51#ifndef O_NDELAY
52#define O_NDELAY 0
53#endif
54
55#ifdef NO_OPEN3
56/* We need the #define's even though we don't use them. */
57#include "open3.h"
58#endif
59
60#ifdef EMUL_OPEN3
61/* Simulated 3-argument open for systems that don't have it */
62#include "open3.h"
63#endif
64
65extern int errno; /* From libc.a */
66extern time_t time(); /* From libc.a */
67extern char *index(); /* From libc.a or port.c */
68
69#include "tar.h"
70#include "port.h"
71
72extern FILE *msg_file;
73
74extern union record *head; /* Points to current tape header */
75extern struct stat hstat; /* Stat struct corresponding */
76extern int head_standard; /* Tape header is in ANSI format */
77
78extern char *save_name;
79extern long save_totsize;
80extern long save_sizeleft;
81
82extern void print_header();
83extern void skip_file();
84extern void skip_extended_headers();
85extern void pr_mkdir();
86
87int make_dirs(); /* Makes required directories */
88
89static time_t now = 0; /* Current time */
90static we_are_root = 0; /* True if our effective uid == 0 */
91static int notumask = ~0; /* Masks out bits user doesn't want */
92
93/*
94 * "Scratch" space to store the information about a sparse file before
95 * writing the info into the header or extended header
96 */
97/*struct sp_array *sparsearray;*/
98
99/* number of elts storable in the sparsearray */
100/*int sp_array_size = 10;*/
101
102/*
103 * Set up to extract files.
104 */
105extr_init()
106{
107 int ourmask;
108
109 now = time((time_t *)0);
110 if (geteuid() == 0)
111 we_are_root = 1;
112
113 /*
114 * We need to know our umask. But if f_use_protection is set,
115 * leave our kernel umask at 0, and our "notumask" at ~0.
116 */
117 ourmask = umask(0); /* Read it */
118 if (!f_use_protection) {
119 (void) umask (ourmask); /* Set it back how it was */
120 notumask = ~ourmask; /* Make umask override permissions */
121 }
122}
123
124
125/*
126 * Extract a file from the archive.
127 */
128void
129extract_archive()
130{
131 register char *data;
132 int fd, check, namelen, written, openflag;
133 long size;
134 time_t acc_upd_times[2];
135 register int skipcrud;
136 register int i;
137 int sparse_ind = 0;
138 union record *exhdr;
139 int end_nulls;
140
141 saverec(&head); /* Make sure it sticks around */
142 userec(head); /* And go past it in the archive */
143 decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */
144
145 if(f_confirm && !confirm("extract",head->header.name)) {
146 if (head->header.isextended)
147 skip_extended_headers();
148 skip_file((long)hstat.st_size);
149 saverec((union record **)0);
150 return;
151 }
152
153 /* Print the record from 'head' and 'hstat' */
154 if (f_verbose)
155 print_header();
156
157 /*
158 * Check for fully specified pathnames and other atrocities.
159 *
160 * Note, we can't just make a pointer to the new file name,
161 * since saverec() might move the header and adjust "head".
162 * We have to start from "head" every time we want to touch
163 * the header record.
164 */
165 skipcrud = 0;
166 while (!f_absolute_paths && '/' == head->header.name[skipcrud]) {
167 static int warned_once = 0;
168
169 skipcrud++; /* Force relative path */
170 if (!warned_once++) {
171 msg("Removing leading / from absolute path names in the archive.");
172 }
173 }
174
175 switch (head->header.linkflag) {
176
177 default:
178 msg("Unknown file type '%c' for %s, extracted as normal file",
179 head->header.linkflag, skipcrud+head->header.name);
180 /* FALL THRU */
181
182 /*
183 * JK - What we want to do if the file is sparse is loop through
184 * the array of sparse structures in the header and read in
185 * and translate the character strings representing 1) the offset
186 * at which to write and 2) how many bytes to write into numbers,
187 * which we store into the scratch array, "sparsearray". This
188 * array makes our life easier the same way it did in creating
189 * the tar file that had to deal with a sparse file.
190 *
191 * After we read in the first five (at most) sparse structures,
192 * we check to see if the file has an extended header, i.e.,
193 * if more sparse structures are needed to describe the contents
194 * of the new file. If so, we read in the extended headers
195 * and continue to store their contents into the sparsearray.
196 */
197 case LF_SPARSE:
198 sp_array_size = 10;
199 sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
200 for (i = 0; i < SPARSE_IN_HDR; i++) {
201 sparsearray[i].offset =
202 from_oct(1+12, head->header.sp[i].offset);
203 sparsearray[i].numbytes =
204 from_oct(1+12, head->header.sp[i].numbytes);
205 if (!sparsearray[i].numbytes)
206 break;
207 }
208
209/* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
210
211 if (head->header.isextended) {
212 /* read in the list of extended headers
213 and translate them into the sparsearray
214 as before */
215
216 /* static */ int ind = SPARSE_IN_HDR;
217
218 for (;;) {
219
220 exhdr = findrec();
221 for (i = 0; i < SPARSE_EXT_HDR; i++) {
222
223 if (i+ind > sp_array_size-1) {
224 /*
225 * realloc the scratch area
226 * since we've run out of room --
227 */
228 sparsearray = (struct sp_array *)
229 realloc(sparsearray,
230 2 * sp_array_size * (sizeof(struct sp_array)));
231 sp_array_size *= 2;
232 }
233 if (!exhdr->ext_hdr.sp[i].numbytes)
234 break;
235 sparsearray[i+ind].offset =
236 from_oct(1+12, exhdr->ext_hdr.sp[i].offset);
237 sparsearray[i+ind].numbytes =
238 from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes);
239 }
240 if (!exhdr->ext_hdr.isextended)
241 break;
242 else {
243 ind += SPARSE_EXT_HDR;
244 userec(exhdr);
245 }
246 }
247 userec(exhdr);
248 }
249
250 /* FALL THRU */
251 case LF_OLDNORMAL:
252 case LF_NORMAL:
253 case LF_CONTIG:
254 /*
255 * Appears to be a file.
256 * See if it's really a directory.
257 */
258 namelen = strlen(skipcrud+head->header.name)-1;
259 if (head->header.name[skipcrud+namelen] == '/')
260 goto really_dir;
261
262 /* FIXME, deal with protection issues */
263 again_file:
264 openflag = (f_keep?
265 O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
266 O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
267 | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
268 /*
269 * JK - The last | is a kludge to solve the problem
270 * the O_APPEND flag causes with files we are
271 * trying to make sparse: when a file is opened
272 * with O_APPEND, it writes to the last place
273 * that something was written, thereby ignoring
274 * any lseeks that we have done. We add this
275 * extra condition to make it able to lseek when
276 * a file is sparse, i.e., we don't open the new
277 * file with this flag. (Grump -- this bug caused
278 * me to waste a good deal of time, I might add)
279 */
280
281 if(f_exstdout) {
282 fd = 1;
283 goto extract_file;
284 }
285#ifdef O_CTG
286 /*
287 * Contiguous files (on the Masscomp) have to specify
288 * the size in the open call that creates them.
289 */
290 if (head->header.linkflag == LF_CONTIG)
291 fd = open(skipcrud+head->header.name, openflag | O_CTG,
292 hstat.st_mode, hstat.st_size);
293 else
294#endif
295 {
296#ifdef NO_OPEN3
297 /*
298 * On raw V7 we won't let them specify -k (f_keep), but
299 * we just bull ahead and create the files.
300 */
301 fd = creat(skipcrud+head->header.name,
302 hstat.st_mode);
303#else
304 /*
305 * With 3-arg open(), we can do this up right.
306 */
307 fd = open(skipcrud+head->header.name, openflag,
308 hstat.st_mode);
309#endif
310 }
311
312 if (fd < 0) {
313 if (make_dirs(skipcrud+head->header.name))
314 goto again_file;
315 msg_perror("Could not create file %s",skipcrud+head->header.name);
316 if (head->header.isextended)
317 skip_extended_headers();
318 skip_file((long)hstat.st_size);
319 goto quit;
320 }
321
322 extract_file:
323 if (head->header.linkflag == LF_SPARSE) {
324 char *name;
325 int namelen;
326
327 /*
328 * Kludge alert. NAME is assigned to header.name
329 * because during the extraction, the space that
330 * contains the header will get scribbled on, and
331 * the name will get munged, so any error messages
332 * that happen to contain the filename will look
333 * REAL interesting unless we do this.
334 */
335 namelen = strlen(skipcrud+head->header.name);
336 name = (char *) malloc((sizeof(char)) * namelen);
337 bcopy(skipcrud+head->header.name, name, namelen);
338 size = hstat.st_size;
339 extract_sparse_file(fd, &size, hstat.st_size,
340 name);
341 }
342 else
343 for (size = hstat.st_size;
344 size > 0;
345 size -= written) {
346
347 long offset,
348 numbytes;
349
350 if(f_multivol) {
351 save_name=head->header.name;
352 save_totsize=hstat.st_size;
353 save_sizeleft=size;
354 }
355
356 /*
357 * Locate data, determine max length
358 * writeable, write it, record that
359 * we have used the data, then check
360 * if the write worked.
361 */
362 data = findrec()->charptr;
363 if (data == NULL) { /* Check it... */
364 msg("Unexpected EOF on archive file");
365 break;
366 }
367 /*
368 * JK - If the file is sparse, use the sparsearray
369 * that we created before to lseek into the new
370 * file the proper amount, and to see how many
371 * bytes we want to write at that position.
372 */
373/* if (head->header.linkflag == LF_SPARSE) {
374 off_t pos;
375
376 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
377 printf("%d at %d\n", (int) pos, sparse_ind);
378 written = sparsearray[sparse_ind++].numbytes;
379 } else*/
380 written = endofrecs()->charptr - data;
381 if (written > size)
382 written = size;
383 errno = 0;
384 check = write(fd, data, written);
385 /*
386 * The following is in violation of strict
387 * typing, since the arg to userec
388 * should be a struct rec *. FIXME.
389 */
390 userec((union record *)(data + written - 1));
391 if (check == written) continue;
392 /*
393 * Error in writing to file.
394 * Print it, skip to next file in archive.
395 */
396 if(check<0)
397 msg_perror("couldn't write to file %s",skipcrud+head->header.name);
398 else
399 msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.name);
400 skip_file((long)(size - written));
401 break; /* Still do the close, mod time, chmod, etc */
402 }
403
404 if(f_multivol)
405 save_name = 0;
406
407 /* If writing to stdout, don't try to do anything
408 to the filename; it doesn't exist, or we don't
409 want to touch it anyway */
410 if(f_exstdout)
411 break;
412
413/* if (head->header.isextended) {
414 register union record *exhdr;
415 register int i;
416
417 for (i = 0; i < 21; i++) {
418 long offset;
419
420 if (!exhdr->ext_hdr.sp[i].numbytes)
421 break;
422 offset = from_oct(1+12,
423 exhdr->ext_hdr.sp[i].offset);
424 written = from_oct(1+12,
425 exhdr->ext_hdr.sp[i].numbytes);
426 lseek(fd, offset, 0);
427 check = write(fd, data, written);
428 if (check == written) continue;
429
430 }
431
432
433 }*/
434 check = close(fd);
435 if (check < 0) {
436 msg_perror("Error while closing %s",skipcrud+head->header.name);
437 }
438
439
440 set_filestat:
441
442 /*
443 * If we are root, set the owner and group of the extracted
444 * file. This does what is wanted both on real Unix and on
445 * System V. If we are running as a user, we extract as that
446 * user; if running as root, we extract as the original owner.
447 */
448 if (we_are_root || f_do_chown) {
449 if (chown(skipcrud+head->header.name, hstat.st_uid,
450 hstat.st_gid) < 0) {
451 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
452 }
453 }
454
455 /*
456 * Set the modified time of the file.
457 *
458 * Note that we set the accessed time to "now", which
459 * is really "the time we started extracting files".
460 * unless f_gnudump is used, in which case .st_atime is used
461 */
462 if (!f_modified) {
463 /* fixme if f_gnudump should set ctime too, but how? */
464 if(f_gnudump)
465 acc_upd_times[0]=hstat.st_atime;
466 else acc_upd_times[0] = now; /* Accessed now */
467 acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
468 if (utime(skipcrud+head->header.name,
469 acc_upd_times) < 0) {
470 msg_perror("couldn't change access and modification times of %s",skipcrud+head->header.name);
471 }
472 }
473 /* We do the utime before the chmod because some versions of
474 utime are broken and trash the modes of the file. Since
475 we then change the mode anyway, we don't care. . . */
476
477 /*
478 * If '-k' is not set, open() or creat() could have saved
479 * the permission bits from a previously created file,
480 * ignoring the ones we specified.
481 * Even if -k is set, if the file has abnormal
482 * mode bits, we must chmod since writing or chown() has
483 * probably reset them.
484 *
485 * If -k is set, we know *we* created this file, so the mode
486 * bits were set by our open(). If the file is "normal", we
487 * skip the chmod. This works because we did umask(0) if -p
488 * is set, so umask will have left the specified mode alone.
489 */
490 if ((!f_keep)
491 || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
492 if (chmod(skipcrud+head->header.name,
493 notumask & (int)hstat.st_mode) < 0) {
494 msg_perror("cannot change mode of file %s to %ld",skipcrud+head->header.name,notumask & (int)hstat.st_mode);
495 }
496 }
497
498 quit:
499 break;
500
501 case LF_LINK:
502 again_link:
503 {
504 struct stat st1,st2;
505
506 check = link (head->header.linkname,
507 skipcrud+head->header.name);
508 if (check == 0)
509 break;
510 if (make_dirs(skipcrud+head->header.name))
511 goto again_link;
512 if(f_gnudump && errno==EEXIST)
513 break;
514 if( stat(head->header.linkname, &st1) == 0
515 && stat(skipcrud+head->header.name, &st2)==0
516 && st1.st_dev==st2.st_dev
517 && st1.st_ino==st2.st_ino)
518 break;
519 msg_perror("Could not link %s to %s",
520 skipcrud+head->header.name,head->header.linkname);
521 }
522 break;
523
524#ifdef S_IFLNK
525 case LF_SYMLINK:
526 again_symlink:
527 check = symlink(head->header.linkname,
528 skipcrud+head->header.name);
529 /* FIXME, don't worry uid, gid, etc... */
530 if (check == 0)
531 break;
532 if (make_dirs(skipcrud+head->header.name))
533 goto again_symlink;
534 msg_perror("Could not create symlink to %s",head->header.linkname);
535 break;
536#endif
537
538#ifdef S_IFCHR
539 case LF_CHR:
540 hstat.st_mode |= S_IFCHR;
541 goto make_node;
542#endif
543
544#ifdef S_IFBLK
545 case LF_BLK:
546 hstat.st_mode |= S_IFBLK;
547 goto make_node;
548#endif
549
550#ifdef S_IFIFO
551 /* If local system doesn't support FIFOs, use default case */
552 case LF_FIFO:
553 hstat.st_mode |= S_IFIFO;
554 hstat.st_rdev = 0; /* FIXME, do we need this? */
555 goto make_node;
556#endif
557
558 make_node:
559 check = mknod(skipcrud+head->header.name,
560 (int) hstat.st_mode, (int) hstat.st_rdev);
561 if (check != 0) {
562 if (make_dirs(skipcrud+head->header.name))
563 goto make_node;
564 msg_perror("Could not make %s",skipcrud+head->header.name);
565 break;
566 };
567 goto set_filestat;
568
569 case LF_DIR:
570 case LF_DUMPDIR:
571 namelen = strlen(skipcrud+head->header.name)-1;
572 really_dir:
573 /* Check for trailing /, and zap as many as we find. */
574 while (namelen && head->header.name[skipcrud+namelen] == '/')
575 head->header.name[skipcrud+namelen--] = '\0';
576 if(f_gnudump) { /* Read the entry and delete files
577 that aren't listed in the archive */
578 gnu_restore(skipcrud);
579
580 } else if(head->header.linkflag==LF_DUMPDIR)
581 skip_file((long)(hstat.st_size));
582
583
584 again_dir:
585 check = mkdir(skipcrud+head->header.name,
586 (we_are_root ? 0 : 0300) | (int)hstat.st_mode);
587 if (check != 0) {
588 struct stat st1;
589
590 if (make_dirs(skipcrud+head->header.name))
591 goto again_dir;
592 /* If we're trying to create '.', let it be. */
593 if (head->header.name[skipcrud+namelen] == '.' &&
594 (namelen==0 ||
595 head->header.name[skipcrud+namelen-1]=='/'))
596 goto check_perms;
597 if( errno==EEXIST
598 && stat(skipcrud+head->header.name,&st1)==0
599 && (st1.st_mode&S_IFMT)==S_IFDIR)
600 break;
601 msg_perror("Could not create directory %s",skipcrud+head->header.name);
602 break;
603 }
604
605 check_perms:
606 if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) {
607 hstat.st_mode |= 0300;
608 msg("Added write and execute permission to directory %s",
609 skipcrud+head->header.name);
610 }
611
612 goto set_filestat;
613 /* FIXME, Remember timestamps for after files created? */
614 /* FIXME, change mode after files created (if was R/O dir) */
615 case LF_VOLHDR:
616 if(f_verbose) {
617 printf("Reading %s\n",head->header.name);
618 }
619 break;
620
621 case LF_NAMES:
622 extract_mangle(head);
623 break;
624
625 case LF_MULTIVOL:
626 msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
627 skip_file((long)hstat.st_size);
628 break;
629
630 }
631
632 /* We don't need to save it any longer. */
633 saverec((union record **) 0); /* Unsave it */
634}
635
636/*
637 * After a file/link/symlink/dir creation has failed, see if
638 * it's because some required directory was not present, and if
639 * so, create all required dirs.
640 */
641int
642make_dirs(pathname)
643 char *pathname;
644{
645 char *p; /* Points into path */
646 int madeone = 0; /* Did we do anything yet? */
647 int save_errno = errno; /* Remember caller's errno */
648 int check;
649
650 if (errno != ENOENT)
651 return 0; /* Not our problem */
652
653 for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
654 /* Avoid mkdir of empty string, if leading or double '/' */
655 if (p == pathname || p[-1] == '/')
656 continue;
657 /* Avoid mkdir where last part of path is '.' */
658 if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
659 continue;
660 *p = 0; /* Truncate the path there */
661 check = mkdir (pathname, 0777); /* Try to create it as a dir */
662 if (check == 0) {
663 /* Fix ownership */
664 if (we_are_root) {
665 if (chown(pathname, hstat.st_uid,
666 hstat.st_gid) < 0) {
667 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
668 }
669 }
670 pr_mkdir(pathname, p-pathname, notumask&0777);
671 madeone++; /* Remember if we made one */
672 *p = '/';
673 continue;
674 }
675 *p = '/';
676 if (errno == EEXIST) /* Directory already exists */
677 continue;
678 /*
679 * Some other error in the mkdir. We return to the caller.
680 */
681 break;
682 }
683
684 errno = save_errno; /* Restore caller's errno */
685 return madeone; /* Tell them to retry if we made one */
686}
687
688extract_sparse_file(fd, sizeleft, totalsize, name)
689 int fd;
690 long *sizeleft,
691 totalsize;
692 char *name;
693{
694 register char *data;
695 union record *datarec;
696 int sparse_ind = 0;
697 int written,
698 count;
699
700 /* assuming sizeleft is initially totalsize */
701
702
703 while (*sizeleft > 0) {
704 datarec = findrec();
705 if (datarec == NULL) {
706 msg("Unexpected EOF on archive file");
707 return;
708 }
709 lseek(fd, sparsearray[sparse_ind].offset, 0);
710 written = sparsearray[sparse_ind++].numbytes;
711 while (written > RECORDSIZE) {
712 count = write(fd, datarec->charptr, RECORDSIZE);
713 if (count < 0)
714 msg_perror("couldn't write to file %s", name);
715 written -= count;
716 *sizeleft -= count;
717 userec(datarec);
718 datarec = findrec();
719 }
720
721 count = write(fd, datarec->charptr, written);
722
723 if (count < 0) {
724 msg_perror("couldn't write to file %s", name);
725 } else if (count != written) {
726 msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
727 skip_file((long) (*sizeleft));
728 }
729
730 written -= count;
731 *sizeleft -= count;
732 userec(datarec);
733 }
734 free(sparsearray);
735/* if (end_nulls) {
736 register int i;
737
738 printf("%d\n", (int) end_nulls);
739 for (i = 0; i < end_nulls; i++)
740 write(fd, "\000", 1);
741 }*/
742 userec(datarec);
743}