3#if !defined(__unix__) && !defined(__APPLE__)
4#error "pixie/io/file_output_sink.h requires POSIX file support"
18#include <system_error>
37 descriptor_ = ::open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
38 if (descriptor_ == -1) {
39 throw std::system_error(errno, std::generic_category(),
40 "Failed to open binary output file");
49 : descriptor_(std::exchange(other.descriptor_, -1)),
50 size_bytes_(std::exchange(other.size_bytes_, 0)) {}
56 descriptor_ = std::exchange(other.descriptor_, -1);
57 size_bytes_ = std::exchange(other.size_bytes_, 0);
66 std::size_t
size_bytes() const noexcept {
return size_bytes_; }
74 void write(std::span<const std::byte> bytes) {
76 require_file_range(size_bytes_, bytes.size());
77 while (!bytes.empty()) {
78 const std::size_t chunk = std::min(
80 static_cast<std::size_t
>(std::numeric_limits<ssize_t>::max()));
81 const ssize_t written =
::write(descriptor_, bytes.data(), chunk);
86 throw std::system_error(errno, std::generic_category(),
87 "Failed to write binary output file");
90 throw std::system_error(EIO, std::generic_category(),
91 "Binary output file write made no progress");
93 const std::size_t count =
static_cast<std::size_t
>(written);
95 bytes = bytes.subspan(count);
106 void write_at(std::size_t position, std::span<const std::byte> bytes) {
108 if (position > size_bytes_ || bytes.size() > size_bytes_ - position) {
109 throw std::out_of_range(
"Binary output patch is outside the file");
111 require_file_range(position, bytes.size());
112 while (!bytes.empty()) {
113 const std::size_t chunk = std::min(
115 static_cast<std::size_t
>(std::numeric_limits<ssize_t>::max()));
116 const off_t offset =
static_cast<off_t
>(position);
117 const ssize_t written =
118 ::pwrite(descriptor_, bytes.data(), chunk, offset);
120 if (errno == EINTR) {
123 throw std::system_error(errno, std::generic_category(),
124 "Failed to patch binary output file");
127 throw std::system_error(EIO, std::generic_category(),
128 "Binary output file patch made no progress");
130 const std::size_t count =
static_cast<std::size_t
>(written);
132 bytes = bytes.subspan(count);
142 if (descriptor_ == -1) {
145 const int descriptor = std::exchange(descriptor_, -1);
146 if (::close(descriptor) == -1) {
147 throw std::system_error(errno, std::generic_category(),
148 "Failed to close binary output file");
153 static void require_file_range(std::size_t position, std::size_t count) {
154 constexpr auto kMaximumOffset = std::numeric_limits<off_t>::max();
155 const auto maximum =
static_cast<std::uintmax_t
>(kMaximumOffset);
156 if (position > maximum || count > maximum - position) {
157 throw std::length_error(
"Binary output file offset is too large");
161 void require_open()
const {
162 if (descriptor_ == -1) {
163 throw std::logic_error(
"Binary output file is already finished");
167 void close_noexcept() noexcept {
168 if (descriptor_ != -1) {
169 const int descriptor = std::exchange(descriptor_, -1);
170 (void)::close(descriptor);
174 int descriptor_ = -1;
175 std::size_t size_bytes_ = 0;
Move-only seekable sink for a newly created or truncated POSIX file.
Definition file_output_sink.h:30
std::size_t size_bytes() const noexcept
Return the number of bytes appended to the output.
Definition file_output_sink.h:66
FileOutputSink(const std::filesystem::path &path)
Open path for binary output, creating or truncating it.
Definition file_output_sink.h:36
void write_at(std::size_t position, std::span< const std::byte > bytes)
Replace already-written bytes beginning at position.
Definition file_output_sink.h:106
FileOutputSink & operator=(FileOutputSink &&other) noexcept
Close the current file and transfer ownership from other.
Definition file_output_sink.h:53
~FileOutputSink()
Close the output file without reporting errors.
Definition file_output_sink.h:63
FileOutputSink(FileOutputSink &&other) noexcept
Transfer ownership of an open output file.
Definition file_output_sink.h:48
void finish()
Close the file and report any close error.
Definition file_output_sink.h:141
void write(std::span< const std::byte > bytes)
Append all bytes to the file.
Definition file_output_sink.h:74