Git fork
at reftables-rust 3335 lines 88 kB view raw
1#define USE_THE_REPOSITORY_VARIABLE 2#define DISABLE_SIGN_COMPARE_WARNINGS 3 4#include "git-compat-util.h" 5#include "abspath.h" 6#include "alloc.h" 7#include "config.h" 8#include "dir.h" 9#include "environment.h" 10#include "gettext.h" 11#include "run-command.h" 12#include "strbuf.h" 13#include "symlinks.h" 14#include "trace2.h" 15#include "win32.h" 16#include "win32/lazyload.h" 17#include "wrapper.h" 18#include <aclapi.h> 19#include <conio.h> 20#include <sddl.h> 21#define SECURITY_WIN32 22#include <sspi.h> 23#include <wchar.h> 24#include <winternl.h> 25 26#define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056) 27 28#define HCAST(type, handle) ((type)(intptr_t)handle) 29 30static const int delay[] = { 0, 1, 10, 20, 40 }; 31 32void open_in_gdb(void) 33{ 34 static struct child_process cp = CHILD_PROCESS_INIT; 35 36 strvec_pushl(&cp.args, "mintty", "gdb", NULL); 37 strvec_pushf(&cp.args, "--pid=%d", getpid()); 38 cp.clean_on_exit = 1; 39 if (start_command(&cp) < 0) 40 die_errno("Could not start gdb"); 41 sleep(1); 42} 43 44int err_win_to_posix(DWORD winerr) 45{ 46 int error = ENOSYS; 47 switch(winerr) { 48 case ERROR_ACCESS_DENIED: error = EACCES; break; 49 case ERROR_ACCOUNT_DISABLED: error = EACCES; break; 50 case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break; 51 case ERROR_ALREADY_ASSIGNED: error = EBUSY; break; 52 case ERROR_ALREADY_EXISTS: error = EEXIST; break; 53 case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break; 54 case ERROR_BAD_COMMAND: error = EIO; break; 55 case ERROR_BAD_DEVICE: error = ENODEV; break; 56 case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break; 57 case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break; 58 case ERROR_BAD_FORMAT: error = ENOEXEC; break; 59 case ERROR_BAD_LENGTH: error = EINVAL; break; 60 case ERROR_BAD_PATHNAME: error = ENOENT; break; 61 case ERROR_BAD_PIPE: error = EPIPE; break; 62 case ERROR_BAD_UNIT: error = ENODEV; break; 63 case ERROR_BAD_USERNAME: error = EINVAL; break; 64 case ERROR_BROKEN_PIPE: error = EPIPE; break; 65 case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break; 66 case ERROR_BUSY: error = EBUSY; break; 67 case ERROR_BUSY_DRIVE: error = EBUSY; break; 68 case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break; 69 case ERROR_CANNOT_MAKE: error = EACCES; break; 70 case ERROR_CANTOPEN: error = EIO; break; 71 case ERROR_CANTREAD: error = EIO; break; 72 case ERROR_CANTWRITE: error = EIO; break; 73 case ERROR_CRC: error = EIO; break; 74 case ERROR_CURRENT_DIRECTORY: error = EACCES; break; 75 case ERROR_DEVICE_IN_USE: error = EBUSY; break; 76 case ERROR_DEV_NOT_EXIST: error = ENODEV; break; 77 case ERROR_DIRECTORY: error = EINVAL; break; 78 case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break; 79 case ERROR_DISK_CHANGE: error = EIO; break; 80 case ERROR_DISK_FULL: error = ENOSPC; break; 81 case ERROR_DRIVE_LOCKED: error = EBUSY; break; 82 case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break; 83 case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break; 84 case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break; 85 case ERROR_FILE_EXISTS: error = EEXIST; break; 86 case ERROR_FILE_INVALID: error = ENODEV; break; 87 case ERROR_FILE_NOT_FOUND: error = ENOENT; break; 88 case ERROR_GEN_FAILURE: error = EIO; break; 89 case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break; 90 case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break; 91 case ERROR_INVALID_ACCESS: error = EACCES; break; 92 case ERROR_INVALID_ADDRESS: error = EFAULT; break; 93 case ERROR_INVALID_BLOCK: error = EFAULT; break; 94 case ERROR_INVALID_DATA: error = EINVAL; break; 95 case ERROR_INVALID_DRIVE: error = ENODEV; break; 96 case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break; 97 case ERROR_INVALID_FLAGS: error = EINVAL; break; 98 case ERROR_INVALID_FUNCTION: error = ENOSYS; break; 99 case ERROR_INVALID_HANDLE: error = EBADF; break; 100 case ERROR_INVALID_LOGON_HOURS: error = EACCES; break; 101 case ERROR_INVALID_NAME: error = EINVAL; break; 102 case ERROR_INVALID_OWNER: error = EINVAL; break; 103 case ERROR_INVALID_PARAMETER: error = EINVAL; break; 104 case ERROR_INVALID_PASSWORD: error = EPERM; break; 105 case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break; 106 case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break; 107 case ERROR_INVALID_TARGET_HANDLE: error = EIO; break; 108 case ERROR_INVALID_WORKSTATION: error = EACCES; break; 109 case ERROR_IO_DEVICE: error = EIO; break; 110 case ERROR_IO_INCOMPLETE: error = EINTR; break; 111 case ERROR_LOCKED: error = EBUSY; break; 112 case ERROR_LOCK_VIOLATION: error = EACCES; break; 113 case ERROR_LOGON_FAILURE: error = EACCES; break; 114 case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break; 115 case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break; 116 case ERROR_MORE_DATA: error = EPIPE; break; 117 case ERROR_NEGATIVE_SEEK: error = ESPIPE; break; 118 case ERROR_NOACCESS: error = EFAULT; break; 119 case ERROR_NONE_MAPPED: error = EINVAL; break; 120 case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break; 121 case ERROR_NOT_READY: error = EAGAIN; break; 122 case ERROR_NOT_SAME_DEVICE: error = EXDEV; break; 123 case ERROR_NO_DATA: error = EPIPE; break; 124 case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break; 125 case ERROR_NO_PROC_SLOTS: error = EAGAIN; break; 126 case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break; 127 case ERROR_OPEN_FAILED: error = EIO; break; 128 case ERROR_OPEN_FILES: error = EBUSY; break; 129 case ERROR_OPERATION_ABORTED: error = EINTR; break; 130 case ERROR_OUTOFMEMORY: error = ENOMEM; break; 131 case ERROR_PASSWORD_EXPIRED: error = EACCES; break; 132 case ERROR_PATH_BUSY: error = EBUSY; break; 133 case ERROR_PATH_NOT_FOUND: error = ENOENT; break; 134 case ERROR_PIPE_BUSY: error = EBUSY; break; 135 case ERROR_PIPE_CONNECTED: error = EPIPE; break; 136 case ERROR_PIPE_LISTENING: error = EPIPE; break; 137 case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break; 138 case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break; 139 case ERROR_READ_FAULT: error = EIO; break; 140 case ERROR_SEEK: error = EIO; break; 141 case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break; 142 case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break; 143 case ERROR_SHARING_VIOLATION: error = EACCES; break; 144 case ERROR_STACK_OVERFLOW: error = ENOMEM; break; 145 case ERROR_SUCCESS: BUG("err_win_to_posix() called without an error!"); 146 case ERROR_SWAPERROR: error = ENOENT; break; 147 case ERROR_TOO_MANY_MODULES: error = EMFILE; break; 148 case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break; 149 case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break; 150 case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break; 151 case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break; 152 case ERROR_WRITE_FAULT: error = EIO; break; 153 case ERROR_WRITE_PROTECT: error = EROFS; break; 154 } 155 return error; 156} 157 158static inline int is_file_in_use_error(DWORD errcode) 159{ 160 switch (errcode) { 161 case ERROR_SHARING_VIOLATION: 162 case ERROR_ACCESS_DENIED: 163 return 1; 164 } 165 166 return 0; 167} 168 169static int read_yes_no_answer(void) 170{ 171 char answer[1024]; 172 173 if (fgets(answer, sizeof(answer), stdin)) { 174 size_t answer_len = strlen(answer); 175 int got_full_line = 0, c; 176 177 /* remove the newline */ 178 if (answer_len >= 2 && answer[answer_len-2] == '\r') { 179 answer[answer_len-2] = '\0'; 180 got_full_line = 1; 181 } else if (answer_len >= 1 && answer[answer_len-1] == '\n') { 182 answer[answer_len-1] = '\0'; 183 got_full_line = 1; 184 } 185 /* flush the buffer in case we did not get the full line */ 186 if (!got_full_line) 187 while ((c = getchar()) != EOF && c != '\n') 188 ; 189 } else 190 /* we could not read, return the 191 * default answer which is no */ 192 return 0; 193 194 if (tolower(answer[0]) == 'y' && !answer[1]) 195 return 1; 196 if (!strncasecmp(answer, "yes", sizeof(answer))) 197 return 1; 198 if (tolower(answer[0]) == 'n' && !answer[1]) 199 return 0; 200 if (!strncasecmp(answer, "no", sizeof(answer))) 201 return 0; 202 203 /* did not find an answer we understand */ 204 return -1; 205} 206 207static int ask_yes_no_if_possible(const char *format, ...) 208{ 209 char question[4096]; 210 const char *retry_hook; 211 va_list args; 212 213 va_start(args, format); 214 vsnprintf(question, sizeof(question), format, args); 215 va_end(args); 216 217 retry_hook = mingw_getenv("GIT_ASK_YESNO"); 218 if (retry_hook) { 219 struct child_process cmd = CHILD_PROCESS_INIT; 220 221 strvec_pushl(&cmd.args, retry_hook, question, NULL); 222 return !run_command(&cmd); 223 } 224 225 if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr))) 226 return 0; 227 228 while (1) { 229 int answer; 230 fprintf(stderr, "%s (y/n) ", question); 231 232 if ((answer = read_yes_no_answer()) >= 0) 233 return answer; 234 235 fprintf(stderr, "Sorry, I did not understand your answer. " 236 "Please type 'y' or 'n'\n"); 237 } 238} 239 240/* Windows only */ 241enum hide_dotfiles_type { 242 HIDE_DOTFILES_FALSE = 0, 243 HIDE_DOTFILES_TRUE, 244 HIDE_DOTFILES_DOTGITONLY 245}; 246 247static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; 248static char *unset_environment_variables; 249 250int mingw_core_config(const char *var, const char *value, 251 const struct config_context *ctx UNUSED, 252 void *cb UNUSED) 253{ 254 if (!strcmp(var, "core.hidedotfiles")) { 255 if (value && !strcasecmp(value, "dotgitonly")) 256 hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; 257 else 258 hide_dotfiles = git_config_bool(var, value); 259 return 0; 260 } 261 262 if (!strcmp(var, "core.unsetenvvars")) { 263 if (!value) 264 return config_error_nonbool(var); 265 free(unset_environment_variables); 266 unset_environment_variables = xstrdup(value); 267 return 0; 268 } 269 270 return 0; 271} 272 273/* Normalizes NT paths as returned by some low-level APIs. */ 274static wchar_t *normalize_ntpath(wchar_t *wbuf) 275{ 276 int i; 277 /* fix absolute path prefixes */ 278 if (wbuf[0] == '\\') { 279 /* strip NT namespace prefixes */ 280 if (!wcsncmp(wbuf, L"\\??\\", 4) || 281 !wcsncmp(wbuf, L"\\\\?\\", 4)) 282 wbuf += 4; 283 else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12)) 284 wbuf += 12; 285 /* replace remaining '...UNC\' with '\\' */ 286 if (!wcsnicmp(wbuf, L"UNC\\", 4)) { 287 wbuf += 2; 288 *wbuf = '\\'; 289 } 290 } 291 /* convert backslashes to slashes */ 292 for (i = 0; wbuf[i]; i++) 293 if (wbuf[i] == '\\') 294 wbuf[i] = '/'; 295 return wbuf; 296} 297 298int mingw_unlink(const char *pathname, int handle_in_use_error) 299{ 300 int ret, tries = 0; 301 wchar_t wpathname[MAX_PATH]; 302 if (xutftowcs_path(wpathname, pathname) < 0) 303 return -1; 304 305 if (DeleteFileW(wpathname)) 306 return 0; 307 308 /* read-only files cannot be removed */ 309 _wchmod(wpathname, 0666); 310 while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) { 311 if (!is_file_in_use_error(GetLastError())) 312 break; 313 if (!handle_in_use_error) 314 return ret; 315 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 333static 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 355int 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 411static 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 443static 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 456int mingw_mkdir(const char *path, int mode UNUSED) 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 */ 487static 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 | FILE_SHARE_DELETE, 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 * Ideally, we'd use `_wopen()` to implement this functionality so that we 534 * don't have to reimplement it, but unfortunately we do not have tight control 535 * over the share mode there. And while `_wsopen()` and friends exist that give 536 * us _some_ control over the share mode, this family of functions doesn't give 537 * us the ability to enable FILE_SHARE_DELETE, either. But this is a strict 538 * requirement for us though so that we can unlink or rename over files that 539 * are held open by another process. 540 * 541 * We are thus forced to implement our own emulation of `open()`. To make our 542 * life simpler we only implement basic support for this, namely opening 543 * existing files for reading and/or writing. This means that newly created 544 * files won't have their sharing mode set up correctly, but for now I couldn't 545 * find any case where this matters. We may have to revisit that in the future 546 * though based on our needs. 547 */ 548static int mingw_open_existing(const wchar_t *filename, int oflags, ...) 549{ 550 SECURITY_ATTRIBUTES security_attributes = { 551 .nLength = sizeof(security_attributes), 552 .bInheritHandle = !(oflags & O_NOINHERIT), 553 }; 554 HANDLE handle; 555 DWORD access; 556 int fd; 557 558 /* We only support basic flags. */ 559 if (oflags & ~(O_ACCMODE | O_NOINHERIT)) { 560 errno = ENOSYS; 561 return -1; 562 } 563 564 switch (oflags & O_ACCMODE) { 565 case O_RDWR: 566 access = GENERIC_READ | GENERIC_WRITE; 567 break; 568 case O_WRONLY: 569 access = GENERIC_WRITE; 570 break; 571 default: 572 access = GENERIC_READ; 573 break; 574 } 575 576 handle = CreateFileW(filename, access, 577 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, 578 &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 579 if (handle == INVALID_HANDLE_VALUE) { 580 DWORD err = GetLastError(); 581 if (err == ERROR_ACCESS_DENIED) { 582 DWORD attrs = GetFileAttributesW(filename); 583 if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) 584 handle = CreateFileW(filename, access, 585 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, 586 &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL| FILE_FLAG_BACKUP_SEMANTICS, NULL); 587 } 588 589 if (handle == INVALID_HANDLE_VALUE) { 590 err = GetLastError(); 591 592 /* See `mingw_open_append()` for why we have this conversion. */ 593 if (err == ERROR_INVALID_PARAMETER) 594 err = ERROR_PATH_NOT_FOUND; 595 596 errno = err_win_to_posix(err); 597 return -1; 598 } 599 } 600 601 fd = _open_osfhandle((intptr_t)handle, oflags | O_BINARY); 602 if (fd < 0) 603 CloseHandle(handle); 604 return fd; 605} 606 607/* 608 * Does the pathname map to the local named pipe filesystem? 609 * That is, does it have a "//./pipe/" prefix? 610 */ 611static int is_local_named_pipe_path(const char *filename) 612{ 613 return (is_dir_sep(filename[0]) && 614 is_dir_sep(filename[1]) && 615 filename[2] == '.' && 616 is_dir_sep(filename[3]) && 617 !strncasecmp(filename+4, "pipe", 4) && 618 is_dir_sep(filename[8]) && 619 filename[9]); 620} 621 622int mingw_open (const char *filename, int oflags, ...) 623{ 624 typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...); 625 va_list args; 626 unsigned mode; 627 int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL); 628 wchar_t wfilename[MAX_PATH]; 629 open_fn_t open_fn; 630 631 DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void); 632 633 va_start(args, oflags); 634 mode = va_arg(args, int); 635 va_end(args); 636 637 if (!is_valid_win32_path(filename, !create)) { 638 errno = create ? EINVAL : ENOENT; 639 return -1; 640 } 641 642 if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename)) 643 open_fn = mingw_open_append; 644 else if (!(oflags & ~(O_ACCMODE | O_NOINHERIT))) 645 open_fn = mingw_open_existing; 646 else 647 open_fn = _wopen; 648 649 if (filename && !strcmp(filename, "/dev/null")) 650 wcscpy(wfilename, L"nul"); 651 else if (xutftowcs_path(wfilename, filename) < 0) 652 return -1; 653 654 fd = open_fn(wfilename, oflags, mode); 655 656 /* 657 * Internally, `_wopen()` uses the `CreateFile()` API with CREATE_NEW, 658 * which may error out with ERROR_ACCESS_DENIED and an NtStatus of 659 * STATUS_DELETE_PENDING when the file is scheduled for deletion via 660 * `DeleteFileW()`. The file essentially exists, so we map errno to 661 * EEXIST instead of EACCESS so that callers don't have to special-case 662 * this. 663 * 664 * This fixes issues for example with the lockfile interface when one 665 * process has a lock that it is about to commit or release while 666 * another process wants to acquire it. 667 */ 668 if (fd < 0 && create && GetLastError() == ERROR_ACCESS_DENIED && 669 INIT_PROC_ADDR(RtlGetLastNtStatus) && RtlGetLastNtStatus() == STATUS_DELETE_PENDING) 670 errno = EEXIST; 671 if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) { 672 DWORD attrs = GetFileAttributesW(wfilename); 673 if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) 674 errno = EISDIR; 675 } 676 if ((oflags & O_CREAT) && needs_hiding(filename)) { 677 /* 678 * Internally, _wopen() uses the CreateFile() API which errors 679 * out with an ERROR_ACCESS_DENIED if CREATE_ALWAYS was 680 * specified and an already existing file's attributes do not 681 * match *exactly*. As there is no mode or flag we can set that 682 * would correspond to FILE_ATTRIBUTE_HIDDEN, let's just try 683 * again *without* the O_CREAT flag (that corresponds to the 684 * CREATE_ALWAYS flag of CreateFile()). 685 */ 686 if (fd < 0 && errno == EACCES) 687 fd = open_fn(wfilename, oflags & ~O_CREAT, mode); 688 if (fd >= 0 && set_hidden_flag(wfilename, 1)) 689 warning("could not mark '%s' as hidden.", filename); 690 } 691 return fd; 692} 693 694static BOOL WINAPI ctrl_ignore(DWORD type UNUSED) 695{ 696 return TRUE; 697} 698 699#undef fgetc 700int mingw_fgetc(FILE *stream) 701{ 702 int ch; 703 if (!isatty(_fileno(stream))) 704 return fgetc(stream); 705 706 SetConsoleCtrlHandler(ctrl_ignore, TRUE); 707 while (1) { 708 ch = fgetc(stream); 709 if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED) 710 break; 711 712 /* Ctrl+C was pressed, simulate SIGINT and retry */ 713 mingw_raise(SIGINT); 714 } 715 SetConsoleCtrlHandler(ctrl_ignore, FALSE); 716 return ch; 717} 718 719#undef fopen 720FILE *mingw_fopen (const char *filename, const char *otype) 721{ 722 int hide = needs_hiding(filename); 723 FILE *file; 724 wchar_t wfilename[MAX_PATH], wotype[4]; 725 if (filename && !strcmp(filename, "/dev/null")) 726 wcscpy(wfilename, L"nul"); 727 else if (!is_valid_win32_path(filename, 1)) { 728 int create = otype && strchr(otype, 'w'); 729 errno = create ? EINVAL : ENOENT; 730 return NULL; 731 } else if (xutftowcs_path(wfilename, filename) < 0) 732 return NULL; 733 734 if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) 735 return NULL; 736 737 if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) { 738 error("could not unhide %s", filename); 739 return NULL; 740 } 741 file = _wfopen(wfilename, wotype); 742 if (!file && GetLastError() == ERROR_INVALID_NAME) 743 errno = ENOENT; 744 if (file && hide && set_hidden_flag(wfilename, 1)) 745 warning("could not mark '%s' as hidden.", filename); 746 return file; 747} 748 749FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream) 750{ 751 int hide = needs_hiding(filename); 752 FILE *file; 753 wchar_t wfilename[MAX_PATH], wotype[4]; 754 if (filename && !strcmp(filename, "/dev/null")) 755 wcscpy(wfilename, L"nul"); 756 else if (!is_valid_win32_path(filename, 1)) { 757 int create = otype && strchr(otype, 'w'); 758 errno = create ? EINVAL : ENOENT; 759 return NULL; 760 } else if (xutftowcs_path(wfilename, filename) < 0) 761 return NULL; 762 763 if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0) 764 return NULL; 765 766 if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) { 767 error("could not unhide %s", filename); 768 return NULL; 769 } 770 file = _wfreopen(wfilename, wotype, stream); 771 if (file && hide && set_hidden_flag(wfilename, 1)) 772 warning("could not mark '%s' as hidden.", filename); 773 return file; 774} 775 776#undef fflush 777int mingw_fflush(FILE *stream) 778{ 779 int ret = fflush(stream); 780 781 /* 782 * write() is used behind the scenes of stdio output functions. 783 * Since git code does not check for errors after each stdio write 784 * operation, it can happen that write() is called by a later 785 * stdio function even if an earlier write() call failed. In the 786 * case of a pipe whose readable end was closed, only the first 787 * call to write() reports EPIPE on Windows. Subsequent write() 788 * calls report EINVAL. It is impossible to notice whether this 789 * fflush invocation triggered such a case, therefore, we have to 790 * catch all EINVAL errors whole-sale. 791 */ 792 if (ret && errno == EINVAL) 793 errno = EPIPE; 794 795 return ret; 796} 797 798#undef write 799ssize_t mingw_write(int fd, const void *buf, size_t len) 800{ 801 ssize_t result = write(fd, buf, len); 802 803 if (result < 0 && (errno == EINVAL || errno == ENOSPC) && buf) { 804 int orig = errno; 805 806 /* check if fd is a pipe */ 807 HANDLE h = (HANDLE) _get_osfhandle(fd); 808 if (GetFileType(h) != FILE_TYPE_PIPE) 809 errno = orig; 810 else if (orig == EINVAL) 811 errno = EPIPE; 812 else { 813 DWORD buf_size; 814 815 if (!GetNamedPipeInfo(h, NULL, NULL, &buf_size, NULL)) 816 buf_size = 4096; 817 if (len > buf_size) 818 return write(fd, buf, buf_size); 819 errno = orig; 820 } 821 } 822 823 return result; 824} 825 826int mingw_access(const char *filename, int mode) 827{ 828 wchar_t wfilename[MAX_PATH]; 829 if (!strcmp("nul", filename) || !strcmp("/dev/null", filename)) 830 return 0; 831 if (xutftowcs_path(wfilename, filename) < 0) 832 return -1; 833 /* X_OK is not supported by the MSVCRT version */ 834 return _waccess(wfilename, mode & ~X_OK); 835} 836 837int mingw_chdir(const char *dirname) 838{ 839 wchar_t wdirname[MAX_PATH]; 840 if (xutftowcs_path(wdirname, dirname) < 0) 841 return -1; 842 return _wchdir(wdirname); 843} 844 845int mingw_chmod(const char *filename, int mode) 846{ 847 wchar_t wfilename[MAX_PATH]; 848 if (xutftowcs_path(wfilename, filename) < 0) 849 return -1; 850 return _wchmod(wfilename, mode); 851} 852 853/* 854 * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC. 855 * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch. 856 */ 857static inline long long filetime_to_hnsec(const FILETIME *ft) 858{ 859 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; 860 /* Windows to Unix Epoch conversion */ 861 return winTime - 116444736000000000LL; 862} 863 864static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts) 865{ 866 long long hnsec = filetime_to_hnsec(ft); 867 ts->tv_sec = (time_t)(hnsec / 10000000); 868 ts->tv_nsec = (hnsec % 10000000) * 100; 869} 870 871/** 872 * Verifies that safe_create_leading_directories() would succeed. 873 */ 874static int has_valid_directory_prefix(wchar_t *wfilename) 875{ 876 size_t n = wcslen(wfilename); 877 878 while (n > 0) { 879 wchar_t c = wfilename[--n]; 880 DWORD attributes; 881 882 if (!is_dir_sep(c)) 883 continue; 884 885 wfilename[n] = L'\0'; 886 attributes = GetFileAttributesW(wfilename); 887 wfilename[n] = c; 888 if (attributes & 889 (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) 890 return 1; 891 if (attributes == INVALID_FILE_ATTRIBUTES) 892 switch (GetLastError()) { 893 case ERROR_PATH_NOT_FOUND: 894 continue; 895 case ERROR_FILE_NOT_FOUND: 896 /* This implies parent directory exists. */ 897 return 1; 898 } 899 return 0; 900 } 901 return 1; 902} 903 904/* We keep the do_lstat code in a separate function to avoid recursion. 905 * When a path ends with a slash, the stat will fail with ENOENT. In 906 * this case, we strip the trailing slashes and stat again. 907 * 908 * If follow is true then act like stat() and report on the link 909 * target. Otherwise report on the link itself. 910 */ 911static int do_lstat(int follow, const char *file_name, struct stat *buf) 912{ 913 WIN32_FILE_ATTRIBUTE_DATA fdata; 914 wchar_t wfilename[MAX_PATH]; 915 if (xutftowcs_path(wfilename, file_name) < 0) 916 return -1; 917 918 if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) { 919 buf->st_ino = 0; 920 buf->st_gid = 0; 921 buf->st_uid = 0; 922 buf->st_nlink = 1; 923 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); 924 buf->st_size = fdata.nFileSizeLow | 925 (((off_t)fdata.nFileSizeHigh)<<32); 926 buf->st_dev = buf->st_rdev = 0; /* not used by Git */ 927 filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim)); 928 filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim)); 929 filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim)); 930 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { 931 WIN32_FIND_DATAW findbuf; 932 HANDLE handle = FindFirstFileW(wfilename, &findbuf); 933 if (handle != INVALID_HANDLE_VALUE) { 934 if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && 935 (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) { 936 if (follow) { 937 char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; 938 buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 939 } else { 940 buf->st_mode = S_IFLNK; 941 } 942 buf->st_mode |= S_IREAD; 943 if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) 944 buf->st_mode |= S_IWRITE; 945 } 946 FindClose(handle); 947 } 948 } 949 return 0; 950 } 951 switch (GetLastError()) { 952 case ERROR_ACCESS_DENIED: 953 case ERROR_SHARING_VIOLATION: 954 case ERROR_LOCK_VIOLATION: 955 case ERROR_SHARING_BUFFER_EXCEEDED: 956 errno = EACCES; 957 break; 958 case ERROR_BUFFER_OVERFLOW: 959 errno = ENAMETOOLONG; 960 break; 961 case ERROR_NOT_ENOUGH_MEMORY: 962 errno = ENOMEM; 963 break; 964 case ERROR_PATH_NOT_FOUND: 965 if (!has_valid_directory_prefix(wfilename)) { 966 errno = ENOTDIR; 967 break; 968 } 969 /* fallthru */ 970 default: 971 errno = ENOENT; 972 break; 973 } 974 return -1; 975} 976 977/* We provide our own lstat/fstat functions, since the provided 978 * lstat/fstat functions are so slow. These stat functions are 979 * tailored for Git's usage (read: fast), and are not meant to be 980 * complete. Note that Git stat()s are redirected to mingw_lstat() 981 * too, since Windows doesn't really handle symlinks that well. 982 */ 983static int do_stat_internal(int follow, const char *file_name, struct stat *buf) 984{ 985 size_t namelen; 986 char alt_name[PATH_MAX]; 987 988 if (!do_lstat(follow, file_name, buf)) 989 return 0; 990 991 /* if file_name ended in a '/', Windows returned ENOENT; 992 * try again without trailing slashes 993 */ 994 if (errno != ENOENT) 995 return -1; 996 997 namelen = strlen(file_name); 998 if (namelen && file_name[namelen-1] != '/') 999 return -1; 1000 while (namelen && file_name[namelen-1] == '/') 1001 --namelen; 1002 if (!namelen || namelen >= PATH_MAX) 1003 return -1; 1004 1005 memcpy(alt_name, file_name, namelen); 1006 alt_name[namelen] = 0; 1007 return do_lstat(follow, alt_name, buf); 1008} 1009 1010static int get_file_info_by_handle(HANDLE hnd, struct stat *buf) 1011{ 1012 BY_HANDLE_FILE_INFORMATION fdata; 1013 1014 if (!GetFileInformationByHandle(hnd, &fdata)) { 1015 errno = err_win_to_posix(GetLastError()); 1016 return -1; 1017 } 1018 1019 buf->st_ino = 0; 1020 buf->st_gid = 0; 1021 buf->st_uid = 0; 1022 buf->st_nlink = 1; 1023 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); 1024 buf->st_size = fdata.nFileSizeLow | 1025 (((off_t)fdata.nFileSizeHigh)<<32); 1026 buf->st_dev = buf->st_rdev = 0; /* not used by Git */ 1027 filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim)); 1028 filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim)); 1029 filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim)); 1030 return 0; 1031} 1032 1033int mingw_lstat(const char *file_name, struct stat *buf) 1034{ 1035 return do_stat_internal(0, file_name, buf); 1036} 1037int mingw_stat(const char *file_name, struct stat *buf) 1038{ 1039 return do_stat_internal(1, file_name, buf); 1040} 1041 1042int mingw_fstat(int fd, struct stat *buf) 1043{ 1044 HANDLE fh = (HANDLE)_get_osfhandle(fd); 1045 DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE; 1046 1047 switch (type) { 1048 case FILE_TYPE_DISK: 1049 return get_file_info_by_handle(fh, buf); 1050 1051 case FILE_TYPE_CHAR: 1052 case FILE_TYPE_PIPE: 1053 /* initialize stat fields */ 1054 memset(buf, 0, sizeof(*buf)); 1055 buf->st_nlink = 1; 1056 1057 if (type == FILE_TYPE_CHAR) { 1058 buf->st_mode = _S_IFCHR; 1059 } else { 1060 buf->st_mode = _S_IFIFO; 1061 if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL)) 1062 buf->st_size = avail; 1063 } 1064 return 0; 1065 1066 default: 1067 errno = EBADF; 1068 return -1; 1069 } 1070} 1071 1072static inline void time_t_to_filetime(time_t t, FILETIME *ft) 1073{ 1074 long long winTime = t * 10000000LL + 116444736000000000LL; 1075 ft->dwLowDateTime = winTime; 1076 ft->dwHighDateTime = winTime >> 32; 1077} 1078 1079int mingw_utime (const char *file_name, const struct utimbuf *times) 1080{ 1081 FILETIME mft, aft; 1082 int rc; 1083 DWORD attrs; 1084 wchar_t wfilename[MAX_PATH]; 1085 HANDLE osfilehandle; 1086 1087 if (xutftowcs_path(wfilename, file_name) < 0) 1088 return -1; 1089 1090 /* must have write permission */ 1091 attrs = GetFileAttributesW(wfilename); 1092 if (attrs != INVALID_FILE_ATTRIBUTES && 1093 (attrs & FILE_ATTRIBUTE_READONLY)) { 1094 /* ignore errors here; open() will report them */ 1095 SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY); 1096 } 1097 1098 osfilehandle = CreateFileW(wfilename, 1099 FILE_WRITE_ATTRIBUTES, 1100 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1101 NULL, 1102 OPEN_EXISTING, 1103 (attrs != INVALID_FILE_ATTRIBUTES && 1104 (attrs & FILE_ATTRIBUTE_DIRECTORY)) ? 1105 FILE_FLAG_BACKUP_SEMANTICS : 0, 1106 NULL); 1107 if (osfilehandle == INVALID_HANDLE_VALUE) { 1108 errno = err_win_to_posix(GetLastError()); 1109 rc = -1; 1110 goto revert_attrs; 1111 } 1112 1113 if (times) { 1114 time_t_to_filetime(times->modtime, &mft); 1115 time_t_to_filetime(times->actime, &aft); 1116 } else { 1117 GetSystemTimeAsFileTime(&mft); 1118 aft = mft; 1119 } 1120 1121 if (!SetFileTime(osfilehandle, NULL, &aft, &mft)) { 1122 errno = EINVAL; 1123 rc = -1; 1124 } else 1125 rc = 0; 1126 1127 if (osfilehandle != INVALID_HANDLE_VALUE) 1128 CloseHandle(osfilehandle); 1129 1130revert_attrs: 1131 if (attrs != INVALID_FILE_ATTRIBUTES && 1132 (attrs & FILE_ATTRIBUTE_READONLY)) { 1133 /* ignore errors again */ 1134 SetFileAttributesW(wfilename, attrs); 1135 } 1136 return rc; 1137} 1138 1139#undef strftime 1140size_t mingw_strftime(char *s, size_t max, 1141 const char *format, const struct tm *tm) 1142{ 1143 /* a pointer to the original strftime in case we can't find the UCRT version */ 1144 static size_t (*fallback)(char *, size_t, const char *, const struct tm *) = strftime; 1145 size_t ret; 1146 DECLARE_PROC_ADDR(ucrtbase.dll, size_t, __cdecl, strftime, char *, size_t, 1147 const char *, const struct tm *); 1148 1149 if (INIT_PROC_ADDR(strftime)) 1150 ret = strftime(s, max, format, tm); 1151 else 1152 ret = fallback(s, max, format, tm); 1153 1154 if (!ret && errno == EINVAL) 1155 die("invalid strftime format: '%s'", format); 1156 return ret; 1157} 1158 1159unsigned int sleep (unsigned int seconds) 1160{ 1161 Sleep(seconds*1000); 1162 return 0; 1163} 1164 1165char *mingw_mktemp(char *template) 1166{ 1167 wchar_t wtemplate[MAX_PATH]; 1168 if (xutftowcs_path(wtemplate, template) < 0) 1169 return NULL; 1170 if (!_wmktemp(wtemplate)) 1171 return NULL; 1172 if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0) 1173 return NULL; 1174 return template; 1175} 1176 1177int mkstemp(char *template) 1178{ 1179 return git_mkstemp_mode(template, 0600); 1180} 1181 1182int gettimeofday(struct timeval *tv, void *tz UNUSED) 1183{ 1184 FILETIME ft; 1185 long long hnsec; 1186 1187 GetSystemTimeAsFileTime(&ft); 1188 hnsec = filetime_to_hnsec(&ft); 1189 tv->tv_sec = hnsec / 10000000; 1190 tv->tv_usec = (hnsec % 10000000) / 10; 1191 return 0; 1192} 1193 1194int pipe(int filedes[2]) 1195{ 1196 HANDLE h[2]; 1197 1198 /* this creates non-inheritable handles */ 1199 if (!CreatePipe(&h[0], &h[1], NULL, 8192)) { 1200 errno = err_win_to_posix(GetLastError()); 1201 return -1; 1202 } 1203 filedes[0] = _open_osfhandle(HCAST(int, h[0]), O_NOINHERIT); 1204 if (filedes[0] < 0) { 1205 CloseHandle(h[0]); 1206 CloseHandle(h[1]); 1207 return -1; 1208 } 1209 filedes[1] = _open_osfhandle(HCAST(int, h[1]), O_NOINHERIT); 1210 if (filedes[1] < 0) { 1211 close(filedes[0]); 1212 CloseHandle(h[1]); 1213 return -1; 1214 } 1215 return 0; 1216} 1217 1218#ifndef __MINGW64__ 1219struct tm *gmtime_r(const time_t *timep, struct tm *result) 1220{ 1221 if (gmtime_s(result, timep) == 0) 1222 return result; 1223 return NULL; 1224} 1225 1226struct tm *localtime_r(const time_t *timep, struct tm *result) 1227{ 1228 if (localtime_s(result, timep) == 0) 1229 return result; 1230 return NULL; 1231} 1232#endif 1233 1234char *mingw_getcwd(char *pointer, int len) 1235{ 1236 wchar_t cwd[MAX_PATH], wpointer[MAX_PATH]; 1237 DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd); 1238 1239 if (!ret || ret >= ARRAY_SIZE(cwd)) { 1240 errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError()); 1241 return NULL; 1242 } 1243 ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer)); 1244 if (!ret && GetLastError() == ERROR_ACCESS_DENIED) { 1245 HANDLE hnd = CreateFileW(cwd, 0, 1246 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 1247 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 1248 if (hnd == INVALID_HANDLE_VALUE) 1249 return NULL; 1250 ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0); 1251 CloseHandle(hnd); 1252 if (!ret || ret >= ARRAY_SIZE(wpointer)) 1253 return NULL; 1254 if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0) 1255 return NULL; 1256 return pointer; 1257 } 1258 if (!ret || ret >= ARRAY_SIZE(wpointer)) 1259 return NULL; 1260 if (GetFileAttributesW(wpointer) == INVALID_FILE_ATTRIBUTES) { 1261 errno = ENOENT; 1262 return NULL; 1263 } 1264 if (xwcstoutf(pointer, wpointer, len) < 0) 1265 return NULL; 1266 convert_slashes(pointer); 1267 return pointer; 1268} 1269 1270/* 1271 * See "Parsing C++ Command-Line Arguments" at Microsoft's Docs: 1272 * https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments 1273 */ 1274static const char *quote_arg_msvc(const char *arg) 1275{ 1276 /* count chars to quote */ 1277 int len = 0, n = 0; 1278 int force_quotes = 0; 1279 char *q, *d; 1280 const char *p = arg; 1281 if (!*p) force_quotes = 1; 1282 while (*p) { 1283 if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'') 1284 force_quotes = 1; 1285 else if (*p == '"') 1286 n++; 1287 else if (*p == '\\') { 1288 int count = 0; 1289 while (*p == '\\') { 1290 count++; 1291 p++; 1292 len++; 1293 } 1294 if (*p == '"' || !*p) 1295 n += count*2 + 1; 1296 continue; 1297 } 1298 len++; 1299 p++; 1300 } 1301 if (!force_quotes && n == 0) 1302 return arg; 1303 1304 /* insert \ where necessary */ 1305 d = q = xmalloc(st_add3(len, n, 3)); 1306 *d++ = '"'; 1307 while (*arg) { 1308 if (*arg == '"') 1309 *d++ = '\\'; 1310 else if (*arg == '\\') { 1311 int count = 0; 1312 while (*arg == '\\') { 1313 count++; 1314 *d++ = *arg++; 1315 } 1316 if (*arg == '"' || !*arg) { 1317 while (count-- > 0) 1318 *d++ = '\\'; 1319 /* don't escape the surrounding end quote */ 1320 if (!*arg) 1321 break; 1322 *d++ = '\\'; 1323 } 1324 } 1325 *d++ = *arg++; 1326 } 1327 *d++ = '"'; 1328 *d++ = '\0'; 1329 return q; 1330} 1331 1332#include "quote.h" 1333 1334static const char *quote_arg_msys2(const char *arg) 1335{ 1336 struct strbuf buf = STRBUF_INIT; 1337 const char *p2 = arg, *p; 1338 1339 for (p = arg; *p; p++) { 1340 int ws = isspace(*p); 1341 if (!ws && *p != '\\' && *p != '"' && *p != '{' && *p != '\'' && 1342 *p != '?' && *p != '*' && *p != '~') 1343 continue; 1344 if (!buf.len) 1345 strbuf_addch(&buf, '"'); 1346 if (p != p2) 1347 strbuf_add(&buf, p2, p - p2); 1348 if (*p == '\\' || *p == '"') 1349 strbuf_addch(&buf, '\\'); 1350 p2 = p; 1351 } 1352 1353 if (p == arg) 1354 strbuf_addch(&buf, '"'); 1355 else if (!buf.len) 1356 return arg; 1357 else 1358 strbuf_add(&buf, p2, p - p2); 1359 1360 strbuf_addch(&buf, '"'); 1361 return strbuf_detach(&buf, 0); 1362} 1363 1364static const char *parse_interpreter(const char *cmd) 1365{ 1366 static char buf[100]; 1367 char *p, *opt; 1368 ssize_t n; /* read() can return negative values */ 1369 int fd; 1370 1371 /* don't even try a .exe */ 1372 n = strlen(cmd); 1373 if (n >= 4 && !strcasecmp(cmd+n-4, ".exe")) 1374 return NULL; 1375 1376 fd = open(cmd, O_RDONLY); 1377 if (fd < 0) 1378 return NULL; 1379 n = read(fd, buf, sizeof(buf)-1); 1380 close(fd); 1381 if (n < 4) /* at least '#!/x' and not error */ 1382 return NULL; 1383 1384 if (buf[0] != '#' || buf[1] != '!') 1385 return NULL; 1386 buf[n] = '\0'; 1387 p = buf + strcspn(buf, "\r\n"); 1388 if (!*p) 1389 return NULL; 1390 1391 *p = '\0'; 1392 if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\'))) 1393 return NULL; 1394 /* strip options */ 1395 if ((opt = strchr(p+1, ' '))) 1396 *opt = '\0'; 1397 return p+1; 1398} 1399 1400/* 1401 * exe_only means that we only want to detect .exe files, but not scripts 1402 * (which do not have an extension) 1403 */ 1404static char *lookup_prog(const char *dir, int dirlen, const char *cmd, 1405 int isexe, int exe_only) 1406{ 1407 char path[MAX_PATH]; 1408 wchar_t wpath[MAX_PATH]; 1409 snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd); 1410 1411 if (xutftowcs_path(wpath, path) < 0) 1412 return NULL; 1413 1414 if (!isexe && _waccess(wpath, F_OK) == 0) 1415 return xstrdup(path); 1416 wpath[wcslen(wpath)-4] = '\0'; 1417 if ((!exe_only || isexe) && _waccess(wpath, F_OK) == 0) { 1418 if (!(GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY)) { 1419 path[strlen(path)-4] = '\0'; 1420 return xstrdup(path); 1421 } 1422 } 1423 return NULL; 1424} 1425 1426/* 1427 * Determines the absolute path of cmd using the split path in path. 1428 * If cmd contains a slash or backslash, no lookup is performed. 1429 */ 1430static char *path_lookup(const char *cmd, int exe_only) 1431{ 1432 const char *path; 1433 char *prog = NULL; 1434 size_t len = strlen(cmd); 1435 int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe"); 1436 1437 if (strpbrk(cmd, "/\\")) 1438 return xstrdup(cmd); 1439 1440 path = mingw_getenv("PATH"); 1441 if (!path) 1442 return NULL; 1443 1444 while (!prog) { 1445 const char *sep = strchrnul(path, ';'); 1446 int dirlen = sep - path; 1447 if (dirlen) 1448 prog = lookup_prog(path, dirlen, cmd, isexe, exe_only); 1449 if (!*sep) 1450 break; 1451 path = sep + 1; 1452 } 1453 1454 return prog; 1455} 1456 1457char *mingw_locate_in_PATH(const char *cmd) 1458{ 1459 return path_lookup(cmd, 0); 1460} 1461 1462static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c) 1463{ 1464 while (*s && *s != c) 1465 s++; 1466 return s; 1467} 1468 1469/* Compare only keys */ 1470static int wenvcmp(const void *a, const void *b) 1471{ 1472 wchar_t *p = *(wchar_t **)a, *q = *(wchar_t **)b; 1473 size_t p_len, q_len; 1474 1475 /* Find the keys */ 1476 p_len = wcschrnul(p, L'=') - p; 1477 q_len = wcschrnul(q, L'=') - q; 1478 1479 /* If the length differs, include the shorter key's NUL */ 1480 if (p_len < q_len) 1481 p_len++; 1482 else if (p_len > q_len) 1483 p_len = q_len + 1; 1484 1485 return _wcsnicmp(p, q, p_len); 1486} 1487 1488/* 1489 * Build an environment block combining the inherited environment 1490 * merged with the given list of settings. 1491 * 1492 * Values of the form "KEY=VALUE" in deltaenv override inherited values. 1493 * Values of the form "KEY" in deltaenv delete inherited values. 1494 * 1495 * Multiple entries in deltaenv for the same key are explicitly allowed. 1496 * 1497 * We return a contiguous block of UNICODE strings with a final trailing 1498 * zero word. 1499 */ 1500static wchar_t *make_environment_block(char **deltaenv) 1501{ 1502 wchar_t *wenv = GetEnvironmentStringsW(), *wdeltaenv, *result, *p; 1503 size_t wlen, s, delta_size, size; 1504 1505 wchar_t **array = NULL; 1506 size_t alloc = 0, nr = 0, i; 1507 1508 size = 1; /* for extra NUL at the end */ 1509 1510 /* If there is no deltaenv to apply, simply return a copy. */ 1511 if (!deltaenv || !*deltaenv) { 1512 for (p = wenv; p && *p; ) { 1513 size_t s = wcslen(p) + 1; 1514 size += s; 1515 p += s; 1516 } 1517 1518 DUP_ARRAY(result, wenv, size); 1519 FreeEnvironmentStringsW(wenv); 1520 return result; 1521 } 1522 1523 /* 1524 * If there is a deltaenv, let's accumulate all keys into `array`, 1525 * sort them using the stable git_stable_qsort() and then copy, 1526 * skipping duplicate keys 1527 */ 1528 for (p = wenv; p && *p; ) { 1529 ALLOC_GROW(array, nr + 1, alloc); 1530 s = wcslen(p) + 1; 1531 array[nr++] = p; 1532 p += s; 1533 size += s; 1534 } 1535 1536 /* (over-)assess size needed for wchar version of deltaenv */ 1537 for (delta_size = 0, i = 0; deltaenv[i]; i++) 1538 delta_size += strlen(deltaenv[i]) * 2 + 1; 1539 ALLOC_ARRAY(wdeltaenv, delta_size); 1540 1541 /* convert the deltaenv, appending to array */ 1542 for (i = 0, p = wdeltaenv; deltaenv[i]; i++) { 1543 ALLOC_GROW(array, nr + 1, alloc); 1544 wlen = xutftowcs(p, deltaenv[i], wdeltaenv + delta_size - p); 1545 array[nr++] = p; 1546 p += wlen + 1; 1547 } 1548 1549 git_stable_qsort(array, nr, sizeof(*array), wenvcmp); 1550 ALLOC_ARRAY(result, size + delta_size); 1551 1552 for (p = result, i = 0; i < nr; i++) { 1553 /* Skip any duplicate keys; last one wins */ 1554 while (i + 1 < nr && !wenvcmp(array + i, array + i + 1)) 1555 i++; 1556 1557 /* Skip "to delete" entry */ 1558 if (!wcschr(array[i], L'=')) 1559 continue; 1560 1561 size = wcslen(array[i]) + 1; 1562 COPY_ARRAY(p, array[i], size); 1563 p += size; 1564 } 1565 *p = L'\0'; 1566 1567 free(array); 1568 free(wdeltaenv); 1569 FreeEnvironmentStringsW(wenv); 1570 return result; 1571} 1572 1573static void do_unset_environment_variables(void) 1574{ 1575 static int done; 1576 char *p = unset_environment_variables; 1577 1578 if (done || !p) 1579 return; 1580 done = 1; 1581 1582 for (;;) { 1583 char *comma = strchr(p, ','); 1584 1585 if (comma) 1586 *comma = '\0'; 1587 unsetenv(p); 1588 if (!comma) 1589 break; 1590 p = comma + 1; 1591 } 1592} 1593 1594struct pinfo_t { 1595 struct pinfo_t *next; 1596 pid_t pid; 1597 HANDLE proc; 1598}; 1599static struct pinfo_t *pinfo = NULL; 1600CRITICAL_SECTION pinfo_cs; 1601 1602/* Used to match and chomp off path components */ 1603static inline int match_last_path_component(const char *path, size_t *len, 1604 const char *component) 1605{ 1606 size_t component_len = strlen(component); 1607 if (*len < component_len + 1 || 1608 !is_dir_sep(path[*len - component_len - 1]) || 1609 fspathncmp(path + *len - component_len, component, component_len)) 1610 return 0; 1611 *len -= component_len + 1; 1612 /* chomp off repeated dir separators */ 1613 while (*len > 0 && is_dir_sep(path[*len - 1])) 1614 (*len)--; 1615 return 1; 1616} 1617 1618static int is_msys2_sh(const char *cmd) 1619{ 1620 if (!cmd) 1621 return 0; 1622 1623 if (!strcmp(cmd, "sh")) { 1624 static int ret = -1; 1625 char *p; 1626 1627 if (ret >= 0) 1628 return ret; 1629 1630 p = path_lookup(cmd, 0); 1631 if (!p) 1632 ret = 0; 1633 else { 1634 size_t len = strlen(p); 1635 1636 ret = match_last_path_component(p, &len, "sh.exe") && 1637 match_last_path_component(p, &len, "bin") && 1638 match_last_path_component(p, &len, "usr"); 1639 free(p); 1640 } 1641 return ret; 1642 } 1643 1644 if (ends_with(cmd, "\\sh.exe") || ends_with(cmd, "/sh.exe")) { 1645 static char *sh; 1646 1647 if (!sh) 1648 sh = path_lookup("sh", 0); 1649 1650 return !fspathcmp(cmd, sh); 1651 } 1652 1653 return 0; 1654} 1655 1656static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv, 1657 const char *dir, 1658 int prepend_cmd, int fhin, int fhout, int fherr) 1659{ 1660 STARTUPINFOEXW si; 1661 PROCESS_INFORMATION pi; 1662 LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL; 1663 HANDLE stdhandles[3]; 1664 DWORD stdhandles_count = 0; 1665 SIZE_T size; 1666 struct strbuf args; 1667 wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL; 1668 unsigned flags = CREATE_UNICODE_ENVIRONMENT; 1669 BOOL ret; 1670 HANDLE cons; 1671 const char *(*quote_arg)(const char *arg) = 1672 is_msys2_sh(cmd ? cmd : *argv) ? 1673 quote_arg_msys2 : quote_arg_msvc; 1674 const char *strace_env; 1675 1676 /* Make sure to override previous errors, if any */ 1677 errno = 0; 1678 1679 do_unset_environment_variables(); 1680 1681 /* Determine whether or not we are associated to a console */ 1682 cons = CreateFileW(L"CONOUT$", GENERIC_WRITE, 1683 FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 1684 FILE_ATTRIBUTE_NORMAL, NULL); 1685 if (cons == INVALID_HANDLE_VALUE) { 1686 /* There is no console associated with this process. 1687 * Since the child is a console process, Windows 1688 * would normally create a console window. But 1689 * since we'll be redirecting std streams, we do 1690 * not need the console. 1691 * It is necessary to use DETACHED_PROCESS 1692 * instead of CREATE_NO_WINDOW to make ssh 1693 * recognize that it has no console. 1694 */ 1695 flags |= DETACHED_PROCESS; 1696 } else { 1697 /* There is already a console. If we specified 1698 * DETACHED_PROCESS here, too, Windows would 1699 * disassociate the child from the console. 1700 * The same is true for CREATE_NO_WINDOW. 1701 * Go figure! 1702 */ 1703 CloseHandle(cons); 1704 } 1705 memset(&si, 0, sizeof(si)); 1706 si.StartupInfo.cb = sizeof(si); 1707 si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin); 1708 si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout); 1709 si.StartupInfo.hStdError = winansi_get_osfhandle(fherr); 1710 1711 /* The list of handles cannot contain duplicates */ 1712 if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE) 1713 stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput; 1714 if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE && 1715 si.StartupInfo.hStdOutput != si.StartupInfo.hStdInput) 1716 stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput; 1717 if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE && 1718 si.StartupInfo.hStdError != si.StartupInfo.hStdInput && 1719 si.StartupInfo.hStdError != si.StartupInfo.hStdOutput) 1720 stdhandles[stdhandles_count++] = si.StartupInfo.hStdError; 1721 if (stdhandles_count) 1722 si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; 1723 1724 if (*argv && !strcmp(cmd, *argv)) 1725 wcmd[0] = L'\0'; 1726 else if (xutftowcs_path(wcmd, cmd) < 0) 1727 return -1; 1728 if (dir && xutftowcs_path(wdir, dir) < 0) 1729 return -1; 1730 1731 /* concatenate argv, quoting args as we go */ 1732 strbuf_init(&args, 0); 1733 if (prepend_cmd) { 1734 char *quoted = (char *)quote_arg(cmd); 1735 strbuf_addstr(&args, quoted); 1736 if (quoted != cmd) 1737 free(quoted); 1738 } 1739 for (; *argv; argv++) { 1740 char *quoted = (char *)quote_arg(*argv); 1741 if (*args.buf) 1742 strbuf_addch(&args, ' '); 1743 strbuf_addstr(&args, quoted); 1744 if (quoted != *argv) 1745 free(quoted); 1746 } 1747 1748 strace_env = getenv("GIT_STRACE_COMMANDS"); 1749 if (strace_env) { 1750 char *p = path_lookup("strace.exe", 1); 1751 if (!p) 1752 return error("strace not found!"); 1753 if (xutftowcs_path(wcmd, p) < 0) { 1754 free(p); 1755 return -1; 1756 } 1757 free(p); 1758 if (!strcmp("1", strace_env) || 1759 !strcasecmp("yes", strace_env) || 1760 !strcasecmp("true", strace_env)) 1761 strbuf_insert(&args, 0, "strace ", 7); 1762 else { 1763 const char *quoted = quote_arg(strace_env); 1764 struct strbuf buf = STRBUF_INIT; 1765 strbuf_addf(&buf, "strace -o %s ", quoted); 1766 if (quoted != strace_env) 1767 free((char *)quoted); 1768 strbuf_insert(&args, 0, buf.buf, buf.len); 1769 strbuf_release(&buf); 1770 } 1771 } 1772 1773 ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1)); 1774 xutftowcs(wargs, args.buf, 2 * args.len + 1); 1775 strbuf_release(&args); 1776 1777 wenvblk = make_environment_block(deltaenv); 1778 1779 memset(&pi, 0, sizeof(pi)); 1780 if (stdhandles_count && 1781 (InitializeProcThreadAttributeList(NULL, 1, 0, &size) || 1782 GetLastError() == ERROR_INSUFFICIENT_BUFFER) && 1783 (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST) 1784 (HeapAlloc(GetProcessHeap(), 0, size))) && 1785 InitializeProcThreadAttributeList(attr_list, 1, 0, &size) && 1786 UpdateProcThreadAttribute(attr_list, 0, 1787 PROC_THREAD_ATTRIBUTE_HANDLE_LIST, 1788 stdhandles, 1789 stdhandles_count * sizeof(HANDLE), 1790 NULL, NULL)) { 1791 si.lpAttributeList = attr_list; 1792 flags |= EXTENDED_STARTUPINFO_PRESENT; 1793 } 1794 1795 ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, 1796 stdhandles_count ? TRUE : FALSE, 1797 flags, wenvblk, dir ? wdir : NULL, 1798 &si.StartupInfo, &pi); 1799 1800 /* 1801 * On the off-chance that something with the file handle restriction 1802 * went wrong, silently fall back to trying without it. 1803 */ 1804 if (!ret && stdhandles_count) { 1805 DWORD err = GetLastError(); 1806 struct strbuf buf = STRBUF_INIT; 1807 1808 flags &= ~EXTENDED_STARTUPINFO_PRESENT; 1809 ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, 1810 TRUE, flags, wenvblk, dir ? wdir : NULL, 1811 &si.StartupInfo, &pi); 1812 if (!ret) 1813 errno = err_win_to_posix(GetLastError()); 1814 if (ret && buf.len) { 1815 warning("failed to restrict file handles (%ld)\n\n%s", 1816 err, buf.buf); 1817 } 1818 strbuf_release(&buf); 1819 } else if (!ret) 1820 errno = err_win_to_posix(GetLastError()); 1821 1822 if (si.lpAttributeList) 1823 DeleteProcThreadAttributeList(si.lpAttributeList); 1824 if (attr_list) 1825 HeapFree(GetProcessHeap(), 0, attr_list); 1826 1827 free(wenvblk); 1828 free(wargs); 1829 1830 if (!ret) 1831 return -1; 1832 1833 CloseHandle(pi.hThread); 1834 1835 /* 1836 * The process ID is the human-readable identifier of the process 1837 * that we want to present in log and error messages. The handle 1838 * is not useful for this purpose. But we cannot close it, either, 1839 * because it is not possible to turn a process ID into a process 1840 * handle after the process terminated. 1841 * Keep the handle in a list for waitpid. 1842 */ 1843 EnterCriticalSection(&pinfo_cs); 1844 { 1845 struct pinfo_t *info = xmalloc(sizeof(struct pinfo_t)); 1846 info->pid = pi.dwProcessId; 1847 info->proc = pi.hProcess; 1848 info->next = pinfo; 1849 pinfo = info; 1850 } 1851 LeaveCriticalSection(&pinfo_cs); 1852 1853 return (pid_t)pi.dwProcessId; 1854} 1855 1856static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd) 1857{ 1858 return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2); 1859} 1860 1861pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv, 1862 const char *dir, 1863 int fhin, int fhout, int fherr) 1864{ 1865 pid_t pid; 1866 char *prog = path_lookup(cmd, 0); 1867 1868 if (!prog) { 1869 errno = ENOENT; 1870 pid = -1; 1871 } 1872 else { 1873 const char *interpr = parse_interpreter(prog); 1874 1875 if (interpr) { 1876 const char *argv0 = argv[0]; 1877 char *iprog = path_lookup(interpr, 1); 1878 argv[0] = prog; 1879 if (!iprog) { 1880 errno = ENOENT; 1881 pid = -1; 1882 } 1883 else { 1884 pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1, 1885 fhin, fhout, fherr); 1886 free(iprog); 1887 } 1888 argv[0] = argv0; 1889 } 1890 else 1891 pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0, 1892 fhin, fhout, fherr); 1893 free(prog); 1894 } 1895 return pid; 1896} 1897 1898static int try_shell_exec(const char *cmd, char *const *argv) 1899{ 1900 const char *interpr = parse_interpreter(cmd); 1901 char *prog; 1902 int pid = 0; 1903 1904 if (!interpr) 1905 return 0; 1906 prog = path_lookup(interpr, 1); 1907 if (prog) { 1908 int exec_id; 1909 int argc = 0; 1910 char **argv2; 1911 while (argv[argc]) argc++; 1912 ALLOC_ARRAY(argv2, argc + 1); 1913 argv2[0] = (char *)cmd; /* full path to the script file */ 1914 COPY_ARRAY(&argv2[1], &argv[1], argc); 1915 exec_id = trace2_exec(prog, (const char **)argv2); 1916 pid = mingw_spawnv(prog, (const char **)argv2, 1); 1917 if (pid >= 0) { 1918 int status; 1919 if (waitpid(pid, &status, 0) < 0) 1920 status = 255; 1921 trace2_exec_result(exec_id, status); 1922 exit(status); 1923 } 1924 trace2_exec_result(exec_id, -1); 1925 pid = 1; /* indicate that we tried but failed */ 1926 free(prog); 1927 free(argv2); 1928 } 1929 return pid; 1930} 1931 1932int mingw_execv(const char *cmd, char *const *argv) 1933{ 1934 /* check if git_command is a shell script */ 1935 if (!try_shell_exec(cmd, argv)) { 1936 int pid, status; 1937 int exec_id; 1938 1939 exec_id = trace2_exec(cmd, (const char **)argv); 1940 pid = mingw_spawnv(cmd, (const char **)argv, 0); 1941 if (pid < 0) { 1942 trace2_exec_result(exec_id, -1); 1943 return -1; 1944 } 1945 if (waitpid(pid, &status, 0) < 0) 1946 status = 255; 1947 trace2_exec_result(exec_id, status); 1948 exit(status); 1949 } 1950 return -1; 1951} 1952 1953int mingw_execvp(const char *cmd, char *const *argv) 1954{ 1955 char *prog = path_lookup(cmd, 0); 1956 1957 if (prog) { 1958 mingw_execv(prog, argv); 1959 free(prog); 1960 } else 1961 errno = ENOENT; 1962 1963 return -1; 1964} 1965 1966int mingw_kill(pid_t pid, int sig) 1967{ 1968 if (pid > 0 && sig == SIGTERM) { 1969 HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid); 1970 1971 if (TerminateProcess(h, -1)) { 1972 CloseHandle(h); 1973 return 0; 1974 } 1975 1976 errno = err_win_to_posix(GetLastError()); 1977 CloseHandle(h); 1978 return -1; 1979 } else if (pid > 0 && sig == 0) { 1980 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); 1981 if (h) { 1982 CloseHandle(h); 1983 return 0; 1984 } 1985 } 1986 1987 errno = EINVAL; 1988 return -1; 1989} 1990 1991/* 1992 * UTF-8 versions of getenv(), putenv() and unsetenv(). 1993 * Internally, they use the CRT's stock UNICODE routines 1994 * to avoid data loss. 1995 */ 1996char *mingw_getenv(const char *name) 1997{ 1998#define GETENV_MAX_RETAIN 64 1999 static char *values[GETENV_MAX_RETAIN]; 2000 static int value_counter; 2001 size_t len_key, len_value; 2002 wchar_t *w_key; 2003 char *value; 2004 wchar_t w_value[32768]; 2005 2006 if (!name || !*name) 2007 return NULL; 2008 2009 len_key = strlen(name) + 1; 2010 /* We cannot use xcalloc() here because that uses getenv() itself */ 2011 w_key = calloc(len_key, sizeof(wchar_t)); 2012 if (!w_key) 2013 die("Out of memory, (tried to allocate %"PRIuMAX" wchar_t's)", 2014 (uintmax_t)len_key); 2015 xutftowcs(w_key, name, len_key); 2016 /* GetEnvironmentVariableW() only sets the last error upon failure */ 2017 SetLastError(ERROR_SUCCESS); 2018 len_value = GetEnvironmentVariableW(w_key, w_value, ARRAY_SIZE(w_value)); 2019 if (!len_value && GetLastError() == ERROR_ENVVAR_NOT_FOUND) { 2020 free(w_key); 2021 return NULL; 2022 } 2023 free(w_key); 2024 2025 len_value = len_value * 3 + 1; 2026 /* We cannot use xcalloc() here because that uses getenv() itself */ 2027 value = calloc(len_value, sizeof(char)); 2028 if (!value) 2029 die("Out of memory, (tried to allocate %"PRIuMAX" bytes)", 2030 (uintmax_t)len_value); 2031 xwcstoutf(value, w_value, len_value); 2032 2033 /* 2034 * We return `value` which is an allocated value and the caller is NOT 2035 * expecting to have to free it, so we keep a round-robin array, 2036 * invalidating the buffer after GETENV_MAX_RETAIN getenv() calls. 2037 */ 2038 free(values[value_counter]); 2039 values[value_counter++] = value; 2040 if (value_counter >= ARRAY_SIZE(values)) 2041 value_counter = 0; 2042 2043 return value; 2044} 2045 2046int mingw_putenv(const char *namevalue) 2047{ 2048 size_t size; 2049 wchar_t *wide, *equal; 2050 BOOL result; 2051 2052 if (!namevalue || !*namevalue) 2053 return 0; 2054 2055 size = strlen(namevalue) * 2 + 1; 2056 wide = calloc(size, sizeof(wchar_t)); 2057 if (!wide) 2058 die("Out of memory, (tried to allocate %" PRIuMAX " wchar_t's)", 2059 (uintmax_t)size); 2060 xutftowcs(wide, namevalue, size); 2061 equal = wcschr(wide, L'='); 2062 if (!equal) 2063 result = SetEnvironmentVariableW(wide, NULL); 2064 else { 2065 *equal = L'\0'; 2066 result = SetEnvironmentVariableW(wide, equal + 1); 2067 } 2068 free(wide); 2069 2070 if (!result) 2071 errno = err_win_to_posix(GetLastError()); 2072 2073 return result ? 0 : -1; 2074} 2075 2076static void ensure_socket_initialization(void) 2077{ 2078 WSADATA wsa; 2079 static int initialized = 0; 2080 2081 if (initialized) 2082 return; 2083 2084 if (WSAStartup(MAKEWORD(2,2), &wsa)) 2085 die("unable to initialize winsock subsystem, error %d", 2086 WSAGetLastError()); 2087 2088 atexit((void(*)(void)) WSACleanup); 2089 initialized = 1; 2090} 2091 2092#undef gethostname 2093int mingw_gethostname(char *name, int namelen) 2094{ 2095 ensure_socket_initialization(); 2096 return gethostname(name, namelen); 2097} 2098 2099#undef gethostbyname 2100struct hostent *mingw_gethostbyname(const char *host) 2101{ 2102 ensure_socket_initialization(); 2103 return gethostbyname(host); 2104} 2105 2106#undef getaddrinfo 2107int mingw_getaddrinfo(const char *node, const char *service, 2108 const struct addrinfo *hints, struct addrinfo **res) 2109{ 2110 ensure_socket_initialization(); 2111 return getaddrinfo(node, service, hints, res); 2112} 2113 2114int mingw_socket(int domain, int type, int protocol) 2115{ 2116 int sockfd; 2117 SOCKET s; 2118 2119 ensure_socket_initialization(); 2120 s = WSASocket(domain, type, protocol, NULL, 0, 0); 2121 if (s == INVALID_SOCKET) { 2122 /* 2123 * WSAGetLastError() values are regular BSD error codes 2124 * biased by WSABASEERR. 2125 * However, strerror() does not know about networking 2126 * specific errors, which are values beginning at 38 or so. 2127 * Therefore, we choose to leave the biased error code 2128 * in errno so that _if_ someone looks up the code somewhere, 2129 * then it is at least the number that are usually listed. 2130 */ 2131 errno = WSAGetLastError(); 2132 return -1; 2133 } 2134 /* convert into a file descriptor */ 2135 if ((sockfd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) { 2136 closesocket(s); 2137 return error("unable to make a socket file descriptor: %s", 2138 strerror(errno)); 2139 } 2140 return sockfd; 2141} 2142 2143#undef connect 2144int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz) 2145{ 2146 SOCKET s = (SOCKET)_get_osfhandle(sockfd); 2147 return connect(s, sa, sz); 2148} 2149 2150#undef bind 2151int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz) 2152{ 2153 SOCKET s = (SOCKET)_get_osfhandle(sockfd); 2154 return bind(s, sa, sz); 2155} 2156 2157#undef setsockopt 2158int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen) 2159{ 2160 SOCKET s = (SOCKET)_get_osfhandle(sockfd); 2161 return setsockopt(s, lvl, optname, (const char*)optval, optlen); 2162} 2163 2164#undef shutdown 2165int mingw_shutdown(int sockfd, int how) 2166{ 2167 SOCKET s = (SOCKET)_get_osfhandle(sockfd); 2168 return shutdown(s, how); 2169} 2170 2171#undef listen 2172int mingw_listen(int sockfd, int backlog) 2173{ 2174 SOCKET s = (SOCKET)_get_osfhandle(sockfd); 2175 return listen(s, backlog); 2176} 2177 2178#undef accept 2179int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz) 2180{ 2181 int sockfd2; 2182 2183 SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1); 2184 SOCKET s2 = accept(s1, sa, sz); 2185 2186 /* convert into a file descriptor */ 2187 if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) { 2188 int err = errno; 2189 closesocket(s2); 2190 return error("unable to make a socket file descriptor: %s", 2191 strerror(err)); 2192 } 2193 return sockfd2; 2194} 2195 2196#undef rename 2197int mingw_rename(const char *pold, const char *pnew) 2198{ 2199 static int supports_file_rename_info_ex = 1; 2200 DWORD attrs, gle; 2201 int tries = 0; 2202 wchar_t wpold[MAX_PATH], wpnew[MAX_PATH]; 2203 int wpnew_len; 2204 2205 if (xutftowcs_path(wpold, pold) < 0) 2206 return -1; 2207 wpnew_len = xutftowcs_path(wpnew, pnew); 2208 if (wpnew_len < 0) 2209 return -1; 2210 2211 /* 2212 * Try native rename() first to get errno right. 2213 * It is based on MoveFile(), which cannot overwrite existing files. 2214 */ 2215 if (!_wrename(wpold, wpnew)) 2216 return 0; 2217 if (errno != EEXIST) 2218 return -1; 2219 2220repeat: 2221 if (supports_file_rename_info_ex) { 2222 /* 2223 * Our minimum required Windows version is still set to Windows 2224 * Vista. We thus have to declare required infrastructure for 2225 * FileRenameInfoEx ourselves until we bump _WIN32_WINNT to 2226 * 0x0A00. Furthermore, we have to handle cases where the 2227 * FileRenameInfoEx call isn't supported yet. 2228 */ 2229#define FILE_RENAME_FLAG_REPLACE_IF_EXISTS 0x00000001 2230#define FILE_RENAME_FLAG_POSIX_SEMANTICS 0x00000002 2231 FILE_INFO_BY_HANDLE_CLASS FileRenameInfoEx = 22; 2232 struct { 2233 /* 2234 * This is usually an unnamed union, but that is not 2235 * part of ISO C99. We thus inline the field, as we 2236 * really only care for the Flags field anyway. 2237 */ 2238 DWORD Flags; 2239 HANDLE RootDirectory; 2240 DWORD FileNameLength; 2241 /* 2242 * The actual structure is defined with a single-character 2243 * flex array so that the structure has to be allocated on 2244 * the heap. As we declare this structure ourselves though 2245 * we can avoid the allocation and define FileName to have 2246 * MAX_PATH bytes. 2247 */ 2248 WCHAR FileName[MAX_PATH]; 2249 } rename_info = { 0 }; 2250 HANDLE old_handle = INVALID_HANDLE_VALUE; 2251 BOOL success; 2252 2253 old_handle = CreateFileW(wpold, DELETE, 2254 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, 2255 NULL, OPEN_EXISTING, 2256 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 2257 NULL); 2258 if (old_handle == INVALID_HANDLE_VALUE) { 2259 errno = err_win_to_posix(GetLastError()); 2260 return -1; 2261 } 2262 2263 rename_info.Flags = FILE_RENAME_FLAG_REPLACE_IF_EXISTS | 2264 FILE_RENAME_FLAG_POSIX_SEMANTICS; 2265 rename_info.FileNameLength = wpnew_len * sizeof(WCHAR); 2266 memcpy(rename_info.FileName, wpnew, wpnew_len * sizeof(WCHAR)); 2267 2268 success = SetFileInformationByHandle(old_handle, FileRenameInfoEx, 2269 &rename_info, sizeof(rename_info)); 2270 gle = GetLastError(); 2271 CloseHandle(old_handle); 2272 if (success) 2273 return 0; 2274 2275 /* 2276 * When we see ERROR_INVALID_PARAMETER we can assume that the 2277 * current system doesn't support FileRenameInfoEx. Keep us 2278 * from using it in future calls and retry. 2279 */ 2280 if (gle == ERROR_INVALID_PARAMETER || 2281 gle == ERROR_NOT_SUPPORTED || 2282 gle == ERROR_INVALID_FUNCTION) { 2283 supports_file_rename_info_ex = 0; 2284 goto repeat; 2285 } 2286 2287 /* 2288 * In theory, we shouldn't get ERROR_ACCESS_DENIED because we 2289 * always open files with FILE_SHARE_DELETE But in practice we 2290 * cannot assume that Git is the only one accessing files, and 2291 * other applications may not set FILE_SHARE_DELETE. So we have 2292 * to retry. 2293 */ 2294 } else { 2295 if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING)) 2296 return 0; 2297 gle = GetLastError(); 2298 } 2299 2300 /* TODO: translate more errors */ 2301 if (gle == ERROR_ACCESS_DENIED && 2302 (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) { 2303 if (attrs & FILE_ATTRIBUTE_DIRECTORY) { 2304 DWORD attrsold = GetFileAttributesW(wpold); 2305 if (attrsold == INVALID_FILE_ATTRIBUTES || 2306 !(attrsold & FILE_ATTRIBUTE_DIRECTORY)) 2307 errno = EISDIR; 2308 else if (!_wrmdir(wpnew)) 2309 goto repeat; 2310 return -1; 2311 } 2312 if ((attrs & FILE_ATTRIBUTE_READONLY) && 2313 SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) { 2314 if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING)) 2315 return 0; 2316 gle = GetLastError(); 2317 /* revert file attributes on failure */ 2318 SetFileAttributesW(wpnew, attrs); 2319 } 2320 } 2321 if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) { 2322 /* 2323 * We assume that some other process had the source or 2324 * destination file open at the wrong moment and retry. 2325 * In order to give the other process a higher chance to 2326 * complete its operation, we give up our time slice now. 2327 * If we have to retry again, we do sleep a bit. 2328 */ 2329 Sleep(delay[tries]); 2330 tries++; 2331 goto repeat; 2332 } 2333 if (gle == ERROR_ACCESS_DENIED && 2334 ask_yes_no_if_possible("Rename from '%s' to '%s' failed. " 2335 "Should I try again?", pold, pnew)) 2336 goto repeat; 2337 2338 errno = EACCES; 2339 return -1; 2340} 2341 2342/* 2343 * Note that this doesn't return the actual pagesize, but 2344 * the allocation granularity. If future Windows specific git code 2345 * needs the real getpagesize function, we need to find another solution. 2346 */ 2347int mingw_getpagesize(void) 2348{ 2349 SYSTEM_INFO si; 2350 GetSystemInfo(&si); 2351 return si.dwAllocationGranularity; 2352} 2353 2354/* See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx */ 2355enum EXTENDED_NAME_FORMAT { 2356 NameDisplay = 3, 2357 NameUserPrincipal = 8 2358}; 2359 2360static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type) 2361{ 2362 DECLARE_PROC_ADDR(secur32.dll, BOOL, SEC_ENTRY, GetUserNameExW, 2363 enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG); 2364 static wchar_t wbuffer[1024]; 2365 DWORD len; 2366 2367 if (!INIT_PROC_ADDR(GetUserNameExW)) 2368 return NULL; 2369 2370 len = ARRAY_SIZE(wbuffer); 2371 if (GetUserNameExW(type, wbuffer, &len)) { 2372 char *converted = xmalloc((len *= 3)); 2373 if (xwcstoutf(converted, wbuffer, len) >= 0) 2374 return converted; 2375 free(converted); 2376 } 2377 2378 return NULL; 2379} 2380 2381char *mingw_query_user_email(void) 2382{ 2383 return get_extended_user_info(NameUserPrincipal); 2384} 2385 2386struct passwd *getpwuid(int uid UNUSED) 2387{ 2388 static unsigned initialized; 2389 static char user_name[100]; 2390 static struct passwd *p; 2391 wchar_t buf[100]; 2392 DWORD len; 2393 2394 if (initialized) 2395 return p; 2396 2397 len = ARRAY_SIZE(buf); 2398 if (!GetUserNameW(buf, &len)) { 2399 initialized = 1; 2400 return NULL; 2401 } 2402 2403 if (xwcstoutf(user_name, buf, sizeof(user_name)) < 0) { 2404 initialized = 1; 2405 return NULL; 2406 } 2407 2408 p = xmalloc(sizeof(*p)); 2409 p->pw_name = user_name; 2410 p->pw_gecos = get_extended_user_info(NameDisplay); 2411 if (!p->pw_gecos) 2412 /* 2413 * Data returned by getpwuid(3P) is treated as internal and 2414 * must never be written to or freed. 2415 */ 2416 p->pw_gecos = (char *) "unknown"; 2417 p->pw_dir = NULL; 2418 2419 initialized = 1; 2420 return p; 2421} 2422 2423static HANDLE timer_event; 2424static HANDLE timer_thread; 2425static int timer_interval; 2426static int one_shot; 2427static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL; 2428 2429/* The timer works like this: 2430 * The thread, ticktack(), is a trivial routine that most of the time 2431 * only waits to receive the signal to terminate. The main thread tells 2432 * the thread to terminate by setting the timer_event to the signalled 2433 * state. 2434 * But ticktack() interrupts the wait state after the timer's interval 2435 * length to call the signal handler. 2436 */ 2437 2438static unsigned __stdcall ticktack(void *dummy UNUSED) 2439{ 2440 while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) { 2441 mingw_raise(SIGALRM); 2442 if (one_shot) 2443 break; 2444 } 2445 return 0; 2446} 2447 2448static int start_timer_thread(void) 2449{ 2450 timer_event = CreateEvent(NULL, FALSE, FALSE, NULL); 2451 if (timer_event) { 2452 timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); 2453 if (!timer_thread ) 2454 return errno = ENOMEM, 2455 error("cannot start timer thread"); 2456 } else 2457 return errno = ENOMEM, 2458 error("cannot allocate resources for timer"); 2459 return 0; 2460} 2461 2462static void stop_timer_thread(void) 2463{ 2464 if (timer_event) 2465 SetEvent(timer_event); /* tell thread to terminate */ 2466 if (timer_thread) { 2467 int rc = WaitForSingleObject(timer_thread, 10000); 2468 if (rc == WAIT_TIMEOUT) 2469 error("timer thread did not terminate timely"); 2470 else if (rc != WAIT_OBJECT_0) 2471 error("waiting for timer thread failed: %lu", 2472 GetLastError()); 2473 CloseHandle(timer_thread); 2474 } 2475 if (timer_event) 2476 CloseHandle(timer_event); 2477 timer_event = NULL; 2478 timer_thread = NULL; 2479} 2480 2481static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2) 2482{ 2483 return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec; 2484} 2485 2486int setitimer(int type UNUSED, struct itimerval *in, struct itimerval *out) 2487{ 2488 static const struct timeval zero; 2489 static int atexit_done; 2490 2491 if (out) 2492 return errno = EINVAL, 2493 error("setitimer param 3 != NULL not implemented"); 2494 if (!is_timeval_eq(&in->it_interval, &zero) && 2495 !is_timeval_eq(&in->it_interval, &in->it_value)) 2496 return errno = EINVAL, 2497 error("setitimer: it_interval must be zero or eq it_value"); 2498 2499 if (timer_thread) 2500 stop_timer_thread(); 2501 2502 if (is_timeval_eq(&in->it_value, &zero) && 2503 is_timeval_eq(&in->it_interval, &zero)) 2504 return 0; 2505 2506 timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000; 2507 one_shot = is_timeval_eq(&in->it_interval, &zero); 2508 if (!atexit_done) { 2509 atexit(stop_timer_thread); 2510 atexit_done = 1; 2511 } 2512 return start_timer_thread(); 2513} 2514 2515int sigaction(int sig, struct sigaction *in, struct sigaction *out) 2516{ 2517 if (sig == SIGCHLD) 2518 return -1; 2519 else if (sig != SIGALRM) 2520 return errno = EINVAL, 2521 error("sigaction only implemented for SIGALRM"); 2522 if (out) 2523 return errno = EINVAL, 2524 error("sigaction: param 3 != NULL not implemented"); 2525 2526 timer_fn = in->sa_handler; 2527 return 0; 2528} 2529 2530#undef signal 2531sig_handler_t mingw_signal(int sig, sig_handler_t handler) 2532{ 2533 sig_handler_t old; 2534 2535 switch (sig) { 2536 case SIGALRM: 2537 old = timer_fn; 2538 timer_fn = handler; 2539 break; 2540 2541 case SIGINT: 2542 old = sigint_fn; 2543 sigint_fn = handler; 2544 break; 2545 2546 default: 2547 return signal(sig, handler); 2548 } 2549 2550 return old; 2551} 2552 2553#undef raise 2554int mingw_raise(int sig) 2555{ 2556 switch (sig) { 2557 case SIGALRM: 2558 if (timer_fn == SIG_DFL) { 2559 if (isatty(STDERR_FILENO)) 2560 fputs("Alarm clock\n", stderr); 2561 exit(128 + SIGALRM); 2562 } else if (timer_fn != SIG_IGN) 2563 timer_fn(SIGALRM); 2564 return 0; 2565 2566 case SIGINT: 2567 if (sigint_fn == SIG_DFL) 2568 exit(128 + SIGINT); 2569 else if (sigint_fn != SIG_IGN) 2570 sigint_fn(SIGINT); 2571 return 0; 2572 2573#if defined(_MSC_VER) 2574 case SIGILL: 2575 case SIGFPE: 2576 case SIGSEGV: 2577 case SIGTERM: 2578 case SIGBREAK: 2579 case SIGABRT: 2580 case SIGABRT_COMPAT: 2581 /* 2582 * The <signal.h> header in the MS C Runtime defines 8 signals 2583 * as being supported on the platform. Anything else causes an 2584 * "Invalid signal or error" (which in DEBUG builds causes the 2585 * Abort/Retry/Ignore dialog). We by-pass the CRT for things we 2586 * already know will fail. 2587 */ 2588 return raise(sig); 2589 default: 2590 errno = EINVAL; 2591 return -1; 2592 2593#else 2594 2595 default: 2596 return raise(sig); 2597 2598#endif 2599 2600 } 2601} 2602 2603int link(const char *oldpath, const char *newpath) 2604{ 2605 wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH]; 2606 if (xutftowcs_path(woldpath, oldpath) < 0 || 2607 xutftowcs_path(wnewpath, newpath) < 0) 2608 return -1; 2609 2610 if (!CreateHardLinkW(wnewpath, woldpath, NULL)) { 2611 errno = err_win_to_posix(GetLastError()); 2612 return -1; 2613 } 2614 return 0; 2615} 2616 2617pid_t waitpid(pid_t pid, int *status, int options) 2618{ 2619 HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, 2620 FALSE, pid); 2621 if (!h) { 2622 errno = ECHILD; 2623 return -1; 2624 } 2625 2626 if (pid > 0 && options & WNOHANG) { 2627 if (WAIT_OBJECT_0 != WaitForSingleObject(h, 0)) { 2628 CloseHandle(h); 2629 return 0; 2630 } 2631 options &= ~WNOHANG; 2632 } 2633 2634 if (options == 0) { 2635 struct pinfo_t **ppinfo; 2636 if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) { 2637 CloseHandle(h); 2638 return 0; 2639 } 2640 2641 if (status) 2642 GetExitCodeProcess(h, (LPDWORD)status); 2643 2644 EnterCriticalSection(&pinfo_cs); 2645 2646 ppinfo = &pinfo; 2647 while (*ppinfo) { 2648 struct pinfo_t *info = *ppinfo; 2649 if (info->pid == pid) { 2650 CloseHandle(info->proc); 2651 *ppinfo = info->next; 2652 free(info); 2653 break; 2654 } 2655 ppinfo = &info->next; 2656 } 2657 2658 LeaveCriticalSection(&pinfo_cs); 2659 2660 CloseHandle(h); 2661 return pid; 2662 } 2663 CloseHandle(h); 2664 2665 errno = EINVAL; 2666 return -1; 2667} 2668 2669int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen) 2670{ 2671 int upos = 0, wpos = 0; 2672 const unsigned char *utf = (const unsigned char*) utfs; 2673 if (!utf || !wcs || wcslen < 1) { 2674 errno = EINVAL; 2675 return -1; 2676 } 2677 /* reserve space for \0 */ 2678 wcslen--; 2679 if (utflen < 0) 2680 utflen = INT_MAX; 2681 2682 while (upos < utflen) { 2683 int c = utf[upos++] & 0xff; 2684 if (utflen == INT_MAX && c == 0) 2685 break; 2686 2687 if (wpos >= wcslen) { 2688 wcs[wpos] = 0; 2689 errno = ERANGE; 2690 return -1; 2691 } 2692 2693 if (c < 0x80) { 2694 /* ASCII */ 2695 wcs[wpos++] = c; 2696 } else if (c >= 0xc2 && c < 0xe0 && upos < utflen && 2697 (utf[upos] & 0xc0) == 0x80) { 2698 /* 2-byte utf-8 */ 2699 c = ((c & 0x1f) << 6); 2700 c |= (utf[upos++] & 0x3f); 2701 wcs[wpos++] = c; 2702 } else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen && 2703 !(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */ 2704 (utf[upos] & 0xc0) == 0x80 && 2705 (utf[upos + 1] & 0xc0) == 0x80) { 2706 /* 3-byte utf-8 */ 2707 c = ((c & 0x0f) << 12); 2708 c |= ((utf[upos++] & 0x3f) << 6); 2709 c |= (utf[upos++] & 0x3f); 2710 wcs[wpos++] = c; 2711 } else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen && 2712 wpos + 1 < wcslen && 2713 !(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */ 2714 !(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */ 2715 (utf[upos] & 0xc0) == 0x80 && 2716 (utf[upos + 1] & 0xc0) == 0x80 && 2717 (utf[upos + 2] & 0xc0) == 0x80) { 2718 /* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */ 2719 c = ((c & 0x07) << 18); 2720 c |= ((utf[upos++] & 0x3f) << 12); 2721 c |= ((utf[upos++] & 0x3f) << 6); 2722 c |= (utf[upos++] & 0x3f); 2723 c -= 0x10000; 2724 wcs[wpos++] = 0xd800 | (c >> 10); 2725 wcs[wpos++] = 0xdc00 | (c & 0x3ff); 2726 } else if (c >= 0xa0) { 2727 /* invalid utf-8 byte, printable unicode char: convert 1:1 */ 2728 wcs[wpos++] = c; 2729 } else { 2730 /* invalid utf-8 byte, non-printable unicode: convert to hex */ 2731 static const char *hex = "0123456789abcdef"; 2732 wcs[wpos++] = hex[c >> 4]; 2733 if (wpos < wcslen) 2734 wcs[wpos++] = hex[c & 0x0f]; 2735 } 2736 } 2737 wcs[wpos] = 0; 2738 return wpos; 2739} 2740 2741int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen) 2742{ 2743 if (!wcs || !utf || utflen < 1) { 2744 errno = EINVAL; 2745 return -1; 2746 } 2747 utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL); 2748 if (utflen) 2749 return utflen - 1; 2750 errno = ERANGE; 2751 return -1; 2752} 2753 2754static void setup_windows_environment(void) 2755{ 2756 char *tmp = getenv("TMPDIR"); 2757 2758 /* on Windows it is TMP and TEMP */ 2759 if (!tmp) { 2760 if (!(tmp = getenv("TMP"))) 2761 tmp = getenv("TEMP"); 2762 if (tmp) { 2763 setenv("TMPDIR", tmp, 1); 2764 tmp = getenv("TMPDIR"); 2765 } 2766 } 2767 2768 if (tmp) { 2769 /* 2770 * Convert all dir separators to forward slashes, 2771 * to help shell commands called from the Git 2772 * executable (by not mistaking the dir separators 2773 * for escape characters). 2774 */ 2775 convert_slashes(tmp); 2776 } 2777 2778 /* simulate TERM to enable auto-color (see color.c) */ 2779 if (!getenv("TERM")) 2780 setenv("TERM", "cygwin", 1); 2781 2782 /* calculate HOME if not set */ 2783 if (!getenv("HOME")) { 2784 /* 2785 * try $HOMEDRIVE$HOMEPATH - the home share may be a network 2786 * location, thus also check if the path exists (i.e. is not 2787 * disconnected) 2788 */ 2789 if ((tmp = getenv("HOMEDRIVE"))) { 2790 struct strbuf buf = STRBUF_INIT; 2791 strbuf_addstr(&buf, tmp); 2792 if ((tmp = getenv("HOMEPATH"))) { 2793 strbuf_addstr(&buf, tmp); 2794 if (is_directory(buf.buf)) 2795 setenv("HOME", buf.buf, 1); 2796 else 2797 tmp = NULL; /* use $USERPROFILE */ 2798 } 2799 strbuf_release(&buf); 2800 } 2801 /* use $USERPROFILE if the home share is not available */ 2802 if (!tmp && (tmp = getenv("USERPROFILE"))) 2803 setenv("HOME", tmp, 1); 2804 } 2805} 2806 2807static void get_current_user_sid(PSID *sid, HANDLE *linked_token) 2808{ 2809 HANDLE token; 2810 DWORD len = 0; 2811 TOKEN_ELEVATION_TYPE elevationType; 2812 DWORD size; 2813 2814 *sid = NULL; 2815 *linked_token = NULL; 2816 2817 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) 2818 return; 2819 2820 if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) { 2821 TOKEN_USER *info = xmalloc((size_t)len); 2822 if (GetTokenInformation(token, TokenUser, info, len, &len)) { 2823 len = GetLengthSid(info->User.Sid); 2824 *sid = xmalloc(len); 2825 if (!CopySid(len, *sid, info->User.Sid)) { 2826 error(_("failed to copy SID (%ld)"), 2827 GetLastError()); 2828 FREE_AND_NULL(*sid); 2829 } 2830 } 2831 FREE_AND_NULL(info); 2832 } 2833 2834 if (GetTokenInformation(token, TokenElevationType, &elevationType, sizeof(elevationType), &size) && 2835 elevationType == TokenElevationTypeLimited) { 2836 /* 2837 * The current process is run by a member of the Administrators 2838 * group, but is not running elevated. 2839 */ 2840 if (!GetTokenInformation(token, TokenLinkedToken, linked_token, sizeof(*linked_token), &size)) 2841 linked_token = NULL; /* there is no linked token */ 2842 } 2843 2844 CloseHandle(token); 2845} 2846 2847static BOOL user_sid_to_user_name(PSID sid, LPSTR *str) 2848{ 2849 SID_NAME_USE pe_use; 2850 DWORD len_user = 0, len_domain = 0; 2851 BOOL translate_sid_to_user; 2852 2853 /* 2854 * returns only FALSE, because the string pointers are NULL 2855 */ 2856 LookupAccountSidA(NULL, sid, NULL, &len_user, NULL, &len_domain, 2857 &pe_use); 2858 /* 2859 * Alloc needed space of the strings 2860 */ 2861 ALLOC_ARRAY((*str), (size_t)len_domain + (size_t)len_user); 2862 translate_sid_to_user = LookupAccountSidA(NULL, sid, 2863 (*str) + len_domain, &len_user, *str, &len_domain, &pe_use); 2864 if (!translate_sid_to_user) 2865 FREE_AND_NULL(*str); 2866 else 2867 (*str)[len_domain] = '/'; 2868 return translate_sid_to_user; 2869} 2870 2871static int acls_supported(const char *path) 2872{ 2873 size_t offset = offset_1st_component(path); 2874 WCHAR wroot[MAX_PATH]; 2875 DWORD file_system_flags; 2876 2877 if (offset && 2878 xutftowcsn(wroot, path, MAX_PATH, offset) > 0 && 2879 GetVolumeInformationW(wroot, NULL, 0, NULL, NULL, 2880 &file_system_flags, NULL, 0)) 2881 return !!(file_system_flags & FILE_PERSISTENT_ACLS); 2882 2883 return 0; 2884} 2885 2886int is_path_owned_by_current_sid(const char *path, struct strbuf *report) 2887{ 2888 WCHAR wpath[MAX_PATH]; 2889 PSID sid = NULL; 2890 PSECURITY_DESCRIPTOR descriptor = NULL; 2891 DWORD err; 2892 2893 static wchar_t home[MAX_PATH]; 2894 2895 int result = 0; 2896 2897 if (xutftowcs_path(wpath, path) < 0) 2898 return 0; 2899 2900 /* 2901 * On Windows, the home directory is owned by the administrator, but for 2902 * all practical purposes, it belongs to the user. Do pretend that it is 2903 * owned by the user. 2904 */ 2905 if (!*home) { 2906 DWORD size = ARRAY_SIZE(home); 2907 DWORD len = GetEnvironmentVariableW(L"HOME", home, size); 2908 if (!len || len > size) 2909 wcscpy(home, L"::N/A::"); 2910 } 2911 if (!wcsicmp(wpath, home)) 2912 return 1; 2913 2914 /* Get the owner SID */ 2915 err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT, 2916 OWNER_SECURITY_INFORMATION | 2917 DACL_SECURITY_INFORMATION, 2918 &sid, NULL, NULL, NULL, &descriptor); 2919 2920 if (err != ERROR_SUCCESS) 2921 error(_("failed to get owner for '%s' (%ld)"), path, err); 2922 else if (sid && IsValidSid(sid)) { 2923 /* Now, verify that the SID matches the current user's */ 2924 static PSID current_user_sid; 2925 static HANDLE linked_token; 2926 BOOL is_member; 2927 2928 if (!current_user_sid) 2929 get_current_user_sid(&current_user_sid, &linked_token); 2930 2931 if (current_user_sid && 2932 IsValidSid(current_user_sid) && 2933 EqualSid(sid, current_user_sid)) 2934 result = 1; 2935 else if (IsWellKnownSid(sid, WinBuiltinAdministratorsSid) && 2936 ((CheckTokenMembership(NULL, sid, &is_member) && 2937 is_member) || 2938 (linked_token && 2939 CheckTokenMembership(linked_token, sid, &is_member) && 2940 is_member))) 2941 /* 2942 * If owned by the Administrators group, and the 2943 * current user is an administrator, we consider that 2944 * okay, too. 2945 */ 2946 result = 1; 2947 else if (report && 2948 IsWellKnownSid(sid, WinWorldSid) && 2949 !acls_supported(path)) { 2950 /* 2951 * On FAT32 volumes, ownership is not actually recorded. 2952 */ 2953 strbuf_addf(report, "'%s' is on a file system that does " 2954 "not record ownership\n", path); 2955 } else if (report) { 2956 PCSTR str1, str2, str3, str4; 2957 LPSTR to_free1 = NULL, to_free3 = NULL, 2958 to_local_free2 = NULL, to_local_free4 = NULL; 2959 2960 if (user_sid_to_user_name(sid, &to_free1)) 2961 str1 = to_free1; 2962 else 2963 str1 = "(inconvertible)"; 2964 if (ConvertSidToStringSidA(sid, &to_local_free2)) 2965 str2 = to_local_free2; 2966 else 2967 str2 = "(inconvertible)"; 2968 2969 if (!current_user_sid) { 2970 str3 = "(none)"; 2971 str4 = "(none)"; 2972 } 2973 else if (!IsValidSid(current_user_sid)) { 2974 str3 = "(invalid)"; 2975 str4 = "(invalid)"; 2976 } else { 2977 if (user_sid_to_user_name(current_user_sid, 2978 &to_free3)) 2979 str3 = to_free3; 2980 else 2981 str3 = "(inconvertible)"; 2982 if (ConvertSidToStringSidA(current_user_sid, 2983 &to_local_free4)) 2984 str4 = to_local_free4; 2985 else 2986 str4 = "(inconvertible)"; 2987 } 2988 strbuf_addf(report, 2989 "'%s' is owned by:\n" 2990 "\t%s (%s)\nbut the current user is:\n" 2991 "\t%s (%s)\n", 2992 path, str1, str2, str3, str4); 2993 free(to_free1); 2994 LocalFree(to_local_free2); 2995 free(to_free3); 2996 LocalFree(to_local_free4); 2997 } 2998 } 2999 3000 /* 3001 * We can release the security descriptor struct only now because `sid` 3002 * actually points into this struct. 3003 */ 3004 if (descriptor) 3005 LocalFree(descriptor); 3006 3007 return result; 3008} 3009 3010int is_valid_win32_path(const char *path, int allow_literal_nul) 3011{ 3012 const char *p = path; 3013 int preceding_space_or_period = 0, i = 0, periods = 0; 3014 3015 if (!protect_ntfs) 3016 return 1; 3017 3018 skip_dos_drive_prefix((char **)&path); 3019 goto segment_start; 3020 3021 for (;;) { 3022 char c = *(path++); 3023 switch (c) { 3024 case '\0': 3025 case '/': case '\\': 3026 /* cannot end in ` ` or `.`, except for `.` and `..` */ 3027 if (preceding_space_or_period && 3028 (i != periods || periods > 2)) 3029 return 0; 3030 if (!c) 3031 return 1; 3032 3033 i = periods = preceding_space_or_period = 0; 3034 3035segment_start: 3036 switch (*path) { 3037 case 'a': case 'A': /* AUX */ 3038 if (((c = path[++i]) != 'u' && c != 'U') || 3039 ((c = path[++i]) != 'x' && c != 'X')) { 3040not_a_reserved_name: 3041 path += i; 3042 continue; 3043 } 3044 break; 3045 case 'c': case 'C': 3046 /* COM1 ... COM9, CON, CONIN$, CONOUT$ */ 3047 if ((c = path[++i]) != 'o' && c != 'O') 3048 goto not_a_reserved_name; 3049 c = path[++i]; 3050 if (c == 'm' || c == 'M') { /* COM1 ... COM9 */ 3051 c = path[++i]; 3052 if (c < '1' || c > '9') 3053 goto not_a_reserved_name; 3054 } else if (c == 'n' || c == 'N') { /* CON */ 3055 c = path[i + 1]; 3056 if ((c == 'i' || c == 'I') && 3057 ((c = path[i + 2]) == 'n' || 3058 c == 'N') && 3059 path[i + 3] == '$') 3060 i += 3; /* CONIN$ */ 3061 else if ((c == 'o' || c == 'O') && 3062 ((c = path[i + 2]) == 'u' || 3063 c == 'U') && 3064 ((c = path[i + 3]) == 't' || 3065 c == 'T') && 3066 path[i + 4] == '$') 3067 i += 4; /* CONOUT$ */ 3068 } else 3069 goto not_a_reserved_name; 3070 break; 3071 case 'l': case 'L': /* LPT<N> */ 3072 if (((c = path[++i]) != 'p' && c != 'P') || 3073 ((c = path[++i]) != 't' && c != 'T') || 3074 !isdigit(path[++i])) 3075 goto not_a_reserved_name; 3076 break; 3077 case 'n': case 'N': /* NUL */ 3078 if (((c = path[++i]) != 'u' && c != 'U') || 3079 ((c = path[++i]) != 'l' && c != 'L') || 3080 (allow_literal_nul && 3081 !path[i + 1] && p == path)) 3082 goto not_a_reserved_name; 3083 break; 3084 case 'p': case 'P': /* PRN */ 3085 if (((c = path[++i]) != 'r' && c != 'R') || 3086 ((c = path[++i]) != 'n' && c != 'N')) 3087 goto not_a_reserved_name; 3088 break; 3089 default: 3090 continue; 3091 } 3092 3093 /* 3094 * So far, this looks like a reserved name. Let's see 3095 * whether it actually is one: trailing spaces, a file 3096 * extension, or an NTFS Alternate Data Stream do not 3097 * matter, the name is still reserved if any of those 3098 * follow immediately after the actual name. 3099 */ 3100 i++; 3101 if (path[i] == ' ') { 3102 preceding_space_or_period = 1; 3103 while (path[++i] == ' ') 3104 ; /* skip all spaces */ 3105 } 3106 3107 c = path[i]; 3108 if (c && c != '.' && c != ':' && !is_xplatform_dir_sep(c)) 3109 goto not_a_reserved_name; 3110 3111 /* contains reserved name */ 3112 return 0; 3113 case '.': 3114 periods++; 3115 /* fallthru */ 3116 case ' ': 3117 preceding_space_or_period = 1; 3118 i++; 3119 continue; 3120 case ':': /* DOS drive prefix was already skipped */ 3121 case '<': case '>': case '"': case '|': case '?': case '*': 3122 /* illegal character */ 3123 return 0; 3124 default: 3125 if (c > '\0' && c < '\x20') 3126 /* illegal character */ 3127 return 0; 3128 } 3129 preceding_space_or_period = 0; 3130 i++; 3131 } 3132} 3133 3134#if !defined(_MSC_VER) 3135/* 3136 * Disable MSVCRT command line wildcard expansion (__getmainargs called from 3137 * mingw startup code, see init.c in mingw runtime). 3138 */ 3139int _CRT_glob = 0; 3140#endif 3141 3142static NORETURN void die_startup(void) 3143{ 3144 fputs("fatal: not enough memory for initialization", stderr); 3145 exit(128); 3146} 3147 3148static void *malloc_startup(size_t size) 3149{ 3150 void *result = malloc(size); 3151 if (!result) 3152 die_startup(); 3153 return result; 3154} 3155 3156static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len) 3157{ 3158 len = xwcstoutf(buffer, wcs, len) + 1; 3159 return memcpy(malloc_startup(len), buffer, len); 3160} 3161 3162static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd, 3163 DWORD desired_access, DWORD flags) 3164{ 3165 DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING; 3166 wchar_t buf[MAX_PATH]; 3167 DWORD max = ARRAY_SIZE(buf); 3168 HANDLE handle; 3169 DWORD ret = GetEnvironmentVariableW(key, buf, max); 3170 3171 if (!ret || ret >= max) 3172 return; 3173 3174 /* make sure this does not leak into child processes */ 3175 SetEnvironmentVariableW(key, NULL); 3176 if (!wcscmp(buf, L"off")) { 3177 close(fd); 3178 handle = GetStdHandle(std_id); 3179 if (handle != INVALID_HANDLE_VALUE) 3180 CloseHandle(handle); 3181 return; 3182 } 3183 if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) { 3184 handle = GetStdHandle(STD_OUTPUT_HANDLE); 3185 if (handle == INVALID_HANDLE_VALUE) { 3186 close(fd); 3187 handle = GetStdHandle(std_id); 3188 if (handle != INVALID_HANDLE_VALUE) 3189 CloseHandle(handle); 3190 } else { 3191 int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY); 3192 SetStdHandle(std_id, handle); 3193 dup2(new_fd, fd); 3194 /* do *not* close the new_fd: that would close stdout */ 3195 } 3196 return; 3197 } 3198 handle = CreateFileW(buf, desired_access, 0, NULL, create_flag, 3199 flags, NULL); 3200 if (handle != INVALID_HANDLE_VALUE) { 3201 int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY); 3202 SetStdHandle(std_id, handle); 3203 dup2(new_fd, fd); 3204 close(new_fd); 3205 } 3206} 3207 3208static void maybe_redirect_std_handles(void) 3209{ 3210 maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0, 3211 GENERIC_READ, FILE_ATTRIBUTE_NORMAL); 3212 maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1, 3213 GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL); 3214 maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2, 3215 GENERIC_WRITE, FILE_FLAG_NO_BUFFERING); 3216} 3217 3218#ifdef _MSC_VER 3219#ifdef _DEBUG 3220#include <crtdbg.h> 3221#endif 3222#endif 3223 3224/* 3225 * We implement wmain() and compile with -municode, which would 3226 * normally ignore main(), but we call the latter from the former 3227 * so that we can handle non-ASCII command-line parameters 3228 * appropriately. 3229 * 3230 * To be more compatible with the core git code, we convert 3231 * argv into UTF8 and pass them directly to main(). 3232 */ 3233int wmain(int argc, const wchar_t **wargv) 3234{ 3235 int i, exit_status; 3236 size_t maxlen; 3237 char *buffer, **save; 3238 const char **argv; 3239 3240 trace2_initialize_clock(); 3241 3242#ifdef _MSC_VER 3243#ifdef _DEBUG 3244 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); 3245#endif 3246 3247#ifdef USE_MSVC_CRTDBG 3248 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 3249#endif 3250#endif 3251 3252 maybe_redirect_std_handles(); 3253 3254 /* determine size of argv and environ conversion buffer */ 3255 maxlen = wcslen(wargv[0]); 3256 for (i = 1; i < argc; i++) 3257 maxlen = max(maxlen, wcslen(wargv[i])); 3258 3259 /* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */ 3260 maxlen = 3 * maxlen + 1; 3261 buffer = malloc_startup(maxlen); 3262 3263 /* 3264 * Create a UTF-8 version of w_argv. Also create a "save" copy 3265 * to remember all the string pointers because parse_options() 3266 * will remove claimed items from the argv that we pass down. 3267 */ 3268 ALLOC_ARRAY(argv, argc + 1); 3269 ALLOC_ARRAY(save, argc + 1); 3270 for (i = 0; i < argc; i++) 3271 argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen); 3272 argv[i] = save[i] = NULL; 3273 free(buffer); 3274 3275 /* fix Windows specific environment settings */ 3276 setup_windows_environment(); 3277 3278 unset_environment_variables = xstrdup("PERL5LIB"); 3279 3280 /* initialize critical section for waitpid pinfo_t list */ 3281 InitializeCriticalSection(&pinfo_cs); 3282 3283 /* set up default file mode and file modes for stdin/out/err */ 3284 _fmode = _O_BINARY; 3285 _setmode(_fileno(stdin), _O_BINARY); 3286 _setmode(_fileno(stdout), _O_BINARY); 3287 _setmode(_fileno(stderr), _O_BINARY); 3288 3289 /* initialize Unicode console */ 3290 winansi_init(); 3291 3292 /* invoke the real main() using our utf8 version of argv. */ 3293 exit_status = main(argc, argv); 3294 3295 for (i = 0; i < argc; i++) 3296 free(save[i]); 3297 free(save); 3298 free(argv); 3299 3300 return exit_status; 3301} 3302 3303int uname(struct utsname *buf) 3304{ 3305 unsigned v = (unsigned)GetVersion(); 3306 memset(buf, 0, sizeof(*buf)); 3307 xsnprintf(buf->sysname, sizeof(buf->sysname), "Windows"); 3308 xsnprintf(buf->release, sizeof(buf->release), 3309 "%u.%u", v & 0xff, (v >> 8) & 0xff); 3310 /* assuming NT variants only.. */ 3311 xsnprintf(buf->version, sizeof(buf->version), 3312 "%u", (v >> 16) & 0x7fff); 3313 return 0; 3314} 3315 3316#ifndef NO_UNIX_SOCKETS 3317int mingw_have_unix_sockets(void) 3318{ 3319 SC_HANDLE scm, srvc; 3320 SERVICE_STATUS_PROCESS status; 3321 DWORD bytes; 3322 int ret = 0; 3323 scm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); 3324 if (scm) { 3325 srvc = OpenServiceA(scm, "afunix", SERVICE_QUERY_STATUS); 3326 if (srvc) { 3327 if(QueryServiceStatusEx(srvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(SERVICE_STATUS_PROCESS), &bytes)) 3328 ret = status.dwCurrentState == SERVICE_RUNNING; 3329 CloseServiceHandle(srvc); 3330 } 3331 CloseServiceHandle(scm); 3332 } 3333 return ret; 3334} 3335#endif