1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include <folly/portability/Fcntl.h> |
18 | |
19 | #ifdef _WIN32 |
20 | #include <folly/portability/Sockets.h> |
21 | #include <folly/portability/SysStat.h> |
22 | #include <folly/portability/Windows.h> |
23 | |
24 | namespace folly { |
25 | namespace portability { |
26 | namespace fcntl { |
27 | int creat(char const* fn, int pm) { |
28 | return _creat(fn, pm); |
29 | } |
30 | |
31 | int fcntl(int fd, int cmd, ...) { |
32 | va_list args; |
33 | int res = -1; |
34 | va_start(args, cmd); |
35 | switch (cmd) { |
36 | case F_GETFD: { |
37 | HANDLE h = (HANDLE)_get_osfhandle(fd); |
38 | if (h != INVALID_HANDLE_VALUE) { |
39 | DWORD flags; |
40 | if (GetHandleInformation(h, &flags)) { |
41 | res = int(flags & HANDLE_FLAG_INHERIT); |
42 | } |
43 | } |
44 | break; |
45 | } |
46 | case F_SETFD: { |
47 | int flags = va_arg(args, int); |
48 | HANDLE h = (HANDLE)_get_osfhandle(fd); |
49 | if (h != INVALID_HANDLE_VALUE) { |
50 | if (SetHandleInformation( |
51 | h, HANDLE_FLAG_INHERIT, (DWORD)(flags & FD_CLOEXEC))) { |
52 | res = 0; |
53 | } |
54 | } |
55 | break; |
56 | } |
57 | case F_GETFL: { |
58 | // No idea how to get the IO blocking mode, so return 0. |
59 | res = 0; |
60 | break; |
61 | } |
62 | case F_SETFL: { |
63 | int flags = va_arg(args, int); |
64 | // If it's not a socket, it's probably a pipe. |
65 | if (folly::portability::sockets::is_fh_socket(fd)) { |
66 | SOCKET s = (SOCKET)_get_osfhandle(fd); |
67 | if (s != INVALID_SOCKET) { |
68 | u_long nonBlockingEnabled = (flags & O_NONBLOCK) ? 1 : 0; |
69 | res = ioctlsocket(s, FIONBIO, &nonBlockingEnabled); |
70 | } |
71 | } else { |
72 | HANDLE p = (HANDLE)_get_osfhandle(fd); |
73 | if (GetFileType(p) == FILE_TYPE_PIPE) { |
74 | DWORD newMode = PIPE_READMODE_BYTE; |
75 | newMode |= (flags & O_NONBLOCK) ? PIPE_NOWAIT : PIPE_WAIT; |
76 | if (SetNamedPipeHandleState(p, &newMode, nullptr, nullptr)) { |
77 | res = 0; |
78 | } |
79 | } |
80 | } |
81 | break; |
82 | } |
83 | } |
84 | va_end(args); |
85 | return res; |
86 | } |
87 | |
88 | int open(char const* fn, int of, int pm) { |
89 | int fh; |
90 | int realMode = _S_IREAD; |
91 | if ((of & _O_RDWR) == _O_RDWR) { |
92 | realMode = _S_IREAD | _S_IWRITE; |
93 | } else if ((of & _O_WRONLY) == _O_WRONLY) { |
94 | realMode = _S_IWRITE; |
95 | } else if ((of & _O_RDONLY) != _O_RDONLY) { |
96 | // One of these needs to be present, just fail if |
97 | // none are. |
98 | return -1; |
99 | } |
100 | if (!strcmp(fn, "/dev/null" )) { |
101 | // Windows doesn't have a /dev/null, but it does have |
102 | // NUL, which achieves the same result. |
103 | fn = "NUL" ; |
104 | } |
105 | errno_t res = _sopen_s(&fh, fn, of, _SH_DENYNO, realMode); |
106 | return res ? -1 : fh; |
107 | } |
108 | |
109 | int posix_fallocate(int fd, off_t offset, off_t len) { |
110 | // We'll pretend we always have enough space. We |
111 | // can't exactly pre-allocate on windows anyways. |
112 | return 0; |
113 | } |
114 | } // namespace fcntl |
115 | } // namespace portability |
116 | } // namespace folly |
117 | #endif |
118 | |