int tar_main(int argc UNUSED_PARAM, char **argv) { char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar; archive_handle_t *tar_handle; char *base_dir = NULL; const char *tar_filename = "-"; unsigned opt; int verboseFlag = 0; #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM llist_t *excludes = NULL; #endif /* Initialise default values */ tar_handle = init_handle(); tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL; /* Apparently only root's tar preserves perms (see bug 3844) */ if (getuid() != 0) tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM; /* Prepend '-' to the first argument if required */ opt_complementary = "--:" // first arg is options "tt:vv:" // count -t,-v "?:" // bail out with usage instead of error return "X::T::" // cumulative lists #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM "\xff::" // cumulative lists for --exclude #endif IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive #if ENABLE_FEATURE_TAR_LONG_OPTIONS applet_long_options = tar_longopts; #endif opt = getopt32(argv, "txC:f:Opvk" IF_FEATURE_TAR_CREATE( "ch" ) IF_FEATURE_SEAMLESS_BZ2( "j" ) IF_FEATURE_SEAMLESS_LZMA("a" ) IF_FEATURE_TAR_FROM( "T:X:") IF_FEATURE_SEAMLESS_GZ( "z" ) IF_FEATURE_SEAMLESS_Z( "Z" ) , &base_dir // -C dir , &tar_filename // -f filename IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM , &excludes // --exclude #endif , &verboseFlag // combined count for -t and -v , &verboseFlag // combined count for -t and -v ); argv += optind; if (verboseFlag) tar_handle->action_header = header_verbose_list; if (verboseFlag == 1) tar_handle->action_header = header_list; if (opt & OPT_EXTRACT) tar_handle->action_data = data_extract_all; if (opt & OPT_2STDOUT) tar_handle->action_data = data_extract_to_stdout; if (opt & OPT_KEEP_OLD) tar_handle->ah_flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL; if (opt & OPT_NOPRESERVE_OWN) tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_OWN; if (opt & OPT_NOPRESERVE_PERM) tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM; if (opt & OPT_NUMERIC_OWNER) tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER; if (opt & OPT_GZIP) get_header_ptr = get_header_tar_gz; if (opt & OPT_BZIP2) get_header_ptr = get_header_tar_bz2; if (opt & OPT_LZMA) get_header_ptr = get_header_tar_lzma; if (opt & OPT_COMPRESS) get_header_ptr = get_header_tar_Z; #if ENABLE_FEATURE_TAR_FROM tar_handle->reject = append_file_list_to_list(tar_handle->reject); #if ENABLE_FEATURE_TAR_LONG_OPTIONS /* Append excludes to reject */ while (excludes) { llist_t *next = excludes->link; excludes->link = tar_handle->reject; tar_handle->reject = excludes; excludes = next; } #endif tar_handle->accept = append_file_list_to_list(tar_handle->accept); #endif /* Setup an array of filenames to work with */ /* TODO: This is the same as in ar, separate function ? */ while (*argv) { /* kill trailing '/' unless the string is just "/" */ char *cp = last_char_is(*argv, '/'); if (cp > *argv) *cp = '\0'; llist_add_to_end(&tar_handle->accept, *argv); argv++; } if (tar_handle->accept || tar_handle->reject) tar_handle->filter = filter_accept_reject_list; /* Open the tar file */ { FILE *tar_stream; int flags; if (opt & OPT_CREATE) { /* Make sure there is at least one file to tar up. */ if (tar_handle->accept == NULL) bb_error_msg_and_die("empty archive"); tar_stream = stdout; /* Mimicking GNU tar 1.15.1: */ flags = O_WRONLY | O_CREAT | O_TRUNC; } else { tar_stream = stdin; flags = O_RDONLY; } if (LONE_DASH(tar_filename)) { tar_handle->src_fd = fileno(tar_stream); tar_handle->seek = seek_by_read; } else { if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) { get_header_ptr = get_header_tar; tar_handle->src_fd = open_zipped(tar_filename); if (tar_handle->src_fd < 0) bb_perror_msg_and_die("can't open '%s'", tar_filename); } else { tar_handle->src_fd = xopen(tar_filename, flags); } } } if (base_dir) xchdir(base_dir); #ifdef CHECK_FOR_CHILD_EXITCODE /* We need to know whether child (gzip/bzip/etc) exits abnormally */ signal(SIGCHLD, handle_SIGCHLD); #endif /* create an archive */ if (opt & OPT_CREATE) { #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 int zipMode = 0; if (ENABLE_FEATURE_SEAMLESS_GZ && (opt & OPT_GZIP)) zipMode = 1; if (ENABLE_FEATURE_SEAMLESS_BZ2 && (opt & OPT_BZIP2)) zipMode = 2; #endif /* NB: writeTarFile() closes tar_handle->src_fd */ return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, tar_handle->accept, tar_handle->reject, zipMode); } while (get_header_ptr(tar_handle) == EXIT_SUCCESS) continue; /* Check that every file that should have been extracted was */ while (tar_handle->accept) { if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) && !find_list_entry(tar_handle->passed, tar_handle->accept->data) ) { bb_error_msg_and_die("%s: not found in archive", tar_handle->accept->data); } tar_handle->accept = tar_handle->accept->link; } if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) close(tar_handle->src_fd); return EXIT_SUCCESS; }
int tar_main(int argc, char **argv) { char (*get_header_ptr)(archive_handle_t *) = get_header_tar; archive_handle_t *tar_handle; char *base_dir = NULL; const char *tar_filename = "-"; unsigned long opt; unsigned long ctx_flag = 0; if (argc < 2) { bb_show_usage(); } /* Prepend '-' to the first argument if required */ if (argv[1][0] != '-') { char *tmp; bb_xasprintf(&tmp, "-%s", argv[1]); argv[1] = tmp; } /* Initialise default values */ tar_handle = init_handle(); tar_handle->flags = ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_PRESERVE_DATE | ARCHIVE_EXTRACT_UNCONDITIONAL; bb_opt_complementaly = "c~tx:t~cx:x~ct:X*:T*"; #ifdef CONFIG_FEATURE_TAR_LONG_OPTIONS bb_applet_long_options = tar_long_options; #endif opt = bb_getopt_ulflags(argc, argv, tar_options, &base_dir, /* Change to dir <optarg> */ &tar_filename /* archive filename */ #ifdef CONFIG_FEATURE_TAR_FROM , NULL, &(tar_handle->reject) #endif ); /* Check one and only one context option was given */ if(opt & 0x80000000UL) { bb_show_usage(); } #ifdef CONFIG_FEATURE_TAR_CREATE ctx_flag = opt & (CTX_CREATE | CTX_TEST | CTX_EXTRACT); #else ctx_flag = opt & (CTX_TEST | CTX_EXTRACT); #endif if (ctx_flag == 0) { bb_show_usage(); } if(ctx_flag & CTX_TEST) { if ((tar_handle->action_header == header_list) || (tar_handle->action_header == header_verbose_list)) { tar_handle->action_header = header_verbose_list; } else { tar_handle->action_header = header_list; } } if(ctx_flag & CTX_EXTRACT) { if (tar_handle->action_data != data_extract_to_stdout) tar_handle->action_data = data_extract_all; } if(opt & TAR_OPT_2STDOUT) { /* To stdout */ tar_handle->action_data = data_extract_to_stdout; } if(opt & TAR_OPT_VERBOSE) { if ((tar_handle->action_header == header_list) || (tar_handle->action_header == header_verbose_list)) { tar_handle->action_header = header_verbose_list; } else { tar_handle->action_header = header_list; } } if (opt & TAR_OPT_KEEP_OLD) { tar_handle->flags &= ~ARCHIVE_EXTRACT_UNCONDITIONAL; } #ifdef CONFIG_FEATURE_TAR_GZIP if(opt & TAR_OPT_GZIP) { get_header_ptr = get_header_tar_gz; } #endif #ifdef CONFIG_FEATURE_TAR_BZIP2 if(opt & TAR_OPT_BZIP2) { get_header_ptr = get_header_tar_bz2; } #endif #ifdef CONFIG_FEATURE_TAR_COMPRESS if(opt & TAR_OPT_UNCOMPRESS) { get_header_ptr = get_header_tar_Z; } #endif #ifdef CONFIG_FEATURE_TAR_FROM if(opt & TAR_OPT_EXCLUDE_FROM) { tar_handle->reject = append_file_list_to_list(tar_handle->reject); } #endif /* Check if we are reading from stdin */ if ((argv[optind]) && (*argv[optind] == '-')) { /* Default is to read from stdin, so just skip to next arg */ optind++; } /* Setup an array of filenames to work with */ /* TODO: This is the same as in ar, separate function ? */ while (optind < argc) { char *filename_ptr = last_char_is(argv[optind], '/'); if (filename_ptr) { *filename_ptr = '\0'; } tar_handle->accept = llist_add_to(tar_handle->accept, argv[optind]); optind++; } if ((tar_handle->accept) || (tar_handle->reject)) { tar_handle->filter = filter_accept_reject_list; } /* Open the tar file */ { FILE *tar_stream; int flags; #ifdef CONFIG_FEATURE_TAR_CREATE if (opt & CTX_CREATE) { /* Make sure there is at least one file to tar up. */ if (tar_handle->accept == NULL) { bb_error_msg_and_die("Cowardly refusing to create an empty archive"); } tar_stream = stdout; flags = O_WRONLY | O_CREAT | O_EXCL; unlink(tar_filename); } else #endif { tar_stream = stdin; flags = O_RDONLY; } if ((tar_filename[0] == '-') && (tar_filename[1] == '\0')) { tar_handle->src_fd = fileno(tar_stream); tar_handle->seek = seek_by_char; } else { tar_handle->src_fd = bb_xopen(tar_filename, flags); } } if ((base_dir) && (chdir(base_dir))) { bb_perror_msg_and_die("Couldnt chdir to %s", base_dir); } #ifdef CONFIG_FEATURE_TAR_CREATE /* create an archive */ if (opt & CTX_CREATE) { int verboseFlag = FALSE; int gzipFlag = FALSE; # ifdef CONFIG_FEATURE_TAR_GZIP if (get_header_ptr == get_header_tar_gz) { gzipFlag = TRUE; } # endif /* CONFIG_FEATURE_TAR_GZIP */ # ifdef CONFIG_FEATURE_TAR_BZIP2 if (get_header_ptr == get_header_tar_bz2) { bb_error_msg_and_die("Creating bzip2 compressed archives is not currently supported."); } # endif /* CONFIG_FEATURE_TAR_BZIP2 */ if ((tar_handle->action_header == header_list) || (tar_handle->action_header == header_verbose_list)) { verboseFlag = TRUE; } writeTarFile(tar_handle->src_fd, verboseFlag, opt & TAR_OPT_DEREFERNCE, tar_handle->accept, tar_handle->reject, gzipFlag); } else #endif /* CONFIG_FEATURE_TAR_CREATE */ { while (get_header_ptr(tar_handle) == EXIT_SUCCESS); /* Ckeck that every file that should have been extracted was */ while (tar_handle->accept) { if (find_list_entry(tar_handle->reject, tar_handle->accept->data) == NULL) { if (find_list_entry(tar_handle->passed, tar_handle->accept->data) == NULL) { bb_error_msg_and_die("%s: Not found in archive\n", tar_handle->accept->data); } } tar_handle->accept = tar_handle->accept->link; } } #ifdef CONFIG_FEATURE_CLEAN_UP if (tar_handle->src_fd != STDIN_FILENO) { close(tar_handle->src_fd); } #endif /* CONFIG_FEATURE_CLEAN_UP */ return(EXIT_SUCCESS); }