libutil: add an async writeFile

Change-Id: I062c07446be2b282dfec6c31c21805aac9f44ff4
This commit is contained in:
eldritch horrors
2025-03-03 20:48:59 +01:00
parent ef5573065c
commit ffbd120dcf
2 changed files with 46 additions and 7 deletions
+43 -7
View File
@@ -381,11 +381,27 @@ void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
}
void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
static AutoCloseFD openForWrite(const Path & path, mode_t mode)
{
AutoCloseFD fd{open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode)};
if (!fd)
throw SysError("opening file '%1%'", path);
return fd;
}
static void closeForWrite(const Path & path, AutoCloseFD & fd, bool sync)
{
if (sync)
fd.fsync();
// Explicitly close to make sure exceptions are propagated.
fd.close();
if (sync)
syncParent(path);
}
void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
{
AutoCloseFD fd = openForWrite(path, mode);
std::vector<char> buf(64 * 1024);
@@ -400,12 +416,32 @@ void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
e.addTrace({}, "writing file '%1%'", path);
throw;
}
if (sync)
fd.fsync();
// Explicitly close to make sure exceptions are propagated.
fd.close();
if (sync)
syncParent(path);
closeForWrite(path, fd, sync);
}
kj::Promise<Result<void>>
writeFile(const Path & path, AsyncInputStream & source, mode_t mode, bool sync)
try {
AutoCloseFD fd = openForWrite(path, mode);
std::vector<char> buf(64 * 1024);
try {
while (true) {
if (auto n = TRY_AWAIT(source.read(buf.data(), buf.size()))) {
writeFull(fd.get(), {buf.data(), n});
} else {
break;
}
}
} catch (Error & e) {
e.addTrace({}, "writing file '%1%'", path);
throw;
}
closeForWrite(path, fd, sync);
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
void syncParent(const Path & path)
+3
View File
@@ -5,6 +5,7 @@
* Utiltities for working with the file sytem and file paths.
*/
#include "lix/libutil/async-io.hh"
#include "lix/libutil/box_ptr.hh"
#include "lix/libutil/types.hh"
#include "lix/libutil/file-descriptor.hh"
@@ -191,6 +192,8 @@ Generator<Bytes> readFileSource(const Path & path);
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);
void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);
kj::Promise<Result<void>>
writeFile(const Path & path, AsyncInputStream & source, mode_t mode = 0666, bool sync = false);
/**
* Flush a file's parent directory to disk