From 242a228124f77b57c2e3b3aedb259ffb7913cd3c Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Sat, 21 Jun 2025 11:50:10 +0200 Subject: [PATCH] libutil: close file handle in async NAR parser This bit us while upgrading Hydra[1]: when all the data was read into the hashing sink while receinving NAR contents, the hash was never created which lead to a test failing because file size was correct, but the hash was std::nullopt. [1] https://git.lix.systems/lix-project/hydra/src/commit/7a0dae579b53b4b96a829263b160c6dc9f42ce75/src/hydra-queue-runner/nar-extractor.cc#L70-L73 Change-Id: Ie71b5f1f17c926a2ab95fb2aabf23c7a575ff70b --- lix/libutil/archive.cc | 1 + tests/unit/libutil/archive.cc | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lix/libutil/archive.cc b/lix/libutil/archive.cc index 80e0c9781..6d63abd5a 100644 --- a/lix/libutil/archive.cc +++ b/lix/libutil/archive.cc @@ -708,6 +708,7 @@ struct AsyncParser file->receiveContents({buf.data(), n}); left -= n; } + file->close(); } else if (auto sl = std::get_if(&*i)) { target.createSymlink(name, sl->target); } else if (auto d = std::get_if(&*i)) { diff --git a/tests/unit/libutil/archive.cc b/tests/unit/libutil/archive.cc index 51189d092..509c1d23d 100644 --- a/tests/unit/libutil/archive.cc +++ b/tests/unit/libutil/archive.cc @@ -248,6 +248,7 @@ namespace parseAsync { { bool executable; uint64_t size; + bool closed; std::string contents; operator nar::Entry() const { @@ -292,7 +293,10 @@ namespace parseAsync { file.contents += data; } - void close() override {} + void close() override + { + file.closed = true; + } }; explicit ReconstructVisitor(std::map & parent) : parent(parent) {} @@ -306,7 +310,8 @@ namespace parseAsync { box_ptr createRegularFile(const std::string & name, uint64_t size, bool executable) override { - auto & file = std::get(parent.emplace(name, File{executable, size}).first->second); + auto & file = + std::get(parent.emplace(name, File{executable, size, false}).first->second); return make_box_ptr(file); } @@ -331,6 +336,13 @@ TEST_P(NarTest, parseAsync) auto entries = entriesFn()(); parseDump(rv, source).wait(ws).value(); + + for (auto & [i, val] : contents) { + if (auto f = std::get_if(&val)) { + ASSERT_TRUE(f->closed); + } + } + auto parsed = parseAsync::Directory::toNar(contents.at("")); while (true) { auto e = entries.next();