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 // We aren't hooking into the internals of the CRT, nope, not at all.
58 extern "C" int __cdecl _free_osfhnd(int const fh);
60 if (folly::portability::sockets::is_fh_socket(fh)) {
61 SOCKET h = (SOCKET)_get_osfhandle(fh);
63 // If we were to just call _close on the descriptor, it would
64 // close the HANDLE, but it wouldn't free any of the resources
65 // associated to the SOCKET, and we can't call _close after
66 // calling closesocket, because closesocket has already closed
67 // the HANDLE, and _close would attempt to close the HANDLE
68 // again, resulting in a double free.
69 // Luckily though, there is a function in the internals of the
70 // CRT that is used to free only the file descriptor, so we
71 // can call that to avoid leaking the file descriptor itself.
72 auto c = closesocket(h);
79 int dup(int fh) { return _dup(fh); }
81 int dup2(int fhs, int fhd) { return _dup2(fhs, fhd); }
84 HANDLE h = (HANDLE)_get_osfhandle(fd);
85 if (h == INVALID_HANDLE_VALUE) {
88 if (!FlushFileBuffers(h)) {
94 int ftruncate(int fd, off_t len) {
95 if (_lseek(fd, len, SEEK_SET)) {
99 HANDLE h = (HANDLE)_get_osfhandle(fd);
100 if (h == INVALID_HANDLE_VALUE) {
103 if (!SetEndOfFile(h)) {
109 char* getcwd(char* buf, int sz) { return _getcwd(buf, sz); }
111 int getdtablesize() { return _getmaxstdio(); }
113 int getgid() { return 1; }
115 pid_t getpid() { return pid_t(GetCurrentProcessId()); }
117 // No major need to implement this, and getting a non-potentially
118 // stale ID on windows is a bit involved.
119 pid_t getppid() { return (pid_t)1; }
121 int getuid() { return 1; }
123 int isatty(int fh) { return _isatty(fh); }
125 int lockf(int fd, int cmd, off_t len) { return _locking(fd, cmd, len); }
127 long lseek(int fh, long off, int orig) { return _lseek(fh, off, orig); }
129 int rmdir(const char* path) { return _rmdir(path); }
131 int pipe(int pth[2]) {
132 // We need to be able to listen to pipes with
133 // libevent, so they need to be actual sockets.
134 return socketpair(PF_UNIX, SOCK_STREAM, 0, pth);
137 int pread(int fd, void* buf, size_t count, off_t offset) {
138 return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
141 int pwrite(int fd, const void* buf, size_t count, off_t offset) {
142 return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
145 int read(int fh, void* buf, unsigned int mcc) {
146 if (folly::portability::sockets::is_fh_socket(fh)) {
147 SOCKET s = (SOCKET)_get_osfhandle(fh);
148 if (s != INVALID_SOCKET) {
149 auto r = folly::portability::sockets::recv(fh, buf, (size_t)mcc, 0);
150 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
156 auto r = _read(fh, buf, mcc);
157 if (r == -1 && GetLastError() == ERROR_NO_DATA) {
158 // This only happens if the file was non-blocking and
159 // no data was present. We have to translate the error
160 // to a form that the rest of the world is expecting.
166 ssize_t readlink(const char* path, char* buf, size_t buflen) {
171 HANDLE h = CreateFile(path,
176 FILE_FLAG_BACKUP_SEMANTICS,
178 if (h == INVALID_HANDLE_VALUE) {
182 DWORD ret = GetFinalPathNameByHandleA(h, buf, buflen - 1, VOLUME_NAME_DOS);
183 if (ret >= buflen || ret >= MAX_PATH || !ret) {
193 void* sbrk(intptr_t i) { return (void*)-1; }
195 int setmode(int fh, int md) { return _setmode(fh, md); }
197 unsigned int sleep(unsigned int seconds) {
198 Sleep((DWORD)(seconds * 1000));
202 size_t sysconf(int tp) {
207 return (size_t)inf.dwPageSize;
209 case _SC_NPROCESSORS_ONLN: {
212 return (size_t)inf.dwNumberOfProcessors;
219 long tell(int fh) { return _tell(fh); }
221 int truncate(const char* path, off_t len) {
222 int fd = _open(path, O_WRONLY);
226 if (ftruncate(fd, len)) {
230 return _close(fd) ? -1 : 0;
233 int usleep(unsigned int ms) {
234 Sleep((DWORD)(ms / 1000));
238 int write(int fh, void const* buf, unsigned int count) {
239 if (folly::portability::sockets::is_fh_socket(fh)) {
240 SOCKET s = (SOCKET)_get_osfhandle(fh);
241 if (s != INVALID_SOCKET) {
242 auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0);
243 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
249 auto r = _write(fh, buf, count);
250 if ((r > 0 && r != count) || (r == -1 && errno == ENOSPC)) {
251 // Writing to a pipe with a full buffer doesn't generate
252 // any error type, unless it caused us to write exactly 0
253 // bytes, so we have to see if we have a pipe first. We
254 // don't touch the errno for anything else.
255 HANDLE h = (HANDLE)_get_osfhandle(fh);
256 if (GetFileType(h) == FILE_TYPE_PIPE) {
258 if (GetNamedPipeHandleState(
259 h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
260 if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {