Apache Mesos
write.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_OS_WRITE_HPP__
14 #define __STOUT_OS_WRITE_HPP__
15 
16 #include <cstring>
17 
18 #include <stout/error.hpp>
19 #include <stout/nothing.hpp>
20 #include <stout/try.hpp>
21 
22 #include <stout/os/close.hpp>
23 #include <stout/os/fsync.hpp>
24 #include <stout/os/int_fd.hpp>
25 #include <stout/os/open.hpp>
26 #include <stout/os/socket.hpp>
27 
28 #ifdef __WINDOWS__
30 #else
31 #include <stout/os/posix/write.hpp>
32 #endif // __WINDOWS__
33 
34 namespace os {
35 
36 namespace signal_safe {
37 
38 inline ssize_t write_impl(int_fd fd, const char* buffer, size_t count)
39 {
40  size_t offset = 0;
41 
42  while (offset < count) {
43  ssize_t length = os::write(fd, buffer + offset, count - offset);
44 
45  if (length < 0) {
46 #ifdef __WINDOWS__
47  // NOTE: There is no actual difference between `WSAGetLastError` and
48  // `GetLastError`, the former is an alias for the latter. So we can
49  // simply use the former here for both `HANDLE` and `SOCKET` types of
50  // `int_fd`. See MESOS-8764.
51  int error = ::GetLastError();
52 #else
53  int error = errno;
54 #endif // __WINDOWS__
55 
56  // TODO(benh): Handle a non-blocking fd? (EAGAIN, EWOULDBLOCK).
57  if (net::is_restartable_error(error)) {
58  continue;
59  }
60  return -1;
61  }
62 
63  offset += length;
64  }
65 
66  return offset;
67 }
68 
69 
70 inline ssize_t write(int_fd fd, const char* message)
71 {
72  // `strlen` declared as async-signal safe in POSIX.1-2016 standard.
73  return write_impl(fd, message, std::strlen(message));
74 }
75 
76 
77 inline ssize_t write(int_fd fd, const std::string& message)
78 {
79  return write_impl(fd, message.data(), message.length());
80 }
81 
82 
83 template <typename T, typename... Args>
84 inline ssize_t write(int_fd fd, const T& message, Args... args)
85 {
86  ssize_t result = write(fd, message);
87  if (result < 0) {
88  return result;
89  }
90 
91  return write(fd, args...);
92 }
93 
94 } // namespace signal_safe {
95 
96 
97 // Write out the string to the file at the current fd position.
98 inline Try<Nothing> write(int_fd fd, const std::string& message)
99 {
100  ssize_t result = signal_safe::write(fd, message);
101  if (result < 0) {
102 #ifdef __WINDOWS__
103  return WindowsError();
104 #else
105  return ErrnoError();
106 #endif // __WINDOWS__
107  }
108 
109  return Nothing();
110 }
111 
112 
113 // A wrapper function for the above `write()` with opening and closing the file.
114 // If `sync` is set to true, an `fsync()` will be called before `close()`.
116  const std::string& path,
117  const std::string& message,
118  bool sync = false)
119 {
120  Try<int_fd> fd = os::open(
121  path,
122  O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
124 
125  if (fd.isError()) {
126  return Error(fd.error());
127  }
128 
129  Try<Nothing> write = os::write(fd.get(), message);
130 
131  if (sync && write.isSome()) {
132  // We call `fsync()` before closing the file instead of opening it with the
133  // `O_SYNC` flag for better performance. See:
134  // http://lkml.iu.edu/hypermail/linux/kernel/0105.3/0353.html
135  write = os::fsync(fd.get());
136  }
137 
139 
140  // We propagate `close` failures if `write` on the file was successful.
141  if (write.isSome() && close.isError()) {
142  write =
143  Error("Failed to close '" + stringify(fd.get()) + "':" + close.error());
144  }
145 
146  return write;
147 }
148 
149 
150 // NOTE: This overload is necessary to disambiguate between arguments
151 // of type `HANDLE` (`typedef void*`) and `char*` on Windows.
153  const char* path,
154  const std::string& message,
155  bool sync = false)
156 {
157  return write(std::string(path), message, sync);
158 }
159 
160 } // namespace os {
161 
162 
163 #endif // __STOUT_OS_WRITE_HPP__
SSIZE_T ssize_t
Definition: windows.hpp:186
Definition: path.hpp:29
Definition: nothing.hpp:16
Definition: errorbase.hpp:36
const mode_t S_IRGRP
Definition: windows.hpp:313
T & get()&
Definition: try.hpp:80
ssize_t write(const int_fd &fd, const void *data, size_t size)
Definition: write.hpp:72
Definition: check.hpp:33
const mode_t S_IWUSR
Definition: windows.hpp:306
Try< int_fd > open(const std::string &path, int oflag, mode_t mode=0)
Definition: open.hpp:35
Definition: error.hpp:108
Definition: errorbase.hpp:50
Definition: posix_signalhandler.hpp:23
const mode_t S_IRUSR
Definition: windows.hpp:305
bool is_restartable_error(int error)
Definition: socket.hpp:65
constexpr int O_CLOEXEC
Definition: open.hpp:41
Try< Nothing > close(int fd)
Definition: close.hpp:24
static Try error(const E &e)
Definition: try.hpp:43
Try< Nothing > fsync(int fd)
Definition: fsync.hpp:29
ssize_t write_impl(int_fd fd, const char *buffer, size_t count)
Definition: write.hpp:38
bool isError() const
Definition: try.hpp:78
std::string error(const std::string &msg, uint32_t code)
int int_fd
Definition: int_fd.hpp:35
std::string stringify(int flags)
const mode_t S_IROTH
Definition: windows.hpp:321
ssize_t write(int_fd fd, const char *message)
Definition: write.hpp:70