1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
// This source code is released into the public domain.
export module nihil.posix:write_file;
import nihil.std;
import nihil.util;
import :fd;
import :open;
import :rename;
import :unlink;
namespace nihil {
// Write the contents of a range to a file. Returns the number of bytes
// written.
export [[nodiscard]]
auto write_file(std::filesystem::path const &filename,
std::ranges::contiguous_range auto &&range,
int mode = 0777)
-> std::expected<std::size_t, error>
{
auto file = co_await open(filename, open_write | open_create, mode);
auto nbytes = co_await write(file, range);
co_return nbytes;
}
// Utility wrapper for non-contiguous ranges.
export [[nodiscard]]
auto write_file(std::filesystem::path const &filename,
std::ranges::range auto &&range)
-> std::expected<std::size_t, error>
requires(!std::ranges::contiguous_range<decltype(range)>)
{
return write_file(filename, std::vector(std::from_range, range));
}
// Write the contents of a range to a file safely. The data will be written
// to "<filename>.tmp", and if the write succeeds, the temporary file will be
// renamed to the target filename. If an error occurs, the target file will
// not be modified.
export [[nodiscard]]
auto safe_write_file(std::filesystem::path const &filename,
std::ranges::range auto &&range)
-> std::expected<void, error>
{
auto tmpfile = filename;
tmpfile.remove_filename();
tmpfile /= (filename.filename().native() + ".tmp");
auto tmpfile_guard = guard([&tmpfile] {
std::ignore = unlink(tmpfile.c_str());
});
co_await write_file(tmpfile, range);
co_await rename(tmpfile, filename);
tmpfile_guard.release();
co_return {};
}
} // namespace nihil
|