summaryrefslogtreecommitdiff
path: root/archival/tar.c
diff options
context:
space:
mode:
authorGlenn L McGrath <bug1@ihug.co.nz>2002-09-25 02:47:48 +0000
committerGlenn L McGrath <bug1@ihug.co.nz>2002-09-25 02:47:48 +0000
commit7ca04f328e22fcbee4659d73f9a72dfdf1dd6a23 (patch)
treef38c7ef4317eea28c6abdb0adbbb286fe041711e /archival/tar.c
parentecfa290cfd4953598e6d91989bd66ac16e135f84 (diff)
downloadbusybox-w32-7ca04f328e22fcbee4659d73f9a72dfdf1dd6a23.tar.gz
busybox-w32-7ca04f328e22fcbee4659d73f9a72dfdf1dd6a23.tar.bz2
busybox-w32-7ca04f328e22fcbee4659d73f9a72dfdf1dd6a23.zip
New common unarchive code.
Diffstat (limited to 'archival/tar.c')
-rw-r--r--archival/tar.c243
1 files changed, 107 insertions, 136 deletions
diff --git a/archival/tar.c b/archival/tar.c
index 2ab022954..6ef698edf 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -115,7 +115,7 @@ struct TarBallInfo {
115 tarball lives, so we can avoid trying 115 tarball lives, so we can avoid trying
116 to include the tarball into itself */ 116 to include the tarball into itself */
117 int verboseFlag; /* Whether to print extra stuff or not */ 117 int verboseFlag; /* Whether to print extra stuff or not */
118 char **excludeList; /* List of files to not include */ 118 const llist_t *excludeList; /* List of files to not include */
119 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ 119 HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
120 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ 120 HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
121}; 121};
@@ -325,16 +325,15 @@ static inline int writeTarHeader(struct TarBallInfo *tbInfo,
325} 325}
326 326
327# if defined CONFIG_FEATURE_TAR_EXCLUDE 327# if defined CONFIG_FEATURE_TAR_EXCLUDE
328static inline int exclude_file(char **excluded_files, const char *file) 328static inline int exclude_file(const llist_t *excluded_files, const char *file)
329{ 329{
330 int i; 330 if (excluded_files == NULL) {
331
332 if (excluded_files == NULL)
333 return 0; 331 return 0;
332 }
334 333
335 for (i = 0; excluded_files[i] != NULL; i++) { 334 while (excluded_files) {
336 if (excluded_files[i][0] == '/') { 335 if (excluded_files->data[0] == '/') {
337 if (fnmatch(excluded_files[i], file, 336 if (fnmatch(excluded_files->data, file,
338 FNM_PATHNAME | FNM_LEADING_DIR) == 0) 337 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
339 return 1; 338 return 1;
340 } else { 339 } else {
@@ -342,11 +341,12 @@ static inline int exclude_file(char **excluded_files, const char *file)
342 341
343 for (p = file; p[0] != '\0'; p++) { 342 for (p = file; p[0] != '\0'; p++) {
344 if ((p == file || p[-1] == '/') && p[0] != '/' && 343 if ((p == file || p[-1] == '/') && p[0] != '/' &&
345 fnmatch(excluded_files[i], p, 344 fnmatch(excluded_files->data, p,
346 FNM_PATHNAME | FNM_LEADING_DIR) == 0) 345 FNM_PATHNAME | FNM_LEADING_DIR) == 0)
347 return 1; 346 return 1;
348 } 347 }
349 } 348 }
349 excluded_files = excluded_files->link;
350 } 350 }
351 351
352 return 0; 352 return 0;
@@ -455,8 +455,8 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf,
455 return (TRUE); 455 return (TRUE);
456} 456}
457 457
458static inline int writeTarFile(const char *tarName, int verboseFlag, 458static inline int writeTarFile(const char *tarName, const int verboseFlag,
459 char **argv, char **excludeList, int gzip) 459 const llist_t *include, const llist_t *exclude, const int gzip)
460{ 460{
461#ifdef CONFIG_FEATURE_TAR_GZIP 461#ifdef CONFIG_FEATURE_TAR_GZIP
462 int gzipDataPipe[2] = { -1, -1 }; 462 int gzipDataPipe[2] = { -1, -1 };
@@ -471,8 +471,9 @@ static inline int writeTarFile(const char *tarName, int verboseFlag,
471 tbInfo.hlInfoHead = NULL; 471 tbInfo.hlInfoHead = NULL;
472 472
473 /* Make sure there is at least one file to tar up. */ 473 /* Make sure there is at least one file to tar up. */
474 if (*argv == NULL) 474 if (include == NULL) {
475 error_msg_and_die("Cowardly refusing to create an empty archive"); 475 error_msg_and_die("Cowardly refusing to create an empty archive");
476 }
476 477
477 /* Open the tar file for writing. */ 478 /* Open the tar file for writing. */
478 if (tarName == NULL) { 479 if (tarName == NULL) {
@@ -544,15 +545,16 @@ static inline int writeTarFile(const char *tarName, int verboseFlag,
544 } 545 }
545#endif 546#endif
546 547
547 tbInfo.excludeList = excludeList; 548 tbInfo.excludeList = exclude;
548 549
549 /* Read the directory/files and iterate over them one at a time */ 550 /* Read the directory/files and iterate over them one at a time */
550 while (*argv != NULL) { 551 while (include) {
551 if (!recursive_action(*argv++, TRUE, FALSE, FALSE, 552 if (!recursive_action(include->data, TRUE, FALSE, FALSE,
552 writeFileToTarball, writeFileToTarball, 553 writeFileToTarball, writeFileToTarball,
553 (void *) &tbInfo)) { 554 (void *) &tbInfo)) {
554 errorFlag = TRUE; 555 errorFlag = TRUE;
555 } 556 }
557 include = include->link;
556 } 558 }
557 /* Write two empty blocks to the end of the archive */ 559 /* Write two empty blocks to the end of the archive */
558 for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) { 560 for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) {
@@ -582,64 +584,48 @@ static inline int writeTarFile(const char *tarName, int verboseFlag,
582} 584}
583#endif /* tar_create */ 585#endif /* tar_create */
584 586
585void append_file_to_list(const char *new_name, char ***list, int *list_count) 587#ifdef CONFIG_FEATURE_TAR_EXCLUDE
586{ 588static const llist_t *append_file_list_to_list(const char *filename, const llist_t *list)
587 *list = realloc(*list, sizeof(char *) * (*list_count + 2));
588 (*list)[*list_count] = xstrdup(new_name);
589 (*list_count)++;
590 (*list)[*list_count] = NULL;
591}
592
593void append_file_list_to_list(char *filename, char ***name_list,
594 int *num_of_entries)
595{ 589{
596 FILE *src_stream; 590 FILE *src_stream = xfopen(filename, "r");
597 char *line; 591 while(1) {
598 592 char *line = get_line_from_file(src_stream);
599 src_stream = xfopen(filename, "r"); 593 if (line == NULL) {
600 while ((line = get_line_from_file(src_stream)) != NULL) { 594 break;
595 }
601 chomp(line); 596 chomp(line);
602 append_file_to_list(line, name_list, num_of_entries); 597 list = add_to_list(list, line);
603 free(line); 598 free(line);
604 } 599 }
605 fclose(src_stream); 600 fclose(src_stream);
601
602 return (list);
606} 603}
604#endif
607 605
608int tar_main(int argc, char **argv) 606int tar_main(int argc, char **argv)
609{ 607{
610 enum untar_funct_e { 608#ifdef CONFIG_FEATURE_TAR_GZIP
611 /* This is optional */ 609 char (*get_header_ptr)(archive_handle_t *) = get_header_tar;
612 untar_unzip = 1, 610#endif
613 /* Require one and only one of these */ 611 archive_handle_t *tar_handle;
614 untar_list = 2,
615 untar_create = 4,
616 untar_extract = 8
617 };
618
619 FILE *src_stream = NULL;
620 FILE *uncompressed_stream = NULL;
621 char **include_list = NULL;
622 char **exclude_list = NULL;
623 char *src_filename = NULL;
624 char *dst_prefix = NULL;
625 int opt; 612 int opt;
626 unsigned short untar_funct = 0; 613 char *base_dir = NULL;
627 unsigned short untar_funct_required = 0;
628 unsigned short extract_function = 0;
629 int include_list_count = 0;
630 614
631#ifdef CONFIG_FEATURE_TAR_EXCLUDE 615#ifdef CONFIG_FEATURE_TAR_CREATE
632 int exclude_list_count = 0; 616 char *src_filename = NULL;
633#endif 617 unsigned char tar_create = FALSE;
634#ifdef CONFIG_FEATURE_TAR_GZIP
635 int gunzip_pid;
636 int gz_fd = 0;
637#endif 618#endif
638 619
639 if (argc < 2) { 620 if (argc < 2) {
640 show_usage(); 621 show_usage();
641 } 622 }
642 623
624 /* Initialise default values */
625 tar_handle = init_handle();
626 tar_handle->src_fd = fileno(stdin);
627 tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS;
628
643 /* Prepend '-' to the first argument if required */ 629 /* Prepend '-' to the first argument if required */
644 if (argv[1][0] != '-') { 630 if (argv[1][0] != '-') {
645 char *tmp = xmalloc(strlen(argv[1]) + 2); 631 char *tmp = xmalloc(strlen(argv[1]) + 2);
@@ -648,61 +634,69 @@ int tar_main(int argc, char **argv)
648 strcpy(tmp + 1, argv[1]); 634 strcpy(tmp + 1, argv[1]);
649 argv[1] = tmp; 635 argv[1] = tmp;
650 } 636 }
651
652 while ((opt = getopt(argc, argv, "ctxT:X:C:f:Opvz")) != -1) { 637 while ((opt = getopt(argc, argv, "ctxT:X:C:f:Opvz")) != -1) {
653 switch (opt) { 638 switch (opt) {
654
655 /* One and only one of these is required */ 639 /* One and only one of these is required */
640#ifdef CONFIG_FEATURE_TAR_CREATE
656 case 'c': 641 case 'c':
657 untar_funct_required |= untar_create; 642 tar_create = TRUE;
658 break; 643 break;
644#endif
659 case 't': 645 case 't':
660 untar_funct_required |= untar_list; 646 if ((tar_handle->action_header == header_list) ||
661 extract_function |= extract_list | extract_unconditional; 647 (tar_handle->action_header == header_verbose_list)) {
648 tar_handle->action_header = header_verbose_list;
649 } else {
650 tar_handle->action_header = header_list;
651 }
662 break; 652 break;
663 case 'x': 653 case 'x':
664 untar_funct_required |= untar_extract; 654 tar_handle->action_data = data_extract_all;
665 extract_function |=
666 (extract_all_to_fs | extract_unconditional |
667 extract_create_leading_dirs);
668 break; 655 break;
669 656
670 /* These are optional */ 657 /* These are optional */
671 /* Exclude or Include files listed in <filename> */ 658 /* Exclude or Include files listed in <filename> */
672#ifdef CONFIG_FEATURE_TAR_EXCLUDE 659#ifdef CONFIG_FEATURE_TAR_EXCLUDE
673 case 'X': 660 case 'X':
674 append_file_list_to_list(optarg, &exclude_list, 661 tar_handle->reject =
675 &exclude_list_count); 662 append_file_list_to_list(optarg, tar_handle->reject);
676 break; 663 break;
677#endif 664#endif
678 case 'T': 665 case 'T':
679 /* by default a list is an include list */ 666 /* by default a list is an include list */
680 append_file_list_to_list(optarg, &include_list,
681 &include_list_count);
682 break; 667 break;
683
684 case 'C': /* Change to dir <optarg> */ 668 case 'C': /* Change to dir <optarg> */
685 /* Make sure dst_prefix ends in a '/' */ 669 base_dir = optarg;
686 dst_prefix = concat_path_file(optarg, "/");
687 break; 670 break;
688 case 'f': /* archive filename */ 671 case 'f': /* archive filename */
689 if (strcmp(optarg, "-") == 0) { 672#ifdef CONFIG_FEATURE_TAR_CREATE
690 src_filename = NULL; 673 src_filename = optarg;
691 } else { 674#endif
692 src_filename = xstrdup(optarg); 675 tar_handle->src_fd = xopen(optarg, O_RDONLY);
693 }
694 break; 676 break;
695 case 'O': 677 case 'O': /* To stdout */
696 extract_function |= extract_to_stdout; 678 tar_handle->action_data = data_extract_to_stdout;
697 break; 679 break;
698 case 'p': 680 case 'p':
681 tar_handle->flags |= ARCHIVE_PRESERVE_DATE;
699 break; 682 break;
700 case 'v': 683 case 'v':
701 extract_function |= extract_verbose_list; 684 if ((tar_handle->action_header == header_list) ||
685 (tar_handle->action_header == header_verbose_list)) {
686 tar_handle->action_header = header_verbose_list;
687 } else {
688 tar_handle->action_header = header_list;
689 }
702 break; 690 break;
703#ifdef CONFIG_FEATURE_TAR_GZIP 691#ifdef CONFIG_FEATURE_TAR_GZIP
704 case 'z': 692 case 'z':
705 untar_funct |= untar_unzip; 693 get_header_ptr = get_header_tar_gz;
694 break;
695#endif
696#ifdef CONFIG_FEATURE_TAR_BZIP2
697 /* Not enabled yet */
698 case 'j':
699 archive_handle->archive_action = bunzip2;
706 break; 700 break;
707#endif 701#endif
708 default: 702 default:
@@ -710,77 +704,54 @@ int tar_main(int argc, char **argv)
710 } 704 }
711 } 705 }
712 706
713 /* Make sure the valid arguments were passed */
714 if (untar_funct_required == 0) {
715 error_msg_and_die("You must specify one of the `-ctx' options");
716 }
717 if ((untar_funct_required != untar_create) &&
718 (untar_funct_required != untar_extract) &&
719 (untar_funct_required != untar_list)) {
720 error_msg_and_die("You may not specify more than one `ctx' option.");
721 }
722 untar_funct |= untar_funct_required;
723
724 /* Setup an array of filenames to work with */ 707 /* Setup an array of filenames to work with */
708 /* TODO: This is the same as in ar, seperate function ? */
725 while (optind < argc) { 709 while (optind < argc) {
726 append_file_to_list(argv[optind], &include_list, &include_list_count); 710 char absolute_path[PATH_MAX];
711
712 realpath(argv[optind], absolute_path);
713 tar_handle->accept = add_to_list(tar_handle->accept, absolute_path);
727 optind++; 714 optind++;
728 } 715#ifdef CONFIG_FEATURE_TAR_EXCLUDE
729 if (extract_function & (extract_list | extract_all_to_fs)) { 716 if (tar_handle->reject) {
730 if (dst_prefix == NULL) { 717 tar_handle->filter = filter_accept_reject_list;
731 dst_prefix = xstrdup("./"); 718 } else
719#endif
720 tar_handle->filter = filter_accept_list;
732 } 721 }
733 722
734 /* Setup the source of the tar data */ 723 if ((base_dir) && (chdir(base_dir))) {
735 if (src_filename != NULL) { 724 perror_msg_and_die("Couldnt chdir");
736 src_stream = xfopen(src_filename, "r");
737 } else {
738 src_stream = stdin;
739 } 725 }
740#ifdef CONFIG_FEATURE_TAR_GZIP
741 /* Get a binary tree of all the tar file headers */
742 if (untar_funct & untar_unzip) {
743 uncompressed_stream = gz_open(src_stream, &gunzip_pid);
744 } else
745#endif /* CONFIG_FEATURE_TAR_GZIP */
746 uncompressed_stream = src_stream;
747 726
748 /* extract or list archive */
749 unarchive(uncompressed_stream, stdout, &get_header_tar,
750 extract_function, dst_prefix, include_list, exclude_list);
751 fclose(uncompressed_stream);
752 }
753#ifdef CONFIG_FEATURE_TAR_CREATE 727#ifdef CONFIG_FEATURE_TAR_CREATE
754 /* create an archive */ 728 /* create an archive */
755 else if (untar_funct & untar_create) { 729 if (tar_create == TRUE) {
756 int verboseFlag = FALSE; 730 int verboseFlag = FALSE;
757 int gzipFlag = FALSE; 731 int gzipFlag = FALSE;
758 732
759#ifdef CONFIG_FEATURE_TAR_GZIP 733# ifdef CONFIG_FEATURE_TAR_GZIP
760 if (untar_funct & untar_unzip) 734 if (get_header_ptr == get_header_tar_gz) {
761 gzipFlag = TRUE; 735 gzipFlag = TRUE;
762 736 }
763#endif /* CONFIG_FEATURE_TAR_GZIP */ 737# endif
764 if (extract_function & extract_verbose_list) 738 if (tar_handle->action_header == header_verbose_list) {
765 verboseFlag = TRUE; 739 verboseFlag = TRUE;
766
767 writeTarFile(src_filename, verboseFlag, include_list, exclude_list,
768 gzipFlag);
769 } 740 }
770#endif /* CONFIG_FEATURE_TAR_CREATE */ 741 writeTarFile(src_filename, verboseFlag, tar_handle->accept,
771 742 tar_handle->reject, gzipFlag);
772 /* Cleanups */ 743 } else
744#endif
773#ifdef CONFIG_FEATURE_TAR_GZIP 745#ifdef CONFIG_FEATURE_TAR_GZIP
774 if (!(untar_funct & untar_create) && (untar_funct & untar_unzip)) { 746 if (get_header_ptr == get_header_tar_gz) {
775 fclose(src_stream); 747 get_header_tar_gz(tar_handle);
776 close(gz_fd); 748 } else
777 gz_close(gunzip_pid); 749#endif
778 } 750 while (get_header_tar(tar_handle) == EXIT_SUCCESS);
779#endif /* CONFIG_FEATURE_TAR_GZIP */ 751
780#ifdef CONFIG_FEATURE_CLEAN_UP 752#ifdef CONFIG_FEATURE_CLEAN_UP
781 if (src_filename) { 753 close(tar_handle->src_fd);
782 free(src_filename);
783 }
784#endif 754#endif
785 return (EXIT_SUCCESS); 755
756 return(EXIT_SUCCESS);
786} 757}