git

Форк
0
/
mingw.c 
3184 строки · 81.4 Кб
1
#include "../git-compat-util.h"
2
#include "win32.h"
3
#include <aclapi.h>
4
#include <sddl.h>
5
#include <conio.h>
6
#include <wchar.h>
7
#include "../strbuf.h"
8
#include "../run-command.h"
9
#include "../abspath.h"
10
#include "../alloc.h"
11
#include "win32/lazyload.h"
12
#include "../config.h"
13
#include "../environment.h"
14
#include "../trace2.h"
15
#include "../symlinks.h"
16
#include "../wrapper.h"
17
#include "dir.h"
18
#include "gettext.h"
19
#define SECURITY_WIN32
20
#include <sspi.h>
21

22
#define HCAST(type, handle) ((type)(intptr_t)handle)
23

24
static const int delay[] = { 0, 1, 10, 20, 40 };
25

26
void open_in_gdb(void)
27
{
28
	static struct child_process cp = CHILD_PROCESS_INIT;
29

30
	strvec_pushl(&cp.args, "mintty", "gdb", NULL);
31
	strvec_pushf(&cp.args, "--pid=%d", getpid());
32
	cp.clean_on_exit = 1;
33
	if (start_command(&cp) < 0)
34
		die_errno("Could not start gdb");
35
	sleep(1);
36
}
37

38
int err_win_to_posix(DWORD winerr)
39
{
40
	int error = ENOSYS;
41
	switch(winerr) {
42
	case ERROR_ACCESS_DENIED: error = EACCES; break;
43
	case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
44
	case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
45
	case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
46
	case ERROR_ALREADY_EXISTS: error = EEXIST; break;
47
	case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
48
	case ERROR_BAD_COMMAND: error = EIO; break;
49
	case ERROR_BAD_DEVICE: error = ENODEV; break;
50
	case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
51
	case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
52
	case ERROR_BAD_FORMAT: error = ENOEXEC; break;
53
	case ERROR_BAD_LENGTH: error = EINVAL; break;
54
	case ERROR_BAD_PATHNAME: error = ENOENT; break;
55
	case ERROR_BAD_PIPE: error = EPIPE; break;
56
	case ERROR_BAD_UNIT: error = ENODEV; break;
57
	case ERROR_BAD_USERNAME: error = EINVAL; break;
58
	case ERROR_BROKEN_PIPE: error = EPIPE; break;
59
	case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
60
	case ERROR_BUSY: error = EBUSY; break;
61
	case ERROR_BUSY_DRIVE: error = EBUSY; break;
62
	case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
63
	case ERROR_CANNOT_MAKE: error = EACCES; break;
64
	case ERROR_CANTOPEN: error = EIO; break;
65
	case ERROR_CANTREAD: error = EIO; break;
66
	case ERROR_CANTWRITE: error = EIO; break;
67
	case ERROR_CRC: error = EIO; break;
68
	case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
69
	case ERROR_DEVICE_IN_USE: error = EBUSY; break;
70
	case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
71
	case ERROR_DIRECTORY: error = EINVAL; break;
72
	case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
73
	case ERROR_DISK_CHANGE: error = EIO; break;
74
	case ERROR_DISK_FULL: error = ENOSPC; break;
75
	case ERROR_DRIVE_LOCKED: error = EBUSY; break;
76
	case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
77
	case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
78
	case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
79
	case ERROR_FILE_EXISTS: error = EEXIST; break;
80
	case ERROR_FILE_INVALID: error = ENODEV; break;
81
	case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
82
	case ERROR_GEN_FAILURE: error = EIO; break;
83
	case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
84
	case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
85
	case ERROR_INVALID_ACCESS: error = EACCES; break;
86
	case ERROR_INVALID_ADDRESS: error = EFAULT; break;
87
	case ERROR_INVALID_BLOCK: error = EFAULT; break;
88
	case ERROR_INVALID_DATA: error = EINVAL; break;
89
	case ERROR_INVALID_DRIVE: error = ENODEV; break;
90
	case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
91
	case ERROR_INVALID_FLAGS: error = EINVAL; break;
92
	case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
93
	case ERROR_INVALID_HANDLE: error = EBADF; break;
94
	case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
95
	case ERROR_INVALID_NAME: error = EINVAL; break;
96
	case ERROR_INVALID_OWNER: error = EINVAL; break;
97
	case ERROR_INVALID_PARAMETER: error = EINVAL; break;
98
	case ERROR_INVALID_PASSWORD: error = EPERM; break;
99
	case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
100
	case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
101
	case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
102
	case ERROR_INVALID_WORKSTATION: error = EACCES; break;
103
	case ERROR_IO_DEVICE: error = EIO; break;
104
	case ERROR_IO_INCOMPLETE: error = EINTR; break;
105
	case ERROR_LOCKED: error = EBUSY; break;
106
	case ERROR_LOCK_VIOLATION: error = EACCES; break;
107
	case ERROR_LOGON_FAILURE: error = EACCES; break;
108
	case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
109
	case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
110
	case ERROR_MORE_DATA: error = EPIPE; break;
111
	case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
112
	case ERROR_NOACCESS: error = EFAULT; break;
113
	case ERROR_NONE_MAPPED: error = EINVAL; break;
114
	case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
115
	case ERROR_NOT_READY: error = EAGAIN; break;
116
	case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
117
	case ERROR_NO_DATA: error = EPIPE; break;
118
	case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
119
	case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
120
	case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
121
	case ERROR_OPEN_FAILED: error = EIO; break;
122
	case ERROR_OPEN_FILES: error = EBUSY; break;
123
	case ERROR_OPERATION_ABORTED: error = EINTR; break;
124
	case ERROR_OUTOFMEMORY: error = ENOMEM; break;
125
	case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
126
	case ERROR_PATH_BUSY: error = EBUSY; break;
127
	case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
128
	case ERROR_PIPE_BUSY: error = EBUSY; break;
129
	case ERROR_PIPE_CONNECTED: error = EPIPE; break;
130
	case ERROR_PIPE_LISTENING: error = EPIPE; break;
131
	case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
132
	case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
133
	case ERROR_READ_FAULT: error = EIO; break;
134
	case ERROR_SEEK: error = EIO; break;
135
	case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
136
	case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
137
	case ERROR_SHARING_VIOLATION: error = EACCES; break;
138
	case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
139
	case ERROR_SUCCESS: BUG("err_win_to_posix() called without an error!");
140
	case ERROR_SWAPERROR: error = ENOENT; break;
141
	case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
142
	case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
143
	case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
144
	case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
145
	case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
146
	case ERROR_WRITE_FAULT: error = EIO; break;
147
	case ERROR_WRITE_PROTECT: error = EROFS; break;
148
	}
149
	return error;
150
}
151

152
static inline int is_file_in_use_error(DWORD errcode)
153
{
154
	switch (errcode) {
155
	case ERROR_SHARING_VIOLATION:
156
	case ERROR_ACCESS_DENIED:
157
		return 1;
158
	}
159

160
	return 0;
161
}
162

163
static int read_yes_no_answer(void)
164
{
165
	char answer[1024];
166

167
	if (fgets(answer, sizeof(answer), stdin)) {
168
		size_t answer_len = strlen(answer);
169
		int got_full_line = 0, c;
170

171
		/* remove the newline */
172
		if (answer_len >= 2 && answer[answer_len-2] == '\r') {
173
			answer[answer_len-2] = '\0';
174
			got_full_line = 1;
175
		} else if (answer_len >= 1 && answer[answer_len-1] == '\n') {
176
			answer[answer_len-1] = '\0';
177
			got_full_line = 1;
178
		}
179
		/* flush the buffer in case we did not get the full line */
180
		if (!got_full_line)
181
			while ((c = getchar()) != EOF && c != '\n')
182
				;
183
	} else
184
		/* we could not read, return the
185
		 * default answer which is no */
186
		return 0;
187

188
	if (tolower(answer[0]) == 'y' && !answer[1])
189
		return 1;
190
	if (!strncasecmp(answer, "yes", sizeof(answer)))
191
		return 1;
192
	if (tolower(answer[0]) == 'n' && !answer[1])
193
		return 0;
194
	if (!strncasecmp(answer, "no", sizeof(answer)))
195
		return 0;
196

197
	/* did not find an answer we understand */
198
	return -1;
199
}
200

201
static int ask_yes_no_if_possible(const char *format, ...)
202
{
203
	char question[4096];
204
	const char *retry_hook;
205
	va_list args;
206

207
	va_start(args, format);
208
	vsnprintf(question, sizeof(question), format, args);
209
	va_end(args);
210

211
	retry_hook = mingw_getenv("GIT_ASK_YESNO");
212
	if (retry_hook) {
213
		struct child_process cmd = CHILD_PROCESS_INIT;
214

215
		strvec_pushl(&cmd.args, retry_hook, question, NULL);
216
		return !run_command(&cmd);
217
	}
218

219
	if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr)))
220
		return 0;
221

222
	while (1) {
223
		int answer;
224
		fprintf(stderr, "%s (y/n) ", question);
225

226
		if ((answer = read_yes_no_answer()) >= 0)
227
			return answer;
228

229
		fprintf(stderr, "Sorry, I did not understand your answer. "
230
				"Please type 'y' or 'n'\n");
231
	}
232
}
233

234
/* Windows only */
235
enum hide_dotfiles_type {
236
	HIDE_DOTFILES_FALSE = 0,
237
	HIDE_DOTFILES_TRUE,
238
	HIDE_DOTFILES_DOTGITONLY
239
};
240

241
static int core_restrict_inherited_handles = -1;
242
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
243
static char *unset_environment_variables;
244

245
int mingw_core_config(const char *var, const char *value,
246
		      const struct config_context *ctx, void *cb)
247
{
248
	if (!strcmp(var, "core.hidedotfiles")) {
249
		if (value && !strcasecmp(value, "dotgitonly"))
250
			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
251
		else
252
			hide_dotfiles = git_config_bool(var, value);
253
		return 0;
254
	}
255

256
	if (!strcmp(var, "core.unsetenvvars")) {
257
		if (!value)
258
			return config_error_nonbool(var);
259
		free(unset_environment_variables);
260
		unset_environment_variables = xstrdup(value);
261
		return 0;
262
	}
263

264
	if (!strcmp(var, "core.restrictinheritedhandles")) {
265
		if (value && !strcasecmp(value, "auto"))
266
			core_restrict_inherited_handles = -1;
267
		else
268
			core_restrict_inherited_handles =
269
				git_config_bool(var, value);
270
		return 0;
271
	}
272

273
	return 0;
274
}
275

276
/* Normalizes NT paths as returned by some low-level APIs. */
277
static wchar_t *normalize_ntpath(wchar_t *wbuf)
278
{
279
	int i;
280
	/* fix absolute path prefixes */
281
	if (wbuf[0] == '\\') {
282
		/* strip NT namespace prefixes */
283
		if (!wcsncmp(wbuf, L"\\??\\", 4) ||
284
		    !wcsncmp(wbuf, L"\\\\?\\", 4))
285
			wbuf += 4;
286
		else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12))
287
			wbuf += 12;
288
		/* replace remaining '...UNC\' with '\\' */
289
		if (!wcsnicmp(wbuf, L"UNC\\", 4)) {
290
			wbuf += 2;
291
			*wbuf = '\\';
292
		}
293
	}
294
	/* convert backslashes to slashes */
295
	for (i = 0; wbuf[i]; i++)
296
		if (wbuf[i] == '\\')
297
			wbuf[i] = '/';
298
	return wbuf;
299
}
300

301
int mingw_unlink(const char *pathname)
302
{
303
	int ret, tries = 0;
304
	wchar_t wpathname[MAX_PATH];
305
	if (xutftowcs_path(wpathname, pathname) < 0)
306
		return -1;
307

308
	if (DeleteFileW(wpathname))
309
		return 0;
310

311
	/* read-only files cannot be removed */
312
	_wchmod(wpathname, 0666);
313
	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
314
		if (!is_file_in_use_error(GetLastError()))
315
			break;
316
		/*
317
		 * We assume that some other process had the source or
318
		 * destination file open at the wrong moment and retry.
319
		 * In order to give the other process a higher chance to
320
		 * complete its operation, we give up our time slice now.
321
		 * If we have to retry again, we do sleep a bit.
322
		 */
323
		Sleep(delay[tries]);
324
		tries++;
325
	}
326
	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
327
	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
328
			"Should I try again?", pathname))
329
	       ret = _wunlink(wpathname);
330
	return ret;
331
}
332

333
static int is_dir_empty(const wchar_t *wpath)
334
{
335
	WIN32_FIND_DATAW findbuf;
336
	HANDLE handle;
337
	wchar_t wbuf[MAX_PATH + 2];
338
	wcscpy(wbuf, wpath);
339
	wcscat(wbuf, L"\\*");
340
	handle = FindFirstFileW(wbuf, &findbuf);
341
	if (handle == INVALID_HANDLE_VALUE)
342
		return GetLastError() == ERROR_NO_MORE_FILES;
343

344
	while (!wcscmp(findbuf.cFileName, L".") ||
345
			!wcscmp(findbuf.cFileName, L".."))
346
		if (!FindNextFileW(handle, &findbuf)) {
347
			DWORD err = GetLastError();
348
			FindClose(handle);
349
			return err == ERROR_NO_MORE_FILES;
350
		}
351
	FindClose(handle);
352
	return 0;
353
}
354

