2 * Copyright 2016 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 #include <folly/portability/Unistd.h>
22 #include <folly/portability/Sockets.h>
23 #include <folly/portability/Windows.h>
25 // Generic wrapper for the p* family of functions.
26 template <class F, class... Args>
27 static int wrapPositional(F f, int fd, off_t offset, Args... args) {
28 off_t origLoc = lseek(fd, 0, SEEK_CUR);
29 if (origLoc == (off_t)-1) {
32 if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
36 int res = (int)f(fd, args...);
39 if (lseek(fd, origLoc, SEEK_SET) == (off_t)-1) {
51 namespace portability {
53 int access(char const* fn, int am) { return _access(fn, am); }
55 int chdir(const char* path) { return _chdir(path); }
57 #if defined(_MT) && !defined(_DLL)
58 // We aren't hooking into the internals of the CRT, nope, not at all.
59 extern "C" int __cdecl _free_osfhnd(int const fh);
62 if (folly::portability::sockets::is_fh_socket(fh)) {
63 SOCKET h = (SOCKET)_get_osfhandle(fh);
65 // If we were to just call _close on the descriptor, it would
66 // close the HANDLE, but it wouldn't free any of the resources
67 // associated to the SOCKET, and we can't call _close after
68 // calling closesocket, because closesocket has already closed
69 // the HANDLE, and _close would attempt to close the HANDLE
70 // again, resulting in a double free.
71 // Luckily though, there is a function in the internals of the
72 // CRT that is used to free only the file descriptor, so we
73 // can call that to avoid leaking the file descriptor itself.
75 // Unfortunately, we can only access the function when we're
76 // compiling against the static CRT, as it isn't an exported
77 // symbol. Leaking the file descriptor is less of a leak than
78 // leaking the socket's resources, so we close the socket and
79 // leave the descriptor itself alone.
80 auto c = closesocket(h);
81 #if defined(_MT) && !defined(_DLL)
82 // We're building for the static CRT. We can do things!
90 int dup(int fh) { return _dup(fh); }
92 int dup2(int fhs, int fhd) { return _dup2(fhs, fhd); }
95 HANDLE h = (HANDLE)_get_osfhandle(fd);
96 if (h == INVALID_HANDLE_VALUE) {
99 if (!FlushFileBuffers(h)) {
105 int ftruncate(int fd, off_t len) {
106 if (_lseek(fd, len, SEEK_SET) == -1) {
110 HANDLE h = (HANDLE)_get_osfhandle(fd);
111 if (h == INVALID_HANDLE_VALUE) {
114 if (!SetEndOfFile(h)) {
120 char* getcwd(char* buf, int sz) { return _getcwd(buf, sz); }
122 int getdtablesize() { return _getmaxstdio(); }
124 int getgid() { return 1; }
126 pid_t getpid() { return pid_t(GetCurrentProcessId()); }
128 // No major need to implement this, and getting a non-potentially
129 // stale ID on windows is a bit involved.
130 pid_t getppid() { return (pid_t)1; }
132 int getuid() { return 1; }
134 int isatty(int fh) { return _isatty(fh); }
136 int lockf(int fd, int cmd, off_t len) { return _locking(fd, cmd, len); }
138 long lseek(int fh, long off, int orig) { return _lseek(fh, off, orig); }
140 int rmdir(const char* path) { return _rmdir(path); }
142 int pipe(int pth[2]) {
143 // We need to be able to listen to pipes with
144 // libevent, so they need to be actual sockets.
145 return socketpair(PF_UNIX, SOCK_STREAM, 0, pth);
148 int pread(int fd, void* buf, size_t count, off_t offset) {
149 return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
152 int pwrite(int fd, const void* buf, size_t count, off_t offset) {
153 return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
156 int read(int fh, void* buf, unsigned int mcc) {
157 if (folly::portability::sockets::is_fh_socket(fh)) {
158 SOCKET s = (SOCKET)_get_osfhandle(fh);
159 if (s != INVALID_SOCKET) {
160 auto r = folly::portability::sockets::recv(fh, buf, (size_t)mcc, 0);
161 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
167 auto r = _read(fh, buf, mcc);
168 if (r == -1 && GetLastError() == ERROR_NO_DATA) {
169 // This only happens if the file was non-blocking and
170 // no data was present. We have to translate the error
171 // to a form that the rest of the world is expecting.
177 ssize_t readlink(const char* path, char* buf, size_t buflen) {
182 HANDLE h = CreateFile(path,
187 FILE_FLAG_BACKUP_SEMANTICS,
189 if (h == INVALID_HANDLE_VALUE) {
193 DWORD ret = GetFinalPathNameByHandleA(h, buf, buflen - 1, VOLUME_NAME_DOS);
194 if (ret >= buflen || ret >= MAX_PATH || !ret) {
204 void* sbrk(intptr_t i) { return (void*)-1; }
206 int setmode(int fh, int md) { return _setmode(fh, md); }
208 unsigned int sleep(unsigned int seconds) {
209 Sleep((DWORD)(seconds * 1000));
213 size_t sysconf(int tp) {
218 return (size_t)inf.dwPageSize;
220 case _SC_NPROCESSORS_ONLN: {
223 return (size_t)inf.dwNumberOfProcessors;
230 long tell(int fh) { return _tell(fh); }
232 int truncate(const char* path, off_t len) {
233 int fd = _open(path, O_WRONLY);
237 if (ftruncate(fd, len)) {
241 return _close(fd) ? -1 : 0;
244 int usleep(unsigned int ms) {
245 Sleep((DWORD)(ms / 1000));
249 int write(int fh, void const* buf, unsigned int count) {
250 if (folly::portability::sockets::is_fh_socket(fh)) {
251 SOCKET s = (SOCKET)_get_osfhandle(fh);
252 if (s != INVALID_SOCKET) {
253 auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0);
254 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
260 auto r = _write(fh, buf, count);
261 if ((r > 0 && r != count) || (r == -1 && errno == ENOSPC)) {
262 // Writing to a pipe with a full buffer doesn't generate
263 // any error type, unless it caused us to write exactly 0
264 // bytes, so we have to see if we have a pipe first. We
265 // don't touch the errno for anything else.
266 HANDLE h = (HANDLE)_get_osfhandle(fh);
267 if (GetFileType(h) == FILE_TYPE_PIPE) {
269 if (GetNamedPipeHandleState(
270 h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
271 if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {