static void test_exclusion_and_inclusion(void) { struct archive_entry *ae; struct archive *m; const char *mp; const wchar_t *wp; if (!assert((m = archive_match_new()) != NULL)) return; if (!assert((ae = archive_entry_new()) != NULL)) { archive_match_free(m); return; } assertEqualIntA(m, 0, archive_match_exclude_pattern(m, "^aaa*")); assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"^aa*")); assertEqualIntA(m, 0, archive_match_include_pattern(m, "^a1*")); /* Test with 'aa1234', which should not be excluded. */ archive_entry_copy_pathname(ae, "aa1234"); failure("'aa1234' should not be excluded"); assertEqualInt(0, archive_match_path_excluded(m, ae)); assertEqualInt(0, archive_match_excluded(m, ae)); archive_entry_clear(ae); archive_entry_copy_pathname_w(ae, L"aa1234"); failure("'aa1234' should not be excluded"); assertEqualInt(0, archive_match_path_excluded(m, ae)); assertEqualInt(0, archive_match_excluded(m, ae)); /* Test with 'aaa1234', which should be excluded. */ archive_entry_copy_pathname(ae, "aaa1234"); failure("'aaa1234' should be excluded"); assertEqualInt(1, archive_match_path_excluded(m, ae)); assertEqualInt(1, archive_match_excluded(m, ae)); archive_entry_clear(ae); archive_entry_copy_pathname_w(ae, L"aaa1234"); failure("'aaa1234' should be excluded"); assertEqualInt(1, archive_match_path_excluded(m, ae)); assertEqualInt(1, archive_match_excluded(m, ae)); /* Verify unmatched_inclusions. */ assertEqualInt(1, archive_match_path_unmatched_inclusions(m)); /* Verify unmatched inclusion patterns. */ assertEqualIntA(m, ARCHIVE_OK, archive_match_path_unmatched_inclusions_next(m, &mp)); assertEqualString("^a1*", mp); assertEqualIntA(m, ARCHIVE_EOF, archive_match_path_unmatched_inclusions_next(m, &mp)); /* Verify unmatched inclusion patterns again in Wide-Char. */ assertEqualIntA(m, ARCHIVE_OK, archive_match_path_unmatched_inclusions_next_w(m, &wp)); assertEqualWString(L"^a1*", wp); assertEqualIntA(m, ARCHIVE_EOF, archive_match_path_unmatched_inclusions_next_w(m, &wp)); /* Clean up. */ archive_entry_free(ae); archive_match_free(m); }
static void test_inclusion_wcs(void) { struct archive_entry *ae; struct archive *m; const char *mp; if (!assert((m = archive_match_new()) != NULL)) return; if (!assert((ae = archive_entry_new()) != NULL)) { archive_match_free(m); return; } /* Test for pattern "^aa*" */ assertEqualIntA(m, 0, archive_match_include_pattern_w(m, L"^aa*")); /* Test with 'aa1234', which should not be excluded. */ archive_entry_copy_pathname(ae, "aa1234"); failure("'aa1234' should not be excluded"); assertEqualInt(0, archive_match_path_excluded(m, ae)); assertEqualInt(0, archive_match_excluded(m, ae)); archive_entry_clear(ae); archive_entry_copy_pathname_w(ae, L"aa1234"); failure("'aa1234' should not be excluded"); assertEqualInt(0, archive_match_path_excluded(m, ae)); assertEqualInt(0, archive_match_excluded(m, ae)); /* Test with 'a1234', which should be excluded. */ archive_entry_copy_pathname(ae, "a1234"); failure("'a1234' should be excluded"); assertEqualInt(1, archive_match_path_excluded(m, ae)); assertEqualInt(1, archive_match_excluded(m, ae)); archive_entry_clear(ae); archive_entry_copy_pathname_w(ae, L"a1234"); failure("'a1234' should be excluded"); assertEqualInt(1, archive_match_path_excluded(m, ae)); assertEqualInt(1, archive_match_excluded(m, ae)); /* Verify unmatched_inclusions. */ assertEqualInt(0, archive_match_path_unmatched_inclusions(m)); assertEqualIntA(m, ARCHIVE_EOF, archive_match_path_unmatched_inclusions_next(m, &mp)); /* Clean up. */ archive_entry_free(ae); archive_match_free(m); }
static int unmatched_inclusions_warn(struct archive *matching, const char *msg) { const char *p; int r; if (matching == NULL) return (0); while ((r = archive_match_path_unmatched_inclusions_next( matching, &p)) == ARCHIVE_OK) lafe_warnc(0, "%s: %s", p, msg); if (r == ARCHIVE_FATAL) lafe_errc(1, errno, "Out of memory"); return (archive_match_path_unmatched_inclusions(matching)); }
bool libarchive_tar_extract(const std::string &filename, const std::string &target, const std::vector<std::string> &patterns) { if (target.empty()) { LOGE("%s: Invalid target path for extraction", target.c_str()); return false; } autoclose::archive matcher(archive_match_new(), archive_match_free); if (!matcher) { LOGE("%s: Out of memory when creating matcher", __FUNCTION__); return false; } autoclose::archive in(archive_read_new(), archive_read_free); if (!in) { LOGE("%s: Out of memory when creating archive reader", __FUNCTION__); return false; } autoclose::archive out(archive_write_disk_new(), archive_write_free); if (!out) { LOGE("%s: Out of memory when creating disk writer", __FUNCTION__); return false; } // Set up matcher parameters for (const std::string &pattern : patterns) { if (archive_match_include_pattern( matcher.get(), pattern.c_str()) != ARCHIVE_OK) { LOGE("Invalid pattern: %s", pattern.c_str()); return false; } } // Set up archive reader parameters //archive_read_support_format_gnutar(in.get()); archive_read_support_format_tar(in.get()); //archive_read_support_filter_bzip2(in.get()); //archive_read_support_filter_gzip(in.get()); //archive_read_support_filter_xz(in.get()); // Set up disk writer parameters archive_write_disk_set_standard_lookup(out.get()); archive_write_disk_set_options(out.get(), LIBARCHIVE_DISK_WRITER_FLAGS); if (archive_read_open_filename( in.get(), filename.c_str(), 10240) != ARCHIVE_OK) { LOGE("%s: Failed to open file: %s", filename.c_str(), archive_error_string(in.get())); return false; } archive_entry *entry; int ret; std::string target_path; while (true) { ret = archive_read_next_header(in.get(), &entry); if (ret == ARCHIVE_EOF) { break; } else if (ret == ARCHIVE_RETRY) { LOGW("%s: Retrying header read", filename.c_str()); continue; } else if (ret != ARCHIVE_OK) { LOGE("%s: Failed to read header: %s", filename.c_str(), archive_error_string(in.get())); return false; } const char *path = archive_entry_pathname(entry); if (!path || !*path) { LOGE("%s: Header has null or empty filename", filename.c_str()); return false; } LOGV("%s", path); // Build path target_path = target; if (target_path.back() != '/' && *path != '/') { target_path += '/'; } target_path += path; archive_entry_set_pathname(entry, target_path.c_str()); // Check pattern matches if (archive_match_excluded(matcher.get(), entry)) { continue; } // Extract file ret = archive_read_extract2(in.get(), entry, out.get()); if (ret != ARCHIVE_OK) { LOGE("%s: %s", archive_entry_pathname(entry), archive_error_string(in.get())); return false; } } if (archive_read_close(in.get()) != ARCHIVE_OK) { LOGE("%s: %s", filename.c_str(), archive_error_string(in.get())); return false; } // Check that all patterns were matched const char *pattern; while ((ret = archive_match_path_unmatched_inclusions_next( matcher.get(), &pattern)) == ARCHIVE_OK) { LOGE("%s: Pattern not matched: %s", filename.c_str(), pattern); } if (ret != ARCHIVE_EOF) { LOGE("%s: %s", filename.c_str(), archive_error_string(matcher.get())); return false; } return archive_match_path_unmatched_inclusions(matcher.get()) == 0; }