2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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
21 #include <folly/portability/Unistd.h>
29 #include <folly/portability/Sockets.h>
30 #include <folly/portability/Windows.h>
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.
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) {
45 if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
49 int res = (int)f(fd, args...);
52 if (lseek(fd, origLoc, SEEK_SET) == (off_t)-1) {
64 namespace portability {
66 int access(char const* fn, int am) {
67 return _access(fn, am);
70 int chdir(const char* path) {
75 if (folly::portability::sockets::is_fh_socket(fh)) {
76 SOCKET h = (SOCKET)_get_osfhandle(fh);
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
87 constexpr DWORD protectFlag = HANDLE_FLAG_PROTECT_FROM_CLOSE;
88 DWORD handleFlags = 0;
89 if (!GetHandleInformation((HANDLE)h, &handleFlags)) {
92 if (!SetHandleInformation((HANDLE)h, protectFlag, protectFlag)) {
97 // We expect this to fail. It still closes the file descriptor though.
99 // We just have to catch the SEH exception that gets thrown when we do
100 // this with a debugger attached -_-....
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
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)) {
116 return closesocket(h);
125 int dup2(int fhs, int fhd) {
126 return _dup2(fhs, fhd);
130 HANDLE h = (HANDLE)_get_osfhandle(fd);
131 if (h == INVALID_HANDLE_VALUE) {
134 if (!FlushFileBuffers(h)) {
140 int ftruncate(int fd, off_t len) {
141 if (_lseek(fd, len, SEEK_SET) == -1) {
145 HANDLE h = (HANDLE)_get_osfhandle(fd);
146 if (h == INVALID_HANDLE_VALUE) {
149 if (!SetEndOfFile(h)) {
155 char* getcwd(char* buf, int sz) {
156 return _getcwd(buf, sz);
159 int getdtablesize() {
160 return _getmaxstdio();
168 return (pid_t)uint64_t(GetCurrentProcessId());
171 // No major need to implement this, and getting a non-potentially
172 // stale ID on windows is a bit involved.
185 int lockf(int fd, int cmd, off_t len) {
186 return _locking(fd, cmd, len);
189 off_t lseek(int fh, off_t off, int orig) {
190 return _lseek(fh, off, orig);
193 int rmdir(const char* path) {
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);
203 ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
204 return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
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);
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) {
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.
232 ssize_t readlink(const char* path, char* buf, size_t buflen) {
237 HANDLE h = CreateFileA(
243 FILE_FLAG_BACKUP_SEMANTICS,
245 if (h == INVALID_HANDLE_VALUE) {
250 GetFinalPathNameByHandleA(h, buf, DWORD(buflen - 1), VOLUME_NAME_DOS);
251 if (ret >= buflen || ret >= MAX_PATH || !ret) {
261 void* sbrk(intptr_t /* i */) {
265 unsigned int sleep(unsigned int seconds) {
266 Sleep((DWORD)(seconds * 1000));
270 long sysconf(int tp) {
275 return (long)inf.dwPageSize;
277 case _SC_NPROCESSORS_ONLN: {
280 return (long)inf.dwNumberOfProcessors;
287 int truncate(const char* path, off_t len) {
288 int fd = _open(path, O_WRONLY);
292 if (ftruncate(fd, len)) {
296 return _close(fd) ? -1 : 0;
299 int usleep(unsigned int ms) {
300 Sleep((DWORD)(ms / 1000));
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) {
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) {
324 if (GetNamedPipeHandleState(
325 h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
326 if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {