[files] use libarchive to decompress files

Fixes #87
This commit is contained in:
Timothy Stack 2021-01-10 13:33:20 -08:00
parent be71834733
commit 678be94d75
3 changed files with 37 additions and 7 deletions

4
NEWS
View File

@ -2,6 +2,10 @@ lnav v0.9.1:
Features:
* Added the ':filter-expr' command to filter log messages based on an SQL
expression. This command allows much greater control over filtering.
* Added support for archive files, like zip, and other compression formats,
like xz, when compiled with libarchive. When one of these types of
files is detected, they are unpacked into a temporary directory and
all of the files are loaded into lnav.
* Added an 'xpath()' table-valued function for extracting values from
strings containing XML snippets.
* Added the ':prompt' command to allow for more customization of prompts.

View File

@ -98,14 +98,31 @@ bool is_archive(const ghc::filesystem::path& filename)
archive_read_support_filter_all(arc);
archive_read_support_format_all(arc);
archive_read_support_format_raw(arc);
auto r = archive_read_open_filename(arc, filename.c_str(), 16384);
if (r == ARCHIVE_OK) {
struct archive_entry *entry;
if (archive_read_next_header(arc, &entry) == ARCHIVE_OK) {
static const auto RAW_FORMAT_NAME = string_fragment("raw");
static const auto GZ_FILTER_NAME = string_fragment("gzip");
auto format_name = archive_format_name(arc);
if (RAW_FORMAT_NAME == format_name) {
auto filter_count = archive_filter_count(arc);
if (filter_count == 1) {
return false;
}
auto first_filter_name = archive_filter_name(arc, 0);
if (filter_count == 2 && GZ_FILTER_NAME == first_filter_name) {
return false;
}
}
log_info("detected archive: %s -- %s",
filename.c_str(),
archive_format_name(arc));
filename.c_str(), format_name);
return true;
} else {
log_info("archive read header failed: %s -- %s",
@ -221,6 +238,7 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
arc = archive_read_new();
archive_read_support_format_all(arc);
archive_read_support_format_raw(arc);
archive_read_support_filter_all(arc);
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, FLAGS);
@ -247,9 +265,16 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
archive_error_string(arc)));
}
auto format_name = archive_format_name(arc);
auto filter_count = archive_filter_count(arc);
auto_mem<archive_entry> wentry(archive_entry_free);
wentry = archive_entry_clone(entry);
auto entry_path = tmp_path / fs::path(archive_entry_pathname(entry));
auto desired_pathname = fs::path(archive_entry_pathname(entry));
if (strcmp(format_name, "raw") == 0 && filter_count >= 2) {
desired_pathname = fs::path(filename).filename();
}
auto entry_path = tmp_path / desired_pathname;
auto prog = cb(entry_path,
archive_entry_size_is_set(entry) ?
archive_entry_size(entry) : -1);
@ -264,7 +289,8 @@ static walk_result_t extract(const std::string &filename, const extract_cb &cb)
entry_path.string(),
archive_error_string(ext)));
}
else if (archive_entry_size(entry) > 0) {
else if (!archive_entry_size_is_set(entry) ||
archive_entry_size(entry) > 0) {
TRY(copy_data(filename, arc, entry, ext, entry_path, prog));
}
r = archive_write_finish_entry(ext);

View File

@ -95,8 +95,8 @@ logfile::logfile(const string &filename, logfile_open_options &loo)
this->lf_valid_filename = false;
}
if (!loo.loo_filename.empty()) {
this->set_filename(loo.loo_filename);
if (!this->lf_options.loo_filename.empty()) {
this->set_filename(this->lf_options.loo_filename);
this->lf_valid_filename = false;
}
@ -104,7 +104,7 @@ logfile::logfile(const string &filename, logfile_open_options &loo)
this->lf_line_buffer.set_fd(this->lf_options.loo_fd);
this->lf_index.reserve(INDEX_RESERVE_INCREMENT);
this->lf_indexing = loo.loo_is_visible;
this->lf_indexing = this->lf_options.loo_is_visible;
ensure(this->invariant());
}