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 | // We need to prevent winnt.h from defining the core STATUS codes, |
18 | // otherwise they will conflict with what we're getting from ntstatus.h |
19 | #define UMDF_USING_NTSTATUS |
20 | |
21 | #include <folly/portability/Unistd.h> |
22 | |
23 | #ifdef _WIN32 |
24 | |
25 | #include <cstdio> |
26 | |
27 | #include <fcntl.h> |
28 | |
29 | #include <folly/net/detail/SocketFileDescriptorMap.h> |
30 | #include <folly/portability/Sockets.h> |
31 | #include <folly/portability/Windows.h> |
32 | |
33 | // Generic wrapper for the p* family of functions. |
34 | template <class F, class... Args> |
35 | static int wrapPositional(F f, int fd, off_t offset, Args... args) { |
36 | off_t origLoc = lseek(fd, 0, SEEK_CUR); |
37 | if (origLoc == (off_t)-1) { |
38 | return -1; |
39 | } |
40 | if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { |
41 | return -1; |
42 | } |
43 | |
44 | int res = (int)f(fd, args...); |
45 | |
46 | int curErrNo = errno; |
47 | if (lseek(fd, origLoc, SEEK_SET) == (off_t)-1) { |
48 | if (res == -1) { |
49 | errno = curErrNo; |
50 | } |
51 | return -1; |
52 | } |
53 | errno = curErrNo; |
54 | |
55 | return res; |
56 | } |
57 | |
58 | namespace folly { |
59 | namespace portability { |
60 | namespace unistd { |
61 | int access(char const* fn, int am) { |
62 | return _access(fn, am); |
63 | } |
64 | |
65 | int chdir(const char* path) { |
66 | return _chdir(path); |
67 | } |
68 | |
69 | int close(int fh) { |
70 | if (folly::portability::sockets::is_fh_socket(fh)) { |
71 | return netops::detail::SocketFileDescriptorMap::close(fh); |
72 | } |
73 | return _close(fh); |
74 | } |
75 | |
76 | int dup(int fh) { |
77 | return _dup(fh); |
78 | } |
79 | |
80 | int dup2(int fhs, int fhd) { |
81 | return _dup2(fhs, fhd); |
82 | } |
83 | |
84 | int fsync(int fd) { |
85 | HANDLE h = (HANDLE)_get_osfhandle(fd); |
86 | if (h == INVALID_HANDLE_VALUE) { |
87 | return -1; |
88 | } |
89 | if (!FlushFileBuffers(h)) { |
90 | return -1; |
91 | } |
92 | return 0; |
93 | } |
94 | |
95 | int ftruncate(int fd, off_t len) { |
96 | if (_lseek(fd, len, SEEK_SET) == -1) { |
97 | return -1; |
98 | } |
99 | |
100 | HANDLE h = (HANDLE)_get_osfhandle(fd); |
101 | if (h == INVALID_HANDLE_VALUE) { |
102 | return -1; |
103 | } |
104 | if (!SetEndOfFile(h)) { |
105 | return -1; |
106 | } |
107 | return 0; |
108 | } |
109 | |
110 | char* getcwd(char* buf, int sz) { |
111 | return _getcwd(buf, sz); |
112 | } |
113 | |
114 | int getdtablesize() { |
115 | return _getmaxstdio(); |
116 | } |
117 | |
118 | int getgid() { |
119 | return 1; |
120 | } |
121 | |
122 | pid_t getpid() { |
123 | return (pid_t)uint64_t(GetCurrentProcessId()); |
124 | } |
125 | |
126 | // No major need to implement this, and getting a non-potentially |
127 | // stale ID on windows is a bit involved. |
128 | pid_t getppid() { |
129 | return (pid_t)1; |
130 | } |
131 | |
132 | int getuid() { |
133 | return 1; |
134 | } |
135 | |
136 | int isatty(int fh) { |
137 | return _isatty(fh); |
138 | } |
139 | |
140 | int lockf(int fd, int cmd, off_t len) { |
141 | return _locking(fd, cmd, len); |
142 | } |
143 | |
144 | off_t lseek(int fh, off_t off, int orig) { |
145 | return _lseek(fh, off, orig); |
146 | } |
147 | |
148 | int rmdir(const char* path) { |
149 | return _rmdir(path); |
150 | } |
151 | |
152 | int pipe(int pth[2]) { |
153 | // We need to be able to listen to pipes with |
154 | // libevent, so they need to be actual sockets. |
155 | return socketpair(PF_UNIX, SOCK_STREAM, 0, pth); |
156 | } |
157 | |
158 | ssize_t pread(int fd, void* buf, size_t count, off_t offset) { |
159 | return wrapPositional(_read, fd, offset, buf, (unsigned int)count); |
160 | } |
161 | |
162 | ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) { |
163 | return wrapPositional(_write, fd, offset, buf, (unsigned int)count); |
164 | } |
165 | |
166 | ssize_t read(int fh, void* buf, size_t count) { |
167 | if (folly::portability::sockets::is_fh_socket(fh)) { |
168 | SOCKET s = (SOCKET)_get_osfhandle(fh); |
169 | if (s != INVALID_SOCKET) { |
170 | auto r = folly::portability::sockets::recv(fh, buf, count, 0); |
171 | if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) { |
172 | errno = EAGAIN; |
173 | } |
174 | return r; |
175 | } |
176 | } |
177 | auto r = _read(fh, buf, static_cast<unsigned int>(count)); |
178 | if (r == -1 && GetLastError() == ERROR_NO_DATA) { |
179 | // This only happens if the file was non-blocking and |
180 | // no data was present. We have to translate the error |
181 | // to a form that the rest of the world is expecting. |
182 | errno = EAGAIN; |
183 | } |
184 | return r; |
185 | } |
186 | |
187 | ssize_t readlink(const char* path, char* buf, size_t buflen) { |
188 | if (!buflen) { |
189 | return -1; |
190 | } |
191 | |
192 | HANDLE h = CreateFileA( |
193 | path, |
194 | GENERIC_READ, |
195 | FILE_SHARE_READ, |
196 | nullptr, |
197 | OPEN_EXISTING, |
198 | FILE_FLAG_BACKUP_SEMANTICS, |
199 | nullptr); |
200 | if (h == INVALID_HANDLE_VALUE) { |
201 | return -1; |
202 | } |
203 | |
204 | DWORD ret = |
205 | GetFinalPathNameByHandleA(h, buf, DWORD(buflen - 1), VOLUME_NAME_DOS); |
206 | if (ret >= buflen || ret >= MAX_PATH || !ret) { |
207 | CloseHandle(h); |
208 | return -1; |
209 | } |
210 | |
211 | CloseHandle(h); |
212 | buf[ret] = '\0'; |
213 | return ret; |
214 | } |
215 | |
216 | void* sbrk(intptr_t /* i */) { |
217 | return (void*)-1; |
218 | } |
219 | |
220 | unsigned int sleep(unsigned int seconds) { |
221 | Sleep((DWORD)(seconds * 1000)); |
222 | return 0; |
223 | } |
224 | |
225 | long sysconf(int tp) { |
226 | switch (tp) { |
227 | case _SC_PAGESIZE: { |
228 | SYSTEM_INFO inf; |
229 | GetSystemInfo(&inf); |
230 | return (long)inf.dwPageSize; |
231 | } |
232 | case _SC_NPROCESSORS_ONLN: { |
233 | SYSTEM_INFO inf; |
234 | GetSystemInfo(&inf); |
235 | return (long)inf.dwNumberOfProcessors; |
236 | } |
237 | default: |
238 | return -1L; |
239 | } |
240 | } |
241 | |
242 | int truncate(const char* path, off_t len) { |
243 | int fd = _open(path, O_WRONLY); |
244 | if (!fd) { |
245 | return -1; |
246 | } |
247 | if (ftruncate(fd, len)) { |
248 | _close(fd); |
249 | return -1; |
250 | } |
251 | return _close(fd) ? -1 : 0; |
252 | } |
253 | |
254 | int usleep(unsigned int ms) { |
255 | Sleep((DWORD)(ms / 1000)); |
256 | return 0; |
257 | } |
258 | |
259 | ssize_t write(int fh, void const* buf, size_t count) { |
260 | if (folly::portability::sockets::is_fh_socket(fh)) { |
261 | SOCKET s = (SOCKET)_get_osfhandle(fh); |
262 | if (s != INVALID_SOCKET) { |
263 | auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0); |
264 | if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) { |
265 | errno = EAGAIN; |
266 | } |
267 | return r; |
268 | } |
269 | } |
270 | auto r = _write(fh, buf, static_cast<unsigned int>(count)); |
271 | if ((r > 0 && size_t(r) != count) || (r == -1 && errno == ENOSPC)) { |
272 | // Writing to a pipe with a full buffer doesn't generate |
273 | // any error type, unless it caused us to write exactly 0 |
274 | // bytes, so we have to see if we have a pipe first. We |
275 | // don't touch the errno for anything else. |
276 | HANDLE h = (HANDLE)_get_osfhandle(fh); |
277 | if (GetFileType(h) == FILE_TYPE_PIPE) { |
278 | DWORD state = 0; |
279 | if (GetNamedPipeHandleState( |
280 | h, &state, nullptr, nullptr, nullptr, nullptr, 0)) { |
281 | if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) { |
282 | errno = EAGAIN; |
283 | return -1; |
284 | } |
285 | } |
286 | } |
287 | } |
288 | return r; |
289 | } |
290 | } // namespace unistd |
291 | } // namespace portability |
292 | } // namespace folly |
293 | |
294 | #endif |
295 | |