355
int mingw_rmdir(const char *pathname)
356
{
357
	int ret, tries = 0;
358
	wchar_t wpathname[MAX_PATH];
359
	struct stat st;
360

361
	/*
362
	 * Contrary to Linux' `rmdir()`, Windows' _wrmdir() and _rmdir()
363
	 * (and `RemoveDirectoryW()`) will attempt to remove the target of a
364
	 * symbolic link (if it points to a directory).
365
	 *
366
	 * This behavior breaks the assumption of e.g. `remove_path()` which
367
	 * upon successful deletion of a file will attempt to remove its parent
368
	 * directories recursively until failure (which usually happens when
369
	 * the directory is not empty).
370
	 *
371
	 * Therefore, before calling `_wrmdir()`, we first check if the path is
372
	 * a symbolic link. If it is, we exit and return the same error as
373
	 * Linux' `rmdir()` would, i.e. `ENOTDIR`.
374
	 */
375
	if (!mingw_lstat(pathname, &st) && S_ISLNK(st.st_mode)) {
376
		errno = ENOTDIR;
377
		return -1;
378
	}
379

380
	if (xutftowcs_path(wpathname, pathname) < 0)
381
		return -1;
382

383
	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
384
		if (!is_file_in_use_error(GetLastError()))
385
			errno = err_win_to_posix(GetLastError());
386
		if (errno != EACCES)
387
			break;
388
		if (!is_dir_empty(wpathname)) {
389
			errno = ENOTEMPTY;
390
			break;
391
		}
392
		/*
393
		 * We assume that some other process had the source or
394
		 * destination file open at the wrong moment and retry.
395
		 * In order to give the other process a higher chance to
396
		 * complete its operation, we give up our time slice now.
397
		 * If we have to retry again, we do sleep a bit.
398
		 */
399
		Sleep(delay[tries]);
400
		tries++;
401
	}
402
	while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) &&
403
	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
404
			"Should I try again?", pathname))
405
	       ret = _wrmdir(wpathname);
406
	if (!ret)
407
		invalidate_lstat_cache();
408
	return ret;
409
}
410

411
static inline int needs_hiding(const char *path)
412
{
413
	const char *basename;
414

415
	if (hide_dotfiles == HIDE_DOTFILES_FALSE)
416
		return 0;
417

418
	/* We cannot use basename(), as it would remove trailing slashes */
419
	win32_skip_dos_drive_prefix((char **)&path);
420
	if (!*path)
421
		return 0;
422

423
	for (basename = path; *path; path++)
424
		if (is_dir_sep(*path)) {
425
			do {
426
				path++;
427
			} while (is_dir_sep(*path));
428
			/* ignore trailing slashes */
429
			if (*path)
430
				basename = path;
431
			else
432
				break;
433
		}
434

435
	if (hide_dotfiles == HIDE_DOTFILES_TRUE)
436
		return *basename == '.';
437

438
	assert(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY);
439
	return !strncasecmp(".git", basename, 4) &&
440
		(!basename[4] || is_dir_sep(basename[4]));
441
}
442

443
static int set_hidden_flag(const wchar_t *path, int set)
444
{
445
	DWORD original = GetFileAttributesW(path), modified;
446
	if (set)
447
		modified = original | FILE_ATTRIBUTE_HIDDEN;
448
	else
449
		modified = original & ~FILE_ATTRIBUTE_HIDDEN;
450
	if (original == modified || SetFileAttributesW(path, modified))
451
		return 0;
452
	errno = err_win_to_posix(GetLastError());
453
	return -1;
454
}
455

456
int mingw_mkdir(const char *path, int mode)
457
{
458
	int ret;
459
	wchar_t wpath[MAX_PATH];
460

461
	if (!is_valid_win32_path(path, 0)) {
462
		errno = EINVAL;
463
		return -1;
464
	}
465

466
	if (xutftowcs_path(wpath, path) < 0)
467
		return -1;
468
	ret = _wmkdir(wpath);
469
	if (!ret && needs_hiding(path))
470
		return set_hidden_flag(wpath, 1);
471
	return ret;
472
}
473

474
/*
475
 * Calling CreateFile() using FILE_APPEND_DATA and without FILE_WRITE_DATA
476
 * is documented in [1] as opening a writable file handle in append mode.
477
 * (It is believed that) this is atomic since it is maintained by the
478
 * kernel unlike the O_APPEND flag which is racily maintained by the CRT.
479
 *
480
 * [1] https://docs.microsoft.com/en-us/windows/desktop/fileio/file-access-rights-constants
481
 *
482
 * This trick does not appear to work for named pipes.  Instead it creates
483
 * a named pipe client handle that cannot be written to.  Callers should
484
 * just use the regular _wopen() for them.  (And since client handle gets
485
 * bound to a unique server handle, it isn't really an issue.)
486
 */
487
static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
488
{
489
	HANDLE handle;
490
	int fd;
491
	DWORD create = (oflags & O_CREAT) ? OPEN_ALWAYS : OPEN_EXISTING;
492

493
	/* only these flags are supported */
494
	if ((oflags & ~O_CREAT) != (O_WRONLY | O_APPEND))
495
		return errno = ENOSYS, -1;
496

497
	/*
498
	 * FILE_SHARE_WRITE is required to permit child processes
499
	 * to append to the file.
500
	 */
501
	handle = CreateFileW(wfilename, FILE_APPEND_DATA,
502
			FILE_SHARE_WRITE | FILE_SHARE_READ,
503
			NULL, create, FILE_ATTRIBUTE_NORMAL, NULL);
504
	if (handle == INVALID_HANDLE_VALUE) {
505
		DWORD err = GetLastError();
506

507
		/*
508
		 * Some network storage solutions (e.g. Isilon) might return
509
		 * ERROR_INVALID_PARAMETER instead of expected error
510
		 * ERROR_PATH_NOT_FOUND, which results in an unknown error. If
511
		 * so, let's turn the error to ERROR_PATH_NOT_FOUND instead.
512
		 */
513
		if (err == ERROR_INVALID_PARAMETER)
514
			err = ERROR_PATH_NOT_FOUND;
515

516
		errno = err_win_to_posix(err);
517
		return -1;
518
	}
519

520
	/*
521
	 * No O_APPEND here, because the CRT uses it only to reset the
522
	 * file pointer to EOF before each write(); but that is not
523
	 * necessary (and may lead to races) for a file created with
524
	 * FILE_APPEND_DATA.
525
	 */
526
	fd = _open_osfhandle((intptr_t)handle, O_BINARY);
527
	if (fd < 0)
528
		CloseHandle(handle);
529
	return fd;
530
}
531

532
/*
533
 * Does the pathname map to the local named pipe filesystem?
534
 * That is, does it have a "//./pipe/" prefix?
535
 */
536
static int is_local_named_pipe_path(const char *filename)
537
{
538
	return (is_dir_sep(filename[0]) &&
539
		is_dir_sep(filename[1]) &&
540
		filename[2] == '.'  &&
541
		is_dir_sep(filename[3]) &&
542
		!strncasecmp(filename+4, "pipe", 4) &&
543
		is_dir_sep(filename[8]) &&
544
		filename[9]);
545
}
546

547
int mingw_open (const char *filename, int oflags, ...)
548
{
549
	typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...);
550
	va_list args;
551
	unsigned mode;
552
	int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
553
	wchar_t wfilename[MAX_PATH];
554
	open_fn_t open_fn;
555

556
	va_start(args, oflags);
557
	mode = va_arg(args, int);
558
	va_end(args);
559

560
	if (!is_valid_win32_path(filename, !create)) {
561
		errno = create ? EINVAL : ENOENT;
562
		return -1;
563
	}
564

565
	if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename))
566
		open_fn = mingw_open_append;
567
	else
568
		open_fn = _wopen;
569

570
	if (filename && !strcmp(filename, "/dev/null"))
571
		wcscpy(wfilename, L"nul");
572
	else if (xutftowcs_path(wfilename, filename) < 0)
573
		return -1;
574

575
	fd = open_fn(wfilename, oflags, mode);
576

577
	if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
578
		DWORD attrs = GetFileAttributesW(wfilename);
579
		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
580
			errno = EISDIR;
581
	}
582
	if ((oflags & O_CREAT) && needs_hiding(filename)) {
583
		/*
584
		 * Internally, _wopen() uses the CreateFile() API which errors
585
		 * out with an ERROR_ACCESS_DENIED if CREATE_ALWAYS was
586
		 * specified and an already existing file's attributes do not
587
		 * match *exactly*. As there is no mode or flag we can set that
588
		 * would correspond to FILE_ATTRIBUTE_HIDDEN, let's just try
589
		 * again *without* the O_CREAT flag (that corresponds to the
590
		 * CREATE_ALWAYS flag of CreateFile()).
591
		 */
592
		if (fd < 0 && errno == EACCES)
593
			fd = open_fn(wfilename, oflags & ~O_CREAT, mode);
594
		if (fd >= 0 && set_hidden_flag(wfilename, 1))
595
			warning("could not mark '%s' as hidden.", filename);
596
	}
597
	return fd;
598
}
599

600
static BOOL WINAPI ctrl_ignore(DWORD type)
601
{
602
	return TRUE;
603
}
604

605
#undef fgetc
606
int mingw_fgetc(FILE *stream)
607
{
608
	int ch;
609
	if (!isatty(_fileno(stream)))
610
		return fgetc(stream);
611

612
	SetConsoleCtrlHandler(ctrl_ignore, TRUE);
613
	while (1) {
614
		ch = fgetc(stream);
615
		if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED)
616
			break;
617

618
		/* Ctrl+C was pressed, simulate SIGINT and retry */
619
		mingw_raise(SIGINT);
620
	}
621
	SetConsoleCtrlHandler(ctrl_ignore, FALSE);
622
	return ch;
623
}
624

625
#undef fopen
626
FILE *mingw_fopen (const char *filename, const char *otype)
627
{
628
	int hide = needs_hiding(filename);
629
	FILE *file;
630
	wchar_t wfilename[MAX_PATH], wotype[4];
631
	if (filename && !strcmp(filename, "/dev/null"))
632
		wcscpy(wfilename, L"nul");
633
	else if (!is_valid_win32_path(filename, 1)) {
634
		int create = otype && strchr(otype, 'w');
635
		errno = create ? EINVAL : ENOENT;
636
		return NULL;
637
	} else if (xutftowcs_path(wfilename, filename) < 0)
638
		return NULL;
639

640
	if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
641
		return NULL;
642

643
	if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
644
		error("could not unhide %s", filename);
645
		return NULL;
646
	}
647
	file = _wfopen(wfilename, wotype);
648
	if (!file && GetLastError() == ERROR_INVALID_NAME)
649
		errno = ENOENT;
650
	if (file && hide && set_hidden_flag(wfilename, 1))
651
		warning("could not mark '%s' as hidden.", filename);
652
	return file;
653
}
654

655
FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
656
{
657
	int hide = needs_hiding(filename);
658
	FILE *file;
659
	wchar_t wfilename[MAX_PATH], wotype[4];
660
	if (filename && !strcmp(filename, "/dev/null"))
661
		wcscpy(wfilename, L"nul");
662
	else if (!is_valid_win32_path(filename, 1)) {
663
		int create = otype && strchr(otype, 'w');
664
		errno = create ? EINVAL : ENOENT;
665
		return NULL;
666
	} else if (xutftowcs_path(wfilename, filename) < 0)
667
		return NULL;
668

669
	if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
670
		return NULL;
671

672
	if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
673
		error("could not unhide %s", filename);
674
		return NULL;
675
	}
676
	file = _wfreopen(wfilename, wotype, stream);
677
	if (file && hide && set_hidden_flag(wfilename, 1))
678
		warning("could not mark '%s' as hidden.", filename);
679
	return file;
680
}
681

682
#undef fflush
683
int mingw_fflush(FILE *stream)
684
{
685
	int ret = fflush(stream);
686

687
	/*
688
	 * write() is used behind the scenes of stdio output functions.
689
	 * Since git code does not check for errors after each stdio write
690
	 * operation, it can happen that write() is called by a later
691
	 * stdio function even if an earlier write() call failed. In the
692
	 * case of a pipe whose readable end was closed, only the first
693
	 * call to write() reports EPIPE on Windows. Subsequent write()
694
	 * calls report EINVAL. It is impossible to notice whether this
695
	 * fflush invocation triggered such a case, therefore, we have to
696
	 * catch all EINVAL errors whole-sale.
697
	 */
698
	if (ret && errno == EINVAL)
699
		errno = EPIPE;
700

701
	return ret;
702
}
703

704
#undef write
705
ssize_t mingw_write(int fd, const void *buf, size_t len)
706
{
707
	ssize_t result = write(fd, buf, len);
708

709
	if (result < 0 && (errno == EINVAL || errno == ENOSPC) && buf) {
710
		int orig = errno;
711

712
		/* check if fd is a pipe */
713
		HANDLE h = (HANDLE) _get_osfhandle(fd);
714
		if (GetFileType(h) != FILE_TYPE_PIPE)
715
			errno = orig;
716
		else if (orig == EINVAL)
717
			errno = EPIPE;
718
		else {
719
			DWORD buf_size;
720

721
			if (!GetNamedPipeInfo(h, NULL, NULL, &buf_size, NULL))
722
				buf_size = 4096;
723
			if (len > buf_size)
724
				return write(fd, buf, buf_size);
725
			errno = orig;
726
		}
727
	}
728

729
	return result;
730
}
731

732
int mingw_access(const char *filename, int mode)
733
{
734
	wchar_t wfilename[MAX_PATH];
735
	if (!strcmp("nul", filename) || !strcmp("/dev/null", filename))
736
		return 0;
737
	if (xutftowcs_path(wfilename, filename) < 0)
738
		return -1;
739
	/* X_OK is not supported by the MSVCRT version */
740
	return _waccess(wfilename, mode & ~X_OK);
741
}
742

743
int mingw_chdir(const char *dirname)
744
{
745
	wchar_t wdirname[MAX_PATH];
746
	if (xutftowcs_path(wdirname, dirname) < 0)
747
		return -1;
748
	return _wchdir(wdirname);
749
}
750

751
int mingw_chmod(const char *filename, int mode)
752
{
753
	wchar_t wfilename[MAX_PATH];
754
	if (xutftowcs_path(wfilename, filename) < 0)
755
		return -1;
756
	return _wchmod(wfilename, mode);
757
}
758

759
/*
760
 * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
761
 * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
762
 */
