aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.posix/write_file.ccm
blob: 471ef85ef32b372c29174bf2ffd351ee893ddccf (plain) (blame)
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