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