1 // ----------------------------------------------------------------------------
2 // mingw.c
3 //
4 // The following routines were copied from git-1.6.1.2/compat/mingw.c:
5 // git_vsnprintf git_snprintf sleep mingw_getcwd mingw_getenv mingw_rename
6 //
7 // The uname routine was adapted from libgw32c 0.4.
8 //
9 // The rest:
10 // Copyright (C) 2009
11 // Stelios Bounanos, M0GLD
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 2014
14 // David Freese, W1HKJ
15 //
16 // This file is part of flmsg
17 //
18 // flrig is free software; you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation; either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 // flrig is distributed in the hope that it will be useful,
24 // but WITHOUT ANY WARRANTY; without even the implied warranty of
25 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 // GNU General Public License for more details.
27 //
28 // You should have received a copy of the GNU General Public License
29 // along with this program. If not, see <http://www.gnu.org/licenses/>.
30 // ----------------------------------------------------------------------------
31
32 #include <config.h>
33
34 #include <ctype.h>
35 #include "compat.h"
36
37 /* default mode for stdin, stdout and stderr */
38 unsigned int _CRT_fmode = _O_BINARY;
39
40 /******************************************************************************/
41
42 /*
43 * The size parameter specifies the available space, i.e. includes
44 * the trailing NUL byte; but Windows's vsnprintf expects the
45 * number of characters to write without the trailing NUL.
46 */
47 #define SNPRINTF_SIZE_CORR 1
48
49 #undef vsnprintf
git_vsnprintf(char * str,size_t maxsize,const char * format,va_list ap)50 int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
51 {
52 char *s;
53 int ret = -1;
54
55 if (maxsize > 0) {
56 ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
57 if (ret == maxsize-1)
58 ret = -1;
59 /* Windows does not NUL-terminate if result fills buffer */
60 str[maxsize-1] = 0;
61 }
62 if (ret != -1)
63 return ret;
64
65 s = NULL;
66 if (maxsize < 128)
67 maxsize = 128;
68
69 while (ret == -1) {
70 maxsize *= 4;
71 str = realloc(s, maxsize);
72 if (! str)
73 break;
74 s = str;
75 ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
76 if (ret == maxsize-1)
77 ret = -1;
78 }
79 free(s);
80 return ret;
81 }
82
git_snprintf(char * str,size_t maxsize,const char * format,...)83 int git_snprintf(char *str, size_t maxsize, const char *format, ...)
84 {
85 va_list ap;
86 int ret;
87
88 va_start(ap, format);
89 ret = git_vsnprintf(str, maxsize, format, ap);
90 va_end(ap);
91
92 return ret;
93 }
94
sleep(unsigned seconds)95 unsigned sleep(unsigned seconds)
96 {
97 Sleep(seconds*1000);
98 return 0;
99 }
100
101 #undef getcwd
mingw_getcwd(char * pointer,int len)102 char *mingw_getcwd(char *pointer, int len)
103 {
104 int i;
105 char *ret = getcwd(pointer, len);
106 if (!ret)
107 return ret;
108 for (i = 0; pointer[i]; i++)
109 if (pointer[i] == '\\')
110 pointer[i] = '/';
111 return ret;
112 }
113
114 #undef getenv
mingw_getenv(const char * name)115 char *mingw_getenv(const char *name)
116 {
117 char *result = getenv(name);
118 if (!result && !strcmp(name, "TMPDIR")) {
119 /* on Windows it is TMP and TEMP */
120 result = getenv("TMP");
121 if (!result)
122 result = getenv("TEMP");
123 }
124 return result;
125 }
126
127 #undef rename
mingw_rename(const char * pold,const char * pnew)128 int mingw_rename(const char *pold, const char *pnew)
129 {
130 DWORD attrs;
131
132 /*
133 * Try native rename() first to get errno right.
134 * It is based on MoveFile(), which cannot overwrite existing files.
135 */
136 if (!rename(pold, pnew))
137 return 0;
138 if (errno != EEXIST)
139 return -1;
140 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
141 return 0;
142 /* TODO: translate more errors */
143 if (GetLastError() == ERROR_ACCESS_DENIED &&
144 (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
145 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
146 errno = EISDIR;
147 return -1;
148 }
149 if ((attrs & FILE_ATTRIBUTE_READONLY) &&
150 SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
151 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
152 return 0;
153 /* revert file attributes on failure */
154 SetFileAttributes(pnew, attrs);
155 }
156 }
157 errno = EACCES;
158 return -1;
159 }
160
161 /******************************************************************************/
162
163 __attribute__((constructor))
wsa_init(void)164 static void wsa_init(void)
165 {
166 WSADATA wsa;
167
168 static int wsa_init_ = 0;
169 if (wsa_init_)
170 return;
171
172 if (WSAStartup(MAKEWORD(2, 2), &wsa)) {
173 fprintf(stderr, "unable to initialize winsock: error %d", WSAGetLastError());
174 exit(EXIT_FAILURE);
175 }
176 atexit((void(*)(void)) WSACleanup);
177 wsa_init_ = 1;
178 }
179
socketpair(int family,int type,int protocol,int * sv)180 int socketpair(int family, int type, int protocol, int *sv)
181 {
182 struct sockaddr_in addr;
183 SOCKET sfd;
184 int err, len = sizeof(addr);
185
186 if (sv == NULL || family != AF_INET || type != SOCK_STREAM || protocol) {
187 WSASetLastError(WSAEINVAL);
188 return SOCKET_ERROR;
189 }
190
191 sv[0] = sv[1] = INVALID_SOCKET;
192 if ((sfd = socket(family, type, 0)) == INVALID_SOCKET)
193 return SOCKET_ERROR;
194
195 memset(&addr, 0, sizeof(addr));
196 addr.sin_family = family;
197 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
198 addr.sin_port = 0; /* any port */
199
200 if ((err = bind(sfd, (const struct sockaddr*)&addr, sizeof(addr))) == SOCKET_ERROR) {
201 err = WSAGetLastError();
202 closesocket(sfd);
203 WSASetLastError(err);
204 return SOCKET_ERROR;
205 }
206
207 if ((err = getsockname(sfd, (struct sockaddr*)&addr, &len)) == SOCKET_ERROR) {
208 err = WSAGetLastError();
209 closesocket(sfd);
210 WSASetLastError(err);
211 return SOCKET_ERROR;
212 }
213
214 do {
215 if (listen(sfd, 1) == SOCKET_ERROR)
216 break;
217 if ((sv[0] = WSASocket(family, type, 0, NULL, 0, 0)) == INVALID_SOCKET)
218 break;
219 if (connect(sv[0], (const struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
220 break;
221 if ((sv[1] = accept(sfd, NULL, NULL)) == INVALID_SOCKET)
222 break;
223 closesocket(sfd);
224 return 0;
225 } while (0);
226
227 /* error */
228 err = WSAGetLastError();
229 closesocket(sfd);
230 closesocket(sv[0]);
231 closesocket(sv[1]);
232 WSASetLastError(err);
233 return SOCKET_ERROR;
234 }
235
236 /******************************************************************************/
237
nanosleep(const struct timespec * req,struct timespec * rem)238 int nanosleep(const struct timespec *req, struct timespec *rem)
239 {
240 if (req->tv_nsec < 0 || req->tv_nsec < 0L || req->tv_nsec > 999999999L) {
241 errno = EINVAL;
242 return -1;
243 }
244 Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000L);
245 if (rem) {
246 rem->tv_sec = 0;
247 rem->tv_nsec = 0L;
248 }
249 return 0;
250 }
251
252 BOOL GetOsInfo(LPSTR OsName, LPSTR Release, LPSTR Version);
253 BOOL GetMachInfo(LPSTR MachineName, LPSTR ProcessorName);
uname(struct utsname * name)254 int uname(struct utsname *name)
255 {
256 char processor[1024];
257
258 if (name == NULL) {
259 errno = EINVAL;
260 return -1;
261 }
262
263 if (gethostname(name->nodename, sizeof(name->nodename)) < 0) {
264 name->nodename[0] = '\0';
265 errno = ENOSYS;
266 return -1;
267 }
268
269 if (!GetOsInfo(name->sysname, name->release, name->version)) {
270 strncpy (name->sysname, "win32", sizeof (name->sysname));
271 strncpy (name->release, "unknown", sizeof (name->release));
272 strncpy (name->version, "unknown", sizeof (name->version));
273 }
274 /* "windows32" is as yet the only universal windows description allowed
275 by config.guess and config.sub */
276 strncpy(name->sysname, "windows32", sizeof (name->sysname));
277 if (!GetMachInfo(name->machine, processor))
278 strncpy(name->machine, "i386", sizeof (name->machine));
279
280 return 0;
281 }
282
getrusage(int who,struct rusage * usage)283 int getrusage(int who, struct rusage *usage)
284 {
285 FILETIME ct, et, kt, ut;
286 ULARGE_INTEGER uli;
287
288 if (who != RUSAGE_SELF) {
289 errno = EINVAL;
290 return -1;
291 }
292 if (!usage) {
293 errno = EFAULT;
294 return -1;
295 }
296
297 if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
298 errno = ENOENT;
299 return -1;
300 }
301
302 // FILETIMEs use 100-ns units
303 memcpy(&uli, &kt, sizeof(FILETIME));
304 usage->ru_stime.tv_sec = uli.QuadPart / 10000000L;
305 usage->ru_stime.tv_usec = uli.QuadPart % 10000000L;
306 memcpy(&uli, &ut, sizeof(FILETIME));
307 usage->ru_utime.tv_sec = uli.QuadPart / 10000000L;
308 usage->ru_utime.tv_usec = uli.QuadPart % 10000000L;
309
310 return 0;
311 }
312