Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmtar / extract.c
blob925f621588d0313318a7c967f71b95f24c85d3b5
1 /*
2 ** Copyright 1998-2003 University of Illinois Board of Trustees
3 ** Copyright 1998-2003 Mark D. Roth
4 ** All rights reserved.
5 **
6 ** extract.c - libtar code to extract a file from a tar archive
7 **
8 ** Mark D. Roth <roth@uiuc.edu>
9 ** Campus Information Technologies and Educational Services
10 ** University of Illinois at Urbana-Champaign
13 #include <libtarint/internal.h>
15 #include <stdio.h>
16 #include <libtar/compat.h>
17 #include <sys/types.h>
18 #include <fcntl.h>
19 #include <errno.h>
21 #if defined(_WIN32) && !defined(__CYGWIN__)
22 # ifdef _MSC_VER
23 # include <sys/utime.h>
24 # else
25 # include <utime.h>
26 # endif
27 # include <io.h>
28 # include <direct.h>
29 #else
30 # include <utime.h>
31 # include <sys/param.h>
32 #endif
34 #ifdef STDC_HEADERS
35 # include <stdlib.h>
36 # include <string.h>
37 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
43 #ifdef HAVE_SYS_MKDEV_H
44 # include <sys/mkdev.h>
45 #endif
48 struct linkname
50 char ln_save[TAR_MAXPATHLEN];
51 char ln_real[TAR_MAXPATHLEN];
53 typedef struct linkname linkname_t;
56 static int
57 tar_set_file_perms(TAR *t, char *realname)
59 mode_t mode;
60 uid_t uid;
61 gid_t gid;
62 struct utimbuf ut;
63 char *filename;
64 char *pathname = 0;
66 if (realname)
68 filename = realname;
70 else
72 pathname = th_get_pathname(t);
73 filename = pathname;
76 mode = th_get_mode(t);
77 uid = th_get_uid(t);
78 gid = th_get_gid(t);
79 ut.modtime = ut.actime = th_get_mtime(t);
81 /* change owner/group */
82 #ifndef WIN32
83 if (geteuid() == 0)
84 #ifdef HAVE_LCHOWN
85 if (lchown(filename, uid, gid) == -1)
87 # ifdef DEBUG
88 fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
89 filename, uid, gid, strerror(errno));
90 # endif
91 #else /* ! HAVE_LCHOWN */
92 if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
94 # ifdef DEBUG
95 fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
96 filename, uid, gid, strerror(errno));
97 # endif
98 #endif /* HAVE_LCHOWN */
99 if (pathname)
101 free(pathname);
103 return -1;
106 /* change access/modification time */
107 if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
109 #ifdef DEBUG
110 perror("utime()");
111 #endif
112 if (pathname)
114 free(pathname);
116 return -1;
118 /* change permissions */
119 if (!TH_ISSYM(t) && chmod(filename, mode & 07777) == -1)
121 #ifdef DEBUG
122 perror("chmod()");
123 #endif
124 if (pathname)
126 free(pathname);
128 return -1;
131 #else /* WIN32 */
132 (void)filename;
133 (void)gid;
134 (void)uid;
135 (void)mode;
136 #endif /* WIN32 */
138 if (pathname)
140 free(pathname);
142 return 0;
146 /* switchboard */
148 tar_extract_file(TAR *t, char *realname)
150 int i;
151 linkname_t *lnp;
152 char *pathname;
154 if (t->options & TAR_NOOVERWRITE)
156 struct stat s;
158 #ifdef WIN32
159 if (stat(realname, &s) == 0 || errno != ENOENT)
160 #else
161 if (lstat(realname, &s) == 0 || errno != ENOENT)
162 #endif
164 errno = EEXIST;
165 return -1;
169 if (TH_ISDIR(t))
171 i = tar_extract_dir(t, realname);
172 if (i == 1)
173 i = 0;
175 #ifndef _WIN32
176 else if (TH_ISLNK(t))
177 i = tar_extract_hardlink(t, realname);
178 else if (TH_ISSYM(t))
179 i = tar_extract_symlink(t, realname);
180 else if (TH_ISCHR(t))
181 i = tar_extract_chardev(t, realname);
182 else if (TH_ISBLK(t))
183 i = tar_extract_blockdev(t, realname);
184 else if (TH_ISFIFO(t))
185 i = tar_extract_fifo(t, realname);
186 #endif
187 else /* if (TH_ISREG(t)) */
188 i = tar_extract_regfile(t, realname);
190 if (i != 0)
191 return i;
193 i = tar_set_file_perms(t, realname);
194 if (i != 0)
195 return i;
197 lnp = (linkname_t *)calloc(1, sizeof(linkname_t));
198 if (lnp == NULL)
199 return -1;
200 pathname = th_get_pathname(t);
201 strlcpy(lnp->ln_save, pathname, sizeof(lnp->ln_save));
202 strlcpy(lnp->ln_real, realname, sizeof(lnp->ln_real));
203 #ifdef DEBUG
204 printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
205 "value=\"%s\"\n", pathname, realname);
206 #endif
207 if (pathname)
209 free(pathname);
211 if (libtar_hash_add(t->h, lnp) != 0)
212 return -1;
214 return 0;
218 /* extract regular file */
220 tar_extract_regfile(TAR *t, char *realname)
222 mode_t mode;
223 size_t size;
224 uid_t uid;
225 gid_t gid;
226 int fdout;
227 ssize_t i, k;
228 char buf[T_BLOCKSIZE];
229 char *filename;
230 char *pathname = 0;
232 #ifdef DEBUG
233 printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t,
234 realname);
235 #endif
237 if (!TH_ISREG(t))
239 errno = EINVAL;
240 return -1;
243 if (realname)
245 filename = realname;
247 else
249 pathname = th_get_pathname(t);
250 filename = pathname;
252 mode = th_get_mode(t);
253 size = th_get_size(t);
254 uid = th_get_uid(t);
255 gid = th_get_gid(t);
257 /* Make a copy of the string because dirname and mkdirhier may modify the
258 * string */
259 strncpy(buf, filename, sizeof(buf)-1);
260 buf[sizeof(buf)-1] = 0;
262 if (mkdirhier(dirname(buf)) == -1)
264 if (pathname)
266 free(pathname);
268 return -1;
271 #ifdef DEBUG
272 printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
273 filename, mode, uid, gid, size);
274 #endif
275 fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
276 #ifdef O_BINARY
277 | O_BINARY
278 #endif
279 , 0666);
280 if (fdout == -1)
282 #ifdef DEBUG
283 perror("open()");
284 #endif
285 if (pathname)
287 free(pathname);
289 return -1;
292 #if 0
293 /* change the owner. (will only work if run as root) */
294 if (fchown(fdout, uid, gid) == -1 && errno != EPERM)
296 #ifdef DEBUG
297 perror("fchown()");
298 #endif
299 if (pathname)
301 free(pathname);
303 return -1;
306 /* make sure the mode isn't inheritted from a file we're overwriting */
307 if (fchmod(fdout, mode & 07777) == -1)
309 #ifdef DEBUG
310 perror("fchmod()");
311 #endif
312 if (pathname)
314 free(pathname);
316 return -1;
318 #endif
320 /* extract the file */
321 for (i = size; i > 0; i -= T_BLOCKSIZE)
323 k = tar_block_read(t, buf);
324 if (k != T_BLOCKSIZE)
326 if (k != -1)
327 errno = EINVAL;
328 if (pathname)
330 free(pathname);
332 return -1;
335 /* write block to output file */
336 if (write(fdout, buf,
337 ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : (unsigned int)i)) == -1)
339 if (pathname)
341 free(pathname);
343 return -1;
347 /* close output file */
348 if (close(fdout) == -1)
350 if (pathname)
352 free(pathname);
354 return -1;
357 #ifdef DEBUG
358 printf("### done extracting %s\n", filename);
359 #endif
361 (void)filename;
362 (void)gid;
363 (void)uid;
364 (void)mode;
366 if (pathname)
368 free(pathname);
370 return 0;
374 /* skip regfile */
376 tar_skip_regfile(TAR *t)
378 ssize_t i, k;
379 size_t size;
380 char buf[T_BLOCKSIZE];
382 if (!TH_ISREG(t))
384 errno = EINVAL;
385 return -1;
388 size = th_get_size(t);
389 for (i = size; i > 0; i -= T_BLOCKSIZE)
391 k = tar_block_read(t, buf);
392 if (k != T_BLOCKSIZE)
394 if (k != -1)
395 errno = EINVAL;
396 return -1;
400 return 0;
404 /* hardlink */
406 tar_extract_hardlink(TAR * t, char *realname)
408 char *filename;
409 char *linktgt;
410 linkname_t *lnp;
411 libtar_hashptr_t hp;
412 char buf[T_BLOCKSIZE];
413 char *pathname = 0;
415 if (!TH_ISLNK(t))
417 errno = EINVAL;
418 return -1;
421 if (realname)
423 filename = realname;
425 else
427 pathname = th_get_pathname(t);
428 filename = pathname;
431 /* Make a copy of the string because dirname and mkdirhier may modify the
432 * string */
433 strncpy(buf, filename, sizeof(buf)-1);
434 buf[sizeof(buf)-1] = 0;
436 if (mkdirhier(dirname(buf)) == -1)
438 if (pathname)
440 free(pathname);
442 return -1;
444 libtar_hashptr_reset(&hp);
445 if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
446 (libtar_matchfunc_t)libtar_str_match) != 0)
448 lnp = (linkname_t *)libtar_hashptr_data(&hp);
449 linktgt = lnp->ln_real;
451 else
452 linktgt = th_get_linkname(t);
454 #ifdef DEBUG
455 printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
456 #endif
457 #ifndef WIN32
458 if (link(linktgt, filename) == -1)
459 #else
460 (void)linktgt;
461 #endif
463 #ifdef DEBUG
464 perror("link()");
465 #endif
466 if (pathname)
468 free(pathname);
470 return -1;
473 #ifndef WIN32
474 if (pathname)
476 free(pathname);
478 return 0;
479 #endif
483 /* symlink */
485 tar_extract_symlink(TAR *t, char *realname)
487 char *filename;
488 char buf[T_BLOCKSIZE];
489 char *pathname = 0;
491 #ifndef _WIN32
492 if (!TH_ISSYM(t))
494 errno = EINVAL;
495 return -1;
497 #endif
499 if (realname)
501 filename = realname;
503 else
505 pathname = th_get_pathname(t);
506 filename = pathname;
509 /* Make a copy of the string because dirname and mkdirhier may modify the
510 * string */
511 strncpy(buf, filename, sizeof(buf)-1);
512 buf[sizeof(buf)-1] = 0;
514 if (mkdirhier(dirname(buf)) == -1)
516 if (pathname)
518 free(pathname);
520 return -1;
523 if (unlink(filename) == -1 && errno != ENOENT)
525 if (pathname)
527 free(pathname);
529 return -1;
532 #ifdef DEBUG
533 printf(" ==> extracting: %s (symlink to %s)\n",
534 filename, th_get_linkname(t));
535 #endif
536 #ifndef WIN32
537 if (symlink(th_get_linkname(t), filename) == -1)
538 #endif
540 #ifdef DEBUG
541 perror("symlink()");
542 #endif
543 if (pathname)
545 free(pathname);
547 return -1;
550 #ifndef WIN32
551 if (pathname)
553 free(pathname);
555 return 0;
556 #endif
560 /* character device */
562 tar_extract_chardev(TAR *t, char *realname)
564 mode_t mode;
565 unsigned long devmaj, devmin;
566 char *filename;
567 char buf[T_BLOCKSIZE];
568 char *pathname = 0;
570 #ifndef _WIN32
571 if (!TH_ISCHR(t))
573 errno = EINVAL;
574 return -1;
576 #endif
577 if (realname)
579 filename = realname;
581 else
583 pathname = th_get_pathname(t);
584 filename = pathname;
586 mode = th_get_mode(t);
587 devmaj = th_get_devmajor(t);
588 devmin = th_get_devminor(t);
590 /* Make a copy of the string because dirname and mkdirhier may modify the
591 * string */
592 strncpy(buf, filename, sizeof(buf)-1);
593 buf[sizeof(buf)-1] = 0;
595 if (mkdirhier(dirname(buf)) == -1)
597 if (pathname)
599 free(pathname);
601 return -1;
604 #ifdef DEBUG
605 printf(" ==> extracting: %s (character device %ld,%ld)\n",
606 filename, devmaj, devmin);
607 #endif
608 #ifndef WIN32
609 if (mknod(filename, mode | S_IFCHR,
610 compat_makedev(devmaj, devmin)) == -1)
611 #else
612 (void)devmin;
613 (void)devmaj;
614 (void)mode;
615 #endif
617 #ifdef DEBUG
618 perror("mknod()");
619 #endif
620 if (pathname)
622 free(pathname);
624 return -1;
627 #ifndef WIN32
628 if (pathname)
630 free(pathname);
632 return 0;
633 #endif
637 /* block device */
639 tar_extract_blockdev(TAR *t, char *realname)
641 mode_t mode;
642 unsigned long devmaj, devmin;
643 char *filename;
644 char buf[T_BLOCKSIZE];
645 char *pathname = 0;
647 if (!TH_ISBLK(t))
649 errno = EINVAL;
650 return -1;
653 if (realname)
655 filename = realname;
657 else
659 pathname = th_get_pathname(t);
660 filename = pathname;
662 mode = th_get_mode(t);
663 devmaj = th_get_devmajor(t);
664 devmin = th_get_devminor(t);
666 /* Make a copy of the string because dirname and mkdirhier may modify the
667 * string */
668 strncpy(buf, filename, sizeof(buf)-1);
669 buf[sizeof(buf)-1] = 0;
671 if (mkdirhier(dirname(buf)) == -1)
673 if (pathname)
675 free(pathname);
677 return -1;
680 #ifdef DEBUG
681 printf(" ==> extracting: %s (block device %ld,%ld)\n",
682 filename, devmaj, devmin);
683 #endif
684 #ifndef WIN32
685 if (mknod(filename, mode | S_IFBLK,
686 compat_makedev(devmaj, devmin)) == -1)
687 #else
688 (void)devmin;
689 (void)devmaj;
690 (void)mode;
691 #endif
693 #ifdef DEBUG
694 perror("mknod()");
695 #endif
696 if (pathname)
698 free(pathname);
700 return -1;
703 #ifndef WIN32
704 if (pathname)
706 free(pathname);
708 return 0;
709 #endif
713 /* directory */
715 tar_extract_dir(TAR *t, char *realname)
717 mode_t mode;
718 char *filename;
719 char buf[T_BLOCKSIZE];
720 char *pathname = 0;
721 size_t len = 0;
723 if (!TH_ISDIR(t))
725 errno = EINVAL;
726 return -1;
729 if (realname)
731 filename = realname;
733 else
735 pathname = th_get_pathname(t);
736 filename = pathname;
738 mode = th_get_mode(t);
740 /* Make a copy of the string because dirname and mkdirhier may modify the
741 * string */
742 strncpy(buf, filename, sizeof(buf)-1);
743 buf[sizeof(buf)-1] = 0;
745 if (mkdirhier(dirname(buf)) == -1)
747 if (pathname)
749 free(pathname);
751 return -1;
754 /* Strip trailing '/'...it confuses some Unixes (and BeOS)... */
755 strncpy(buf, filename, sizeof(buf)-1);
756 buf[sizeof(buf)-1] = 0;
757 len = strlen(buf);
758 if ((len > 0) && (buf[len-1] == '/'))
760 buf[len-1] = '\0';
763 #ifdef DEBUG
764 printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
765 mode);
766 #endif
767 #ifdef WIN32
768 if (mkdir(buf) == -1)
769 #else
770 if (mkdir(buf, mode & 07777) == -1)
771 #endif
773 #ifdef __BORLANDC__
774 /* There is a bug in the Borland Run time library which makes MKDIR
775 return EACCES when it should return EEXIST
776 if it is some other error besides directory exists
777 then return false */
778 if ( errno == EACCES)
780 errno = EEXIST;
782 #endif
783 if (errno == EEXIST)
785 if (chmod(filename, mode & 07777) == -1)
787 #ifdef DEBUG
788 perror("chmod()");
789 #endif
790 if (pathname)
792 free(pathname);
794 return -1;
796 else
798 #ifdef DEBUG
799 puts(" *** using existing directory");
800 #endif
801 if (pathname)
803 free(pathname);
805 return 1;
808 else
810 #ifdef DEBUG
811 perror("mkdir()");
812 #endif
813 if (pathname)
815 free(pathname);
817 return -1;
821 if (pathname)
823 free(pathname);
825 return 0;
829 /* FIFO */
831 tar_extract_fifo(TAR *t, char *realname)
833 mode_t mode;
834 char *filename;
835 char buf[T_BLOCKSIZE];
836 char *pathname = 0;
838 if (!TH_ISFIFO(t))
840 errno = EINVAL;
841 return -1;
844 if (realname)
846 filename = realname;
848 else
850 pathname = th_get_pathname(t);
851 filename = pathname;
853 mode = th_get_mode(t);
855 /* Make a copy of the string because dirname and mkdirhier may modify the
856 * string */
857 strncpy(buf, filename, sizeof(buf)-1);
858 buf[sizeof(buf)-1] = 0;
860 if (mkdirhier(dirname(buf)) == -1)
862 if (pathname)
864 free(pathname);
866 return -1;
869 #ifdef DEBUG
870 printf(" ==> extracting: %s (fifo)\n", filename);
871 #endif
872 #ifndef WIN32
873 if (mkfifo(filename, mode & 07777) == -1)
874 #else
875 (void)mode;
876 #endif
878 #ifdef DEBUG
879 perror("mkfifo()");
880 #endif
881 if (pathname)
883 free(pathname);
885 return -1;
888 #ifndef WIN32
889 if (pathname)
891 free(pathname);
893 return 0;
894 #endif