763
static inline long long filetime_to_hnsec(const FILETIME *ft)
764
{
765
	long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
766
	/* Windows to Unix Epoch conversion */
767
	return winTime - 116444736000000000LL;
768
}
769

770
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
771
{
772
	long long hnsec = filetime_to_hnsec(ft);
773
	ts->tv_sec = (time_t)(hnsec / 10000000);
774
	ts->tv_nsec = (hnsec % 10000000) * 100;
775
}
776

777
/**
778
 * Verifies that safe_create_leading_directories() would succeed.
779
 */
780
static int has_valid_directory_prefix(wchar_t *wfilename)
781
{
782
	int n = wcslen(wfilename);
783

784
	while (n > 0) {
785
		wchar_t c = wfilename[--n];
786
		DWORD attributes;
787

788
		if (!is_dir_sep(c))
789
			continue;
790

791
		wfilename[n] = L'\0';
792
		attributes = GetFileAttributesW(wfilename);
793
		wfilename[n] = c;
794
		if (attributes &
795
		    (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE))
796
			return 1;
797
		if (attributes == INVALID_FILE_ATTRIBUTES)
798
			switch (GetLastError()) {
799
			case ERROR_PATH_NOT_FOUND:
800
				continue;
801
			case ERROR_FILE_NOT_FOUND:
802
				/* This implies parent directory exists. */
803
				return 1;
804
			}
805
		return 0;
806
	}
807
	return 1;
808
}
809

810
/* We keep the do_lstat code in a separate function to avoid recursion.
811
 * When a path ends with a slash, the stat will fail with ENOENT. In
812
 * this case, we strip the trailing slashes and stat again.
813
 *
814
 * If follow is true then act like stat() and report on the link
815
 * target. Otherwise report on the link itself.
816
 */
817
static int do_lstat(int follow, const char *file_name, struct stat *buf)
818
{
819
	WIN32_FILE_ATTRIBUTE_DATA fdata;
820
	wchar_t wfilename[MAX_PATH];
821
	if (xutftowcs_path(wfilename, file_name) < 0)
822
		return -1;
823

824
	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
825
		buf->st_ino = 0;
826
		buf->st_gid = 0;
827
		buf->st_uid = 0;
828
		buf->st_nlink = 1;
829
		buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
830
		buf->st_size = fdata.nFileSizeLow |
831
			(((off_t)fdata.nFileSizeHigh)<<32);
832
		buf->st_dev = buf->st_rdev = 0; /* not used by Git */
833
		filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
834
		filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
835
		filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
836
		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
837
			WIN32_FIND_DATAW findbuf;
838
			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
839
			if (handle != INVALID_HANDLE_VALUE) {
840
				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
841
						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
842
					if (follow) {
843
						char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
844
						buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
845
					} else {
846
						buf->st_mode = S_IFLNK;
847
					}
848
					buf->st_mode |= S_IREAD;
849
					if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
850
						buf->st_mode |= S_IWRITE;
851
				}
852
				FindClose(handle);
853
			}
854
		}
855
		return 0;
856
	}
857
	switch (GetLastError()) {
858
	case ERROR_ACCESS_DENIED:
859
	case ERROR_SHARING_VIOLATION:
860
	case ERROR_LOCK_VIOLATION:
861
	case ERROR_SHARING_BUFFER_EXCEEDED:
862
		errno = EACCES;
863
		break;
864
	case ERROR_BUFFER_OVERFLOW:
865
		errno = ENAMETOOLONG;
866
		break;
867
	case ERROR_NOT_ENOUGH_MEMORY:
868
		errno = ENOMEM;
869
		break;
870
	case ERROR_PATH_NOT_FOUND:
871
		if (!has_valid_directory_prefix(wfilename)) {
872
			errno = ENOTDIR;
873
			break;
874
		}
875
		/* fallthru */
876
	default:
877
		errno = ENOENT;
878
		break;
879
	}
880
	return -1;
881
}
882

883
/* We provide our own lstat/fstat functions, since the provided
884
 * lstat/fstat functions are so slow. These stat functions are
885
 * tailored for Git's usage (read: fast), and are not meant to be
886
 * complete. Note that Git stat()s are redirected to mingw_lstat()
887
 * too, since Windows doesn't really handle symlinks that well.
888
 */
889
static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
890
{
891
	int namelen;
892
	char alt_name[PATH_MAX];
893

894
	if (!do_lstat(follow, file_name, buf))
895
		return 0;
896

897
	/* if file_name ended in a '/', Windows returned ENOENT;
898
	 * try again without trailing slashes
899
	 */
900
	if (errno != ENOENT)
901
		return -1;
902

903
	namelen = strlen(file_name);
904
	if (namelen && file_name[namelen-1] != '/')
905
		return -1;
906
	while (namelen && file_name[namelen-1] == '/')
907
		--namelen;
908
	if (!namelen || namelen >= PATH_MAX)
909
		return -1;
910

911
	memcpy(alt_name, file_name, namelen);
912
	alt_name[namelen] = 0;
913
	return do_lstat(follow, alt_name, buf);
914
}
915

916
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
917
{
918
	BY_HANDLE_FILE_INFORMATION fdata;
919

920
	if (!GetFileInformationByHandle(hnd, &fdata)) {
921
		errno = err_win_to_posix(GetLastError());
922
		return -1;
923
	}
924

925
	buf->st_ino = 0;
926
	buf->st_gid = 0;
927
	buf->st_uid = 0;
928
	buf->st_nlink = 1;
929
	buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
930
	buf->st_size = fdata.nFileSizeLow |
931
		(((off_t)fdata.nFileSizeHigh)<<32);
932
	buf->st_dev = buf->st_rdev = 0; /* not used by Git */
933
	filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
934
	filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
935
	filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
936
	return 0;
937
}
938

939
int mingw_lstat(const char *file_name, struct stat *buf)
940
{
941
	return do_stat_internal(0, file_name, buf);
942
}
943
int mingw_stat(const char *file_name, struct stat *buf)
944
{
945
	return do_stat_internal(1, file_name, buf);
946
}
947

948
int mingw_fstat(int fd, struct stat *buf)
949
{
950
	HANDLE fh = (HANDLE)_get_osfhandle(fd);
951
	DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
952

953
	switch (type) {
954
	case FILE_TYPE_DISK:
955
		return get_file_info_by_handle(fh, buf);
956

957
	case FILE_TYPE_CHAR:
958
	case FILE_TYPE_PIPE:
959
		/* initialize stat fields */
960
		memset(buf, 0, sizeof(*buf));
961
		buf->st_nlink = 1;
962

963
		if (type == FILE_TYPE_CHAR) {
964
			buf->st_mode = _S_IFCHR;
965
		} else {
966
			buf->st_mode = _S_IFIFO;
967
			if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
968
				buf->st_size = avail;
969
		}
970
		return 0;
971

972
	default:
973
		errno = EBADF;
974
		return -1;
975
	}
976
}
977

978
static inline void time_t_to_filetime(time_t t, FILETIME *ft)
979
{
980
	long long winTime = t * 10000000LL + 116444736000000000LL;
981
	ft->dwLowDateTime = winTime;
982
	ft->dwHighDateTime = winTime >> 32;
983
}
984

985
int mingw_utime (const char *file_name, const struct utimbuf *times)
986
{
987
	FILETIME mft, aft;
988
	int rc;
989
	DWORD attrs;
990
	wchar_t wfilename[MAX_PATH];
991
	HANDLE osfilehandle;
992

993
	if (xutftowcs_path(wfilename, file_name) < 0)
994
		return -1;
995

996
	/* must have write permission */
997
	attrs = GetFileAttributesW(wfilename);
998
	if (attrs != INVALID_FILE_ATTRIBUTES &&
999
	    (attrs & FILE_ATTRIBUTE_READONLY)) {
1000
		/* ignore errors here; open() will report them */
1001
		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
1002
	}
1003

1004
	osfilehandle = CreateFileW(wfilename,
1005
				   FILE_WRITE_ATTRIBUTES,
1006
				   0 /*FileShare.None*/,
1007
				   NULL,
1008
				   OPEN_EXISTING,
1009
				   (attrs != INVALID_FILE_ATTRIBUTES &&
1010
					(attrs & FILE_ATTRIBUTE_DIRECTORY)) ?
1011
					FILE_FLAG_BACKUP_SEMANTICS : 0,
1012
				   NULL);
1013
	if (osfilehandle == INVALID_HANDLE_VALUE) {
1014
		errno = err_win_to_posix(GetLastError());
1015
		rc = -1;
1016
		goto revert_attrs;
1017
	}
1018

1019
	if (times) {
1020
		time_t_to_filetime(times->modtime, &mft);
1021
		time_t_to_filetime(times->actime, &aft);
1022
	} else {
1023
		GetSystemTimeAsFileTime(&mft);
1024
		aft = mft;
1025
	}
1026

1027
	if (!SetFileTime(osfilehandle, NULL, &aft, &mft)) {
1028
		errno = EINVAL;
1029
		rc = -1;
1030
	} else
1031
		rc = 0;
1032

1033
	if (osfilehandle != INVALID_HANDLE_VALUE)
1034
		CloseHandle(osfilehandle);
1035

1036
revert_attrs:
1037
	if (attrs != INVALID_FILE_ATTRIBUTES &&
1038
	    (attrs & FILE_ATTRIBUTE_READONLY)) {
1039
		/* ignore errors again */
1040
		SetFileAttributesW(wfilename, attrs);
1041
	}
1042
	return rc;
1043
}
1044

1045
#undef strftime
1046
size_t mingw_strftime(char *s, size_t max,
1047
		      const char *format, const struct tm *tm)
1048
{
1049
	/* a pointer to the original strftime in case we can't find the UCRT version */
1050
	static size_t (*fallback)(char *, size_t, const char *, const struct tm *) = strftime;
1051
	size_t ret;
1052
	DECLARE_PROC_ADDR(ucrtbase.dll, size_t, __cdecl, strftime, char *, size_t,
1053
		const char *, const struct tm *);
1054

1055
	if (INIT_PROC_ADDR(strftime))
1056
		ret = strftime(s, max, format, tm);
1057
	else
1058
		ret = fallback(s, max, format, tm);
1059

1060
	if (!ret && errno == EINVAL)
1061
		die("invalid strftime format: '%s'", format);
1062
	return ret;
1063
}
1064

1065
unsigned int sleep (unsigned int seconds)
1066
{
1067
	Sleep(seconds*1000);
1068
	return 0;
1069
}
1070

1071
char *mingw_mktemp(char *template)
1072
{
1073
	wchar_t wtemplate[MAX_PATH];
1074
	if (xutftowcs_path(wtemplate, template) < 0)
1075
		return NULL;
1076
	if (!_wmktemp(wtemplate))
1077
		return NULL;
1078
	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
1079
		return NULL;
1080
	return template;
1081
}
1082

1083
int mkstemp(char *template)
1084
{
1085
	return git_mkstemp_mode(template, 0600);
1086
}
1087

1088
int gettimeofday(struct timeval *tv, void *tz)
1089
{
1090
	FILETIME ft;
1091
	long long hnsec;
1092

1093
	GetSystemTimeAsFileTime(&ft);
1094
	hnsec = filetime_to_hnsec(&ft);
1095
	tv->tv_sec = hnsec / 10000000;
1096
	tv->tv_usec = (hnsec % 10000000) / 10;
1097
	return 0;
1098
}
1099

1100
int pipe(int filedes[2])
1101
{
1102
	HANDLE h[2];
1103

1104
	/* this creates non-inheritable handles */
1105
	if (!CreatePipe(&h[0], &h[1], NULL, 8192)) {
1106
		errno = err_win_to_posix(GetLastError());
1107
		return -1;
1108
	}
1109
	filedes[0] = _open_osfhandle(HCAST(int, h[0]), O_NOINHERIT);
1110
	if (filedes[0] < 0) {
1111
		CloseHandle(h[0]);
1112
		CloseHandle(h[1]);
1113
		return -1;
1114
	}
1115
	filedes[1] = _open_osfhandle(HCAST(int, h[1]), O_NOINHERIT);
1116
	if (filedes[1] < 0) {
1117
		close(filedes[0]);
1118
		CloseHandle(h[1]);
1119
		return -1;
1120
	}
1121
	return 0;
1122
}
1123

1124
#ifndef __MINGW64__
1125
struct tm *gmtime_r(const time_t *timep, struct tm *result)
1126
{
1127
	if (gmtime_s(result, timep) == 0)
1128
		return result;
1129
	return NULL;
1130
}
1131

1132
struct tm *localtime_r(const time_t *timep, struct tm *result)
1133
{
1134
	if (localtime_s(result, timep) == 0)
1135
		return result;
1136
	return NULL;
1137
}
1138
#endif
1139

1140
char *mingw_getcwd(char *pointer, int len)
1141
{
1142
	wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
1143
	DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
1144

1145
	if (!ret || ret >= ARRAY_SIZE(cwd)) {
1146
		errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
1147
		return NULL;
1148
	}
1149
	ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
1150
	if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
1151
		HANDLE hnd = CreateFileW(cwd, 0,
1152
			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
1153
			OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1154
		if (hnd == INVALID_HANDLE_VALUE)
1155
			return NULL;
1156
		ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
1157
		CloseHandle(hnd);
1158
		if (!ret || ret >= ARRAY_SIZE(wpointer))
1159
			return NULL;
1160
		if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0)
1161
			return NULL;
1162
		return pointer;
1163
	}
1164
	if (!ret || ret >= ARRAY_SIZE(wpointer))
1165
		return NULL;
1166
	if (GetFileAttributesW(wpointer) == INVALID_FILE_ATTRIBUTES) {
1167
		errno = ENOENT;
1168
		return NULL;
1169
	}
1170
	if (xwcstoutf(pointer, wpointer, len) < 0)
1171
		return NULL;
1172
	convert_slashes(pointer);
1173
	return pointer;
1174
}
1175

1176
/*
1177
 * See "Parsing C++ Command-Line Arguments" at Microsoft's Docs:
1178
 * https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments
1179
 */
1180
static const char *quote_arg_msvc(const char *arg)
1181
{
1182
	/* count chars to quote */
1183
	int len = 0, n = 0;
1184
	int force_quotes = 0;
1185
	char *q, *d;
1186
	const char *p = arg;
1187
	if (!*p) force_quotes = 1;
1188
	while (*p) {
1189
		if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
1190
			force_quotes = 1;
1191
		else if (*p == '"')
1192
			n++;
1193
		else if (*p == '\\') {
1194
			int count = 0;
1195
			while (*p == '\\') {
1196
				count++;
1197
				p++;
1198
				len++;
1199
			}
1200
			if (*p == '"' || !*p)
1201
				n += count*2 + 1;
1202
			continue;
1203
		}
1204
		len++;
1205
		p++;
1206
	}
1207
	if (!force_quotes && n == 0)
1208
		return arg;
1209

1210
	/* insert \ where necessary */
1211
	d = q = xmalloc(st_add3(len, n, 3));
1212
	*d++ = '"';
1213
	while (*arg) {
1214
		if (*arg == '"')
1215
			*d++ = '\\';
1216
		else if (*arg == '\\') {
1217
			int count = 0;
1218
			while (*arg == '\\') {
1219
				count++;
1220
				*d++ = *arg++;
1221
			}
1222
			if (*arg == '"' || !*arg) {
1223
				while (count-- > 0)
1224
					*d++ = '\\';
1225
				/* don't escape the surrounding end quote */
1226
				if (!*arg)
1227
					break;
1228
				*d++ = '\\';
1229
			}
1230
		}
1231
		*d++ = *arg++;
1232
	}
1233
	*d++ = '"';
1234
	*d++ = '\0';
1235
	return q;
1236
}
1237

1238
#include "quote.h"
1239

1240
static const char *quote_arg_msys2(const char *arg)
1241
{
1242
	struct strbuf buf = STRBUF_INIT;
1243
	const char *p2 = arg, *p;
1244

1245
	for (p = arg; *p; p++) {
1246
		int ws = isspace(*p);
1247
		if (!ws && *p != '\\' && *p != '"' && *p != '{' && *p != '\'' &&
1248
		    *p != '?' && *p != '*' && *p != '~')
1249
			continue;
1250
		if (!buf.len)
1251
			strbuf_addch(&buf, '"');
1252
		if (p != p2)
1253
			strbuf_add(&buf, p2, p - p2);
1254
		if (*p == '\\' || *p == '"')
1255
			strbuf_addch(&buf, '\\');
1256
		p2 = p;
1257
	}
1258

1259
	if (p == arg)
1260
		strbuf_addch(&buf, '"');
1261
	else if (!buf.len)
1262
		return arg;
1263
	else
1264
		strbuf_add(&buf, p2, p - p2);
1265

1266
	strbuf_addch(&buf, '"');
1267
	return strbuf_detach(&buf, 0);
1268
}
1269

1270
static const char *parse_interpreter(const char *cmd)
1271
{
1272
	static char buf[100];
1273
	char *p, *opt;
1274
	int n, fd;
1275

1276
	/* don't even try a .exe */
1277
	n = strlen(cmd);
1278
	if (n >= 4 && !strcasecmp(cmd+n-4, ".exe"))
1279
		return NULL;
1280

1281
	fd = open(cmd, O_RDONLY);
1282
	if (fd < 0)
1283
		return NULL;
1284
	n = read(fd, buf, sizeof(buf)-1);
1285
	close(fd);
1286
	if (n < 4)	/* at least '#!/x' and not error */
1287
		return NULL;
1288

1289
	if (buf[0] != '#' || buf[1] != '!')
1290
		return NULL;
1291
	buf[n] = '\0';
1292
	p = buf + strcspn(buf, "\r\n");
1293
	if (!*p)
1294
		return NULL;
1295

1296
	*p = '\0';
1297
	if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\')))
1298
		return NULL;
1299
	/* strip options */
1300
	if ((opt = strchr(p+1, ' ')))
1301
		*opt = '\0';
1302
	return p+1;
1303
}
1304

1305
/*
1306
 * exe_only means that we only want to detect .exe files, but not scripts
1307
 * (which do not have an extension)
1308
 */
1309
static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
1310
			 int isexe, int exe_only)
1311
{
1312
	char path[MAX_PATH];
1313
	wchar_t wpath[MAX_PATH];
1314
	snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
1315

1316
	if (xutftowcs_path(wpath, path) < 0)
1317
		return NULL;
1318

1319
	if (!isexe && _waccess(wpath, F_OK) == 0)
1320
		return xstrdup(path);
1321
	wpath[wcslen(wpath)-4] = '\0';
1322
	if ((!exe_only || isexe) && _waccess(wpath, F_OK) == 0) {
1323
		if (!(GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY)) {
1324
			path[strlen(path)-4] = '\0';
1325
			return xstrdup(path);
1326
		}
1327
	}
1328
	return NULL;
1329
}
1330

1331
/*
1332
 * Determines the absolute path of cmd using the split path in path.
1333
 * If cmd contains a slash or backslash, no lookup is performed.
1334
 */
1335
static char *path_lookup(const char *cmd, int exe_only)
1336
{
1337
	const char *path;
1338
	char *prog = NULL;
1339
	int len = strlen(cmd);
1340
	int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
1341

1342
	if (strpbrk(cmd, "/\\"))
1343
		return xstrdup(cmd);
1344

1345
	path = mingw_getenv("PATH");
1346
	if (!path)
1347
		return NULL;
1348

1349
	while (!prog) {
1350
		const char *sep = strchrnul(path, ';');
1351
		int dirlen = sep - path;
1352
		if (dirlen)
1353
			prog = lookup_prog(path, dirlen, cmd, isexe, exe_only);
1354
		if (!*sep)
1355
			break;
1356
		path = sep + 1;
1357
	}
1358

1359
	return prog;
1360
}
1361

1362
char *mingw_locate_in_PATH(const char *cmd)
1363
{
1364
	return path_lookup(cmd, 0);
1365
}
1366

1367
static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c)
1368
{
1369
	while (*s && *s != c)
1370
		s++;
1371
	return s;
1372
}
1373

1374
/* Compare only keys */
1375
static int wenvcmp(const void *a, const void *b)
1376
{
1377
	wchar_t *p = *(wchar_t **)a, *q = *(wchar_t **)b;
1378
	size_t p_len, q_len;
1379

1380
	/* Find the keys */
1381
	p_len = wcschrnul(p, L'=') - p;
1382
	q_len = wcschrnul(q, L'=') - q;
1383

1384
	/* If the length differs, include the shorter key's NUL */
1385
	if (p_len < q_len)
1386
		p_len++;
1387
	else if (p_len > q_len)
1388
		p_len = q_len + 1;
1389

1390
	return _wcsnicmp(p, q, p_len);
1391
}
1392

1393
/*
1394
 * Build an environment block combining the inherited environment
1395
 * merged with the given list of settings.
1396
 *
1397
 * Values of the form "KEY=VALUE" in deltaenv override inherited values.
1398
 * Values of the form "KEY" in deltaenv delete inherited values.
1399
 *
1400
 * Multiple entries in deltaenv for the same key are explicitly allowed.
1401
 *
1402
 * We return a contiguous block of UNICODE strings with a final trailing
1403
 * zero word.
1404
 */
1405
static wchar_t *make_environment_block(char **deltaenv)
1406
{
1407
	wchar_t *wenv = GetEnvironmentStringsW(), *wdeltaenv, *result, *p;
1408
	size_t wlen, s, delta_size, size;
1409

1410
	wchar_t **array = NULL;
1411
	size_t alloc = 0, nr = 0, i;
1412

1413
	size = 1; /* for extra NUL at the end */
1414

1415
	/* If there is no deltaenv to apply, simply return a copy. */
1416
	if (!deltaenv || !*deltaenv) {
1417
		for (p = wenv; p && *p; ) {
1418
			size_t s = wcslen(p) + 1;
1419
			size += s;
1420
			p += s;
1421
		}
1422

1423
		DUP_ARRAY(result, wenv, size);
1424
		FreeEnvironmentStringsW(wenv);
1425
		return result;
1426
	}
1427

1428
	/*
1429
	 * If there is a deltaenv, let's accumulate all keys into `array`,
1430
	 * sort them using the stable git_stable_qsort() and then copy,
1431
	 * skipping duplicate keys
1432
	 */
1433
	for (p = wenv; p && *p; ) {
1434
		ALLOC_GROW(array, nr + 1, alloc);
1435
		s = wcslen(p) + 1;
1436
		array[nr++] = p;
1437
		p += s;
1438
		size += s;
1439
	}
1440

1441
	/* (over-)assess size needed for wchar version of deltaenv */
1442
	for (delta_size = 0, i = 0; deltaenv[i]; i++)
1443
		delta_size += strlen(deltaenv[i]) * 2 + 1;
1444
	ALLOC_ARRAY(wdeltaenv, delta_size);
1445

1446
	/* convert the deltaenv, appending to array */
1447
	for (i = 0, p = wdeltaenv; deltaenv[i]; i++) {
1448
		ALLOC_GROW(array, nr + 1, alloc);
1449
		wlen = xutftowcs(p, deltaenv[i], wdeltaenv + delta_size - p);
1450
		array[nr++] = p;
1451
		p += wlen + 1;
1452
	}
1453

1454
	git_stable_qsort(array, nr, sizeof(*array), wenvcmp);
1455
	ALLOC_ARRAY(result, size + delta_size);
1456

1457
	for (p = result, i = 0; i < nr; i++) {
1458
		/* Skip any duplicate keys; last one wins */
1459
		while (i + 1 < nr && !wenvcmp(array + i, array + i + 1))
1460
		       i++;
1461

1462
		/* Skip "to delete" entry */
1463
		if (!wcschr(array[i], L'='))
1464
			continue;
1465

1466
		size = wcslen(array[i]) + 1;
1467
		COPY_ARRAY(p, array[i], size);
1468
		p += size;
1469
	}
1470
	*p = L'\0';
1471

1472
	free(array);
1473
	free(wdeltaenv);
1474
	FreeEnvironmentStringsW(wenv);
1475
	return result;
1476
}
1477

1478
static void do_unset_environment_variables(void)
1479
{
1480
	static int done;
1481
	char *p = unset_environment_variables;
1482

1483
	if (done || !p)
1484
		return;
1485
	done = 1;
1486

1487
	for (;;) {
1488
		char *comma = strchr(p, ',');
1489

1490
		if (comma)
1491
			*comma = '\0';
1492
		unsetenv(p);
1493
		if (!comma)
1494
			break;
1495
		p = comma + 1;
1496
	}
1497
}
1498

1499
struct pinfo_t {
1500
	struct pinfo_t *next;
1501
	pid_t pid;
1502
	HANDLE proc;
1503
};
1504
static struct pinfo_t *pinfo = NULL;
1505
CRITICAL_SECTION pinfo_cs;
1506

1507
/* Used to match and chomp off path components */
1508
static inline int match_last_path_component(const char *path, size_t *len,
1509
					    const char *component)
1510
{
1511
	size_t component_len = strlen(component);
1512
	if (*len < component_len + 1 ||
1513
	    !is_dir_sep(path[*len - component_len - 1]) ||
1514
	    fspathncmp(path + *len - component_len, component, component_len))
1515
		return 0;
1516
	*len -= component_len + 1;
1517
	/* chomp off repeated dir separators */
1518
	while (*len > 0 && is_dir_sep(path[*len - 1]))
1519
		(*len)--;
1520
	return 1;
1521
}
1522

1523
static int is_msys2_sh(const char *cmd)
1524
{
1525
	if (!cmd)
1526
		return 0;
1527

1528
	if (!strcmp(cmd, "sh")) {
1529
		static int ret = -1;
1530
		char *p;
1531

1532
		if (ret >= 0)
1533
			return ret;
1534

1535
		p = path_lookup(cmd, 0);
1536
		if (!p)
1537
			ret = 0;
1538
		else {
1539
			size_t len = strlen(p);
1540

1541
			ret = match_last_path_component(p, &len, "sh.exe") &&
1542
				match_last_path_component(p, &len, "bin") &&
1543
				match_last_path_component(p, &len, "usr");
1544
			free(p);
1545
		}
1546
		return ret;
1547
	}
1548

1549
	if (ends_with(cmd, "\\sh.exe") || ends_with(cmd, "/sh.exe")) {
1550
		static char *sh;
1551

1552
		if (!sh)
1553
			sh = path_lookup("sh", 0);
1554

1555
		return !fspathcmp(cmd, sh);
1556
	}
1557

1558
	return 0;
1559
}
1560

1561
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
1562
			      const char *dir,
1563
			      int prepend_cmd, int fhin, int fhout, int fherr)
