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>
26 #include <folly/portability/Sockets.h>
27 #include <folly/portability/Windows.h>
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.
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) {
42 if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
46 int res = (int)f(fd, args...);
49 if (lseek(fd, origLoc, SEEK_SET) == (off_t)-1) {
61 namespace portability {
63 int access(char const* fn, int am) { return _access(fn, am); }
65 int chdir(const char* path) { return _chdir(path); }
68 if (folly::portability::sockets::is_fh_socket(fh)) {
69 SOCKET h = (SOCKET)_get_osfhandle(fh);
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
80 constexpr DWORD protectFlag = HANDLE_FLAG_PROTECT_FROM_CLOSE;
81 DWORD handleFlags = 0;
82 if (!GetHandleInformation((HANDLE)h, &handleFlags)) {
85 if (!SetHandleInformation((HANDLE)h, protectFlag, protectFlag)) {
90 // We expect this to fail. It still closes the file descriptor though.
92 // We just have to catch the SEH exception that gets thrown when we do
93 // this with a debugger attached -_-....
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
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)) {
109 return closesocket(h);
114 int dup(int fh) { return _dup(fh); }
116 int dup2(int fhs, int fhd) { return _dup2(fhs, fhd); }
119 HANDLE h = (HANDLE)_get_osfhandle(fd);
120 if (h == INVALID_HANDLE_VALUE) {
123 if (!FlushFileBuffers(h)) {
129 int ftruncate(int fd, off_t len) {
130 if (_lseek(fd, len, SEEK_SET) == -1) {
134 HANDLE h = (HANDLE)_get_osfhandle(fd);
135 if (h == INVALID_HANDLE_VALUE) {
138 if (!SetEndOfFile(h)) {
144 char* getcwd(char* buf, int sz) { return _getcwd(buf, sz); }
146 int getdtablesize() { return _getmaxstdio(); }
148 int getgid() { return 1; }
150 pid_t getpid() { return (pid_t)uint64_t(GetCurrentProcessId()); }
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; }
156 int getuid() { return 1; }
158 int isatty(int fh) { return _isatty(fh); }
160 int lockf(int fd, int cmd, off_t len) { return _locking(fd, cmd, len); }
162 off_t lseek(int fh, off_t off, int orig) {
163 return _lseek(fh, off, orig);
166 int rmdir(const char* path) { return _rmdir(path); }
168 int pipe(int pth[2]) {
169 // We need to be able to listen to pipes with
170 // libevent, so they need to be actual sockets.
171 return socketpair(PF_UNIX, SOCK_STREAM, 0, pth);
174 ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
175 return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
178 ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
179 return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
182 ssize_t read(int fh, void* buf, size_t count) {
183 if (folly::portability::sockets::is_fh_socket(fh)) {
184 SOCKET s = (SOCKET)_get_osfhandle(fh);
185 if (s != INVALID_SOCKET) {
186 auto r = folly::portability::sockets::recv(fh, buf, count, 0);
187 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
193 auto r = _read(fh, buf, unsigned int(count));
194 if (r == -1 && GetLastError() == ERROR_NO_DATA) {
195 // This only happens if the file was non-blocking and
196 // no data was present. We have to translate the error
197 // to a form that the rest of the world is expecting.
203 ssize_t readlink(const char* path, char* buf, size_t buflen) {
208 HANDLE h = CreateFile(path,
213 FILE_FLAG_BACKUP_SEMANTICS,
215 if (h == INVALID_HANDLE_VALUE) {
220 GetFinalPathNameByHandleA(h, buf, DWORD(buflen - 1), VOLUME_NAME_DOS);
221 if (ret >= buflen || ret >= MAX_PATH || !ret) {
231 void* sbrk(intptr_t i) { return (void*)-1; }
233 unsigned int sleep(unsigned int seconds) {
234 Sleep((DWORD)(seconds * 1000));
238 long sysconf(int tp) {
243 return (long)inf.dwPageSize;
245 case _SC_NPROCESSORS_ONLN: {
248 return (long)inf.dwNumberOfProcessors;
255 int truncate(const char* path, off_t len) {
256 int fd = _open(path, O_WRONLY);
260 if (ftruncate(fd, len)) {
264 return _close(fd) ? -1 : 0;
267 int usleep(unsigned int ms) {
268 Sleep((DWORD)(ms / 1000));
272 ssize_t write(int fh, void const* buf, size_t count) {
273 if (folly::portability::sockets::is_fh_socket(fh)) {
274 SOCKET s = (SOCKET)_get_osfhandle(fh);
275 if (s != INVALID_SOCKET) {
276 auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0);
277 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
283 auto r = _write(fh, buf, unsigned int(count));
284 if ((r > 0 && size_t(r) != count) || (r == -1 && errno == ENOSPC)) {
285 // Writing to a pipe with a full buffer doesn't generate
286 // any error type, unless it caused us to write exactly 0
287 // bytes, so we have to see if we have a pipe first. We
288 // don't touch the errno for anything else.
289 HANDLE h = (HANDLE)_get_osfhandle(fh);
290 if (GetFileType(h) == FILE_TYPE_PIPE) {
292 if (GetNamedPipeHandleState(
293 h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
294 if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {