Enable auto-deps in all of Folly
[folly.git] / folly / portability / Unistd.cpp
1 /*
2  * Copyright 2017 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/portability/Sockets.h>
30 #include <folly/portability/Windows.h>
31
32 // Including ntdef.h requires building as a driver, but all we want
33 // is a status code, but we need NTSTATUS defined for that. Luckily
34 // bcrypt.h also defines NTSTATUS, so we'll use that one instead.
35 #include <bcrypt.h> // @manual
36 #include <ntstatus.h> // @manual
37
38 // Generic wrapper for the p* family of functions.
39 template <class F, class... Args>
40 static int wrapPositional(F f, int fd, off_t offset, Args... args) {
41   off_t origLoc = lseek(fd, 0, SEEK_CUR);
42   if (origLoc == (off_t)-1) {
43     return -1;
44   }
45   if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
46     return -1;
47   }
48
49   int res = (int)f(fd, args...);
50
51   int curErrNo = errno;
52   if (lseek(fd, origLoc, SEEK_SET) == (off_t)-1) {
53     if (res == -1) {
54       errno = curErrNo;
55     }
56     return -1;
57   }
58   errno = curErrNo;
59
60   return res;
61 }
62
63 namespace folly {
64 namespace portability {
65 namespace unistd {
66 int access(char const* fn, int am) {
67   return _access(fn, am);
68 }
69
70 int chdir(const char* path) {
71   return _chdir(path);
72 }
73
74 int close(int fh) {
75   if (folly::portability::sockets::is_fh_socket(fh)) {
76     SOCKET h = (SOCKET)_get_osfhandle(fh);
77
78     // If we were to just call _close on the descriptor, it would
79     // close the HANDLE, but it wouldn't free any of the resources
80     // associated to the SOCKET, and we can't call _close after
81     // calling closesocket, because closesocket has already closed
82     // the HANDLE, and _close would attempt to close the HANDLE
83     // again, resulting in a double free.
84     // We can however protect the HANDLE from actually being closed
85     // long enough to close the file descriptor, then close the
86     // socket itself.
87     constexpr DWORD protectFlag = HANDLE_FLAG_PROTECT_FROM_CLOSE;
88     DWORD handleFlags = 0;
89     if (!GetHandleInformation((HANDLE)h, &handleFlags)) {
90       return -1;
91     }
92     if (!SetHandleInformation((HANDLE)h, protectFlag, protectFlag)) {
93       return -1;
94     }
95     int c = 0;
96     __try {
97       // We expect this to fail. It still closes the file descriptor though.
98       c = _close(fh);
99       // We just have to catch the SEH exception that gets thrown when we do
100       // this with a debugger attached -_-....
101     } __except (
102         GetExceptionCode() == STATUS_HANDLE_NOT_CLOSABLE
103             ? EXCEPTION_CONTINUE_EXECUTION
104             : EXCEPTION_CONTINUE_SEARCH) {
105       // We told it to continue execution, so there's nothing here would
106       // be run anyways.
107     }
108     // We're at the core, we don't get the luxery of SCOPE_EXIT because
109     // of circular dependencies.
110     if (!SetHandleInformation((HANDLE)h, protectFlag, handleFlags)) {
111       return -1;
112     }
113     if (c != -1) {
114       return -1;
115     }
116     return closesocket(h);
117   }
118   return _close(fh);
119 }
120
121 int dup(int fh) {
122   return _dup(fh);
123 }
124
125 int dup2(int fhs, int fhd) {
126   return _dup2(fhs, fhd);
127 }
128
129 int fsync(int fd) {
130   HANDLE h = (HANDLE)_get_osfhandle(fd);
131   if (h == INVALID_HANDLE_VALUE) {
132     return -1;
133   }
134   if (!FlushFileBuffers(h)) {
135     return -1;
136   }
137   return 0;
138 }
139
140 int ftruncate(int fd, off_t len) {
141   if (_lseek(fd, len, SEEK_SET) == -1) {
142     return -1;
143   }
144
145   HANDLE h = (HANDLE)_get_osfhandle(fd);
146   if (h == INVALID_HANDLE_VALUE) {
147     return -1;
148   }
149   if (!SetEndOfFile(h)) {
150     return -1;
151   }
152   return 0;
153 }
154
155 char* getcwd(char* buf, int sz) {
156   return _getcwd(buf, sz);
157 }
158
159 int getdtablesize() {
160   return _getmaxstdio();
161 }
162
163 int getgid() {
164   return 1;
165 }
166
167 pid_t getpid() {
168   return (pid_t)uint64_t(GetCurrentProcessId());
169 }
170
171 // No major need to implement this, and getting a non-potentially
172 // stale ID on windows is a bit involved.
173 pid_t getppid() {
174   return (pid_t)1;
175 }
176
177 int getuid() {
178   return 1;
179 }
180
181 int isatty(int fh) {
182   return _isatty(fh);
183 }
184
185 int lockf(int fd, int cmd, off_t len) {
186   return _locking(fd, cmd, len);
187 }
188
189 off_t lseek(int fh, off_t off, int orig) {
190   return _lseek(fh, off, orig);
191 }
192
193 int rmdir(const char* path) {
194   return _rmdir(path);
195 }
196
197 int pipe(int pth[2]) {
198   // We need to be able to listen to pipes with
199   // libevent, so they need to be actual sockets.
200   return socketpair(PF_UNIX, SOCK_STREAM, 0, pth);
201 }
202
203 ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
204   return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
205 }
206
207 ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
208   return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
209 }
210
211 ssize_t read(int fh, void* buf, size_t count) {
212   if (folly::portability::sockets::is_fh_socket(fh)) {
213     SOCKET s = (SOCKET)_get_osfhandle(fh);
214     if (s != INVALID_SOCKET) {
215       auto r = folly::portability::sockets::recv(fh, buf, count, 0);
216       if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
217         errno = EAGAIN;
218       }
219       return r;
220     }
221   }
222   auto r = _read(fh, buf, unsigned int(count));
223   if (r == -1 && GetLastError() == ERROR_NO_DATA) {
224     // This only happens if the file was non-blocking and
225     // no data was present. We have to translate the error
226     // to a form that the rest of the world is expecting.
227     errno = EAGAIN;
228   }
229   return r;
230 }
231
232 ssize_t readlink(const char* path, char* buf, size_t buflen) {
233   if (!buflen) {
234     return -1;
235   }
236
237   HANDLE h = CreateFileA(
238       path,
239       GENERIC_READ,
240       FILE_SHARE_READ,
241       nullptr,
242       OPEN_EXISTING,
243       FILE_FLAG_BACKUP_SEMANTICS,
244       nullptr);
245   if (h == INVALID_HANDLE_VALUE) {
246     return -1;
247   }
248
249   DWORD ret =
250       GetFinalPathNameByHandleA(h, buf, DWORD(buflen - 1), VOLUME_NAME_DOS);
251   if (ret >= buflen || ret >= MAX_PATH || !ret) {
252     CloseHandle(h);
253     return -1;
254   }
255
256   CloseHandle(h);
257   buf[ret] = '\0';
258   return ret;
259 }
260
261 void* sbrk(intptr_t /* i */) {
262   return (void*)-1;
263 }
264
265 unsigned int sleep(unsigned int seconds) {
266   Sleep((DWORD)(seconds * 1000));
267   return 0;
268 }
269
270 long sysconf(int tp) {
271   switch (tp) {
272     case _SC_PAGESIZE: {
273       SYSTEM_INFO inf;
274       GetSystemInfo(&inf);
275       return (long)inf.dwPageSize;
276     }
277     case _SC_NPROCESSORS_ONLN: {
278       SYSTEM_INFO inf;
279       GetSystemInfo(&inf);
280       return (long)inf.dwNumberOfProcessors;
281     }
282     default:
283       return -1L;
284   }
285 }
286
287 int truncate(const char* path, off_t len) {
288   int fd = _open(path, O_WRONLY);
289   if (!fd) {
290     return -1;
291   }
292   if (ftruncate(fd, len)) {
293     _close(fd);
294     return -1;
295   }
296   return _close(fd) ? -1 : 0;
297 }
298
299 int usleep(unsigned int ms) {
300   Sleep((DWORD)(ms / 1000));
301   return 0;
302 }
303
304 ssize_t write(int fh, void const* buf, size_t count) {
305   if (folly::portability::sockets::is_fh_socket(fh)) {
306     SOCKET s = (SOCKET)_get_osfhandle(fh);
307     if (s != INVALID_SOCKET) {
308       auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0);
309       if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
310         errno = EAGAIN;
311       }
312       return r;
313     }
314   }
315   auto r = _write(fh, buf, unsigned int(count));
316   if ((r > 0 && size_t(r) != count) || (r == -1 && errno == ENOSPC)) {
317     // Writing to a pipe with a full buffer doesn't generate
318     // any error type, unless it caused us to write exactly 0
319     // bytes, so we have to see if we have a pipe first. We
320     // don't touch the errno for anything else.
321     HANDLE h = (HANDLE)_get_osfhandle(fh);
322     if (GetFileType(h) == FILE_TYPE_PIPE) {
323       DWORD state = 0;
324       if (GetNamedPipeHandleState(
325               h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
326         if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {
327           errno = EAGAIN;
328           return -1;
329         }
330       }
331     }
332   }
333   return r;
334 }
335 }
336 }
337 }
338
339 #endif