diff --git a/include/dwarfs/inode_manager.h b/include/dwarfs/inode_manager.h index 2164f4a3..96d5b52d 100644 --- a/include/dwarfs/inode_manager.h +++ b/include/dwarfs/inode_manager.h @@ -81,7 +81,7 @@ class inode_manager { } void scan_background(worker_group& wg, os_access const& os, - std::shared_ptr ino, file const* p) const { + std::shared_ptr ino, file* p) const { impl_->scan_background(wg, os, std::move(ino), p); } @@ -103,9 +103,8 @@ class inode_manager { virtual void for_each_inode_in_order( std::function const&)> const& fn) const = 0; virtual fragment_infos fragment_category_info() const = 0; - virtual void - scan_background(worker_group& wg, os_access const& os, - std::shared_ptr ino, file const* p) const = 0; + virtual void scan_background(worker_group& wg, os_access const& os, + std::shared_ptr ino, file* p) const = 0; virtual void dump(std::ostream& os) const = 0; virtual sortable_inode_span sortable_span() const = 0; virtual sortable_inode_span diff --git a/src/dwarfs/inode_manager.cpp b/src/dwarfs/inode_manager.cpp index 5496cc38..f590b324 100644 --- a/src/dwarfs/inode_manager.cpp +++ b/src/dwarfs/inode_manager.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include +#include #include #include @@ -548,9 +550,8 @@ class inode_manager_ final : public inode_manager::impl { return rv; } - void - scan_background(worker_group& wg, os_access const& os, - std::shared_ptr ino, file const* p) const override; + void scan_background(worker_group& wg, os_access const& os, + std::shared_ptr ino, file* p) const override; void dump(std::ostream& os) const override; @@ -592,7 +593,7 @@ template void inode_manager_::scan_background(worker_group& wg, os_access const& os, std::shared_ptr ino, - file const* p) const { + file* p) const { // TODO: I think the size check makes everything more complex. // If we don't check the size, we get the code to run // that ensures `fragments_` is updated. Also, there @@ -603,7 +604,16 @@ void inode_manager_::scan_background(worker_group& wg, auto const size = p->size(); std::shared_ptr mm; if (size > 0) { - mm = os.map_file(p->fs_path(), size); + try { + mm = os.map_file(p->fs_path(), size); + } catch (...) { + LOG_ERROR << "failed to map file \"" << p->path_as_string() + << "\": " << folly::exceptionStr(std::current_exception()) + << ", creating empty inode"; + ++prog_.errors; + p->override_size(0); + // don't return here, we still need scan() to run + } } ino->scan(mm.get(), opts_, prog_); update_prog(ino, p); diff --git a/test/test_helpers.cpp b/test/test_helpers.cpp index e7442a4d..478d114b 100644 --- a/test/test_helpers.cpp +++ b/test/test_helpers.cpp @@ -328,6 +328,11 @@ void os_access_mock::set_access_fail(fs::path const& path) { access_fail_set_.emplace(path); } +void os_access_mock::set_map_file_error(std::filesystem::path const& path, + std::exception_ptr ep) { + map_file_err_[path] = std::move(ep); +} + size_t os_access_mock::size() const { return root_ ? root_->size() : 0; } std::vector os_access_mock::splitpath(fs::path const& path) { @@ -426,6 +431,10 @@ std::unique_ptr os_access_mock::map_file(fs::path const& path, size_t size) const { if (auto de = find(path); de && de->status.type() == posix_file_type::regular) { + if (auto it = map_file_err_.find(path); it != map_file_err_.end()) { + std::rethrow_exception(it->second); + } + return std::make_unique( std::visit(overloaded{ [this](std::string const& str) { return str; }, diff --git a/test/test_helpers.h b/test/test_helpers.h index 28d27143..a3907748 100644 --- a/test/test_helpers.h +++ b/test/test_helpers.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -91,6 +92,8 @@ class os_access_mock : public os_access { void add_local_files(std::filesystem::path const& path); void set_access_fail(std::filesystem::path const& path); + void + set_map_file_error(std::filesystem::path const& path, std::exception_ptr ep); void setenv(std::string name, std::string value); @@ -125,6 +128,7 @@ class os_access_mock : public os_access { std::unique_ptr root_; size_t ino_{1000000}; std::set access_fail_set_; + std::map map_file_err_; std::map env_; }; diff --git a/test/tool_main_test.cpp b/test/tool_main_test.cpp index 67c0aba9..5de7ca71 100644 --- a/test/tool_main_test.cpp +++ b/test/tool_main_test.cpp @@ -2101,3 +2101,16 @@ TEST_P(segmenter_repeating_sequence_test, github161) { INSTANTIATE_TEST_SUITE_P(dwarfs, segmenter_repeating_sequence_test, ::testing::Values('\0', 'G', '\xff')); + +TEST(mkdwarfs_test, map_file_error) { + mkdwarfs_tester t; + t.os->set_map_file_error( + "/somedir/ipsum.py", + std::make_exception_ptr(std::runtime_error("map_file_error"))); + + EXPECT_EQ(2, t.run("-i / -o - --categorize")) << t.err(); + + EXPECT_THAT(t.err(), + ::testing::HasSubstr("map_file_error, creating empty inode")); + EXPECT_THAT(t.err(), ::testing::HasSubstr("filesystem created with 1 error")); +}