summaryrefslogtreecommitdiffstats
path: root/src/archive_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/archive_manager.cc73
1 files changed, 51 insertions, 22 deletions
diff --git a/src/archive_manager.cc b/src/archive_manager.cc
index 705842e..0f33cba 100644
--- a/src/archive_manager.cc
+++ b/src/archive_manager.cc
@@ -29,6 +29,8 @@
* @file archive_manager.cc
*/
+#include <future>
+
#include <unistd.h>
#include "config.h"
@@ -48,7 +50,7 @@
#include "base/lnav_log.hh"
#include "base/paths.hh"
#include "fmt/format.h"
-#include "lnav_util.hh"
+#include "hasher.hh"
namespace fs = ghc::filesystem;
@@ -72,10 +74,13 @@ enable_desired_archive_formats(archive* arc)
}
#endif
-bool
-is_archive(const fs::path& filename)
+Result<describe_result, std::string>
+describe(const fs::path& filename)
{
#if HAVE_ARCHIVE_H
+ static const auto RAW_FORMAT_NAME = string_fragment::from_const("raw");
+ static const auto GZ_FILTER_NAME = string_fragment::from_const("gzip");
+
auto_mem<archive> arc(archive_read_free);
arc = archive_read_new();
@@ -94,39 +99,56 @@ is_archive(const fs::path& filename)
if (archive_read_next_header(arc, &entry) == ARCHIVE_OK) {
log_debug("read next done %s", filename.c_str());
- static const auto RAW_FORMAT_NAME = string_fragment("raw");
- static const auto GZ_FILTER_NAME = string_fragment("gzip");
-
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;
+ return Ok(describe_result{unknown_file{}});
}
const auto* first_filter_name = archive_filter_name(arc, 0);
if (filter_count == 2 && GZ_FILTER_NAME == first_filter_name) {
- return false;
+ return Ok(describe_result{unknown_file{}});
}
}
log_info(
"detected archive: %s -- %s", filename.c_str(), format_name);
- return true;
+ auto ai = archive_info{
+ format_name,
+ };
+
+ do {
+ ai.ai_entries.emplace_back(archive_info::entry{
+ archive_entry_pathname_utf8(entry),
+ archive_entry_strmode(entry),
+ archive_entry_mtime(entry),
+ archive_entry_size_is_set(entry)
+ ? nonstd::make_optional(archive_entry_size(entry))
+ : nonstd::nullopt,
+ });
+ } while (archive_read_next_header(arc, &entry) == ARCHIVE_OK);
+
+ return Ok(describe_result{ai});
}
- log_info("archive read header failed: %s -- %s",
- filename.c_str(),
- archive_error_string(arc));
+ const auto* errstr = archive_error_string(arc);
+ log_info(
+ "archive read header failed: %s -- %s", filename.c_str(), errstr);
+ return Err(
+ fmt::format(FMT_STRING("unable to read archive header: {} -- {}"),
+ filename,
+ errstr ? errstr : "not an archive"));
} else {
- log_info("archive open failed: %s -- %s",
- filename.c_str(),
- archive_error_string(arc));
+ const auto* errstr = archive_error_string(arc);
+ log_info("archive open failed: %s -- %s", filename.c_str(), errstr);
+ return Err(fmt::format(FMT_STRING("unable to open file: {} -- {}"),
+ filename,
+ errstr ? errstr : "unknown"));
}
#endif
- return false;
+ return Ok(describe_result{unknown_file{}});
}
static fs::path
@@ -143,7 +165,7 @@ filename_to_tmp_path(const std::string& filename)
hasher h;
h.update(basename);
- auto fd = auto_fd(lnav::filesystem::openp(filename, O_RDONLY));
+ auto fd = auto_fd(lnav::filesystem::openp(filename, O_RDONLY | O_CLOEXEC));
if (fd != -1) {
char buffer[1024];
int rc;
@@ -226,9 +248,10 @@ extract(const std::string& filename, const extract_cb& cb)
fs::create_directories(tmp_path.parent_path(), ec);
if (ec) {
- return Err(fmt::format("unable to create directory: {} -- {}",
- tmp_path.parent_path().string(),
- ec.message()));
+ return Err(
+ fmt::format(FMT_STRING("unable to create directory: {} -- {}"),
+ tmp_path.parent_path().string(),
+ ec.message()));
}
auto arc_lock = lnav::filesystem::file_lock(tmp_path);
@@ -352,13 +375,19 @@ walk_archive_files(
return result;
}
- for (const auto& entry : fs::recursive_directory_iterator(tmp_path)) {
+ std::error_code ec;
+ for (const auto& entry : fs::recursive_directory_iterator(tmp_path, ec)) {
if (!entry.is_regular_file()) {
continue;
}
callback(tmp_path, entry);
}
+ if (ec) {
+ return Err(fmt::format(FMT_STRING("failed to walk temp dir: {} -- {}"),
+ tmp_path.string(),
+ ec.message()));
+ }
return Ok();
#else