Apache Mesos
windows.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_WINDOWS_HPP__
14 #define __STOUT_WINDOWS_HPP__
15 
16 // We include `WinSock2.h` before `Windows.h` explicitly to avoid symbol
17 // re-definitions. This is a documented pattern, because `Windows.h` will
18 // otherwise include `winsock.h` for "historical reasons". Note that
19 // `winsock.h` is for Windows Sockets 1.1, last used in Windows 2000.
20 //
21 // NOTE: The capitalization of these headers is based on the files
22 // included in the SDK, rather than MSDN documentation.
23 //
24 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms738562(v=vs.85).aspx
25 // NOLINT(whitespace/line_length)
26 #include <WinSock2.h> // For Windows Sockets 2.
27 #include <WS2tcpip.h> // For `getaddrinfo` etc.
28 #include <iphlpapi.h> // For `GetAdaptersInfo`.
29 #include <MSWSock.h> // For `TransmitFile`.
30 #include <winioctl.h> // For `DeviceIoControl`
31 #include <Windows.h> // For everything else.
32 
33 #include <direct.h> // For `_mkdir`.
34 #include <errno.h> // For `_set_errno`.
35 #include <fcntl.h> // For file access flags like `_O_CREAT`.
36 #include <io.h> // For `_read`, `_write`.
37 #include <process.h> // For `_getpid`.
38 #include <stdlib.h> // For `_PATH_MAX`.
39 
40 #include <sys/stat.h> // For permissions flags.
41 
42 #include <basetsd.h> // For `SSIZE_T`.
43 
44 #include <memory>
45 
46 #include <glog/logging.h>
47 
48 
49 #if !defined(_UNICODE) || !defined(UNICODE)
50 // Much of the Windows API is available both in `string` and `wstring`
51 // varieties. To avoid polluting the namespace with two versions of every
52 // function, a common pattern in the Windows headers is to offer a single macro
53 // that expands to the `string` or `wstring` version, depending on whether the
54 // `_UNICODE` and `UNICODE` preprocessor symbols are set. For example,
55 // `GetMessage` will expand to either `GetMessageA` (the `string` version) or
56 // `GetMessageW` (the `wstring` version) depending on whether these symbols are
57 // defined.
58 //
59 // Unfortunately the `string` version is not UTF-8, like a developer would
60 // expect on Linux, but is instead the current Windows code page, and thus may
61 // take a different value at runtime. This makes it potentially difficult to
62 // decode, whereas the `wstring` version is always encoded as UTF-16, and thus
63 // can be programatically converted to UTF-8 using the `stringify()` function
64 // (converting UTF-8 to UTF-16 is done with `wide_stringify()`).
65 //
66 // Furthermore, support for NTFS long paths requires the use of the `wstring`
67 // APIs, coupled with the `\\?\` long path prefix marker for paths longer than
68 // the max path limit. This is accomplished by wrapping paths sent to Windows
69 // APIs with the `internal::windows::longpath()` helper. In order to prevent
70 // future regressions, we enforce the definitions of `_UNICODE` and `UNICODE`.
71 //
72 // NOTE: The Mesos code should always use the explicit `W` suffixed APIs in
73 // order to avoid type ambiguity.
74 #error "Mesos must be built with `_UNICODE` and `UNICODE` defined."
75 #endif // !defined(_UNICODE) || !defined(UNICODE)
76 
77 // An RAII `HANDLE`.
78 class SharedHandle : public std::shared_ptr<void>
79 {
80  static_assert(std::is_same<HANDLE, void*>::value,
81  "Expected `HANDLE` to be of type `void*`.");
82 
83 public:
84  // We delete the default constructor so that the callsite is forced to make
85  // an explicit decision about what the empty `HANDLE` value should be, as it
86  // is not the same for all `HANDLE` types. For example, `OpenProcess`
87  // returns a `nullptr` for an invalid handle, but `CreateFile` returns an
88  // `INVALID_HANDLE_VALUE` instead. This inconsistency is inherent in the
89  // Windows API.
90  SharedHandle() = delete;
91 
92  template <typename Deleter>
93  SharedHandle(HANDLE handle, Deleter deleter)
94  : std::shared_ptr<void>(handle, deleter) {}
95 
96  HANDLE get_handle() const { return this->get(); }
97 };
98 
99 
100 // Definitions and constants used for Windows compat.
101 //
102 // Gathers most of the Windows-compatibility definitions. This makes it
103 // possible for files throughout the codebase to remain relatively free of all
104 // the #if's we'd need to make them work.
105 //
106 // Roughly, the things that should go in this file are definitions and
107 // declarations that one would not mind being:
108 // * in global scope.
109 // * globally available throughout both the Stout codebase, and any code
110 // that uses it (such as Mesos).
111 
112 
113 // This code un-defines the global `GetMessage` macro defined by the Windows
114 // headers, and replaces it with an inline function that is equivalent.
115 //
116 // There are two reasons for doing this. The first is because this macro
117 // interferes with `google::protobufs::Reflection::GetMessage`. Replacing the
118 // `GetMessage` macro with an inline function allows people calling the
119 // `GetMessage` macro to carry on doing so with no code changes, but it will
120 // also allow us to use `google::protobufs::Reflection::GetMessage` without
121 // interference from the macro.
122 //
123 // The second is because we don't want to obliterate the `GetMessage` macro for
124 // people who include this header, either on purpose, or incidentally as part
125 // of some other Mesos header. The effect is that our need to call protobuf's
126 // `GetMessage` function has no deleterious effect on customers of this API.
127 //
128 // NOTE: the Windows headers also don't use define-once semantics for the
129 // `GetMessage` macro. In particular, this means that every time you include
130 // `Winuser.h` and a `GetMessage` macro isn't defined, the Windows headers will
131 // redefine it for you. The impact of this is that you should re-un-define the
132 // macro every time you include `Windows.h`; since we should be including
133 // `Windows.h` only from this file, we un-define it just after we include
134 // `Windows.h`.
135 #ifdef GetMessage
136 inline BOOL GetMessageWindows(
137  LPMSG lpMsg,
138  HWND hWnd,
139  UINT wMsgFilterMin,
140  UINT wMsgFilterMax)
141 {
142  return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
143 }
144 #undef GetMessage
145 inline BOOL GetMessage(
146  LPMSG lpMsg,
147  HWND hWnd,
148  UINT wMsgFilterMin,
149  UINT wMsgFilterMax)
150 {
151  return GetMessageWindows(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
152 }
153 #endif // GetMessage
154 
155 
156 // Define constants used for Windows compat. Allows a lot of code on
157 // Windows and POSIX systems to be the same, because we can pass the
158 // same constants to functions we call to do things like file I/O.
159 #define STDIN_FILENO 0
160 #define STDOUT_FILENO 1
161 #define STDERR_FILENO 2
162 
163 #define R_OK 0x4
164 #define W_OK 0x2
165 #define X_OK 0x0 // No such permission on Windows.
166 #define F_OK 0x0
167 
168 #define MAXHOSTNAMELEN NI_MAXHOST
169 
170 #define PATH_MAX _MAX_PATH
171 
172 // NOTE: for details on what this value should be, consult [1], [2], and [3].
173 //
174 // [1] http://www.opensource.apple.com/source/gnumake/gnumake-119/make/w32/include/dirent.h
175 // [2] https://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
176 // [3] https://msdn.microsoft.com/en-us/library/930f87yf.aspx
177 const int NAME_MAX = PATH_MAX;
178 
179 // Corresponds to `mode_t` defined in sys/types.h of the POSIX spec.
180 // See large "permissions API" comment below for an explanation of
181 // why this is an int instead of unsigned short (as is common on
182 // POSIX).
183 typedef int mode_t;
184 
185 // `DWORD` is expected to be the type holding PIDs throughout the Windows API,
186 // including functions like `OpenProcess`.
187 typedef DWORD pid_t;
188 
189 typedef int uid_t;
190 typedef int gid_t;
191 
192 typedef SSIZE_T ssize_t;
193 
194 // Socket flags. Define behavior of a socket when it (e.g.) shuts down. We map
195 // the Windows versions of these flags to their POSIX equivalents so we don't
196 // have to change any socket code.
197 constexpr int SHUT_RD = SD_RECEIVE;
198 constexpr int SHUT_WR = SD_SEND;
199 constexpr int SHUT_RDWR = SD_BOTH;
200 constexpr int MSG_NOSIGNAL = 0; // `SIGPIPE` signal does not exist on Windows.
201 
202 // The following functions are usually macros on POSIX; we provide them here as
203 // functions to avoid having global macros lying around. Note that these
204 // operate on the `_stat` struct (a Windows version of the standard POSIX
205 // `stat` struct), of which the `st_mode` field is known to be an `int`.
206 inline bool S_ISDIR(const int mode)
207 {
208  return (mode & S_IFMT) == S_IFDIR; // Directory.
209 }
210 
211 
212 inline bool S_ISREG(const int mode)
213 {
214  return (mode & S_IFMT) == S_IFREG; // File.
215 }
216 
217 
218 inline bool S_ISCHR(const int mode)
219 {
220  return (mode & S_IFMT) == S_IFCHR; // Character device.
221 }
222 
223 
224 inline bool S_ISFIFO(const int mode)
225 {
226  return (mode & S_IFMT) == _S_IFIFO; // Pipe.
227 }
228 
229 
230 inline bool S_ISBLK(const int mode)
231 {
232  return false; // Block special device.
233 }
234 
235 
236 inline bool S_ISSOCK(const int mode)
237 {
238  return false; // Socket.
239 }
240 
241 
242 inline bool S_ISLNK(const int mode)
243 {
244  return false; // Symbolic link.
245 }
246 
247 // Permissions API. (cf. MESOS-3176 to track ongoing permissions work.)
248 //
249 // We are currently able to emulate a subset of the POSIX permissions model
250 // with the Windows model:
251 // [x] User write permissions.
252 // [x] User read permissions.
253 // [ ] User execute permissions.
254 // [ ] Group permissions of any sort.
255 // [ ] Other permissions of any sort.
256 // [x] Flags to control "fallback" behavior (e.g., we might choose
257 // to fall back to user readability when the user passes the
258 // group readability flag in, since we currently do not support
259 // group readability).
260 //
261 //
262 // Rationale:
263 // Windows currently implements two permissions models: (1) an extremely
264 // primitive permission model it largely inherited from DOS, and (2) the Access
265 // Control List (ACL) API. Because there is no trivial way to map the classic
266 // POSIX model into the ACL model, we have implemented POSIX-style permissions
267 // in terms of the DOS model. The result is the permissions limitations above.
268 //
269 //
270 // Flag implementation:
271 // Flags fall into the following two categories.
272 // (1) Flags which exist in both permission models, but which have
273 // different names (e.g., `S_IRUSR` in POSIX is called `_S_IREAD` on
274 // Windows). In this case, we define the POSIX name to be the Windows
275 // value (e.g., we define `S_IRUSR` to have the same value as `_S_IREAD`),
276 // so that we can pass the POSIX name into Windows functions like
277 // `_open`.
278 // (2) Flags which exist only on POSIX (e.g., `S_IXUSR`). Here we
279 // define the POSIX name to be the value given in the glibc
280 // documentation[1], shifted left by 16 bits (since `mode_t`
281 // is unsigned short on POSIX and `int` on Windows). We give these
282 // flags glibc values to stay consistent, and so that existing
283 // calls to functions like `open` do not break when they try to
284 // use a flag that doesn't exist on Windows. But, of course,
285 // these flags do not affect the execution of these functions.
286 //
287 //
288 // Flag strictness:
289 // Because the current implementation does not directly support setting or
290 // getting group or other permission bits on the Windows platform, there is a
291 // question of what we should fall back to when these flags are passed in to
292 // Stout methods.
293 //
294 // TODO(hausdorff): Investigate permissions mappings.
295 // We force "strictness" of the permission flag semantics:
296 // * The group permissions flags will not fall back to anything, and will be
297 // completely ignored.
298 // * Other permissions: Same as above, but with other permissions.
299 //
300 //
301 // Execute permissions:
302 // Because DOS has no notion of "execute permissions", we define execute
303 // permissions to be read permissions. This is not ideal, but it is closest to
304 // being accurate.
305 //
306 //
307 // [1] http://www.delorie.com/gnu/docs/glibc/libc_288.html
308 
309 
310 // User permission flags.
311 const mode_t S_IRUSR = mode_t(_S_IREAD); // Readable by user.
312 const mode_t S_IWUSR = mode_t(_S_IWRITE); // Writeable by user.
313 const mode_t S_IXUSR = S_IRUSR; // Fallback to user read.
315 
316 
317 // Group permission flags. Lossy mapping to Windows permissions. See
318 // note above about flag strictness for explanation.
319 const mode_t S_IRGRP = 0x00200000; // No-op.
320 const mode_t S_IWGRP = 0x00100000; // No-op.
321 const mode_t S_IXGRP = 0x00080000; // No-op.
323 
324 
325 // Other permission flags. Lossy mapping to Windows permissions. See
326 // note above about flag stictness for explanation.
327 const mode_t S_IROTH = 0x00040000; // No-op.
328 const mode_t S_IWOTH = 0x00020000; // No-op.
329 const mode_t S_IXOTH = 0x00010000; // No-op.
331 
332 
333 // Flags for set-ID-on-exec.
334 const mode_t S_ISUID = 0x08000000; // No-op.
335 const mode_t S_ISGID = 0x04000000; // No-op.
336 const mode_t S_ISVTX = 0x02000000; // No-op.
337 
338 
339 // Flags not supported by Windows.
340 const mode_t O_SYNC = 0x00000000; // No-op.
341 const mode_t O_NONBLOCK = 0x00000000; // No-op.
342 
343 // Even though SIGKILL doesn't exist on Windows, we define
344 // it here, because Docker defines it. So, the docker
345 // executor needs this signal value to properly kill containers.
346 const mode_t SIGKILL = 0x00000009; // Signal Kill.
347 
348 inline auto strerror_r(int errnum, char* buffer, size_t length) ->
349 decltype(strerror_s(buffer, length, errnum))
350 {
351  return strerror_s(buffer, length, errnum);
352 }
353 
354 
355 // NOTE: Signals do not exist on Windows, so all signals are unknown.
356 // If the signal number is unknown, the Posix specification leaves the
357 // return value of `strsignal` unspecified.
358 inline const char* strsignal(int signum)
359 {
360  static const char UNKNOWN_STRSIGNAL[] = "Unknown signal";
361  return UNKNOWN_STRSIGNAL;
362 }
363 
364 
365 #define SIGPIPE 100
366 
367 // `os::system` returns -1 if the processor cannot be started
368 // therefore any return value indicates the process has been started
369 #ifndef WIFEXITED
370 #define WIFEXITED(x) ((x) != -1)
371 #endif // WIFEXITED
372 
373 // Returns the exit status of the child.
374 // On Windows, they are a 32 bit unsigned integer.
375 #ifndef WEXITSTATUS
376 #define WEXITSTATUS(x) static_cast<DWORD>(x)
377 #endif // WEXITSTATUS
378 
379 #ifndef WIFSIGNALED
380 #define WIFSIGNALED(x) ((x) != -1)
381 #endif // WIFSIGNALED
382 
383 // Returns the number of the signal that caused the child process to
384 // terminate, only be used if WIFSIGNALED is true.
385 #ifndef WTERMSIG
386 #define WTERMSIG(x) 0
387 #endif // WTERMSIG
388 
389 // Whether the child produced a core dump, only be used if WIFSIGNALED is true.
390 #ifndef WCOREDUMP
391 #define WCOREDUMP(x) false
392 #endif // WCOREDUMP
393 
394 // Whether the child was stopped by delivery of a signal.
395 #ifndef WIFSTOPPED
396 #define WIFSTOPPED(x) false
397 #endif // WIFSTOPPED
398 
399 // Whether the child was stopped by delivery of a signal.
400 #ifndef WSTOPSIG
401 #define WSTOPSIG(x) 0
402 #endif // WSTOPSIG
403 
404 // Specifies that `::waitpid` should return immediately rather than
405 // blocking and waiting for child to notify of state change.
406 #ifndef WNOHANG
407 #define WNOHANG 1
408 #endif // WNOHANG
409 
410 #ifndef WUNTRACED
411 #define WUNTRACED 2 // Tell about stopped, untraced children.
412 #endif // WUNTRACED
413 
414 #endif // __STOUT_WINDOWS_HPP__
SharedHandle(HANDLE handle, Deleter deleter)
Definition: windows.hpp:93
SSIZE_T ssize_t
Definition: windows.hpp:192
const mode_t S_IXOTH
Definition: windows.hpp:329
const mode_t S_IRGRP
Definition: windows.hpp:319
bool S_ISDIR(const int mode)
Definition: windows.hpp:206
HANDLE get_handle() const
Definition: windows.hpp:96
Definition: windows.hpp:78
const mode_t SIGKILL
Definition: windows.hpp:346
const mode_t S_IWUSR
Definition: windows.hpp:312
const char * strsignal(int signum)
Definition: windows.hpp:358
bool S_ISSOCK(const int mode)
Definition: windows.hpp:236
bool S_ISREG(const int mode)
Definition: windows.hpp:212
constexpr int SHUT_RDWR
Definition: windows.hpp:199
const mode_t S_IRUSR
Definition: windows.hpp:311
const mode_t O_SYNC
Definition: windows.hpp:340
bool S_ISFIFO(const int mode)
Definition: windows.hpp:224
const int NAME_MAX
Definition: windows.hpp:177
const mode_t S_IRWXO
Definition: windows.hpp:330
const mode_t S_ISVTX
Definition: windows.hpp:336
DWORD pid_t
Definition: windows.hpp:187
int mode_t
Definition: windows.hpp:183
const mode_t S_IXGRP
Definition: windows.hpp:321
SharedHandle()=delete
constexpr Handle HANDLE
Definition: ingress.hpp:37
auto strerror_r(int errnum, char *buffer, size_t length) ->
Definition: windows.hpp:348
int uid_t
Definition: windows.hpp:189
const mode_t S_IXUSR
Definition: windows.hpp:313
#define PATH_MAX
Definition: windows.hpp:170
bool S_ISBLK(const int mode)
Definition: windows.hpp:230
const mode_t O_NONBLOCK
Definition: windows.hpp:341
const mode_t S_IRWXU
Definition: windows.hpp:314
const mode_t S_IWGRP
Definition: windows.hpp:320
const mode_t S_ISUID
Definition: windows.hpp:334
const mode_t S_IRWXG
Definition: windows.hpp:322
constexpr int MSG_NOSIGNAL
Definition: windows.hpp:200
bool S_ISLNK(const int mode)
Definition: windows.hpp:242
Try< mode_t > mode(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:126
const mode_t S_IWOTH
Definition: windows.hpp:328
constexpr int SHUT_RD
Definition: windows.hpp:197
int gid_t
Definition: windows.hpp:190
const mode_t S_ISGID
Definition: windows.hpp:335
bool S_ISCHR(const int mode)
Definition: windows.hpp:218
const mode_t S_IROTH
Definition: windows.hpp:327
constexpr int SHUT_WR
Definition: windows.hpp:198