Support read and write from blocking and non-blocking pipes and sockets
[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 #include <folly/portability/Unistd.h>
18
19 #ifdef _WIN32
20 #include <cstdio>
21 #include <fcntl.h>
22 #include <folly/portability/Sockets.h>
23 #include <folly/portability/Windows.h>
24
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) {
30     return -1;
31   }
32   if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
33     return -1;
34   }
35
36   int res = (int)f(fd, args...);
37
38   int curErrNo = errno;
39   if (lseek(fd, origLoc, SEEK_SET) == (off_t)-1) {
40     if (res == -1) {
41       errno = curErrNo;
42     }
43     return -1;
44   }
45   errno = curErrNo;
46
47   return res;
48 }
49
50 namespace folly {
51 namespace portability {
52 namespace unistd {
53 int access(char const* fn, int am) { return _access(fn, am); }
54
55 int chdir(const char* path) { return _chdir(path); }
56
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);
59 int close(int fh) {
60   if (folly::portability::sockets::is_fh_socket(fh)) {
61     SOCKET h = (SOCKET)_get_osfhandle(fh);
62
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);
73     _free_osfhnd(fh);
74     return c;
75   }
76   return _close(fh);
77 }
78
79 int dup(int fh) { return _dup(fh); }
80
81 int dup2(int fhs, int fhd) { return _dup2(fhs, fhd); }
82
83 int fsync(int fd) {
84   HANDLE h = (HANDLE)_get_osfhandle(fd);
85   if (h == INVALID_HANDLE_VALUE) {
86     return -1;
87   }
88   if (!FlushFileBuffers(h)) {
89     return -1;
90   }
91   return 0;
92 }
93
94 int ftruncate(int fd, off_t len) {
95   if (_lseek(fd, len, SEEK_SET)) {
96     return -1;
97   }
98
99   HANDLE h = (HANDLE)_get_osfhandle(fd);
100   if (h == INVALID_HANDLE_VALUE) {
101     return -1;
102   }
103   if (!SetEndOfFile(h)) {
104     return -1;
105   }
106   return 0;
107 }
108
109 char* getcwd(char* buf, int sz) { return _getcwd(buf, sz); }
110
111 int getdtablesize() { return _getmaxstdio(); }
112
113 int getgid() { return 1; }
114
115 pid_t getpid() { return pid_t(GetCurrentProcessId()); }
116
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; }
120
121 int getuid() { return 1; }
122
123 int isatty(int fh) { return _isatty(fh); }
124
125 int lockf(int fd, int cmd, off_t len) { return _locking(fd, cmd, len); }
126
127 long lseek(int fh, long off, int orig) { return _lseek(fh, off, orig); }
128
129 int rmdir(const char* path) { return _rmdir(path); }
130
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);
135 }
136
137 int pread(int fd, void* buf, size_t count, off_t offset) {
138   return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
139 }
140
141 int pwrite(int fd, const void* buf, size_t count, off_t offset) {
142   return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
143 }
144
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) {
151         errno = EAGAIN;
152       }
153       return r;
154     }
155   }
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.
161     errno = EAGAIN;
162   }
163   return r;
164 }
165
166 ssize_t readlink(const char* path, char* buf, size_t buflen) {
167   if (!buflen) {
168     return -1;
169   }
170
171   HANDLE h = CreateFile(path,
172                         GENERIC_READ,
173                         FILE_SHARE_READ,
174                         nullptr,
175                         OPEN_EXISTING,
176                         FILE_FLAG_BACKUP_SEMANTICS,
177                         nullptr);
178   if (h == INVALID_HANDLE_VALUE) {
179     return -1;
180   }
181
182   DWORD ret = GetFinalPathNameByHandleA(h, buf, buflen - 1, VOLUME_NAME_DOS);
183   if (ret >= buflen || ret >= MAX_PATH || !ret) {
184     CloseHandle(h);
185     return -1;
186   }
187
188   CloseHandle(h);
189   buf[ret] = '\0';
190   return ret;
191 }
192
193 void* sbrk(intptr_t i) { return (void*)-1; }
194
195 int setmode(int fh, int md) { return _setmode(fh, md); }
196
197 unsigned int sleep(unsigned int seconds) {
198   Sleep((DWORD)(seconds * 1000));
199   return 0;
200 }
201
202 size_t sysconf(int tp) {
203   switch (tp) {
204     case _SC_PAGESIZE: {
205       SYSTEM_INFO inf;
206       GetSystemInfo(&inf);
207       return (size_t)inf.dwPageSize;
208     }
209     case _SC_NPROCESSORS_ONLN: {
210       SYSTEM_INFO inf;
211       GetSystemInfo(&inf);
212       return (size_t)inf.dwNumberOfProcessors;
213     }
214     default:
215       return (size_t)-1;
216   }
217 }
218
219 long tell(int fh) { return _tell(fh); }
220
221 int truncate(const char* path, off_t len) {
222   int fd = _open(path, O_WRONLY);
223   if (!fd) {
224     return -1;
225   }
226   if (ftruncate(fd, len)) {
227     _close(fd);
228     return -1;
229   }
230   return _close(fd) ? -1 : 0;
231 }
232
233 int usleep(unsigned int ms) {
234   Sleep((DWORD)(ms / 1000));
235   return 0;
236 }
237
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) {
244         errno = EAGAIN;
245       }
246       return r;
247     }
248   }
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) {
257       DWORD state = 0;
258       if (GetNamedPipeHandleState(
259               h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
260         if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {
261           errno = EAGAIN;
262           return -1;
263         }
264       }
265     }
266   }
267   return r;
268 }
269 }
270 }
271 }
272 #endif