diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2002-09-25 02:47:48 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2002-09-25 02:47:48 +0000 |
commit | 7ca04f328e22fcbee4659d73f9a72dfdf1dd6a23 (patch) | |
tree | f38c7ef4317eea28c6abdb0adbbb286fe041711e /archival/tar.c | |
parent | ecfa290cfd4953598e6d91989bd66ac16e135f84 (diff) | |
download | busybox-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.c | 243 |
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 |
328 | static inline int exclude_file(char **excluded_files, const char *file) | 328 | static 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 | ||
458 | static inline int writeTarFile(const char *tarName, int verboseFlag, | 458 | static 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 | ||
585 | void append_file_to_list(const char *new_name, char ***list, int *list_count) | 587 | #ifdef CONFIG_FEATURE_TAR_EXCLUDE |
586 | { | 588 | static 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 | |||
593 | void 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 | ||
608 | int tar_main(int argc, char **argv) | 606 | int 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 | } |