1564
{
1565
	static int restrict_handle_inheritance = -1;
1566
	STARTUPINFOEXW si;
1567
	PROCESS_INFORMATION pi;
1568
	LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
1569
	HANDLE stdhandles[3];
1570
	DWORD stdhandles_count = 0;
1571
	SIZE_T size;
1572
	struct strbuf args;
1573
	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
1574
	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
1575
	BOOL ret;
1576
	HANDLE cons;
1577
	const char *(*quote_arg)(const char *arg) =
1578
		is_msys2_sh(cmd ? cmd : *argv) ?
1579
		quote_arg_msys2 : quote_arg_msvc;
1580
	const char *strace_env;
1581

1582
	/* Make sure to override previous errors, if any */
1583
	errno = 0;
1584

1585
	if (restrict_handle_inheritance < 0)
1586
		restrict_handle_inheritance = core_restrict_inherited_handles;
1587
	/*
1588
	 * The following code to restrict which handles are inherited seems
1589
	 * to work properly only on Windows 7 and later, so let's disable it
1590
	 * on Windows Vista and 2008.
1591
	 */
1592
	if (restrict_handle_inheritance < 0)
1593
		restrict_handle_inheritance = GetVersion() >> 16 >= 7601;
1594

1595
	do_unset_environment_variables();
1596

1597
	/* Determine whether or not we are associated to a console */
1598
	cons = CreateFileW(L"CONOUT$", GENERIC_WRITE,
1599
			FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1600
			FILE_ATTRIBUTE_NORMAL, NULL);
1601
	if (cons == INVALID_HANDLE_VALUE) {
1602
		/* There is no console associated with this process.
1603
		 * Since the child is a console process, Windows
1604
		 * would normally create a console window. But
1605
		 * since we'll be redirecting std streams, we do
1606
		 * not need the console.
1607
		 * It is necessary to use DETACHED_PROCESS
1608
		 * instead of CREATE_NO_WINDOW to make ssh
1609
		 * recognize that it has no console.
1610
		 */
1611
		flags |= DETACHED_PROCESS;
1612
	} else {
1613
		/* There is already a console. If we specified
1614
		 * DETACHED_PROCESS here, too, Windows would
1615
		 * disassociate the child from the console.
1616
		 * The same is true for CREATE_NO_WINDOW.
1617
		 * Go figure!
1618
		 */
1619
		CloseHandle(cons);
1620
	}
1621
	memset(&si, 0, sizeof(si));
1622
	si.StartupInfo.cb = sizeof(si);
1623
	si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin);
1624
	si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout);
1625
	si.StartupInfo.hStdError = winansi_get_osfhandle(fherr);
1626

1627
	/* The list of handles cannot contain duplicates */
1628
	if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE)
1629
		stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput;
1630
	if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
1631
	    si.StartupInfo.hStdOutput != si.StartupInfo.hStdInput)
1632
		stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput;
1633
	if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE &&
1634
	    si.StartupInfo.hStdError != si.StartupInfo.hStdInput &&
1635
	    si.StartupInfo.hStdError != si.StartupInfo.hStdOutput)
1636
		stdhandles[stdhandles_count++] = si.StartupInfo.hStdError;
1637
	if (stdhandles_count)
1638
		si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
1639

1640
	if (*argv && !strcmp(cmd, *argv))
1641
		wcmd[0] = L'\0';
1642
	else if (xutftowcs_path(wcmd, cmd) < 0)
1643
		return -1;
1644
	if (dir && xutftowcs_path(wdir, dir) < 0)
1645
		return -1;
1646

1647
	/* concatenate argv, quoting args as we go */
1648
	strbuf_init(&args, 0);
1649
	if (prepend_cmd) {
1650
		char *quoted = (char *)quote_arg(cmd);
1651
		strbuf_addstr(&args, quoted);
1652
		if (quoted != cmd)
1653
			free(quoted);
1654
	}
1655
	for (; *argv; argv++) {
1656
		char *quoted = (char *)quote_arg(*argv);
1657
		if (*args.buf)
1658
			strbuf_addch(&args, ' ');
1659
		strbuf_addstr(&args, quoted);
1660
		if (quoted != *argv)
1661
			free(quoted);
1662
	}
1663

1664
	strace_env = getenv("GIT_STRACE_COMMANDS");
1665
	if (strace_env) {
1666
		char *p = path_lookup("strace.exe", 1);
1667
		if (!p)
1668
			return error("strace not found!");
1669
		if (xutftowcs_path(wcmd, p) < 0) {
1670
			free(p);
1671
			return -1;
1672
		}
1673
		free(p);
1674
		if (!strcmp("1", strace_env) ||
1675
		    !strcasecmp("yes", strace_env) ||
1676
		    !strcasecmp("true", strace_env))
1677
			strbuf_insert(&args, 0, "strace ", 7);
1678
		else {
1679
			const char *quoted = quote_arg(strace_env);
1680
			struct strbuf buf = STRBUF_INIT;
1681
			strbuf_addf(&buf, "strace -o %s ", quoted);
1682
			if (quoted != strace_env)
1683
				free((char *)quoted);
1684
			strbuf_insert(&args, 0, buf.buf, buf.len);
1685
			strbuf_release(&buf);
1686
		}
1687
	}
1688

1689
	ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1));
1690
	xutftowcs(wargs, args.buf, 2 * args.len + 1);
1691
	strbuf_release(&args);
1692

1693
	wenvblk = make_environment_block(deltaenv);
1694

1695
	memset(&pi, 0, sizeof(pi));
1696
	if (restrict_handle_inheritance && stdhandles_count &&
1697
	    (InitializeProcThreadAttributeList(NULL, 1, 0, &size) ||
1698
	     GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
1699
	    (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)
1700
			(HeapAlloc(GetProcessHeap(), 0, size))) &&
1701
	    InitializeProcThreadAttributeList(attr_list, 1, 0, &size) &&
1702
	    UpdateProcThreadAttribute(attr_list, 0,
1703
				      PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1704
				      stdhandles,
1705
				      stdhandles_count * sizeof(HANDLE),
1706
				      NULL, NULL)) {
1707
		si.lpAttributeList = attr_list;
1708
		flags |= EXTENDED_STARTUPINFO_PRESENT;
1709
	}
1710

1711
	ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
1712
			     stdhandles_count ? TRUE : FALSE,
1713
			     flags, wenvblk, dir ? wdir : NULL,
1714
			     &si.StartupInfo, &pi);
1715

1716
	/*
1717
	 * On Windows 2008 R2, it seems that specifying certain types of handles
1718
	 * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1719
	 * error. Rather than playing finicky and fragile games, let's just try
1720
	 * to detect this situation and simply try again without restricting any
1721
	 * handle inheritance. This is still better than failing to create
1722
	 * processes.
1723
	 */
1724
	if (!ret && restrict_handle_inheritance && stdhandles_count) {
1725
		DWORD err = GetLastError();
1726
		struct strbuf buf = STRBUF_INIT;
1727

1728
		if (err != ERROR_NO_SYSTEM_RESOURCES &&
1729
		    /*
1730
		     * On Windows 7 and earlier, handles on pipes and character
1731
		     * devices are inherited automatically, and cannot be
1732
		     * specified in the thread handle list. Rather than trying
1733
		     * to catch each and every corner case (and running the
1734
		     * chance of *still* forgetting a few), let's just fall
1735
		     * back to creating the process without trying to limit the
1736
		     * handle inheritance.
1737
		     */
1738
		    !(err == ERROR_INVALID_PARAMETER &&
1739
		      GetVersion() >> 16 < 9200) &&
1740
		    !getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) {
1741
			DWORD fl = 0;
1742
			int i;
1743

1744
			setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1);
1745

1746
			for (i = 0; i < stdhandles_count; i++) {
1747
				HANDLE h = stdhandles[i];
1748
				strbuf_addf(&buf, "handle #%d: %p (type %lx, "
1749
					    "handle info (%d) %lx\n", i, h,
1750
					    GetFileType(h),
1751
					    GetHandleInformation(h, &fl),
1752
					    fl);
1753
			}
1754
			strbuf_addstr(&buf, "\nThis is a bug; please report it "
1755
				      "at\nhttps://github.com/git-for-windows/"
1756
				      "git/issues/new\n\n"
1757
				      "To suppress this warning, please set "
1758
				      "the environment variable\n\n"
1759
				      "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1760
				      "\n");
1761
		}
1762
		restrict_handle_inheritance = 0;
1763
		flags &= ~EXTENDED_STARTUPINFO_PRESENT;
1764
		ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
1765
				     TRUE, flags, wenvblk, dir ? wdir : NULL,
1766
				     &si.StartupInfo, &pi);
1767
		if (!ret)
1768
			errno = err_win_to_posix(GetLastError());
1769
		if (ret && buf.len) {
1770
			warning("failed to restrict file handles (%ld)\n\n%s",
1771
				err, buf.buf);
1772
		}
1773
		strbuf_release(&buf);
1774
	} else if (!ret)
1775
		errno = err_win_to_posix(GetLastError());
1776

1777
	if (si.lpAttributeList)
1778
		DeleteProcThreadAttributeList(si.lpAttributeList);
1779
	if (attr_list)
1780
		HeapFree(GetProcessHeap(), 0, attr_list);
1781

1782
	free(wenvblk);
1783
	free(wargs);
1784

1785
	if (!ret)
1786
		return -1;
1787

1788
	CloseHandle(pi.hThread);
1789

1790
	/*
1791
	 * The process ID is the human-readable identifier of the process
1792
	 * that we want to present in log and error messages. The handle
1793
	 * is not useful for this purpose. But we cannot close it, either,
1794
	 * because it is not possible to turn a process ID into a process
1795
	 * handle after the process terminated.
1796
	 * Keep the handle in a list for waitpid.
1797
	 */
1798
	EnterCriticalSection(&pinfo_cs);
1799
	{
1800
		struct pinfo_t *info = xmalloc(sizeof(struct pinfo_t));
1801
		info->pid = pi.dwProcessId;
1802
		info->proc = pi.hProcess;
1803
		info->next = pinfo;
1804
		pinfo = info;
1805
	}
1806
	LeaveCriticalSection(&pinfo_cs);
1807

1808
	return (pid_t)pi.dwProcessId;
1809
}
1810

1811
static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
1812
{
1813
	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
1814
}
1815

1816
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1817
		     const char *dir,
1818
		     int fhin, int fhout, int fherr)
1819
{
1820
	pid_t pid;
1821
	char *prog = path_lookup(cmd, 0);
1822

1823
	if (!prog) {
1824
		errno = ENOENT;
1825
		pid = -1;
1826
	}
1827
	else {
1828
		const char *interpr = parse_interpreter(prog);
1829

1830
		if (interpr) {
1831
			const char *argv0 = argv[0];
1832
			char *iprog = path_lookup(interpr, 1);
1833
			argv[0] = prog;
1834
			if (!iprog) {
1835
				errno = ENOENT;
1836
				pid = -1;
1837
			}
1838
			else {
1839
				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
1840
						       fhin, fhout, fherr);
1841
				free(iprog);
1842
			}
1843
			argv[0] = argv0;
1844
		}
1845
		else
1846
			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
1847
					       fhin, fhout, fherr);
1848
		free(prog);
1849
	}
1850
	return pid;
1851
}
1852

1853
static int try_shell_exec(const char *cmd, char *const *argv)
1854
{
1855
	const char *interpr = parse_interpreter(cmd);
1856
	char *prog;
1857
	int pid = 0;
1858

1859
	if (!interpr)
1860
		return 0;
1861
	prog = path_lookup(interpr, 1);
1862
	if (prog) {
1863
		int exec_id;
1864
		int argc = 0;
1865
		char **argv2;
1866
		while (argv[argc]) argc++;
1867
		ALLOC_ARRAY(argv2, argc + 1);
1868
		argv2[0] = (char *)cmd;	/* full path to the script file */
1869
		COPY_ARRAY(&argv2[1], &argv[1], argc);
1870
		exec_id = trace2_exec(prog, (const char **)argv2);
1871
		pid = mingw_spawnv(prog, (const char **)argv2, 1);
1872
		if (pid >= 0) {
1873
			int status;
1874
			if (waitpid(pid, &status, 0) < 0)
1875
				status = 255;
1876
			trace2_exec_result(exec_id, status);
1877
			exit(status);
1878
		}
1879
		trace2_exec_result(exec_id, -1);
1880
		pid = 1;	/* indicate that we tried but failed */
1881
		free(prog);
1882
		free(argv2);
1883
	}
1884
	return pid;
1885
}
1886

1887
int mingw_execv(const char *cmd, char *const *argv)
1888
{
1889
	/* check if git_command is a shell script */
1890
	if (!try_shell_exec(cmd, argv)) {
1891
		int pid, status;
1892
		int exec_id;
1893

1894
		exec_id = trace2_exec(cmd, (const char **)argv);
1895
		pid = mingw_spawnv(cmd, (const char **)argv, 0);
1896
		if (pid < 0) {
1897
			trace2_exec_result(exec_id, -1);
1898
			return -1;
1899
		}
1900
		if (waitpid(pid, &status, 0) < 0)
1901
			status = 255;
1902
		trace2_exec_result(exec_id, status);
1903
		exit(status);
1904
	}
1905
	return -1;
1906
}
1907

1908
int mingw_execvp(const char *cmd, char *const *argv)
1909
{
1910
	char *prog = path_lookup(cmd, 0);
1911

1912
	if (prog) {
1913
		mingw_execv(prog, argv);
1914
		free(prog);
1915
	} else
1916
		errno = ENOENT;
1917

1918
	return -1;
1919
}
1920

1921
int mingw_kill(pid_t pid, int sig)
1922
{
1923
	if (pid > 0 && sig == SIGTERM) {
1924
		HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
1925

1926
		if (TerminateProcess(h, -1)) {
1927
			CloseHandle(h);
1928
			return 0;
1929
		}
1930

1931
		errno = err_win_to_posix(GetLastError());
1932
		CloseHandle(h);
1933
		return -1;
1934
	} else if (pid > 0 && sig == 0) {
1935
		HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
1936
		if (h) {
1937
			CloseHandle(h);
1938
			return 0;
1939
		}
1940
	}
1941

1942
	errno = EINVAL;
1943
	return -1;
1944
}
1945

1946
/*
1947
 * UTF-8 versions of getenv(), putenv() and unsetenv().
1948
 * Internally, they use the CRT's stock UNICODE routines
1949
 * to avoid data loss.
1950
 */
