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