1/*
2 * Copyright 2016-present 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// 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
20
21#include <folly/portability/Unistd.h>
22
23#ifdef _WIN32
24
25#include <cstdio>
26
27#include <fcntl.h>
28
29#include <folly/net/detail/SocketFileDescriptorMap.h>
30#include <folly/portability/Sockets.h>
31#include <folly/portability/Windows.h>
32
33// Generic wrapper for the p* family of functions.
34template <class F, class... Args>
35static int wrapPositional(F f, int fd, off_t offset, Args... args) {
36 off_t origLoc = lseek(fd, 0, SEEK_CUR);
37 if (origLoc == (off_t)-1) {
38 return -1;
39 }
40 if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
41 return -1;
42 }
43
44 int res = (int)f(fd, args...);
45
46 int curErrNo = errno;
47 if (lseek(fd, origLoc, SEEK_SET) == (off_t)-1) {
48 if (res == -1) {
49 errno = curErrNo;
50 }
51 return -1;
52 }
53 errno = curErrNo;
54
55 return res;
56}
57
58namespace folly {
59namespace portability {
60namespace unistd {
61int access(char const* fn, int am) {
62 return _access(fn, am);
63}
64
65int chdir(const char* path) {
66 return _chdir(path);
67}
68
69int close(int fh) {
70 if (folly::portability::sockets::is_fh_socket(fh)) {
71 return netops::detail::SocketFileDescriptorMap::close(fh);
72 }
73 return _close(fh);
74}
75
76int dup(int fh) {
77 return _dup(fh);
78}
79
80int dup2(int fhs, int fhd) {
81 return _dup2(fhs, fhd);
82}
83
84int fsync(int fd) {
85 HANDLE h = (HANDLE)_get_osfhandle(fd);
86 if (h == INVALID_HANDLE_VALUE) {
87 return -1;
88 }
89 if (!FlushFileBuffers(h)) {
90 return -1;
91 }
92 return 0;
93}
94
95int ftruncate(int fd, off_t len) {
96 if (_lseek(fd, len, SEEK_SET) == -1) {
97 return -1;
98 }
99
100 HANDLE h = (HANDLE)_get_osfhandle(fd);
101 if (h == INVALID_HANDLE_VALUE) {
102 return -1;
103 }
104 if (!SetEndOfFile(h)) {
105 return -1;
106 }
107 return 0;
108}
109
110char* getcwd(char* buf, int sz) {
111 return _getcwd(buf, sz);
112}
113
114int getdtablesize() {
115 return _getmaxstdio();
116}
117
118int getgid() {
119 return 1;
120}
121
122pid_t getpid() {
123 return (pid_t)uint64_t(GetCurrentProcessId());
124}
125
126// No major need to implement this, and getting a non-potentially
127// stale ID on windows is a bit involved.
128pid_t getppid() {
129 return (pid_t)1;
130}
131
132int getuid() {
133 return 1;
134}
135
136int isatty(int fh) {
137 return _isatty(fh);
138}
139
140int lockf(int fd, int cmd, off_t len) {
141 return _locking(fd, cmd, len);
142}
143
144off_t lseek(int fh, off_t off, int orig) {
145 return _lseek(fh, off, orig);
146}
147
148int rmdir(const char* path) {
149 return _rmdir(path);
150}
151
152int pipe(int pth[2]) {
153 // We need to be able to listen to pipes with
154 // libevent, so they need to be actual sockets.
155 return socketpair(PF_UNIX, SOCK_STREAM, 0, pth);
156}
157
158ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
159 return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
160}
161
162ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
163 return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
164}
165
166ssize_t read(int fh, void* buf, size_t count) {
167 if (folly::portability::sockets::is_fh_socket(fh)) {
168 SOCKET s = (SOCKET)_get_osfhandle(fh);
169 if (s != INVALID_SOCKET) {
170 auto r = folly::portability::sockets::recv(fh, buf, count, 0);
171 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
172 errno = EAGAIN;
173 }
174 return r;
175 }
176 }
177 auto r = _read(fh, buf, static_cast<unsigned int>(count));
178 if (r == -1 && GetLastError() == ERROR_NO_DATA) {
179 // This only happens if the file was non-blocking and
180 // no data was present. We have to translate the error
181 // to a form that the rest of the world is expecting.
182 errno = EAGAIN;
183 }
184 return r;
185}
186
187ssize_t readlink(const char* path, char* buf, size_t buflen) {
188 if (!buflen) {
189 return -1;
190 }
191
192 HANDLE h = CreateFileA(
193 path,
194 GENERIC_READ,
195 FILE_SHARE_READ,
196 nullptr,
197 OPEN_EXISTING,
198 FILE_FLAG_BACKUP_SEMANTICS,
199 nullptr);
200 if (h == INVALID_HANDLE_VALUE) {
201 return -1;
202 }
203
204 DWORD ret =
205 GetFinalPathNameByHandleA(h, buf, DWORD(buflen - 1), VOLUME_NAME_DOS);
206 if (ret >= buflen || ret >= MAX_PATH || !ret) {
207 CloseHandle(h);
208 return -1;
209 }
210
211 CloseHandle(h);
212 buf[ret] = '\0';
213 return ret;
214}
215
216void* sbrk(intptr_t /* i */) {
217 return (void*)-1;
218}
219
220unsigned int sleep(unsigned int seconds) {
221 Sleep((DWORD)(seconds * 1000));
222 return 0;
223}
224
225long sysconf(int tp) {
226 switch (tp) {
227 case _SC_PAGESIZE: {
228 SYSTEM_INFO inf;
229 GetSystemInfo(&inf);
230 return (long)inf.dwPageSize;
231 }
232 case _SC_NPROCESSORS_ONLN: {
233 SYSTEM_INFO inf;
234 GetSystemInfo(&inf);
235 return (long)inf.dwNumberOfProcessors;
236 }
237 default:
238 return -1L;
239 }
240}
241
242int truncate(const char* path, off_t len) {
243 int fd = _open(path, O_WRONLY);
244 if (!fd) {
245 return -1;
246 }
247 if (ftruncate(fd, len)) {
248 _close(fd);
249 return -1;
250 }
251 return _close(fd) ? -1 : 0;
252}
253
254int usleep(unsigned int ms) {
255 Sleep((DWORD)(ms / 1000));
256 return 0;
257}
258
259ssize_t write(int fh, void const* buf, size_t count) {
260 if (folly::portability::sockets::is_fh_socket(fh)) {
261 SOCKET s = (SOCKET)_get_osfhandle(fh);
262 if (s != INVALID_SOCKET) {
263 auto r = folly::portability::sockets::send(fh, buf, (size_t)count, 0);
264 if (r == -1 && WSAGetLastError() == WSAEWOULDBLOCK) {
265 errno = EAGAIN;
266 }
267 return r;
268 }
269 }
270 auto r = _write(fh, buf, static_cast<unsigned int>(count));
271 if ((r > 0 && size_t(r) != count) || (r == -1 && errno == ENOSPC)) {
272 // Writing to a pipe with a full buffer doesn't generate
273 // any error type, unless it caused us to write exactly 0
274 // bytes, so we have to see if we have a pipe first. We
275 // don't touch the errno for anything else.
276 HANDLE h = (HANDLE)_get_osfhandle(fh);
277 if (GetFileType(h) == FILE_TYPE_PIPE) {
278 DWORD state = 0;
279 if (GetNamedPipeHandleState(
280 h, &state, nullptr, nullptr, nullptr, nullptr, 0)) {
281 if ((state & PIPE_NOWAIT) == PIPE_NOWAIT) {
282 errno = EAGAIN;
283 return -1;
284 }
285 }
286 }
287 }
288 return r;
289}
290} // namespace unistd
291} // namespace portability
292} // namespace folly
293
294#endif
295