1951
char *mingw_getenv(const char *name)
1952
{
1953
#define GETENV_MAX_RETAIN 64
1954
	static char *values[GETENV_MAX_RETAIN];
1955
	static int value_counter;
1956
	int len_key, len_value;
1957
	wchar_t *w_key;
1958
	char *value;
1959
	wchar_t w_value[32768];
1960

1961
	if (!name || !*name)
1962
		return NULL;
1963

1964
	len_key = strlen(name) + 1;
1965
	/* We cannot use xcalloc() here because that uses getenv() itself */
1966
	w_key = calloc(len_key, sizeof(wchar_t));
1967
	if (!w_key)
1968
		die("Out of memory, (tried to allocate %u wchar_t's)", len_key);
1969
	xutftowcs(w_key, name, len_key);
1970
	/* GetEnvironmentVariableW() only sets the last error upon failure */
1971
	SetLastError(ERROR_SUCCESS);
1972
	len_value = GetEnvironmentVariableW(w_key, w_value, ARRAY_SIZE(w_value));
1973
	if (!len_value && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
1974
		free(w_key);
1975
		return NULL;
1976
	}
1977
	free(w_key);
1978

1979
	len_value = len_value * 3 + 1;
1980
	/* We cannot use xcalloc() here because that uses getenv() itself */
1981
	value = calloc(len_value, sizeof(char));
1982
	if (!value)
1983
		die("Out of memory, (tried to allocate %u bytes)", len_value);
1984
	xwcstoutf(value, w_value, len_value);
1985

1986
	/*
1987
	 * We return `value` which is an allocated value and the caller is NOT
1988
	 * expecting to have to free it, so we keep a round-robin array,
1989
	 * invalidating the buffer after GETENV_MAX_RETAIN getenv() calls.
1990
	 */
1991
	free(values[value_counter]);
1992
	values[value_counter++] = value;
1993
	if (value_counter >= ARRAY_SIZE(values))
1994
		value_counter = 0;
1995

1996
	return value;
1997
}
1998

1999
int mingw_putenv(const char *namevalue)
2000
{
2001
	int size;
2002
	wchar_t *wide, *equal;
2003
	BOOL result;
2004

2005
	if (!namevalue || !*namevalue)
2006
		return 0;
2007

2008
	size = strlen(namevalue) * 2 + 1;
2009
	wide = calloc(size, sizeof(wchar_t));
2010
	if (!wide)
2011
		die("Out of memory, (tried to allocate %u wchar_t's)", size);
2012
	xutftowcs(wide, namevalue, size);
2013
	equal = wcschr(wide, L'=');
2014
	if (!equal)
2015
		result = SetEnvironmentVariableW(wide, NULL);
2016
	else {
2017
		*equal = L'\0';
2018
		result = SetEnvironmentVariableW(wide, equal + 1);
2019
	}
2020
	free(wide);
2021

2022
	if (!result)
2023
		errno = err_win_to_posix(GetLastError());
2024

2025
	return result ? 0 : -1;
2026
}
2027

2028
static void ensure_socket_initialization(void)
2029
{
2030
	WSADATA wsa;
2031
	static int initialized = 0;
2032

2033
	if (initialized)
2034
		return;
2035

2036
	if (WSAStartup(MAKEWORD(2,2), &wsa))
2037
		die("unable to initialize winsock subsystem, error %d",
2038
			WSAGetLastError());
2039

2040
	atexit((void(*)(void)) WSACleanup);
2041
	initialized = 1;
2042
}
2043

2044
#undef gethostname
2045
int mingw_gethostname(char *name, int namelen)
2046
{
2047
    ensure_socket_initialization();
2048
    return gethostname(name, namelen);
2049
}
2050

2051
#undef gethostbyname
2052
struct hostent *mingw_gethostbyname(const char *host)
2053
{
2054
	ensure_socket_initialization();
2055
	return gethostbyname(host);
2056
}
2057

2058
#undef getaddrinfo
2059
int mingw_getaddrinfo(const char *node, const char *service,
2060
		      const struct addrinfo *hints, struct addrinfo **res)
2061
{
2062
	ensure_socket_initialization();
2063
	return getaddrinfo(node, service, hints, res);
2064
}
2065

2066
int mingw_socket(int domain, int type, int protocol)
2067
{
2068
	int sockfd;
2069
	SOCKET s;
2070

2071
	ensure_socket_initialization();
2072
	s = WSASocket(domain, type, protocol, NULL, 0, 0);
2073
	if (s == INVALID_SOCKET) {
2074
		/*
2075
		 * WSAGetLastError() values are regular BSD error codes
2076
		 * biased by WSABASEERR.
2077
		 * However, strerror() does not know about networking
2078
		 * specific errors, which are values beginning at 38 or so.
2079
		 * Therefore, we choose to leave the biased error code
2080
		 * in errno so that _if_ someone looks up the code somewhere,
2081
		 * then it is at least the number that are usually listed.
2082
		 */
2083
		errno = WSAGetLastError();
2084
		return -1;
2085
	}
2086
	/* convert into a file descriptor */
2087
	if ((sockfd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) {
2088
		closesocket(s);
2089
		return error("unable to make a socket file descriptor: %s",
2090
			strerror(errno));
2091
	}
2092
	return sockfd;
2093
}
2094

2095
#undef connect
2096
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
2097
{
2098
	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2099
	return connect(s, sa, sz);
2100
}
2101

2102
#undef bind
2103
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
2104
{
2105
	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2106
	return bind(s, sa, sz);
2107
}
2108

2109
#undef setsockopt
2110
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
2111
{
2112
	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2113
	return setsockopt(s, lvl, optname, (const char*)optval, optlen);
2114
}
2115

2116
#undef shutdown
2117
int mingw_shutdown(int sockfd, int how)
2118
{
2119
	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2120
	return shutdown(s, how);
2121
}
2122

2123
#undef listen
2124
int mingw_listen(int sockfd, int backlog)
2125
{
2126
	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
2127
	return listen(s, backlog);
2128
}
2129

2130
#undef accept
2131
int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
2132
{
2133
	int sockfd2;
2134

2135
	SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
2136
	SOCKET s2 = accept(s1, sa, sz);
2137

2138
	/* convert into a file descriptor */
2139
	if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
2140
		int err = errno;
2141
		closesocket(s2);
2142
		return error("unable to make a socket file descriptor: %s",
2143
			strerror(err));
2144
	}
2145
	return sockfd2;
2146
}
2147

2148
#undef rename
2149
int mingw_rename(const char *pold, const char *pnew)
2150
{
2151
	DWORD attrs, gle;
2152
	int tries = 0;
2153
	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
2154
	if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
2155
		return -1;
2156

2157
	/*
2158
	 * Try native rename() first to get errno right.
2159
	 * It is based on MoveFile(), which cannot overwrite existing files.
2160
	 */
2161
	if (!_wrename(wpold, wpnew))
2162
		return 0;
2163
	if (errno != EEXIST)
2164
		return -1;
2165
repeat:
2166
	if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
2167
		return 0;
2168
	/* TODO: translate more errors */
2169
	gle = GetLastError();
2170
	if (gle == ERROR_ACCESS_DENIED &&
2171
	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
2172
		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
2173
			DWORD attrsold = GetFileAttributesW(wpold);
2174
			if (attrsold == INVALID_FILE_ATTRIBUTES ||
2175
			    !(attrsold & FILE_ATTRIBUTE_DIRECTORY))
2176
				errno = EISDIR;
2177
			else if (!_wrmdir(wpnew))
2178
				goto repeat;
2179
			return -1;
2180
		}
2181
		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
2182
		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
2183
			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
2184
				return 0;
2185
			gle = GetLastError();
2186
			/* revert file attributes on failure */
2187
			SetFileAttributesW(wpnew, attrs);
2188
		}
2189
	}
2190
	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
2191
		/*
2192
		 * We assume that some other process had the source or
2193
		 * destination file open at the wrong moment and retry.
2194
		 * In order to give the other process a higher chance to
2195
		 * complete its operation, we give up our time slice now.
2196
		 * If we have to retry again, we do sleep a bit.
2197
		 */
2198
		Sleep(delay[tries]);
2199
		tries++;
2200
		goto repeat;
2201
	}
2202
	if (gle == ERROR_ACCESS_DENIED &&
2203
	       ask_yes_no_if_possible("Rename from '%s' to '%s' failed. "
2204
		       "Should I try again?", pold, pnew))
2205
		goto repeat;
2206

2207
	errno = EACCES;
2208
	return -1;
2209
}
2210

2211
/*
2212
 * Note that this doesn't return the actual pagesize, but
2213
 * the allocation granularity. If future Windows specific git code
2214
 * needs the real getpagesize function, we need to find another solution.
2215
 */
2216
int mingw_getpagesize(void)
2217
{
2218
	SYSTEM_INFO si;
2219
	GetSystemInfo(&si);
2220
	return si.dwAllocationGranularity;
2221
}
2222

2223
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx */
2224
enum EXTENDED_NAME_FORMAT {
2225
	NameDisplay = 3,
2226
	NameUserPrincipal = 8
2227
};
2228

2229
static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type)
2230
{
2231
	DECLARE_PROC_ADDR(secur32.dll, BOOL, SEC_ENTRY, GetUserNameExW,
2232
		enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG);
2233
	static wchar_t wbuffer[1024];
2234
	DWORD len;
2235

2236
	if (!INIT_PROC_ADDR(GetUserNameExW))
2237
		return NULL;
2238

2239
	len = ARRAY_SIZE(wbuffer);
2240
	if (GetUserNameExW(type, wbuffer, &len)) {
2241
		char *converted = xmalloc((len *= 3));
2242
		if (xwcstoutf(converted, wbuffer, len) >= 0)
2243
			return converted;
2244
		free(converted);
2245
	}
2246

2247
	return NULL;
2248
}
2249

2250
char *mingw_query_user_email(void)
2251
{
2252
	return get_extended_user_info(NameUserPrincipal);
2253
}
2254

2255
struct passwd *getpwuid(int uid)
2256
{
2257
	static unsigned initialized;
2258
	static char user_name[100];
2259
	static struct passwd *p;
2260
	wchar_t buf[100];
2261
	DWORD len;
2262

2263
	if (initialized)
2264
		return p;
2265

2266
	len = ARRAY_SIZE(buf);
2267
	if (!GetUserNameW(buf, &len)) {
2268
		initialized = 1;
2269
		return NULL;
2270
	}
2271

2272
	if (xwcstoutf(user_name, buf, sizeof(user_name)) < 0) {
2273
		initialized = 1;
2274
		return NULL;
2275
	}
2276

2277
	p = xmalloc(sizeof(*p));
2278
	p->pw_name = user_name;
2279
	p->pw_gecos = get_extended_user_info(NameDisplay);
2280
	if (!p->pw_gecos)
2281
		/*
2282
		 * Data returned by getpwuid(3P) is treated as internal and
2283
		 * must never be written to or freed.
2284
		 */
2285
		p->pw_gecos = (char *) "unknown";
2286
	p->pw_dir = NULL;
2287

2288
	initialized = 1;
2289
	return p;
2290
}
2291

2292
static HANDLE timer_event;
2293
static HANDLE timer_thread;
2294
static int timer_interval;
2295
static int one_shot;
2296
static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
2297

2298
/* The timer works like this:
2299
 * The thread, ticktack(), is a trivial routine that most of the time
2300
 * only waits to receive the signal to terminate. The main thread tells
2301
 * the thread to terminate by setting the timer_event to the signalled
2302
 * state.
2303
 * But ticktack() interrupts the wait state after the timer's interval
2304
 * length to call the signal handler.
2305
 */
2306

2307
static unsigned __stdcall ticktack(void *dummy)
2308
{
2309
	while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
2310
		mingw_raise(SIGALRM);
2311
		if (one_shot)
2312
			break;
2313
	}
2314
	return 0;
2315
}
2316

2317
static int start_timer_thread(void)
2318
{
2319
	timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
2320
	if (timer_event) {
2321
		timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
2322
		if (!timer_thread )
2323
			return errno = ENOMEM,
2324
				error("cannot start timer thread");
2325
	} else
2326
		return errno = ENOMEM,
2327
			error("cannot allocate resources for timer");
2328
	return 0;
2329
}
2330

2331
static void stop_timer_thread(void)
2332
{
2333
	if (timer_event)
2334
		SetEvent(timer_event);	/* tell thread to terminate */
2335
	if (timer_thread) {
2336
		int rc = WaitForSingleObject(timer_thread, 10000);
2337
		if (rc == WAIT_TIMEOUT)
2338
			error("timer thread did not terminate timely");
2339
		else if (rc != WAIT_OBJECT_0)
2340
			error("waiting for timer thread failed: %lu",
2341
			      GetLastError());
2342
		CloseHandle(timer_thread);
2343
	}
2344
	if (timer_event)
2345
		CloseHandle(timer_event);
2346
	timer_event = NULL;
2347
	timer_thread = NULL;
2348
}
2349

2350
static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
2351
{
2352
	return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
2353
}
2354

2355
int setitimer(int type, struct itimerval *in, struct itimerval *out)
2356
{
2357
	static const struct timeval zero;
2358
	static int atexit_done;
2359

2360
	if (out)
2361
		return errno = EINVAL,
2362
			error("setitimer param 3 != NULL not implemented");
2363
	if (!is_timeval_eq(&in->it_interval, &zero) &&
2364
	    !is_timeval_eq(&in->it_interval, &in->it_value))
2365
		return errno = EINVAL,
2366
			error("setitimer: it_interval must be zero or eq it_value");
2367

2368
	if (timer_thread)
2369
		stop_timer_thread();
2370

2371
	if (is_timeval_eq(&in->it_value, &zero) &&
2372
	    is_timeval_eq(&in->it_interval, &zero))
2373
		return 0;
2374

2375
	timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
2376
	one_shot = is_timeval_eq(&in->it_interval, &zero);
2377
	if (!atexit_done) {
2378
		atexit(stop_timer_thread);
2379
		atexit_done = 1;
2380
	}
2381
	return start_timer_thread();
2382
}
2383

2384
int sigaction(int sig, struct sigaction *in, struct sigaction *out)
2385
{
2386
	if (sig != SIGALRM)
2387
		return errno = EINVAL,
2388
			error("sigaction only implemented for SIGALRM");
2389
	if (out)
2390
		return errno = EINVAL,
2391
			error("sigaction: param 3 != NULL not implemented");
2392

2393
	timer_fn = in->sa_handler;
2394
	return 0;
2395
}
2396

