33a8f7a4ec9db165427e960c106a3e72bbcaf461
[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 int close(int fh) {
58   if (folly::portability::sockets::is_fh_socket(fh)) {
59     SOCKET h = (SOCKET)_get_osfhandle(fh);
60     return closesocket(h);
61   }
62   return _close(fh);
63 }
64
65 int dup(int fh) { return _dup(fh); }
66
67 int dup2(int fhs, int fhd) { return _dup2(fhs, fhd); }
68
69 int fsync(int fd) {
70   HANDLE h = (HANDLE)_get_osfhandle(fd);
71   if (h == INVALID_HANDLE_VALUE) {
72     return -1;
73   }
74   if (!FlushFileBuffers(h)) {
75     return -1;
76   }
77   return 0;
78 }
79
80 int ftruncate(int fd, off_t len) {
81   if (_lseek(fd, len, SEEK_SET)) {
82     return -1;
83   }
84
85   HANDLE h = (HANDLE)_get_osfhandle(fd);
86   if (h == INVALID_HANDLE_VALUE) {
87     return -1;
88   }
89   if (!SetEndOfFile(h)) {
90     return -1;
91   }
92   return 0;
93 }
94
95 char* getcwd(char* buf, int sz) { return _getcwd(buf, sz); }
96
97 int getdtablesize() { return _getmaxstdio(); }
98
99 int getgid() { return 1; }
100
101 pid_t getpid() { return pid_t(GetCurrentProcessId()); }
102
103 // No major need to implement this, and getting a non-potentially
104 // stale ID on windows is a bit involved.
105 pid_t getppid() { return (pid_t)1; }
106
107 int getuid() { return 1; }
108
109 int isatty(int fh) { return _isatty(fh); }
110
111 int lockf(int fd, int cmd, off_t len) { return _locking(fd, cmd, len); }
112
113 long lseek(int fh, long off, int orig) { return _lseek(fh, off, orig); }
114
115 int rmdir(const char* path) { return _rmdir(path); }
116
117 int pipe(int* pth) { return _pipe(pth, 0, _O_BINARY); }
118
119 int pread(int fd, void* buf, size_t count, off_t offset) {
120   return wrapPositional(_read, fd, offset, buf, (unsigned int)count);
121 }
122
123 int pwrite(int fd, const void* buf, size_t count, off_t offset) {
124   return wrapPositional(_write, fd, offset, buf, (unsigned int)count);
125 }
126
127 int read(int fh, void* buf, unsigned int mcc) { return _read(fh, buf, mcc); }
128
129 ssize_t readlink(const char* path, char* buf, size_t buflen) {
130   if (!buflen) {
131     return -1;
132   }
133
134   HANDLE h = CreateFile(path,
135                         GENERIC_READ,
136                         FILE_SHARE_READ,
137                         nullptr,
138                         OPEN_EXISTING,
139                         FILE_FLAG_BACKUP_SEMANTICS,
140                         nullptr);
141   if (h == INVALID_HANDLE_VALUE) {
142     return -1;
143   }
144
145   DWORD ret = GetFinalPathNameByHandleA(h, buf, buflen - 1, VOLUME_NAME_DOS);
146   if (ret >= buflen || ret >= MAX_PATH || !ret) {
147     CloseHandle(h);
148     return -1;
149   }
150
151   CloseHandle(h);
152   buf[ret] = '\0';
153   return ret;
154 }
155
156 void* sbrk(intptr_t i) { return (void*)-1; }
157
158 int setmode(int fh, int md) { return _setmode(fh, md); }
159
160 unsigned int sleep(unsigned int seconds) {
161   Sleep((DWORD)(seconds * 1000));
162   return 0;
163 }
164
165 size_t sysconf(int tp) {
166   switch (tp) {
167     case _SC_PAGESIZE: {
168       SYSTEM_INFO inf;
169       GetSystemInfo(&inf);
170       return (size_t)inf.dwPageSize;
171     }
172     case _SC_NPROCESSORS_ONLN: {
173       SYSTEM_INFO inf;
174       GetSystemInfo(&inf);
175       return (size_t)inf.dwNumberOfProcessors;
176     }
177     default:
178       return (size_t)-1;
179   }
180 }
181
182 long tell(int fh) { return _tell(fh); }
183
184 int truncate(const char* path, off_t len) {
185   int fd = _open(path, O_WRONLY);
186   if (!fd) {
187     return -1;
188   }
189   if (ftruncate(fd, len)) {
190     _close(fd);
191     return -1;
192   }
193   return _close(fd) ? -1 : 0;
194 }
195
196 int usleep(unsigned int ms) {
197   Sleep((DWORD)(ms / 1000));
198   return 0;
199 }
200
201 int write(int fh, void const* buf, unsigned int mcc) {
202   return _write(fh, buf, mcc);
203 }
204 }
205 }
206 }
207 #endif