Don't try to call _free_osfhnd when not compiling agains the static CRT
[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 #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);
60 #endif
61 int close(int fh) {
62   if (folly::portability::sockets::is_fh_socket(fh)) {
63     SOCKET h = (SOCKET)_get_osfhandle(fh);
64
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.
74     //
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!
83     _free_osfhnd(fh);
84 #endif
85     return c;
86   }
87   return _close(fh);
88 }
89
90 int dup(int fh) { return _dup(fh); }
91
92 int dup2(int fhs, int fhd) { return _dup2(fhs, fhd); }
93
94 int fsync(int fd) {
95   HANDLE h = (HANDLE)_get_osfhandle(fd);
96   if (h == INVALID_HANDLE_VALUE) {
97     return -1;
98   }
99   if (!FlushFileBuffers(h)) {
100     return -1;
101   }
102   return 0;
103 }
104
105 int ftruncate(int fd, off_t len) {
106   if (_lseek(fd, len, SEEK_SET) == -1) {
107     return -1;
108   }
109
110   HANDLE h = (HANDLE)_get_osfhandle(fd);
111   if (h == INVALID_HANDLE_VALUE) {
112     return -1;
113   }
114   if (!SetEndOfFile(h)) {
115     return -1;
116   }
117   return 0;
118 }
119
120 char* getcwd(char* buf, int sz) { return _getcwd(buf, sz); }
121
122 int getdtablesize() { return _getmaxstdio(); }
123
124 int getgid() { return 1; }
125
126 pid_t getpid() { return pid_t(GetCurrentProcessId()); }
127
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; }
131
132 int getuid() { return 1; }
133
134 int isatty(int fh) { return _isatty(fh); }
135
136 int lockf(int fd, int cmd, off_t len) { return _locking(fd, cmd, len); }
137
138 long lseek(int fh, long off, int orig) { return _lseek(fh, off, orig); }
139
140 int rmdir(const char* path) { return _rmdir(path); }
141
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);
146 }
147
148 int pread(int fd, void* buf, size_t count, off_t offset) {
149   return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
150 }
151
152 int pwrite(int fd, const void* buf, size_t count, off_t offset) {
153   return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
154 }
155
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) {
162         errno = EAGAIN;
163       }
164       return r;
165     }
166   }
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.
172     errno = EAGAIN;
173   }
174   return r;
175 }
176
177 ssize_t readlink(const char* path, char* buf, size_t buflen) {
178   if (!buflen) {
179     return -1;
180   }
181
182   HANDLE h = CreateFile(path,
183                         GENERIC_READ,
184                         FILE_SHARE_READ,
185                         nullptr,
186                         OPEN_EXISTING,
187                         FILE_FLAG_BACKUP_SEMANTICS,
188                         nullptr);
189   if (h == INVALID_HANDLE_VALUE) {
190     return -1;
191   }
192
193   DWORD ret = GetFinalPathNameByHandleA(h, buf, buflen - 1, VOLUME_NAME_DOS);
194   if (ret >= buflen || ret >= MAX_PATH || !ret) {
195     CloseHandle(h);
196     return -1;
197   }
198
199   CloseHandle(h);
200   buf[ret] = '\0';
201   return ret;
202 }
203
204 void* sbrk(intptr_t i) { return (void*)-1; }
205
206 int setmode(int fh, int md) { return _setmode(fh, md); }
207
208 unsigned int sleep(unsigned int seconds) {
209   Sleep((DWORD)(seconds * 1000));
210   return 0;
211 }
212
213 size_t sysconf(int tp) {
214   switch (tp) {
215     case _SC_PAGESIZE: {
216       SYSTEM_INFO inf;
217       GetSystemInfo(&inf);
218       return (size_t)inf.dwPageSize;
219     }
220     case _SC_NPROCESSORS_ONLN: {
221       SYSTEM_INFO inf;
222       GetSystemInfo(&inf);
223       return (size_t)inf.dwNumberOfProcessors;
224     }
225     default:
226       return (size_t)-1;
227   }
228 }
229
230 long tell(int fh) { return _tell(fh); }
231
232 int truncate(const char* path, off_t len) {
233   int fd = _open(path, O_WRONLY);
234   if (!fd) {
235     return -1;
236   }
237   if (ftruncate(fd, len)) {
238     _close(fd);
239     return -1;
240   }
241   return _close(fd) ? -1 : 0;
242 }
243
244 int usleep(unsigned int ms) {
245   Sleep((DWORD)(ms / 1000));
246   return 0;
247 }
248
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) {
255         errno = EAGAIN;
256       }
257       return r;
258     }
259   }
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) {
268       DWORD state = 0;
269       if (GetNamedPipeHandleState(
270               h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
271         if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {
272           errno = EAGAIN;
273           return -1;
274         }
275       }
276     }
277   }
278   return r;
279 }
280 }
281 }
282 }
283 #endif