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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
/*
* This source code is released into the public domain.
*/
module;
#include <coroutine>
#include <expected>
#include <filesystem>
#include <ranges>
#include <system_error>
#include <vector>
#include <fcntl.h>
#include <unistd.h>
export module nihil.posix:write_file;
import nihil.error;
import nihil.guard;
import nihil.monad;
import :fd;
import :open;
import :rename;
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] {
::unlink(tmpfile.c_str());
});
co_await write_file(tmpfile, range);
co_await nihil::rename(tmpfile, filename);
tmpfile_guard.release();
co_return {};
}
} // namespace nihil
|