static void set_reader_options(struct bsdtar *bsdtar, struct archive *a) { const char *reader_options; int r; (void)bsdtar; /* UNUSED */ reader_options = getenv(ENV_READER_OPTIONS); if (reader_options != NULL) { char *p; /* Set default write options. */ p = malloc(sizeof(IGNORE_WRONG_MODULE_NAME) + strlen(reader_options) + 1); if (p == NULL) lafe_errc(1, errno, "Out of memory"); /* Prepend magic code to ignore options for * a format or filters which are not added to * the archive write object. */ strncpy(p, IGNORE_WRONG_MODULE_NAME, sizeof(IGNORE_WRONG_MODULE_NAME) -1); strcpy(p + sizeof(IGNORE_WRONG_MODULE_NAME) -1, reader_options); r = archive_read_set_options(a, p); free(p); if (r < ARCHIVE_WARN) lafe_errc(1, 0, "%s", archive_error_string(a)); else archive_clear_error(a); } }
static void test_read_format_ustar_filename_KOI8R_CP1251(const char *refname) { struct archive *a; struct archive_entry *ae; /* * Read KOI8-R filename in CP1251 with "hdrcharset=KOI8-R" option. */ if (NULL == setlocale(LC_ALL, "Russian_Russia") && NULL == setlocale(LC_ALL, "ru_RU.CP1251")) { skipping("CP1251 locale not available on this system."); return; } assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=KOI8-R")) { skipping("This system cannot convert character-set" " from KOI8-R to CP1251."); goto cleanup; } assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xef\xf0\xe8\xe2\xe5\xf2", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xcf\xd0\xc8\xc2\xc5\xd2", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_COMPRESS, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_USTAR, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); cleanup: assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
static void test_read_format_ustar_filename_CP866_UTF8(const char *refname) { struct archive *a; struct archive_entry *ae; /* * Read CP866 filename in en_US.UTF-8 with "hdrcharset=CP866" option. */ if (NULL == setlocale(LC_ALL, "en_US.UTF-8")) { skipping("en_US.UTF-8 locale not available on this system."); return; } assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=CP866")) { skipping("This system cannot convert character-set" " from CP866 to UTF-8."); goto cleanup; } assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xd0\x9f\xd0\xa0\xd0\x98\xd0\x92\xd0\x95\xd0\xa2", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_COMPRESS, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_USTAR, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); cleanup: assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
static void test_read_format_ustar_filename_eucJP_CP932(const char *refname) { struct archive *a; struct archive_entry *ae; /* * Read eucJP filename in CP932/SJIS with "hdrcharset=eucJP" option. */ if (NULL == setlocale(LC_ALL, "Japanese_Japan") && NULL == setlocale(LC_ALL, "ja_JP.SJIS")) { skipping("CP932 locale not available on this system."); return; } assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=eucJP")) { skipping("This system cannot convert character-set" " from eucJP."); goto cleanup; } assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\x8a\xbf\x8e\x9a.txt", archive_entry_pathname(ae)); assertEqualInt(8, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\x95\x5c.txt", archive_entry_pathname(ae)); assertEqualInt(4, archive_entry_size(ae)); assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_COMPRESS, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_USTAR, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); cleanup: assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
static void test_read_format_cab_filename_CP932_eucJP(const char *refname) { struct archive *a; struct archive_entry *ae; /* * Read CAB filename in ja_JP.eucJP with "hdrcharset=CP932" option. */ if (NULL == setlocale(LC_ALL, "ja_JP.eucJP")) { skipping("ja_JP.eucJP locale not available on this system."); return; } assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=CP932")) { skipping("This system cannot convert character-set" " from CP932 to eucJP."); goto cleanup; } assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString( "\xc9\xbd\xa4\xc0\xa4\xe8\x2f\xb4\xc1\xbb\xfa\x2e\x74\x78\x74", archive_entry_pathname(ae)); assertEqualInt(5, archive_entry_size(ae)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString( "\xc9\xbd\xa4\xc0\xa4\xe8\x2f\xb0\xec\xcd\xf7\xc9\xbd\x2e\x74\x78\x74", archive_entry_pathname(ae)); assertEqualInt(5, archive_entry_size(ae)); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a)); assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a)); /* Close the archive. */ cleanup: assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
/* * Copy from specified archive to current archive. Returns non-zero * for write errors (which force us to terminate the entire archiving * operation). If there are errors reading the input archive, we set * bsdtar->return_value but return zero, so the overall archiving * operation will complete and return non-zero. */ static int append_archive_filename(struct bsdtar *bsdtar, struct archive *a, const char *raw_filename) { struct archive *ina; const char *filename = raw_filename; int rc; if (strcmp(filename, "-") == 0) filename = NULL; /* Library uses NULL for stdio. */ ina = archive_read_new(); archive_read_support_format_all(ina); archive_read_support_filter_all(ina); set_reader_options(bsdtar, ina); archive_read_set_options(ina, "mtree:checkfs"); if (bsdtar->passphrase != NULL) rc = archive_read_add_passphrase(a, bsdtar->passphrase); else rc = archive_read_set_passphrase_callback(ina, bsdtar, &passphrase_callback); if (rc != ARCHIVE_OK) lafe_errc(1, 0, "%s", archive_error_string(a)); if (archive_read_open_filename(ina, filename, bsdtar->bytes_per_block)) { lafe_warnc(0, "%s", archive_error_string(ina)); bsdtar->return_value = 1; return (0); } rc = append_archive(bsdtar, a, ina); if (rc != ARCHIVE_OK) { lafe_warnc(0, "Error reading archive %s: %s", raw_filename, archive_error_string(ina)); bsdtar->return_value = 1; } archive_read_free(ina); return (rc); }
static void test_unicode_CP932(void) { char buff[30]; const char reffile[] = "test_read_format_rar_unicode.rar"; const char test_txt[] = "kanji"; struct archive_entry *ae; struct archive *a; if (NULL == setlocale(LC_ALL, "Japanese_Japan") && NULL == setlocale(LC_ALL, "ja_JP.SJIS")) { skipping("CP932 locale not available on this system."); return; } extract_reference_file(reffile); assert((a = archive_read_new()) != NULL); assertA(0 == archive_read_support_filter_all(a)); assertA(0 == archive_read_support_format_all(a)); /* Specify the charset of symbolic-link file name. */ if (ARCHIVE_OK != archive_read_set_options(a, "rar:hdrcharset=UTF-8")) { skipping("This system cannot convert character-set" " from UTF-8 to CP932."); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); return; } assertA(0 == archive_read_open_file(a, reffile, 10240)); /* First header. */ assertA(0 == archive_read_next_header(a, &ae)); assertEqualString("\x95\x5c\x82\xbe\x82\xe6/\x90\x56\x82\xb5\x82\xa2" "\x83\x74\x83\x48\x83\x8b\x83\x5f/\x90\x56\x8b\x4b\x83\x65\x83\x4c" "\x83\x58\x83\x67 \x83\x68\x83\x4c\x83\x85\x83\x81\x83\x93\x83\x67.txt", archive_entry_pathname(ae)); assertA((int)archive_entry_mtime(ae)); assertEqualInt(0, archive_entry_size(ae)); assertEqualInt(33188, archive_entry_mode(ae)); /* Second header. */ assertA(0 == archive_read_next_header(a, &ae)); assertEqualString("\x95\x5c\x82\xbe\x82\xe6/\x8a\xbf\x8e\x9a" "\x92\xb7\x82\xa2\x83\x74\x83\x40\x83\x43\x83\x8b\x96\xbc\x6c" "\x6f\x6e\x67\x2d\x66\x69\x6c\x65\x6e\x61\x6d\x65\x2d\x69\x6e" "\x2d\x8a\xbf\x8e\x9a.txt", archive_entry_pathname(ae)); assertA((int)archive_entry_mtime(ae)); assertEqualInt(5, archive_entry_size(ae)); assertEqualInt(33188, archive_entry_mode(ae)); assertA(5 == archive_read_data(a, buff, 5)); assertEqualMem(buff, test_txt, 5); /* Third header. */ assertA(0 == archive_read_next_header(a, &ae)); assertEqualString("\x95\x5c\x82\xbe\x82\xe6/" "\x90\x56\x82\xb5\x82\xa2\x83\x74\x83\x48\x83\x8b\x83\x5f", archive_entry_pathname(ae)); assertA((int)archive_entry_mtime(ae)); assertEqualInt(0, archive_entry_size(ae)); assertEqualInt(16877, archive_entry_mode(ae)); /* Fourth header. */ assertA(0 == archive_read_next_header(a, &ae)); assertEqualString("\x95\x5c\x82\xbe\x82\xe6", archive_entry_pathname(ae)); assertA((int)archive_entry_mtime(ae)); assertEqualInt(0, archive_entry_size(ae)); assertEqualInt(16877, archive_entry_mode(ae)); /* Fifth header, which has a symbolic-link name in multi-byte characters. */ assertA(0 == archive_read_next_header(a, &ae)); assertEqualString("\x95\x5c\x82\xbe\x82\xe6/" "\x83\x74\x83\x40\x83\x43\x83\x8B", archive_entry_pathname(ae)); assertEqualString("\x8a\xbf\x8e\x9a" "\x92\xb7\x82\xa2\x83\x74\x83\x40\x83\x43\x83\x8b\x96\xbc\x6c" "\x6f\x6e\x67\x2d\x66\x69\x6c\x65\x6e\x61\x6d\x65\x2d\x69\x6e" "\x2d\x8a\xbf\x8e\x9a.txt", archive_entry_symlink(ae)); assertA((int)archive_entry_mtime(ae)); assertEqualInt(0, archive_entry_size(ae)); assertEqualInt(41453, archive_entry_mode(ae)); assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff))); /* Test EOF */ assertA(1 == archive_read_next_header(a, &ae)); assertEqualInt(5, archive_file_count(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
/* * Handle 'x' and 't' modes. */ static void read_archive(struct bsdtar *bsdtar, char mode) { struct progress_data progress_data; FILE *out; struct archive *a; struct archive_entry *entry; const struct stat *st; int r; while (*bsdtar->argv) { lafe_include(&bsdtar->matching, *bsdtar->argv); bsdtar->argv++; } if (bsdtar->names_from_file != NULL) lafe_include_from_file(&bsdtar->matching, bsdtar->names_from_file, bsdtar->option_null); a = archive_read_new(); if (bsdtar->compress_program != NULL) archive_read_support_compression_program(a, bsdtar->compress_program); else archive_read_support_compression_all(a); archive_read_support_format_all(a); if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options)) lafe_errc(1, 0, "%s", archive_error_string(a)); if (archive_read_open_file(a, bsdtar->filename, bsdtar->bytes_per_block != 0 ? bsdtar->bytes_per_block : DEFAULT_BYTES_PER_BLOCK)) lafe_errc(1, 0, "Error opening archive: %s", archive_error_string(a)); do_chdir(bsdtar); if (mode == 'x') { /* Set an extract callback so that we can handle SIGINFO. */ progress_data.bsdtar = bsdtar; progress_data.archive = a; archive_read_extract_set_progress_callback(a, progress_func, &progress_data); } if (mode == 'x' && bsdtar->option_chroot) { #if HAVE_CHROOT if (chroot(".") != 0) lafe_errc(1, errno, "Can't chroot to \".\""); #else lafe_errc(1, 0, "chroot isn't supported on this platform"); #endif } for (;;) { /* Support --fast-read option */ if (bsdtar->option_fast_read && lafe_unmatched_inclusions(bsdtar->matching) == 0) break; r = archive_read_next_header(a, &entry); progress_data.entry = entry; if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (r == ARCHIVE_RETRY) { /* Retryable error: try again */ lafe_warnc(0, "Retrying..."); continue; } if (r == ARCHIVE_FATAL) break; if (bsdtar->uid >= 0) { archive_entry_set_uid(entry, bsdtar->uid); archive_entry_set_uname(entry, NULL); } if (bsdtar->gid >= 0) { archive_entry_set_gid(entry, bsdtar->gid); archive_entry_set_gname(entry, NULL); } if (bsdtar->uname) archive_entry_set_uname(entry, bsdtar->uname); if (bsdtar->gname) archive_entry_set_gname(entry, bsdtar->gname); /* * Exclude entries that are too old. */ st = archive_entry_stat(entry); if (bsdtar->newer_ctime_sec > 0) { if (st->st_ctime < bsdtar->newer_ctime_sec) continue; /* Too old, skip it. */ if (st->st_ctime == bsdtar->newer_ctime_sec && ARCHIVE_STAT_CTIME_NANOS(st) <= bsdtar->newer_ctime_nsec) continue; /* Too old, skip it. */ } if (bsdtar->newer_mtime_sec > 0) { if (st->st_mtime < bsdtar->newer_mtime_sec) continue; /* Too old, skip it. */ if (st->st_mtime == bsdtar->newer_mtime_sec && ARCHIVE_STAT_MTIME_NANOS(st) <= bsdtar->newer_mtime_nsec) continue; /* Too old, skip it. */ } /* * Note that pattern exclusions are checked before * pathname rewrites are handled. This gives more * control over exclusions, since rewrites always lose * information. (For example, consider a rewrite * s/foo[0-9]/foo/. If we check exclusions after the * rewrite, there would be no way to exclude foo1/bar * while allowing foo2/bar.) */ if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry))) continue; /* Excluded by a pattern test. */ if (mode == 't') { /* Perversely, gtar uses -O to mean "send to stderr" * when used with -t. */ out = bsdtar->option_stdout ? stderr : stdout; /* * TODO: Provide some reasonable way to * preview rewrites. gtar always displays * the unedited path in -t output, which means * you cannot easily preview rewrites. */ if (bsdtar->verbose < 2) safe_fprintf(out, "%s", archive_entry_pathname(entry)); else list_item_verbose(bsdtar, out, entry); fflush(out); r = archive_read_data_skip(a); if (r == ARCHIVE_WARN) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_RETRY) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_FATAL) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); bsdtar->return_value = 1; break; } fprintf(out, "\n"); } else { /* Note: some rewrite failures prevent extraction. */ if (edit_pathname(bsdtar, entry)) continue; /* Excluded by a rewrite failure. */ if (bsdtar->option_interactive && !yes("extract '%s'", archive_entry_pathname(entry))) continue; /* * Format here is from SUSv2, including the * deferred '\n'. */ if (bsdtar->verbose) { safe_fprintf(stderr, "x %s", archive_entry_pathname(entry)); fflush(stderr); } // TODO siginfo_printinfo(bsdtar, 0); if (bsdtar->option_stdout) r = archive_read_data_into_fd(a, 1); else r = archive_read_extract(a, entry, bsdtar->extract_flags); if (r != ARCHIVE_OK) { if (!bsdtar->verbose) safe_fprintf(stderr, "%s", archive_entry_pathname(entry)); safe_fprintf(stderr, ": %s", archive_error_string(a)); if (!bsdtar->verbose) fprintf(stderr, "\n"); bsdtar->return_value = 1; } if (bsdtar->verbose) fprintf(stderr, "\n"); if (r == ARCHIVE_FATAL) break; } } r = archive_read_close(a); if (r != ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (bsdtar->verbose > 2) fprintf(stdout, "Archive Format: %s, Compression: %s\n", archive_format_name(a), archive_compression_name(a)); archive_read_finish(a); }
/* * Handle 'x' and 't' modes. */ static void read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer) { struct progress_data progress_data; FILE *out; struct archive *a; struct archive_entry *entry; const char *reader_options; int r; while (*bsdtar->argv) { if (archive_match_include_pattern(bsdtar->matching, *bsdtar->argv) != ARCHIVE_OK) lafe_errc(1, 0, "Error inclusion pattern: %s", archive_error_string(bsdtar->matching)); bsdtar->argv++; } if (bsdtar->names_from_file != NULL) if (archive_match_include_pattern_from_file( bsdtar->matching, bsdtar->names_from_file, bsdtar->option_null) != ARCHIVE_OK) lafe_errc(1, 0, "Error inclusion pattern: %s", archive_error_string(bsdtar->matching)); a = archive_read_new(); if (cset_read_support_filter_program(bsdtar->cset, a) == 0) archive_read_support_filter_all(a); archive_read_support_format_all(a); reader_options = getenv(ENV_READER_OPTIONS); if (reader_options != NULL) { char *p; /* Set default read options. */ p = malloc(sizeof(IGNORE_WRONG_MODULE_NAME) + strlen(reader_options) + 1); if (p == NULL) lafe_errc(1, errno, "Out of memory"); /* Prepend magic code to ignore options for * a format or modules which are not added to * the archive read object. */ strncpy(p, IGNORE_WRONG_MODULE_NAME, sizeof(IGNORE_WRONG_MODULE_NAME) -1); strcpy(p + sizeof(IGNORE_WRONG_MODULE_NAME) -1, reader_options); r = archive_read_set_options(a, p); free(p); if (r == ARCHIVE_FATAL) lafe_errc(1, 0, "%s", archive_error_string(a)); else archive_clear_error(a); } if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options)) lafe_errc(1, 0, "%s", archive_error_string(a)); if (archive_read_open_filename(a, bsdtar->filename, bsdtar->bytes_per_block)) lafe_errc(1, 0, "Error opening archive: %s", archive_error_string(a)); do_chdir(bsdtar); if (mode == 'x') { /* Set an extract callback so that we can handle SIGINFO. */ progress_data.bsdtar = bsdtar; progress_data.archive = a; archive_read_extract_set_progress_callback(a, progress_func, &progress_data); } if (mode == 'x' && bsdtar->option_chroot) { #if HAVE_CHROOT if (chroot(".") != 0) lafe_errc(1, errno, "Can't chroot to \".\""); #else lafe_errc(1, 0, "chroot isn't supported on this platform"); #endif } for (;;) { /* Support --fast-read option */ if (bsdtar->option_fast_read && archive_match_path_unmatched_inclusions(bsdtar->matching) == 0) break; r = archive_read_next_header(a, &entry); progress_data.entry = entry; if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (r == ARCHIVE_RETRY) { /* Retryable error: try again */ lafe_warnc(0, "Retrying..."); continue; } if (r == ARCHIVE_FATAL) break; if (bsdtar->uid >= 0) { archive_entry_set_uid(entry, bsdtar->uid); archive_entry_set_uname(entry, NULL); } if (bsdtar->gid >= 0) { archive_entry_set_gid(entry, bsdtar->gid); archive_entry_set_gname(entry, NULL); } if (bsdtar->uname) archive_entry_set_uname(entry, bsdtar->uname); if (bsdtar->gname) archive_entry_set_gname(entry, bsdtar->gname); /* * Note that pattern exclusions are checked before * pathname rewrites are handled. This gives more * control over exclusions, since rewrites always lose * information. (For example, consider a rewrite * s/foo[0-9]/foo/. If we check exclusions after the * rewrite, there would be no way to exclude foo1/bar * while allowing foo2/bar.) */ if (archive_match_excluded(bsdtar->matching, entry)) continue; /* Excluded by a pattern test. */ if (mode == 't') { /* Perversely, gtar uses -O to mean "send to stderr" * when used with -t. */ out = bsdtar->option_stdout ? stderr : stdout; /* * TODO: Provide some reasonable way to * preview rewrites. gtar always displays * the unedited path in -t output, which means * you cannot easily preview rewrites. */ if (bsdtar->verbose < 2) safe_fprintf(out, "%s", archive_entry_pathname(entry)); else list_item_verbose(bsdtar, out, entry); fflush(out); r = archive_read_data_skip(a); if (r == ARCHIVE_WARN) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_RETRY) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); } if (r == ARCHIVE_FATAL) { fprintf(out, "\n"); lafe_warnc(0, "%s", archive_error_string(a)); bsdtar->return_value = 1; break; } fprintf(out, "\n"); } else { /* Note: some rewrite failures prevent extraction. */ if (edit_pathname(bsdtar, entry)) continue; /* Excluded by a rewrite failure. */ if (bsdtar->option_interactive && !yes("extract '%s'", archive_entry_pathname(entry))) continue; /* * Format here is from SUSv2, including the * deferred '\n'. */ if (bsdtar->verbose) { safe_fprintf(stderr, "x %s", archive_entry_pathname(entry)); fflush(stderr); } /* TODO siginfo_printinfo(bsdtar, 0); */ if (bsdtar->option_stdout) r = archive_read_data_into_fd(a, 1); else r = archive_read_extract2(a, entry, writer); if (r != ARCHIVE_OK) { if (!bsdtar->verbose) safe_fprintf(stderr, "%s", archive_entry_pathname(entry)); safe_fprintf(stderr, ": %s", archive_error_string(a)); if (!bsdtar->verbose) fprintf(stderr, "\n"); bsdtar->return_value = 1; } if (bsdtar->verbose) fprintf(stderr, "\n"); if (r == ARCHIVE_FATAL) break; } } r = archive_read_close(a); if (r != ARCHIVE_OK) lafe_warnc(0, "%s", archive_error_string(a)); if (r <= ARCHIVE_WARN) bsdtar->return_value = 1; if (bsdtar->verbose > 2) fprintf(stdout, "Archive Format: %s, Compression: %s\n", archive_format_name(a), archive_filter_name(a, 0)); archive_read_free(a); }
static void test_read_format_cab_filename_CP932_UTF8(const char *refname) { struct archive *a; struct archive_entry *ae; /* * Read CAB filename in en_US.UTF-8 with "hdrcharset=CP932" option. */ if (NULL == setlocale(LC_ALL, "en_US.UTF-8")) { skipping("en_US.UTF-8 locale not available on this system."); return; } assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=CP932")) { skipping("This system cannot convert character-set" " from CP932 to UTF-8."); goto cleanup; } assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); #if defined(__APPLE__) /* Compare NFD string. */ assertEqualUTF8String( "\xe8\xa1\xa8\xe3\x81\x9f\xe3\x82\x99\xe3\x82\x88\x2f" "\xe6\xbc\xa2\xe5\xad\x97\x2e\x74\x78\x74", archive_entry_pathname(ae)); assertEqualInt(5, archive_entry_size(ae)); #else /* Compare NFC string. */ assertEqualUTF8String( "\xe8\xa1\xa8\xe3\x81\xa0\xe3\x82\x88\x2f" "\xe6\xbc\xa2\xe5\xad\x97\x2e\x74\x78\x74", archive_entry_pathname(ae)); assertEqualInt(5, archive_entry_size(ae)); #endif /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); #if defined(__APPLE__) /* Compare NFD string. */ assertEqualUTF8String( "\xe8\xa1\xa8\xe3\x81\x9f\xe3\x82\x99\xe3\x82\x88\x2f" "\xe4\xb8\x80\xe8\xa6\xa7\xe8\xa1\xa8\x2e\x74\x78\x74", archive_entry_pathname(ae)); #else /* Compare NFC string. */ assertEqualUTF8String( "\xe8\xa1\xa8\xe3\x81\xa0\xe3\x82\x88\x2f" "\xe4\xb8\x80\xe8\xa6\xa7\xe8\xa1\xa8\x2e\x74\x78\x74", archive_entry_pathname(ae)); #endif assertEqualInt(5, archive_entry_size(ae)); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_COMPRESSION_NONE, archive_compression(a)); assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a)); /* Close the archive. */ cleanup: assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
////////////////////////////////////////////////////////////////////// // Constructor: static int ar_read(lua_State *L) { struct archive** self_ref; static named_setter format_names[] = { /* Copied from archive.h */ { "all", archive_read_support_format_all }, { "ar", archive_read_support_format_ar }, { "cpio", archive_read_support_format_cpio }, { "empty", archive_read_support_format_empty }, { "gnutar", archive_read_support_format_gnutar }, { "iso9660", archive_read_support_format_iso9660 }, { "mtree", archive_read_support_format_mtree }, { "tar", archive_read_support_format_tar }, { "zip", archive_read_support_format_zip }, { NULL, NULL } }; static named_setter compression_names[] = { { "all", archive_read_support_compression_all }, { "bzip2", archive_read_support_compression_bzip2 }, { "compress", archive_read_support_compression_compress }, { "gzip", archive_read_support_compression_gzip }, { "lzma", archive_read_support_compression_lzma }, { "none", archive_read_support_compression_none }, { "xz", archive_read_support_compression_xz }, { NULL, NULL } }; luaL_checktype(L, 1, LUA_TTABLE); self_ref = (struct archive**) lua_newuserdata(L, sizeof(struct archive*)); // {ud} *self_ref = NULL; luaL_getmetatable(L, AR_READ); // {ud}, [read] lua_setmetatable(L, -2); // {ud} __ref_count++; *self_ref = archive_read_new(); // Register it in the weak metatable: ar_registry_set(L, *self_ref); // Create an environment to store a reference to the callbacks: lua_createtable(L, 1, 0); // {ud}, {fenv} lua_getfield(L, 1, "reader"); // {ud}, {fenv}, fn if ( ! lua_isfunction(L, -1) ) err("MissingArgument: required parameter 'reader' must be a function"); lua_setfield(L, -2, "reader"); // {ud}, {fenv} lua_setfenv(L, -2); // {ud} // Do it the easy way for now... perhaps in the future we will // have a parameter to support toggling which algorithms are // supported: if ( ARCHIVE_OK != archive_read_support_compression_all(*self_ref) ) { err("archive_read_support_compression_all: %s", archive_error_string(*self_ref)); } if ( ARCHIVE_OK != archive_read_support_format_all(*self_ref) ) { err("archive_read_support_format_all: %s", archive_error_string(*self_ref)); } // Extract various fields and prepare the archive: lua_getfield(L, 1, "format"); if ( NULL == lua_tostring(L, -1) ) { lua_pop(L, 1); lua_pushliteral(L, "all"); } if ( 0 == call_setters(L, *self_ref, "archive_read_support_format_", format_names, lua_tostring(L, -1)) ) { // We will be strict for now... perhaps in the future we will // default to "all"? err("empty format='%s' is not allowed, you must specify at least one format", lua_tostring(L, -1)); } lua_pop(L, 1); lua_getfield(L, 1, "compression"); if ( NULL == lua_tostring(L, -1) ) { lua_pop(L, 1); lua_pushliteral(L, "none"); } call_setters(L, *self_ref, "archive_read_support_compression_", compression_names, lua_tostring(L, -1)); lua_pop(L, 1); lua_getfield(L, 1, "options"); if ( ! lua_isnil(L, -1) && ARCHIVE_OK != archive_read_set_options(*self_ref, lua_tostring(L, -1)) ) { err("archive_read_set_options: %s", archive_error_string(*self_ref)); } lua_pop(L, 1); if ( ARCHIVE_OK != archive_read_open(*self_ref, L, NULL, &ar_read_cb, NULL) ) { err("archive_read_open: %s", archive_error_string(*self_ref)); } return 1; }
static void test_read_format_tar_filename_KOI8R_CP866(const char *refname) { struct archive *a; struct archive_entry *ae; /* * Read filename in ru_RU.CP866 with "hdrcharset=KOI8-R" option. * We should correctly read two filenames. */ if (NULL == setlocale(LC_ALL, "Russian_Russia.866") && NULL == setlocale(LC_ALL, "ru_RU.CP866")) { skipping("ru_RU.CP866 locale not available on this system."); return; } /* Test if the platform can convert from UTF-8. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_tar(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=UTF-8")) { assertEqualInt(ARCHIVE_OK, archive_read_free(a)); skipping("This system cannot convert character-set" " from UTF-8 to CP866."); return; } assertEqualInt(ARCHIVE_OK, archive_read_free(a)); assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=KOI8-R")) { skipping("This system cannot convert character-set" " from KOI8-R to CP866."); goto next_test; } assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* Verify regular first file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\x8f\x90\x88\x82\x85\x92", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* Verify regular second file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xaf\xe0\xa8\xa2\xa5\xe2", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_COMPRESS, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); next_test: assertEqualInt(ARCHIVE_OK, archive_read_free(a)); /* * Read filename in ru_RU.CP866 without "hdrcharset=KOI8-R" option. * The filename we can properly read is only second file. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* * Verify regular first file. * The filename is not translated to CP866 because hdrcharset * attribute is BINARY and there is not way to know its charset. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); /* A filename is in KOI8-R. */ assertEqualString("\xf0\xf2\xe9\xf7\xe5\xf4", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* * Verify regular second file. * The filename is translated from UTF-8 to CP866 */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xaf\xe0\xa8\xa2\xa5\xe2", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_COMPRESS, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }
static void test_read_format_tar_filename_KOI8R_UTF8(const char *refname) { struct archive *a; struct archive_entry *ae; /* * Read filename in en_US.UTF-8 with "hdrcharset=KOI8-R" option. * We should correctly read two filenames. */ if (NULL == setlocale(LC_ALL, "en_US.UTF-8")) { skipping("en_US.UTF-8 locale not available on this system."); return; } assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); if (ARCHIVE_OK != archive_read_set_options(a, "hdrcharset=KOI8-R")) { assertEqualInt(ARCHIVE_OK, archive_read_free(a)); skipping("This system cannot convert character-set" " from KOI8-R to UTF-8."); return; } assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xd0\x9f\xd0\xa0\xd0\x98\xd0\x92\xd0\x95\xd0\xa2", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* Verify regular file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_COMPRESS, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); /* * Read filename in en_US.UTF-8 without "hdrcharset=KOI8-R" option. * The filename we can properly read is only second file. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240)); /* * Verify regular first file. * The filename is not translated to UTF-8 because hdrcharset * attribute is BINARY and there is not way to know its charset. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); /* A filename is in KOI8-R. */ assertEqualString("\xf0\xf2\xe9\xf7\xe5\xf4", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* * Verify regular second file. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualString("\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82", archive_entry_pathname(ae)); assertEqualInt(6, archive_entry_size(ae)); /* End of archive. */ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); /* Verify archive format. */ assertEqualIntA(a, ARCHIVE_FILTER_COMPRESS, archive_filter_code(a, 0)); assertEqualIntA(a, ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE, archive_format(a)); /* Close the archive. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); }