]> 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_dir_info
98 {
99 char *path;
100 int mode;
101 int atime;
102 int mtime;
103 struct saved_dir_info *next;
104 };
105
106 struct saved_dir_info *saved_dir_info_head;
107
108 /*
109 * Set up to extract files.
110 */
111 void
112 extr_init()
113 {
114 int ourmask;
115
116 now = time((time_t *)0);
117 if (geteuid() == 0)
118 we_are_root = 1;
119
120 /*
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.
123 */
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 */
128 }
129 }
130
131
132 /*
133 * Extract a file from the archive.
134 */
135 void
136 extract_archive()
137 {
138 register char *data;
139 int fd, check, namelen, written, openflag;
140 long size;
141 time_t acc_upd_times[2];
142 register int skipcrud;
143 register int i;
144 /* int sparse_ind = 0;*/
145 union record *exhdr;
146 struct saved_dir_info *tmp;
147 /* int end_nulls; */
148 char **longp;
149 char *bp;
150 static char *longname;
151 static char *longlink;
152 int bumplongs;
153
154 saverec(&head); /* Make sure it sticks around */
155 userec(head); /* And go past it in the archive */
156 decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */
157
158 if(f_confirm && !confirm("extract",head->header.name)) {
159 if (head->header.isextended)
160 skip_extended_headers();
161 skip_file((long)hstat.st_size);
162 saverec((union record **)0);
163 return;
164 }
165
166 /* Print the record from 'head' and 'hstat' */
167 if (f_verbose)
168 print_header();
169
170 /*
171 * Check for fully specified pathnames and other atrocities.
172 *
173 * Note, we can't just make a pointer to the new file name,
174 * since saverec() might move the header and adjust "head".
175 * We have to start from "head" every time we want to touch
176 * the header record.
177 */
178 skipcrud = 0;
179 while (!f_absolute_paths
180 && '/' == (longname ? longname : head->header.name)[skipcrud]) {
181 static int warned_once = 0;
182
183 skipcrud++; /* Force relative path */
184 if (!warned_once++) {
185 msg("Removing leading / from absolute path names in the archive.");
186 }
187 }
188
189 bumplongs = (head->header.linkflag != LF_LONGNAME
190 && head->header.linkflag != LF_LONGLINK);
191
192 switch (head->header.linkflag) {
193
194 default:
195 msg("Unknown file type '%c' for %s, extracted as normal file",
196 head->header.linkflag, skipcrud+head->header.name);
197 /* FALL THRU */
198
199 /*
200 * JK - What we want to do if the file is sparse is loop through
201 * the array of sparse structures in the header and read in
202 * and translate the character strings representing 1) the offset
203 * at which to write and 2) how many bytes to write into numbers,
204 * which we store into the scratch array, "sparsearray". This
205 * array makes our life easier the same way it did in creating
206 * the tar file that had to deal with a sparse file.
207 *
208 * After we read in the first five (at most) sparse structures,
209 * we check to see if the file has an extended header, i.e.,
210 * if more sparse structures are needed to describe the contents
211 * of the new file. If so, we read in the extended headers
212 * and continue to store their contents into the sparsearray.
213 */
214 case LF_SPARSE:
215 sp_array_size = 10;
216 sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
217 for (i = 0; i < SPARSE_IN_HDR; i++) {
218 sparsearray[i].offset =
219 from_oct(1+12, head->header.sp[i].offset);
220 sparsearray[i].numbytes =
221 from_oct(1+12, head->header.sp[i].numbytes);
222 if (!sparsearray[i].numbytes)
223 break;
224 }
225
226 /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/
227
228 if (head->header.isextended) {
229 /* read in the list of extended headers
230 and translate them into the sparsearray
231 as before */
232
233 /* static */ int ind = SPARSE_IN_HDR;
234
235 for (;;) {
236
237 exhdr = findrec();
238 for (i = 0; i < SPARSE_EXT_HDR; i++) {
239
240 if (i+ind > sp_array_size-1) {
241 /*
242 * realloc the scratch area
243 * since we've run out of room --
244 */
245 sparsearray = (struct sp_array *)
246 realloc(sparsearray,
247 2 * sp_array_size * (sizeof(struct sp_array)));
248 sp_array_size *= 2;
249 }
250 if (!exhdr->ext_hdr.sp[i].numbytes)
251 break;
252 sparsearray[i+ind].offset =
253 from_oct(1+12, exhdr->ext_hdr.sp[i].offset);
254 sparsearray[i+ind].numbytes =
255 from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes);
256 }
257 if (!exhdr->ext_hdr.isextended)
258 break;
259 else {
260 ind += SPARSE_EXT_HDR;
261 userec(exhdr);
262 }
263 }
264 userec(exhdr);
265 }
266
267 /* FALL THRU */
268 case LF_OLDNORMAL:
269 case LF_NORMAL:
270 case LF_CONTIG:
271 /*
272 * Appears to be a file.
273 * See if it's really a directory.
274 */
275 namelen = strlen(skipcrud+head->header.name)-1;
276 if (head->header.name[skipcrud+namelen] == '/')
277 goto really_dir;
278
279 /* FIXME, deal with protection issues */
280 again_file:
281 openflag = (f_keep?
282 O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
283 O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
284 | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
285 /*
286 * JK - The last | is a kludge to solve the problem
287 * the O_APPEND flag causes with files we are
288 * trying to make sparse: when a file is opened
289 * with O_APPEND, it writes to the last place
290 * that something was written, thereby ignoring
291 * any lseeks that we have done. We add this
292 * extra condition to make it able to lseek when
293 * a file is sparse, i.e., we don't open the new
294 * file with this flag. (Grump -- this bug caused
295 * me to waste a good deal of time, I might add)
296 */
297
298 if(f_exstdout) {
299 fd = 1;
300 goto extract_file;
301 }
302 #ifdef O_CTG
303 /*
304 * Contiguous files (on the Masscomp) have to specify
305 * the size in the open call that creates them.
306 */
307 if (head->header.linkflag == LF_CONTIG)
308 fd = open((longname ? longname : head->header.name)
309 + skipcrud,
310 openflag | O_CTG,
311 hstat.st_mode, hstat.st_size);
312 else
313 #endif
314 {
315 #ifdef NO_OPEN3
316 /*
317 * On raw V7 we won't let them specify -k (f_keep), but
318 * we just bull ahead and create the files.
319 */
320 fd = creat((longname
321 ? longname
322 : head->header.name) + skipcrud,
323 hstat.st_mode);
324 #else
325 /*
326 * With 3-arg open(), we can do this up right.
327 */
328 fd = open((longname
329 ? longname
330 : head->header.name) + skipcrud,
331 openflag, hstat.st_mode);
332 #endif
333 }
334
335 if (fd < 0) {
336 if (make_dirs(longname
337 ? longname
338 : head->header.name) + skipcrud)
339 goto again_file;
340 msg_perror("Could not create file %s",
341 skipcrud
342 +(longname ? longname : head->header.name));
343 if (head->header.isextended)
344 skip_extended_headers();
345 skip_file((long)hstat.st_size);
346 goto quit;
347 }
348
349 extract_file:
350 if (head->header.linkflag == LF_SPARSE) {
351 char *name;
352 int namelen;
353
354 /*
355 * Kludge alert. NAME is assigned to header.name
356 * because during the extraction, the space that
357 * contains the header will get scribbled on, and
358 * the name will get munged, so any error messages
359 * that happen to contain the filename will look
360 * REAL interesting unless we do this.
361 */
362 namelen = strlen(skipcrud+head->header.name);
363 name = (char *) malloc((sizeof(char)) * namelen);
364 bcopy(skipcrud+head->header.name, name, namelen);
365 size = hstat.st_size;
366 extract_sparse_file(fd, &size, hstat.st_size,
367 longname ? longname : name);
368 }
369 else
370 for (size = hstat.st_size;
371 size > 0;
372 size -= written) {
373
374 /* long offset,
375 numbytes;*/
376
377 if(f_multivol) {
378 save_name=(longname
379 ? longname
380 : head->header.name);
381 save_totsize=hstat.st_size;
382 save_sizeleft=size;
383 }
384
385 /*
386 * Locate data, determine max length
387 * writeable, write it, record that
388 * we have used the data, then check
389 * if the write worked.
390 */
391 data = findrec()->charptr;
392 if (data == NULL) { /* Check it... */
393 msg("Unexpected EOF on archive file");
394 break;
395 }
396 /*
397 * JK - If the file is sparse, use the sparsearray
398 * that we created before to lseek into the new
399 * file the proper amount, and to see how many
400 * bytes we want to write at that position.
401 */
402 /* if (head->header.linkflag == LF_SPARSE) {
403 off_t pos;
404
405 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
406 printf("%d at %d\n", (int) pos, sparse_ind);
407 written = sparsearray[sparse_ind++].numbytes;
408 } else*/
409 written = endofrecs()->charptr - data;
410 if (written > size)
411 written = size;
412 errno = 0;
413 check = write(fd, data, written);
414 /*
415 * The following is in violation of strict
416 * typing, since the arg to userec
417 * should be a struct rec *. FIXME.
418 */
419 userec((union record *)(data + written - 1));
420 if (check == written) continue;
421 /*
422 * Error in writing to file.
423 * Print it, skip to next file in archive.
424 */
425 if(check<0)
426 msg_perror("couldn't write to file %s",
427 (longname
428 ? longname
429 : head->header.name) + skipcrud);
430 else
431 msg("could only write %d of %d bytes to file %s",
432 written,check,(longname
433 ? longname
434 : head->header.name) + skipcrud);
435 skip_file((long)(size - written));
436 break; /* Still do the close, mod time, chmod, etc */
437 }
438
439 if(f_multivol)
440 save_name = 0;
441
442 /* If writing to stdout, don't try to do anything
443 to the filename; it doesn't exist, or we don't
444 want to touch it anyway */
445 if(f_exstdout)
446 break;
447
448 /* if (head->header.isextended) {
449 register union record *exhdr;
450 register int i;
451
452 for (i = 0; i < 21; i++) {
453 long offset;
454
455 if (!exhdr->ext_hdr.sp[i].numbytes)
456 break;
457 offset = from_oct(1+12,
458 exhdr->ext_hdr.sp[i].offset);
459 written = from_oct(1+12,
460 exhdr->ext_hdr.sp[i].numbytes);
461 lseek(fd, offset, 0);
462 check = write(fd, data, written);
463 if (check == written) continue;
464
465 }
466
467
468 }*/
469 check = close(fd);
470 if (check < 0) {
471 msg_perror("Error while closing %s",
472 (longname
473 ? longname
474 : head->header.name) + skipcrud);
475 }
476
477
478 set_filestat:
479
480 /*
481 * If we are root, set the owner and group of the extracted
482 * file. This does what is wanted both on real Unix and on
483 * System V. If we are running as a user, we extract as that
484 * user; if running as root, we extract as the original owner.
485 */
486 if (we_are_root || f_do_chown) {
487 if (chown((longname
488 ? longname
489 : head->header.name) + skipcrud,
490 hstat.st_uid, hstat.st_gid) < 0) {
491 msg_perror("cannot chown file %s to uid %d gid %d",
492 (longname
493 ? longname
494 : head->header.name) + skipcrud,
495 hstat.st_uid,hstat.st_gid);
496 }
497 }
498
499 /*
500 * Set the modified time of the file.
501 *
502 * Note that we set the accessed time to "now", which
503 * is really "the time we started extracting files".
504 * unless f_gnudump is used, in which case .st_atime is used
505 */
506 if (!f_modified) {
507 /* fixme if f_gnudump should set ctime too, but how? */
508 if(f_gnudump)
509 acc_upd_times[0]=hstat.st_atime;
510 else acc_upd_times[0] = now; /* Accessed now */
511 acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
512 if (utime((longname
513 ? longname
514 : head->header.name) + skipcrud,
515 acc_upd_times) < 0) {
516 msg_perror("couldn't change access and modification times of %s",(longname ? longname : head->header.name) + skipcrud);
517 }
518 }
519 /* We do the utime before the chmod because some versions of
520 utime are broken and trash the modes of the file. Since
521 we then change the mode anyway, we don't care. . . */
522
523 /*
524 * If '-k' is not set, open() or creat() could have saved
525 * the permission bits from a previously created file,
526 * ignoring the ones we specified.
527 * Even if -k is set, if the file has abnormal
528 * mode bits, we must chmod since writing or chown() has
529 * probably reset them.
530 *
531 * If -k is set, we know *we* created this file, so the mode
532 * bits were set by our open(). If the file is "normal", we
533 * skip the chmod. This works because we did umask(0) if -p
534 * is set, so umask will have left the specified mode alone.
535 */
536 if ((!f_keep)
537 || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
538 if (chmod((longname ? longname : head->header.name) + skipcrud,
539 notumask & (int)hstat.st_mode) < 0) {
540 msg_perror("cannot change mode of file %s to %ld",
541 (longname ? longname : head->header.name) + skipcrud,
542 notumask & (int)hstat.st_mode);
543 }
544 }
545
546 quit:
547 break;
548
549 case LF_LINK:
550 again_link:
551 {
552 struct stat st1,st2;
553
554 check = link (longlink ? longlink : head->header.linkname,
555 (longname ? longname : head->header.name) + skipcrud);
556 if (check == 0)
557 break;
558 if (make_dirs((longname ? longname : head->header.name) + skipcrud))
559 goto again_link;
560 if(f_gnudump && errno==EEXIST)
561 break;
562 if(stat(longlink ? longlink : head->header.linkname, &st1) == 0
563 && stat((longname ? longname : head->header.name) + skipcrud, &st2)==0
564 && st1.st_dev==st2.st_dev
565 && st1.st_ino==st2.st_ino)
566 break;
567 msg_perror("Could not link %s to %s",
568 (longname ? longname : head->header.name) + skipcrud,
569 longlink ? longlink : longlink,
570 head->header.linkname);
571 }
572 break;
573
574 #ifdef S_ISLNK
575 case LF_SYMLINK:
576 again_symlink:
577 check = symlink(longlink ? longlink : head->header.linkname,
578 (longname ? longname : head->header.name) + skipcrud);
579 /* FIXME, don't worry uid, gid, etc... */
580 if (check == 0)
581 break;
582 if (make_dirs((longname ? longname : head->header.name) + skipcrud))
583 goto again_symlink;
584 msg_perror("Could not create symlink to %s",
585 longlink ? longlink : head->header.linkname);
586 break;
587 #endif
588
589 #ifdef S_IFCHR
590 case LF_CHR:
591 hstat.st_mode |= S_IFCHR;
592 goto make_node;
593 #endif
594
595 #ifdef S_IFBLK
596 case LF_BLK:
597 hstat.st_mode |= S_IFBLK;
598 #endif
599 #if defined(S_IFCHR) || defined(S_IFBLK)
600 make_node:
601 check = mknod((longname ? longname: head->header.name) + skipcrud,
602 (int) hstat.st_mode, (int) hstat.st_rdev);
603 if (check != 0) {
604 if (make_dirs((longname
605 ? longname
606 : head->header.name) + skipcrud))
607 goto make_node;
608 msg_perror("Could not make %s",
609 (longname ? longname : head->header.name)
610 + skipcrud);
611 break;
612 };
613 goto set_filestat;
614 #endif
615
616 #ifdef S_ISFIFO
617 /* If local system doesn't support FIFOs, use default case */
618 case LF_FIFO:
619 make_fifo:
620 check = mkfifo((longname ? longname : head->header.name) + skipcrud,
621 (int) hstat.st_mode);
622 if (check != 0) {
623 if (make_dirs((longname ? longname : head->header.name) + skipcrud))
624 goto make_fifo;
625 msg_perror("Could not make %s",
626 (longname ? longname : head->header.name) + skipcrud);
627 break;
628 };
629 goto set_filestat;
630 #endif
631
632 case LF_DIR:
633 case LF_DUMPDIR:
634 namelen = strlen(longname ? longname : head->header.name)
635 + skipcrud - 1;
636 really_dir:
637 /* Check for trailing /, and zap as many as we find. */
638 while (namelen
639 && (longname
640 ? longname
641 : head->header.name)[skipcrud+namelen] == '/')
642 (longname ? longname : head->header.name)[skipcrud+namelen--] = '\0';
643 if(f_gnudump) { /* Read the entry and delete files
644 that aren't listed in the archive */
645 gnu_restore(skipcrud);
646
647 } else if(head->header.linkflag==LF_DUMPDIR)
648 skip_file((long)(hstat.st_size));
649
650
651 again_dir:
652 check = mkdir(skipcrud+(longname ? longname : head->header.name),
653 (we_are_root ? 0 : 0300) | (int)hstat.st_mode);
654 if (check != 0) {
655 struct stat st1;
656
657 if (make_dirs(skipcrud+(longname ? longname : head->header.name)))
658 goto again_dir;
659 /* If we're trying to create '.', let it be. */
660 if ((longname ? longname : head->header.name)[skipcrud+namelen] == '.' &&
661 (namelen==0 ||
662 (longname ? longname : head->header.name)[skipcrud+namelen-1]=='/'))
663 goto check_perms;
664 if( errno==EEXIST
665 && stat(skipcrud+(longname ? longname : head->header.name),&st1)==0
666 && (S_ISDIR(st1.st_mode)))
667 break;
668 msg_perror("Could not create directory %s",skipcrud+(longname ? longname : head->header.name));
669 break;
670 }
671
672 check_perms:
673 if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) {
674 hstat.st_mode |= 0300;
675 msg("Added write and execute permission to directory %s",
676 skipcrud+(longname ? longname : head->header.name));
677 }
678
679 if (f_modified)
680 goto set_filestat;
681 tmp = (struct saved_dir_info *) malloc (sizeof (struct saved_dir_info));
682 tmp->path = malloc (strlen (skipcrud + (longname ? longname : head->header.name)) + 1);
683 strcpy (tmp->path, skipcrud + (longname ? longname : head->header.name));
684 tmp->mode = hstat.st_mode;
685 tmp->atime = hstat.st_atime;
686 tmp->mtime = hstat.st_mtime;
687 tmp->next = saved_dir_info_head;
688 saved_dir_info_head = tmp;
689 case LF_VOLHDR:
690 if(f_verbose) {
691 printf("Reading %s\n",longname ? longname : head->header.name);
692 }
693 break;
694
695 case LF_NAMES:
696 extract_mangle(head);
697 break;
698
699 case LF_MULTIVOL:
700 msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
701 skip_file((long)hstat.st_size);
702 break;
703
704 case LF_LONGNAME:
705 longp = &longname;
706 goto extract_long;
707
708 case LF_LONGLINK:
709 longp = &longlink;
710 extract_long:
711
712 if (*longp)
713 free (*longp);
714 bp = *longp = (char *) ck_malloc (hstat.st_size);
715
716 for (size = hstat.st_size;
717 size > 0;
718 size -= written)
719 {
720 data = findrec ()->charptr;
721 if (data == NULL)
722 {
723 msg ("Unexpected EOF on archive file");
724 break;
725 }
726 written = endofrecs () ->charptr - data;
727 if (written > size)
728 written = size;
729
730 bcopy (data, bp, written);
731 bp += written;
732 userec ((union record *) (data + written - 1));
733 }
734 }
735
736 if (bumplongs)
737 {
738 longname = 0;
739 longlink = 0;
740 }
741
742 /* We don't need to save it any longer. */
743 saverec((union record **) 0); /* Unsave it */
744 }
745
746 /*
747 * After a file/link/symlink/dir creation has failed, see if
748 * it's because some required directory was not present, and if
749 * so, create all required dirs.
750 */
751 int
752 make_dirs(pathname)
753 char *pathname;
754 {
755 char *p; /* Points into path */
756 int madeone = 0; /* Did we do anything yet? */
757 int save_errno = errno; /* Remember caller's errno */
758 int check;
759
760 if (errno != ENOENT)
761 return 0; /* Not our problem */
762
763 for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
764 /* Avoid mkdir of empty string, if leading or double '/' */
765 if (p == pathname || p[-1] == '/')
766 continue;
767 /* Avoid mkdir where last part of path is '.' */
768 if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
769 continue;
770 *p = 0; /* Truncate the path there */
771 check = mkdir (pathname, 0777); /* Try to create it as a dir */
772 if (check == 0) {
773 /* Fix ownership */
774 if (we_are_root) {
775 if (chown(pathname, hstat.st_uid,
776 hstat.st_gid) < 0) {
777 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
778 }
779 }
780 pr_mkdir(pathname, p-pathname, notumask&0777);
781 madeone++; /* Remember if we made one */
782 *p = '/';
783 continue;
784 }
785 *p = '/';
786 if (errno == EEXIST) /* Directory already exists */
787 continue;
788 /*
789 * Some other error in the mkdir. We return to the caller.
790 */
791 break;
792 }
793
794 errno = save_errno; /* Restore caller's errno */
795 return madeone; /* Tell them to retry if we made one */
796 }
797
798 void
799 extract_sparse_file(fd, sizeleft, totalsize, name)
800 int fd;
801 long *sizeleft,
802 totalsize;
803 char *name;
804 {
805 /* register char *data;*/
806 union record *datarec;
807 int sparse_ind = 0;
808 int written,
809 count;
810
811 /* assuming sizeleft is initially totalsize */
812
813
814 while (*sizeleft > 0) {
815 datarec = findrec();
816 if (datarec == NULL) {
817 msg("Unexpected EOF on archive file");
818 return;
819 }
820 lseek(fd, sparsearray[sparse_ind].offset, 0);
821 written = sparsearray[sparse_ind++].numbytes;
822 while (written > RECORDSIZE) {
823 count = write(fd, datarec->charptr, RECORDSIZE);
824 if (count < 0)
825 msg_perror("couldn't write to file %s", name);
826 written -= count;
827 *sizeleft -= count;
828 userec(datarec);
829 datarec = findrec();
830 }
831
832 count = write(fd, datarec->charptr, written);
833
834 if (count < 0) {
835 msg_perror("couldn't write to file %s", name);
836 } else if (count != written) {
837 msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
838 skip_file((long) (*sizeleft));
839 }
840
841 written -= count;
842 *sizeleft -= count;
843 userec(datarec);
844 }
845 free(sparsearray);
846 /* if (end_nulls) {
847 register int i;
848
849 printf("%d\n", (int) end_nulls);
850 for (i = 0; i < end_nulls; i++)
851 write(fd, "\000", 1);
852 }*/
853 userec(datarec);
854 }
855
856 /* Set back the utime and mode for all the extracted directories. */
857 void restore_saved_dir_info ()
858 {
859 time_t acc_upd_times[2];
860 struct saved_dir_info *tmp;
861
862 while (saved_dir_info_head != NULL)
863 {
864 /* fixme if f_gnudump should set ctime too, but how? */
865 if(f_gnudump)
866 acc_upd_times[0]=saved_dir_info_head -> atime;
867 else acc_upd_times[0] = now; /* Accessed now */
868 acc_upd_times[1] = saved_dir_info_head -> mtime; /* Mod'd */
869 if (utime(saved_dir_info_head -> path, acc_upd_times) < 0) {
870 msg_perror("couldn't change access and modification times of %s",
871 saved_dir_info_head -> path);
872 }
873 if ((!f_keep) || (saved_dir_info_head -> mode & (S_ISUID|S_ISGID|S_ISVTX)))
874 {
875 if (chmod(saved_dir_info_head -> path,
876 notumask & saved_dir_info_head -> mode) < 0) {
877 msg_perror("cannot change mode of file %s to %ld",
878 saved_dir_info_head -> path,
879 notumask & saved_dir_info_head -> mode);
880 }
881 }
882 saved_dir_info_head = saved_dir_info_head -> next;
883 }
884 }
This page took 0.070494 seconds and 5 git commands to generate.