2397
#undef signal
2398
sig_handler_t mingw_signal(int sig, sig_handler_t handler)
2399
{
2400
	sig_handler_t old;
2401

2402
	switch (sig) {
2403
	case SIGALRM:
2404
		old = timer_fn;
2405
		timer_fn = handler;
2406
		break;
2407

2408
	case SIGINT:
2409
		old = sigint_fn;
2410
		sigint_fn = handler;
2411
		break;
2412

2413
	default:
2414
		return signal(sig, handler);
2415
	}
2416

2417
	return old;
2418
}
2419

2420
#undef raise
2421
int mingw_raise(int sig)
2422
{
2423
	switch (sig) {
2424
	case SIGALRM:
2425
		if (timer_fn == SIG_DFL) {
2426
			if (isatty(STDERR_FILENO))
2427
				fputs("Alarm clock\n", stderr);
2428
			exit(128 + SIGALRM);
2429
		} else if (timer_fn != SIG_IGN)
2430
			timer_fn(SIGALRM);
2431
		return 0;
2432

2433
	case SIGINT:
2434
		if (sigint_fn == SIG_DFL)
2435
			exit(128 + SIGINT);
2436
		else if (sigint_fn != SIG_IGN)
2437
			sigint_fn(SIGINT);
2438
		return 0;
2439

2440
#if defined(_MSC_VER)
2441
	case SIGILL:
2442
	case SIGFPE:
2443
	case SIGSEGV:
2444
	case SIGTERM:
2445
	case SIGBREAK:
2446
	case SIGABRT:
2447
	case SIGABRT_COMPAT:
2448
		/*
2449
		 * The <signal.h> header in the MS C Runtime defines 8 signals
2450
		 * as being supported on the platform. Anything else causes an
2451
		 * "Invalid signal or error" (which in DEBUG builds causes the
2452
		 * Abort/Retry/Ignore dialog). We by-pass the CRT for things we
2453
		 * already know will fail.
2454
		 */
2455
		return raise(sig);
2456
	default:
2457
		errno = EINVAL;
2458
		return -1;
2459

2460
#else
2461

2462
	default:
2463
		return raise(sig);
2464

2465
#endif
2466

2467
	}
2468
}
2469

2470
int link(const char *oldpath, const char *newpath)
2471
{
2472
	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
2473
	if (xutftowcs_path(woldpath, oldpath) < 0 ||
2474
		xutftowcs_path(wnewpath, newpath) < 0)
2475
		return -1;
2476

2477
	if (!CreateHardLinkW(wnewpath, woldpath, NULL)) {
2478
		errno = err_win_to_posix(GetLastError());
2479
		return -1;
2480
	}
2481
	return 0;
2482
}
2483

2484
pid_t waitpid(pid_t pid, int *status, int options)
2485
{
2486
	HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
2487
	    FALSE, pid);
2488
	if (!h) {
2489
		errno = ECHILD;
2490
		return -1;
2491
	}
2492

2493
	if (pid > 0 && options & WNOHANG) {
2494
		if (WAIT_OBJECT_0 != WaitForSingleObject(h, 0)) {
2495
			CloseHandle(h);
2496
			return 0;
2497
		}
2498
		options &= ~WNOHANG;
2499
	}
2500

2501
	if (options == 0) {
2502
		struct pinfo_t **ppinfo;
2503
		if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
2504
			CloseHandle(h);
2505
			return 0;
2506
		}
2507

2508
		if (status)
2509
			GetExitCodeProcess(h, (LPDWORD)status);
2510

2511
		EnterCriticalSection(&pinfo_cs);
2512

2513
		ppinfo = &pinfo;
2514
		while (*ppinfo) {
2515
			struct pinfo_t *info = *ppinfo;
2516
			if (info->pid == pid) {
2517
				CloseHandle(info->proc);
2518
				*ppinfo = info->next;
2519
				free(info);
2520
				break;
2521
			}
2522
			ppinfo = &info->next;
2523
		}
2524

2525
		LeaveCriticalSection(&pinfo_cs);
2526

2527
		CloseHandle(h);
2528
		return pid;
2529
	}
2530
	CloseHandle(h);
2531

2532
	errno = EINVAL;
2533
	return -1;
2534
}
2535

2536
int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
2537
{
2538
	int upos = 0, wpos = 0;
2539
	const unsigned char *utf = (const unsigned char*) utfs;
2540
	if (!utf || !wcs || wcslen < 1) {
2541
		errno = EINVAL;
2542
		return -1;
2543
	}
2544
	/* reserve space for \0 */
2545
	wcslen--;
2546
	if (utflen < 0)
2547
		utflen = INT_MAX;
2548

2549
	while (upos < utflen) {
2550
		int c = utf[upos++] & 0xff;
2551
		if (utflen == INT_MAX && c == 0)
2552
			break;
2553

2554
		if (wpos >= wcslen) {
2555
			wcs[wpos] = 0;
2556
			errno = ERANGE;
2557
			return -1;
2558
		}
2559

2560
		if (c < 0x80) {
2561
			/* ASCII */
2562
			wcs[wpos++] = c;
2563
		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
2564
				(utf[upos] & 0xc0) == 0x80) {
2565
			/* 2-byte utf-8 */
2566
			c = ((c & 0x1f) << 6);
2567
			c |= (utf[upos++] & 0x3f);
2568
			wcs[wpos++] = c;
2569
		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
2570
				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
2571
				(utf[upos] & 0xc0) == 0x80 &&
2572
				(utf[upos + 1] & 0xc0) == 0x80) {
2573
			/* 3-byte utf-8 */
2574
			c = ((c & 0x0f) << 12);
2575
			c |= ((utf[upos++] & 0x3f) << 6);
2576
			c |= (utf[upos++] & 0x3f);
2577
			wcs[wpos++] = c;
2578
		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
2579
				wpos + 1 < wcslen &&
2580
				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
2581
				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
2582
				(utf[upos] & 0xc0) == 0x80 &&
2583
				(utf[upos + 1] & 0xc0) == 0x80 &&
2584
				(utf[upos + 2] & 0xc0) == 0x80) {
2585
			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
2586
			c = ((c & 0x07) << 18);
2587
			c |= ((utf[upos++] & 0x3f) << 12);
2588
			c |= ((utf[upos++] & 0x3f) << 6);
2589
			c |= (utf[upos++] & 0x3f);
2590
			c -= 0x10000;
2591
			wcs[wpos++] = 0xd800 | (c >> 10);
2592
			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
2593
		} else if (c >= 0xa0) {
2594
			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
2595
			wcs[wpos++] = c;
2596
		} else {
2597
			/* invalid utf-8 byte, non-printable unicode: convert to hex */
2598
			static const char *hex = "0123456789abcdef";
2599
			wcs[wpos++] = hex[c >> 4];
2600
			if (wpos < wcslen)
2601
				wcs[wpos++] = hex[c & 0x0f];
2602
		}
2603
	}
2604
	wcs[wpos] = 0;
2605
	return wpos;
2606
}
2607

2608
int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
2609
{
2610
	if (!wcs || !utf || utflen < 1) {
2611
		errno = EINVAL;
2612
		return -1;
2613
	}
2614
	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
2615
	if (utflen)
2616
		return utflen - 1;
2617
	errno = ERANGE;
2618
	return -1;
2619
}
2620

2621
static void setup_windows_environment(void)
2622
{
2623
	char *tmp = getenv("TMPDIR");
2624

2625
	/* on Windows it is TMP and TEMP */
2626
	if (!tmp) {
2627
		if (!(tmp = getenv("TMP")))
2628
			tmp = getenv("TEMP");
2629
		if (tmp) {
2630
			setenv("TMPDIR", tmp, 1);
2631
			tmp = getenv("TMPDIR");
2632
		}
2633
	}
2634

2635
	if (tmp) {
2636
		/*
2637
		 * Convert all dir separators to forward slashes,
2638
		 * to help shell commands called from the Git
2639
		 * executable (by not mistaking the dir separators
2640
		 * for escape characters).
2641
		 */
2642
		convert_slashes(tmp);
2643
	}
2644

2645
	/* simulate TERM to enable auto-color (see color.c) */
2646
	if (!getenv("TERM"))
2647
		setenv("TERM", "cygwin", 1);
2648

2649
	/* calculate HOME if not set */
2650
	if (!getenv("HOME")) {
2651
		/*
2652
		 * try $HOMEDRIVE$HOMEPATH - the home share may be a network
2653
		 * location, thus also check if the path exists (i.e. is not
2654
		 * disconnected)
2655
		 */
2656
		if ((tmp = getenv("HOMEDRIVE"))) {
2657
			struct strbuf buf = STRBUF_INIT;
2658
			strbuf_addstr(&buf, tmp);
2659
			if ((tmp = getenv("HOMEPATH"))) {
2660
				strbuf_addstr(&buf, tmp);
2661
				if (is_directory(buf.buf))
2662
					setenv("HOME", buf.buf, 1);
2663
				else
2664
					tmp = NULL; /* use $USERPROFILE */
2665
			}
2666
			strbuf_release(&buf);
2667
		}
2668
		/* use $USERPROFILE if the home share is not available */
2669
		if (!tmp && (tmp = getenv("USERPROFILE")))
2670
			setenv("HOME", tmp, 1);
2671
	}
2672
}
2673

2674
static PSID get_current_user_sid(void)
2675
{
2676
	HANDLE token;
2677
	DWORD len = 0;
2678
	PSID result = NULL;
2679

2680
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
2681
		return NULL;
2682

2683
	if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) {
2684
		TOKEN_USER *info = xmalloc((size_t)len);
2685
		if (GetTokenInformation(token, TokenUser, info, len, &len)) {
2686
			len = GetLengthSid(info->User.Sid);
2687
			result = xmalloc(len);
2688
			if (!CopySid(len, result, info->User.Sid)) {
2689
				error(_("failed to copy SID (%ld)"),
2690
				      GetLastError());
2691
				FREE_AND_NULL(result);
2692
			}
2693
		}
2694
		FREE_AND_NULL(info);
2695
	}
2696
	CloseHandle(token);
2697

2698
	return result;
2699
}
2700

2701
static BOOL user_sid_to_user_name(PSID sid, LPSTR *str)
2702
{
2703
	SID_NAME_USE pe_use;
2704
	DWORD len_user = 0, len_domain = 0;
2705
	BOOL translate_sid_to_user;
2706

2707
	/*
2708
	 * returns only FALSE, because the string pointers are NULL
2709
	 */
2710
	LookupAccountSidA(NULL, sid, NULL, &len_user, NULL, &len_domain,
2711
			  &pe_use);
2712
	/*
2713
	 * Alloc needed space of the strings
2714
	 */
2715
	ALLOC_ARRAY((*str), (size_t)len_domain + (size_t)len_user);
2716
	translate_sid_to_user = LookupAccountSidA(NULL, sid,
2717
	    (*str) + len_domain, &len_user, *str, &len_domain, &pe_use);
2718
	if (!translate_sid_to_user)
2719
		FREE_AND_NULL(*str);
2720
	else
2721
		(*str)[len_domain] = '/';
2722
	return translate_sid_to_user;
2723
}
2724

2725
static int acls_supported(const char *path)
2726
{
2727
	size_t offset = offset_1st_component(path);
2728
	WCHAR wroot[MAX_PATH];
2729
	DWORD file_system_flags;
2730

2731
	if (offset &&
2732
	    xutftowcsn(wroot, path, MAX_PATH, offset) > 0 &&
2733
	    GetVolumeInformationW(wroot, NULL, 0, NULL, NULL,
2734
				  &file_system_flags, NULL, 0))
2735
		return !!(file_system_flags & FILE_PERSISTENT_ACLS);
2736

2737
	return 0;
2738
}
2739

2740
int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
2741
{
2742
	WCHAR wpath[MAX_PATH];
2743
	PSID sid = NULL;
2744
	PSECURITY_DESCRIPTOR descriptor = NULL;
2745
	DWORD err;
2746

2747
	static wchar_t home[MAX_PATH];
2748

2749
	int result = 0;
2750

2751
	if (xutftowcs_path(wpath, path) < 0)
2752
		return 0;
2753

2754
	/*
2755
	 * On Windows, the home directory is owned by the administrator, but for
2756
	 * all practical purposes, it belongs to the user. Do pretend that it is
2757
	 * owned by the user.
2758
	 */
2759
	if (!*home) {
2760
		DWORD size = ARRAY_SIZE(home);
2761
		DWORD len = GetEnvironmentVariableW(L"HOME", home, size);
2762
		if (!len || len > size)
2763
			wcscpy(home, L"::N/A::");
2764
	}
2765
	if (!wcsicmp(wpath, home))
2766
		return 1;
2767

2768
	/* Get the owner SID */
2769
	err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT,
2770
				    OWNER_SECURITY_INFORMATION |
2771
				    DACL_SECURITY_INFORMATION,
2772
				    &sid, NULL, NULL, NULL, &descriptor);
2773

2774
	if (err != ERROR_SUCCESS)
2775
		error(_("failed to get owner for '%s' (%ld)"), path, err);
