From 658c775f01b1f5a3300f1f00ffa50a9b4eae3dbf Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Mon, 23 Feb 2026 15:30:39 +0300 Subject: [PATCH] libutil: Fix writeFull to respect allowInterrupts c0e849b696e31644e0f50d7882dd3a03aed06e94 broke interrupt handling since writeFull started throwing Interrupted even when allowInterrupts was false. This would lead to exceptions leaking out when they must not (for example during progress bar shutdown). --- src/libutil/file-descriptor.cc | 2 +- src/libutil/include/nix/util/file-descriptor.hh | 2 +- src/libutil/unix/file-descriptor.cc | 5 +++-- src/libutil/windows/file-descriptor.cc | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libutil/file-descriptor.cc b/src/libutil/file-descriptor.cc index fd2912ae1..9e23ad422 100644 --- a/src/libutil/file-descriptor.cc +++ b/src/libutil/file-descriptor.cc @@ -97,7 +97,7 @@ void writeFull(Descriptor fd, std::string_view s, bool allowInterrupts) if (allowInterrupts) checkInterrupt(); auto res = retryOnBlock(fd, PollDirection::Out, [&]() { - return write(fd, {reinterpret_cast(s.data()), s.size()}); + return write(fd, {reinterpret_cast(s.data()), s.size()}, allowInterrupts); }); if (res > 0) s.remove_prefix(res); diff --git a/src/libutil/include/nix/util/file-descriptor.hh b/src/libutil/include/nix/util/file-descriptor.hh index 72683de54..1e0d726ad 100644 --- a/src/libutil/include/nix/util/file-descriptor.hh +++ b/src/libutil/include/nix/util/file-descriptor.hh @@ -85,7 +85,7 @@ size_t read(Descriptor fd, std::span buffer); * @return The number of bytes actually written * @throws SystemError on failure */ -size_t write(Descriptor fd, std::span buffer); +size_t write(Descriptor fd, std::span buffer, bool allowInterrupts); /** * Get the size of a file. diff --git a/src/libutil/unix/file-descriptor.cc b/src/libutil/unix/file-descriptor.cc index 3d1cd1928..05ec38a67 100644 --- a/src/libutil/unix/file-descriptor.cc +++ b/src/libutil/unix/file-descriptor.cc @@ -42,11 +42,12 @@ size_t readOffset(Descriptor fd, off_t offset, std::span buffer) return static_cast(n); } -size_t write(Descriptor fd, std::span buffer) +size_t write(Descriptor fd, std::span buffer, bool allowInterrupts) { ssize_t n; do { - checkInterrupt(); + if (allowInterrupts) + checkInterrupt(); n = ::write(fd, buffer.data(), buffer.size()); } while (n == -1 && errno == EINTR); if (n == -1) diff --git a/src/libutil/windows/file-descriptor.cc b/src/libutil/windows/file-descriptor.cc index 294dd85f9..2e8d35ed6 100644 --- a/src/libutil/windows/file-descriptor.cc +++ b/src/libutil/windows/file-descriptor.cc @@ -60,9 +60,10 @@ size_t readOffset(Descriptor fd, off_t offset, std::span buffer) return static_cast(n); } -size_t write(Descriptor fd, std::span buffer) +size_t write(Descriptor fd, std::span buffer, bool allowInterrupts) { - checkInterrupt(); // For consistency with unix + if (allowInterrupts) + checkInterrupt(); // For consistency with unix DWORD n; if (!WriteFile(fd, buffer.data(), static_cast(buffer.size()), &n, NULL)) { auto lastError = GetLastError();