2776
	else if (sid && IsValidSid(sid)) {
2777
		/* Now, verify that the SID matches the current user's */
2778
		static PSID current_user_sid;
2779
		BOOL is_member;
2780

2781
		if (!current_user_sid)
2782
			current_user_sid = get_current_user_sid();
2783

2784
		if (current_user_sid &&
2785
		    IsValidSid(current_user_sid) &&
2786
		    EqualSid(sid, current_user_sid))
2787
			result = 1;
2788
		else if (IsWellKnownSid(sid, WinBuiltinAdministratorsSid) &&
2789
			 CheckTokenMembership(NULL, sid, &is_member) &&
2790
			 is_member)
2791
			/*
2792
			 * If owned by the Administrators group, and the
2793
			 * current user is an administrator, we consider that
2794
			 * okay, too.
2795
			 */
2796
			result = 1;
2797
		else if (report &&
2798
			 IsWellKnownSid(sid, WinWorldSid) &&
2799
			 !acls_supported(path)) {
2800
			/*
2801
			 * On FAT32 volumes, ownership is not actually recorded.
2802
			 */
2803
			strbuf_addf(report, "'%s' is on a file system that does "
2804
				    "not record ownership\n", path);
2805
		} else if (report) {
2806
			PCSTR str1, str2, str3, str4;
2807
			LPSTR to_free1 = NULL, to_free3 = NULL,
2808
			    to_local_free2 = NULL, to_local_free4 = NULL;
2809

2810
			if (user_sid_to_user_name(sid, &to_free1))
2811
				str1 = to_free1;
2812
			else
2813
				str1 = "(inconvertible)";
2814
			if (ConvertSidToStringSidA(sid, &to_local_free2))
2815
				str2 = to_local_free2;
2816
			else
2817
				str2 = "(inconvertible)";
2818

2819
			if (!current_user_sid) {
2820
				str3 = "(none)";
2821
				str4 = "(none)";
2822
			}
2823
			else if (!IsValidSid(current_user_sid)) {
2824
				str3 = "(invalid)";
2825
				str4 = "(invalid)";
2826
			} else {
2827
				if (user_sid_to_user_name(current_user_sid,
2828
							  &to_free3))
2829
					str3 = to_free3;
2830
				else
2831
					str3 = "(inconvertible)";
2832
				if (ConvertSidToStringSidA(current_user_sid,
2833
							   &to_local_free4))
2834
					str4 = to_local_free4;
2835
				else
2836
					str4 = "(inconvertible)";
2837
			}
2838
			strbuf_addf(report,
2839
				    "'%s' is owned by:\n"
2840
				    "\t%s (%s)\nbut the current user is:\n"
2841
				    "\t%s (%s)\n",
2842
				    path, str1, str2, str3, str4);
2843
			free(to_free1);
2844
			LocalFree(to_local_free2);
2845
			free(to_free3);
2846
			LocalFree(to_local_free4);
2847
		}
2848
	}
2849

2850
	/*
2851
	 * We can release the security descriptor struct only now because `sid`
2852
	 * actually points into this struct.
2853
	 */
2854
	if (descriptor)
2855
		LocalFree(descriptor);
2856

2857
	return result;
2858
}
2859

2860
int is_valid_win32_path(const char *path, int allow_literal_nul)
2861
{
2862
	const char *p = path;
2863
	int preceding_space_or_period = 0, i = 0, periods = 0;
2864

2865
	if (!protect_ntfs)
2866
		return 1;
2867

2868
	skip_dos_drive_prefix((char **)&path);
2869
	goto segment_start;
2870

2871
	for (;;) {
2872
		char c = *(path++);
2873
		switch (c) {
2874
		case '\0':
2875
		case '/': case '\\':
2876
			/* cannot end in ` ` or `.`, except for `.` and `..` */
2877
			if (preceding_space_or_period &&
2878
			    (i != periods || periods > 2))
2879
				return 0;
2880
			if (!c)
2881
				return 1;
2882

2883
			i = periods = preceding_space_or_period = 0;
2884

2885
segment_start:
2886
			switch (*path) {
2887
			case 'a': case 'A': /* AUX */
2888
				if (((c = path[++i]) != 'u' && c != 'U') ||
2889
				    ((c = path[++i]) != 'x' && c != 'X')) {
2890
not_a_reserved_name:
2891
					path += i;
2892
					continue;
2893
				}
2894
				break;
2895
			case 'c': case 'C':
2896
				/* COM1 ... COM9, CON, CONIN$, CONOUT$ */
2897
				if ((c = path[++i]) != 'o' && c != 'O')
2898
					goto not_a_reserved_name;
2899
				c = path[++i];
2900
				if (c == 'm' || c == 'M') { /* COM1 ... COM9 */
2901
					c = path[++i];
2902
					if (c < '1' || c > '9')
2903
						goto not_a_reserved_name;
2904
				} else if (c == 'n' || c == 'N') { /* CON */
2905
					c = path[i + 1];
2906
					if ((c == 'i' || c == 'I') &&
2907
					    ((c = path[i + 2]) == 'n' ||
2908
					     c == 'N') &&
2909
					    path[i + 3] == '$')
2910
						i += 3; /* CONIN$ */
2911
					else if ((c == 'o' || c == 'O') &&
2912
						 ((c = path[i + 2]) == 'u' ||
2913
						  c == 'U') &&
2914
						 ((c = path[i + 3]) == 't' ||
2915
						  c == 'T') &&
2916
						 path[i + 4] == '$')
2917
						i += 4; /* CONOUT$ */
2918
				} else
2919
					goto not_a_reserved_name;
2920
				break;
2921
			case 'l': case 'L': /* LPT<N> */
2922
				if (((c = path[++i]) != 'p' && c != 'P') ||
2923
				    ((c = path[++i]) != 't' && c != 'T') ||
2924
				    !isdigit(path[++i]))
2925
					goto not_a_reserved_name;
2926
				break;
2927
			case 'n': case 'N': /* NUL */
2928
				if (((c = path[++i]) != 'u' && c != 'U') ||
2929
				    ((c = path[++i]) != 'l' && c != 'L') ||
2930
				    (allow_literal_nul &&
2931
				     !path[i + 1] && p == path))
2932
					goto not_a_reserved_name;
2933
				break;
2934
			case 'p': case 'P': /* PRN */
2935
				if (((c = path[++i]) != 'r' && c != 'R') ||
2936
				    ((c = path[++i]) != 'n' && c != 'N'))
2937
					goto not_a_reserved_name;
2938
				break;
2939
			default:
2940
				continue;
2941
			}
2942

2943
			/*
2944
			 * So far, this looks like a reserved name. Let's see
2945
			 * whether it actually is one: trailing spaces, a file
2946
			 * extension, or an NTFS Alternate Data Stream do not
2947
			 * matter, the name is still reserved if any of those
2948
			 * follow immediately after the actual name.
2949
			 */
2950
			i++;
2951
			if (path[i] == ' ') {
2952
				preceding_space_or_period = 1;
2953
				while (path[++i] == ' ')
2954
					; /* skip all spaces */
2955
			}
2956

2957
			c = path[i];
2958
			if (c && c != '.' && c != ':' && !is_xplatform_dir_sep(c))
2959
				goto not_a_reserved_name;
2960

2961
			/* contains reserved name */
2962
			return 0;
2963
		case '.':
2964
			periods++;
2965
			/* fallthru */
2966
		case ' ':
2967
			preceding_space_or_period = 1;
2968
			i++;
2969
			continue;
2970
		case ':': /* DOS drive prefix was already skipped */
2971
		case '<': case '>': case '"': case '|': case '?': case '*':
2972
			/* illegal character */
2973
			return 0;
2974
		default:
2975
			if (c > '\0' && c < '\x20')
2976
				/* illegal character */
2977
				return 0;
2978
		}
2979
		preceding_space_or_period = 0;
2980
		i++;
2981
	}
2982
}
2983

2984
#if !defined(_MSC_VER)
2985
/*
2986
 * Disable MSVCRT command line wildcard expansion (__getmainargs called from
2987
 * mingw startup code, see init.c in mingw runtime).
2988
 */
2989
int _CRT_glob = 0;
2990
#endif
2991

2992
static NORETURN void die_startup(void)
2993
{
2994
	fputs("fatal: not enough memory for initialization", stderr);
2995
	exit(128);
2996
}
2997

2998
static void *malloc_startup(size_t size)
2999
{
3000
	void *result = malloc(size);
3001
	if (!result)
3002
		die_startup();
3003
	return result;
3004
}
3005

3006
static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
3007
{
3008
	len = xwcstoutf(buffer, wcs, len) + 1;
3009
	return memcpy(malloc_startup(len), buffer, len);
3010
}
3011

3012
static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
3013
				      DWORD desired_access, DWORD flags)
3014
{
3015
	DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
3016
	wchar_t buf[MAX_PATH];
3017
	DWORD max = ARRAY_SIZE(buf);
3018
	HANDLE handle;
3019
	DWORD ret = GetEnvironmentVariableW(key, buf, max);
3020

3021
	if (!ret || ret >= max)
3022
		return;
3023

3024
	/* make sure this does not leak into child processes */
3025
	SetEnvironmentVariableW(key, NULL);
3026
	if (!wcscmp(buf, L"off")) {
3027
		close(fd);
3028
		handle = GetStdHandle(std_id);
3029
		if (handle != INVALID_HANDLE_VALUE)
3030
			CloseHandle(handle);
3031
		return;
3032
	}
3033
	if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
3034
		handle = GetStdHandle(STD_OUTPUT_HANDLE);
3035
		if (handle == INVALID_HANDLE_VALUE) {
3036
			close(fd);
3037
			handle = GetStdHandle(std_id);
3038
			if (handle != INVALID_HANDLE_VALUE)
3039
				CloseHandle(handle);
3040
		} else {
3041
			int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
3042
			SetStdHandle(std_id, handle);
3043
			dup2(new_fd, fd);
3044
			/* do *not* close the new_fd: that would close stdout */
3045
		}
3046
		return;
3047
	}
3048
	handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
3049
			     flags, NULL);
3050
	if (handle != INVALID_HANDLE_VALUE) {
3051
		int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
3052
		SetStdHandle(std_id, handle);
3053
		dup2(new_fd, fd);
3054
		close(new_fd);
3055
	}
3056
}
3057

3058
static void maybe_redirect_std_handles(void)
3059
{
3060
	maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
3061
				  GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
3062
	maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
3063
				  GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
3064
	maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
3065
				  GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
3066
}
3067

3068
#ifdef _MSC_VER
3069
#ifdef _DEBUG
3070
#include <crtdbg.h>
3071
#endif
3072
#endif
3073

3074
/*
3075
 * We implement wmain() and compile with -municode, which would
3076
 * normally ignore main(), but we call the latter from the former
3077
 * so that we can handle non-ASCII command-line parameters
3078
 * appropriately.
3079
 *
3080
 * To be more compatible with the core git code, we convert
3081
 * argv into UTF8 and pass them directly to main().
3082
 */
3083
int wmain(int argc, const wchar_t **wargv)
3084
{
3085
	int i, maxlen, exit_status;
3086
	char *buffer, **save;
3087
	const char **argv;
3088

3089
	trace2_initialize_clock();
3090

3091
#ifdef _MSC_VER
3092
#ifdef _DEBUG
3093
	_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
3094
#endif
3095

3096
#ifdef USE_MSVC_CRTDBG
3097
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
3098
#endif
3099
#endif
3100

3101
	maybe_redirect_std_handles();
3102

3103
	/* determine size of argv and environ conversion buffer */
3104
	maxlen = wcslen(wargv[0]);
3105
	for (i = 1; i < argc; i++)
3106
		maxlen = max(maxlen, wcslen(wargv[i]));
3107

3108
	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
3109
	maxlen = 3 * maxlen + 1;
3110
	buffer = malloc_startup(maxlen);
3111

3112
	/*
3113
	 * Create a UTF-8 version of w_argv. Also create a "save" copy
3114
	 * to remember all the string pointers because parse_options()
3115
	 * will remove claimed items from the argv that we pass down.
3116
	 */
3117
	ALLOC_ARRAY(argv, argc + 1);
3118
	ALLOC_ARRAY(save, argc + 1);
3119
	for (i = 0; i < argc; i++)
3120
		argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
3121
	argv[i] = save[i] = NULL;
3122
	free(buffer);
3123

3124
	/* fix Windows specific environment settings */
3125
	setup_windows_environment();
3126

3127
	unset_environment_variables = xstrdup("PERL5LIB");
3128

3129
	/* initialize critical section for waitpid pinfo_t list */
3130
	InitializeCriticalSection(&pinfo_cs);
3131

3132
	/* set up default file mode and file modes for stdin/out/err */
3133
	_fmode = _O_BINARY;
3134
	_setmode(_fileno(stdin), _O_BINARY);
3135
	_setmode(_fileno(stdout), _O_BINARY);
3136
	_setmode(_fileno(stderr), _O_BINARY);
3137

3138
	/* initialize Unicode console */
3139
	winansi_init();
3140

3141
	/* invoke the real main() using our utf8 version of argv. */
3142
	exit_status = main(argc, argv);
3143

3144
	for (i = 0; i < argc; i++)
3145
		free(save[i]);
3146
	free(save);
3147
	free(argv);
3148

3149
	return exit_status;
3150
}
3151

3152
int uname(struct utsname *buf)
3153
{
3154
	unsigned v = (unsigned)GetVersion();
3155
	memset(buf, 0, sizeof(*buf));
3156
	xsnprintf(buf->sysname, sizeof(buf->sysname), "Windows");
3157
	xsnprintf(buf->release, sizeof(buf->release),
3158
		 "%u.%u", v & 0xff, (v >> 8) & 0xff);
3159
	/* assuming NT variants only.. */
3160
	xsnprintf(buf->version, sizeof(buf->version),
3161
		  "%u", (v >> 16) & 0x7fff);
3162
	return 0;
3163
}
3164

3165
#ifndef NO_UNIX_SOCKETS
3166
int mingw_have_unix_sockets(void)
3167
{
3168
	SC_HANDLE scm, srvc;
3169
	SERVICE_STATUS_PROCESS status;
3170
	DWORD bytes;
3171
	int ret = 0;
3172
	scm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
3173
	if (scm) {
3174
		srvc = OpenServiceA(scm, "afunix", SERVICE_QUERY_STATUS);
3175
		if (srvc) {
3176
			if(QueryServiceStatusEx(srvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(SERVICE_STATUS_PROCESS), &bytes))
3177
				ret = status.dwCurrentState == SERVICE_RUNNING;
3178
			CloseServiceHandle(srvc);
3179
		}
3180
		CloseServiceHandle(scm);
3181
	}
3182
	return ret;
3183
}
3184
#endif
3185

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.