PageRenderTime 101ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/compat/mingw.c

https://bitbucket.org/ssaasen/git
C | 2224 lines | 1832 code | 209 blank | 183 comment | 372 complexity | 8f17c2199ddbe0492148a569693a65db MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. #include "../git-compat-util.h"
  2. #include "win32.h"
  3. #include <conio.h>
  4. #include <wchar.h>
  5. #include "../strbuf.h"
  6. #include "../run-command.h"
  7. #include "../cache.h"
  8. #define HCAST(type, handle) ((type)(intptr_t)handle)
  9. static const int delay[] = { 0, 1, 10, 20, 40 };
  10. int err_win_to_posix(DWORD winerr)
  11. {
  12. int error = ENOSYS;
  13. switch(winerr) {
  14. case ERROR_ACCESS_DENIED: error = EACCES; break;
  15. case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
  16. case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
  17. case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
  18. case ERROR_ALREADY_EXISTS: error = EEXIST; break;
  19. case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
  20. case ERROR_BAD_COMMAND: error = EIO; break;
  21. case ERROR_BAD_DEVICE: error = ENODEV; break;
  22. case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
  23. case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
  24. case ERROR_BAD_FORMAT: error = ENOEXEC; break;
  25. case ERROR_BAD_LENGTH: error = EINVAL; break;
  26. case ERROR_BAD_PATHNAME: error = ENOENT; break;
  27. case ERROR_BAD_PIPE: error = EPIPE; break;
  28. case ERROR_BAD_UNIT: error = ENODEV; break;
  29. case ERROR_BAD_USERNAME: error = EINVAL; break;
  30. case ERROR_BROKEN_PIPE: error = EPIPE; break;
  31. case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
  32. case ERROR_BUSY: error = EBUSY; break;
  33. case ERROR_BUSY_DRIVE: error = EBUSY; break;
  34. case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
  35. case ERROR_CANNOT_MAKE: error = EACCES; break;
  36. case ERROR_CANTOPEN: error = EIO; break;
  37. case ERROR_CANTREAD: error = EIO; break;
  38. case ERROR_CANTWRITE: error = EIO; break;
  39. case ERROR_CRC: error = EIO; break;
  40. case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
  41. case ERROR_DEVICE_IN_USE: error = EBUSY; break;
  42. case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
  43. case ERROR_DIRECTORY: error = EINVAL; break;
  44. case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
  45. case ERROR_DISK_CHANGE: error = EIO; break;
  46. case ERROR_DISK_FULL: error = ENOSPC; break;
  47. case ERROR_DRIVE_LOCKED: error = EBUSY; break;
  48. case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
  49. case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
  50. case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
  51. case ERROR_FILE_EXISTS: error = EEXIST; break;
  52. case ERROR_FILE_INVALID: error = ENODEV; break;
  53. case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
  54. case ERROR_GEN_FAILURE: error = EIO; break;
  55. case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
  56. case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
  57. case ERROR_INVALID_ACCESS: error = EACCES; break;
  58. case ERROR_INVALID_ADDRESS: error = EFAULT; break;
  59. case ERROR_INVALID_BLOCK: error = EFAULT; break;
  60. case ERROR_INVALID_DATA: error = EINVAL; break;
  61. case ERROR_INVALID_DRIVE: error = ENODEV; break;
  62. case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
  63. case ERROR_INVALID_FLAGS: error = EINVAL; break;
  64. case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
  65. case ERROR_INVALID_HANDLE: error = EBADF; break;
  66. case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
  67. case ERROR_INVALID_NAME: error = EINVAL; break;
  68. case ERROR_INVALID_OWNER: error = EINVAL; break;
  69. case ERROR_INVALID_PARAMETER: error = EINVAL; break;
  70. case ERROR_INVALID_PASSWORD: error = EPERM; break;
  71. case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
  72. case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
  73. case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
  74. case ERROR_INVALID_WORKSTATION: error = EACCES; break;
  75. case ERROR_IO_DEVICE: error = EIO; break;
  76. case ERROR_IO_INCOMPLETE: error = EINTR; break;
  77. case ERROR_LOCKED: error = EBUSY; break;
  78. case ERROR_LOCK_VIOLATION: error = EACCES; break;
  79. case ERROR_LOGON_FAILURE: error = EACCES; break;
  80. case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
  81. case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
  82. case ERROR_MORE_DATA: error = EPIPE; break;
  83. case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
  84. case ERROR_NOACCESS: error = EFAULT; break;
  85. case ERROR_NONE_MAPPED: error = EINVAL; break;
  86. case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
  87. case ERROR_NOT_READY: error = EAGAIN; break;
  88. case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
  89. case ERROR_NO_DATA: error = EPIPE; break;
  90. case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
  91. case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
  92. case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
  93. case ERROR_OPEN_FAILED: error = EIO; break;
  94. case ERROR_OPEN_FILES: error = EBUSY; break;
  95. case ERROR_OPERATION_ABORTED: error = EINTR; break;
  96. case ERROR_OUTOFMEMORY: error = ENOMEM; break;
  97. case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
  98. case ERROR_PATH_BUSY: error = EBUSY; break;
  99. case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
  100. case ERROR_PIPE_BUSY: error = EBUSY; break;
  101. case ERROR_PIPE_CONNECTED: error = EPIPE; break;
  102. case ERROR_PIPE_LISTENING: error = EPIPE; break;
  103. case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
  104. case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
  105. case ERROR_READ_FAULT: error = EIO; break;
  106. case ERROR_SEEK: error = EIO; break;
  107. case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
  108. case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
  109. case ERROR_SHARING_VIOLATION: error = EACCES; break;
  110. case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
  111. case ERROR_SWAPERROR: error = ENOENT; break;
  112. case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
  113. case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
  114. case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
  115. case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
  116. case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
  117. case ERROR_WRITE_FAULT: error = EIO; break;
  118. case ERROR_WRITE_PROTECT: error = EROFS; break;
  119. }
  120. return error;
  121. }
  122. static inline int is_file_in_use_error(DWORD errcode)
  123. {
  124. switch (errcode) {
  125. case ERROR_SHARING_VIOLATION:
  126. case ERROR_ACCESS_DENIED:
  127. return 1;
  128. }
  129. return 0;
  130. }
  131. static int read_yes_no_answer(void)
  132. {
  133. char answer[1024];
  134. if (fgets(answer, sizeof(answer), stdin)) {
  135. size_t answer_len = strlen(answer);
  136. int got_full_line = 0, c;
  137. /* remove the newline */
  138. if (answer_len >= 2 && answer[answer_len-2] == '\r') {
  139. answer[answer_len-2] = '\0';
  140. got_full_line = 1;
  141. } else if (answer_len >= 1 && answer[answer_len-1] == '\n') {
  142. answer[answer_len-1] = '\0';
  143. got_full_line = 1;
  144. }
  145. /* flush the buffer in case we did not get the full line */
  146. if (!got_full_line)
  147. while ((c = getchar()) != EOF && c != '\n')
  148. ;
  149. } else
  150. /* we could not read, return the
  151. * default answer which is no */
  152. return 0;
  153. if (tolower(answer[0]) == 'y' && !answer[1])
  154. return 1;
  155. if (!strncasecmp(answer, "yes", sizeof(answer)))
  156. return 1;
  157. if (tolower(answer[0]) == 'n' && !answer[1])
  158. return 0;
  159. if (!strncasecmp(answer, "no", sizeof(answer)))
  160. return 0;
  161. /* did not find an answer we understand */
  162. return -1;
  163. }
  164. static int ask_yes_no_if_possible(const char *format, ...)
  165. {
  166. char question[4096];
  167. const char *retry_hook[] = { NULL, NULL, NULL };
  168. va_list args;
  169. va_start(args, format);
  170. vsnprintf(question, sizeof(question), format, args);
  171. va_end(args);
  172. if ((retry_hook[0] = mingw_getenv("GIT_ASK_YESNO"))) {
  173. retry_hook[1] = question;
  174. return !run_command_v_opt(retry_hook, 0);
  175. }
  176. if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr)))
  177. return 0;
  178. while (1) {
  179. int answer;
  180. fprintf(stderr, "%s (y/n) ", question);
  181. if ((answer = read_yes_no_answer()) >= 0)
  182. return answer;
  183. fprintf(stderr, "Sorry, I did not understand your answer. "
  184. "Please type 'y' or 'n'\n");
  185. }
  186. }
  187. int mingw_unlink(const char *pathname)
  188. {
  189. int ret, tries = 0;
  190. wchar_t wpathname[MAX_PATH];
  191. if (xutftowcs_path(wpathname, pathname) < 0)
  192. return -1;
  193. /* read-only files cannot be removed */
  194. _wchmod(wpathname, 0666);
  195. while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
  196. if (!is_file_in_use_error(GetLastError()))
  197. break;
  198. /*
  199. * We assume that some other process had the source or
  200. * destination file open at the wrong moment and retry.
  201. * In order to give the other process a higher chance to
  202. * complete its operation, we give up our time slice now.
  203. * If we have to retry again, we do sleep a bit.
  204. */
  205. Sleep(delay[tries]);
  206. tries++;
  207. }
  208. while (ret == -1 && is_file_in_use_error(GetLastError()) &&
  209. ask_yes_no_if_possible("Unlink of file '%s' failed. "
  210. "Should I try again?", pathname))
  211. ret = _wunlink(wpathname);
  212. return ret;
  213. }
  214. static int is_dir_empty(const wchar_t *wpath)
  215. {
  216. WIN32_FIND_DATAW findbuf;
  217. HANDLE handle;
  218. wchar_t wbuf[MAX_PATH + 2];
  219. wcscpy(wbuf, wpath);
  220. wcscat(wbuf, L"\\*");
  221. handle = FindFirstFileW(wbuf, &findbuf);
  222. if (handle == INVALID_HANDLE_VALUE)
  223. return GetLastError() == ERROR_NO_MORE_FILES;
  224. while (!wcscmp(findbuf.cFileName, L".") ||
  225. !wcscmp(findbuf.cFileName, L".."))
  226. if (!FindNextFileW(handle, &findbuf)) {
  227. DWORD err = GetLastError();
  228. FindClose(handle);
  229. return err == ERROR_NO_MORE_FILES;
  230. }
  231. FindClose(handle);
  232. return 0;
  233. }
  234. int mingw_rmdir(const char *pathname)
  235. {
  236. int ret, tries = 0;
  237. wchar_t wpathname[MAX_PATH];
  238. if (xutftowcs_path(wpathname, pathname) < 0)
  239. return -1;
  240. while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
  241. if (!is_file_in_use_error(GetLastError()))
  242. errno = err_win_to_posix(GetLastError());
  243. if (errno != EACCES)
  244. break;
  245. if (!is_dir_empty(wpathname)) {
  246. errno = ENOTEMPTY;
  247. break;
  248. }
  249. /*
  250. * We assume that some other process had the source or
  251. * destination file open at the wrong moment and retry.
  252. * In order to give the other process a higher chance to
  253. * complete its operation, we give up our time slice now.
  254. * If we have to retry again, we do sleep a bit.
  255. */
  256. Sleep(delay[tries]);
  257. tries++;
  258. }
  259. while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) &&
  260. ask_yes_no_if_possible("Deletion of directory '%s' failed. "
  261. "Should I try again?", pathname))
  262. ret = _wrmdir(wpathname);
  263. return ret;
  264. }
  265. int mingw_mkdir(const char *path, int mode)
  266. {
  267. int ret;
  268. wchar_t wpath[MAX_PATH];
  269. if (xutftowcs_path(wpath, path) < 0)
  270. return -1;
  271. ret = _wmkdir(wpath);
  272. return ret;
  273. }
  274. int mingw_open (const char *filename, int oflags, ...)
  275. {
  276. va_list args;
  277. unsigned mode;
  278. int fd;
  279. wchar_t wfilename[MAX_PATH];
  280. va_start(args, oflags);
  281. mode = va_arg(args, int);
  282. va_end(args);
  283. if (filename && !strcmp(filename, "/dev/null"))
  284. filename = "nul";
  285. if (xutftowcs_path(wfilename, filename) < 0)
  286. return -1;
  287. fd = _wopen(wfilename, oflags, mode);
  288. if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
  289. DWORD attrs = GetFileAttributesW(wfilename);
  290. if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
  291. errno = EISDIR;
  292. }
  293. return fd;
  294. }
  295. static BOOL WINAPI ctrl_ignore(DWORD type)
  296. {
  297. return TRUE;
  298. }
  299. #undef fgetc
  300. int mingw_fgetc(FILE *stream)
  301. {
  302. int ch;
  303. if (!isatty(_fileno(stream)))
  304. return fgetc(stream);
  305. SetConsoleCtrlHandler(ctrl_ignore, TRUE);
  306. while (1) {
  307. ch = fgetc(stream);
  308. if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED)
  309. break;
  310. /* Ctrl+C was pressed, simulate SIGINT and retry */
  311. mingw_raise(SIGINT);
  312. }
  313. SetConsoleCtrlHandler(ctrl_ignore, FALSE);
  314. return ch;
  315. }
  316. #undef fopen
  317. FILE *mingw_fopen (const char *filename, const char *otype)
  318. {
  319. FILE *file;
  320. wchar_t wfilename[MAX_PATH], wotype[4];
  321. if (filename && !strcmp(filename, "/dev/null"))
  322. filename = "nul";
  323. if (xutftowcs_path(wfilename, filename) < 0 ||
  324. xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
  325. return NULL;
  326. file = _wfopen(wfilename, wotype);
  327. return file;
  328. }
  329. FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
  330. {
  331. FILE *file;
  332. wchar_t wfilename[MAX_PATH], wotype[4];
  333. if (filename && !strcmp(filename, "/dev/null"))
  334. filename = "nul";
  335. if (xutftowcs_path(wfilename, filename) < 0 ||
  336. xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
  337. return NULL;
  338. file = _wfreopen(wfilename, wotype, stream);
  339. return file;
  340. }
  341. #undef fflush
  342. int mingw_fflush(FILE *stream)
  343. {
  344. int ret = fflush(stream);
  345. /*
  346. * write() is used behind the scenes of stdio output functions.
  347. * Since git code does not check for errors after each stdio write
  348. * operation, it can happen that write() is called by a later
  349. * stdio function even if an earlier write() call failed. In the
  350. * case of a pipe whose readable end was closed, only the first
  351. * call to write() reports EPIPE on Windows. Subsequent write()
  352. * calls report EINVAL. It is impossible to notice whether this
  353. * fflush invocation triggered such a case, therefore, we have to
  354. * catch all EINVAL errors whole-sale.
  355. */
  356. if (ret && errno == EINVAL)
  357. errno = EPIPE;
  358. return ret;
  359. }
  360. #undef write
  361. ssize_t mingw_write(int fd, const void *buf, size_t len)
  362. {
  363. ssize_t result = write(fd, buf, len);
  364. if (result < 0 && errno == EINVAL && buf) {
  365. /* check if fd is a pipe */
  366. HANDLE h = (HANDLE) _get_osfhandle(fd);
  367. if (GetFileType(h) == FILE_TYPE_PIPE)
  368. errno = EPIPE;
  369. else
  370. errno = EINVAL;
  371. }
  372. return result;
  373. }
  374. int mingw_access(const char *filename, int mode)
  375. {
  376. wchar_t wfilename[MAX_PATH];
  377. if (xutftowcs_path(wfilename, filename) < 0)
  378. return -1;
  379. /* X_OK is not supported by the MSVCRT version */
  380. return _waccess(wfilename, mode & ~X_OK);
  381. }
  382. int mingw_chdir(const char *dirname)
  383. {
  384. wchar_t wdirname[MAX_PATH];
  385. if (xutftowcs_path(wdirname, dirname) < 0)
  386. return -1;
  387. return _wchdir(wdirname);
  388. }
  389. int mingw_chmod(const char *filename, int mode)
  390. {
  391. wchar_t wfilename[MAX_PATH];
  392. if (xutftowcs_path(wfilename, filename) < 0)
  393. return -1;
  394. return _wchmod(wfilename, mode);
  395. }
  396. /*
  397. * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  398. * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
  399. */
  400. static inline long long filetime_to_hnsec(const FILETIME *ft)
  401. {
  402. long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
  403. /* Windows to Unix Epoch conversion */
  404. return winTime - 116444736000000000LL;
  405. }
  406. static inline time_t filetime_to_time_t(const FILETIME *ft)
  407. {
  408. return (time_t)(filetime_to_hnsec(ft) / 10000000);
  409. }
  410. /**
  411. * Verifies that safe_create_leading_directories() would succeed.
  412. */
  413. static int has_valid_directory_prefix(wchar_t *wfilename)
  414. {
  415. int n = wcslen(wfilename);
  416. while (n > 0) {
  417. wchar_t c = wfilename[--n];
  418. DWORD attributes;
  419. if (!is_dir_sep(c))
  420. continue;
  421. wfilename[n] = L'\0';
  422. attributes = GetFileAttributesW(wfilename);
  423. wfilename[n] = c;
  424. if (attributes == FILE_ATTRIBUTE_DIRECTORY ||
  425. attributes == FILE_ATTRIBUTE_DEVICE)
  426. return 1;
  427. if (attributes == INVALID_FILE_ATTRIBUTES)
  428. switch (GetLastError()) {
  429. case ERROR_PATH_NOT_FOUND:
  430. continue;
  431. case ERROR_FILE_NOT_FOUND:
  432. /* This implies parent directory exists. */
  433. return 1;
  434. }
  435. return 0;
  436. }
  437. return 1;
  438. }
  439. /* We keep the do_lstat code in a separate function to avoid recursion.
  440. * When a path ends with a slash, the stat will fail with ENOENT. In
  441. * this case, we strip the trailing slashes and stat again.
  442. *
  443. * If follow is true then act like stat() and report on the link
  444. * target. Otherwise report on the link itself.
  445. */
  446. static int do_lstat(int follow, const char *file_name, struct stat *buf)
  447. {
  448. WIN32_FILE_ATTRIBUTE_DATA fdata;
  449. wchar_t wfilename[MAX_PATH];
  450. if (xutftowcs_path(wfilename, file_name) < 0)
  451. return -1;
  452. if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
  453. buf->st_ino = 0;
  454. buf->st_gid = 0;
  455. buf->st_uid = 0;
  456. buf->st_nlink = 1;
  457. buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
  458. buf->st_size = fdata.nFileSizeLow |
  459. (((off_t)fdata.nFileSizeHigh)<<32);
  460. buf->st_dev = buf->st_rdev = 0; /* not used by Git */
  461. buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
  462. buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
  463. buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
  464. if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  465. WIN32_FIND_DATAW findbuf;
  466. HANDLE handle = FindFirstFileW(wfilename, &findbuf);
  467. if (handle != INVALID_HANDLE_VALUE) {
  468. if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
  469. (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
  470. if (follow) {
  471. char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
  472. buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  473. } else {
  474. buf->st_mode = S_IFLNK;
  475. }
  476. buf->st_mode |= S_IREAD;
  477. if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
  478. buf->st_mode |= S_IWRITE;
  479. }
  480. FindClose(handle);
  481. }
  482. }
  483. return 0;
  484. }
  485. switch (GetLastError()) {
  486. case ERROR_ACCESS_DENIED:
  487. case ERROR_SHARING_VIOLATION:
  488. case ERROR_LOCK_VIOLATION:
  489. case ERROR_SHARING_BUFFER_EXCEEDED:
  490. errno = EACCES;
  491. break;
  492. case ERROR_BUFFER_OVERFLOW:
  493. errno = ENAMETOOLONG;
  494. break;
  495. case ERROR_NOT_ENOUGH_MEMORY:
  496. errno = ENOMEM;
  497. break;
  498. case ERROR_PATH_NOT_FOUND:
  499. if (!has_valid_directory_prefix(wfilename)) {
  500. errno = ENOTDIR;
  501. break;
  502. }
  503. /* fallthru */
  504. default:
  505. errno = ENOENT;
  506. break;
  507. }
  508. return -1;
  509. }
  510. /* We provide our own lstat/fstat functions, since the provided
  511. * lstat/fstat functions are so slow. These stat functions are
  512. * tailored for Git's usage (read: fast), and are not meant to be
  513. * complete. Note that Git stat()s are redirected to mingw_lstat()
  514. * too, since Windows doesn't really handle symlinks that well.
  515. */
  516. static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
  517. {
  518. int namelen;
  519. char alt_name[PATH_MAX];
  520. if (!do_lstat(follow, file_name, buf))
  521. return 0;
  522. /* if file_name ended in a '/', Windows returned ENOENT;
  523. * try again without trailing slashes
  524. */
  525. if (errno != ENOENT)
  526. return -1;
  527. namelen = strlen(file_name);
  528. if (namelen && file_name[namelen-1] != '/')
  529. return -1;
  530. while (namelen && file_name[namelen-1] == '/')
  531. --namelen;
  532. if (!namelen || namelen >= PATH_MAX)
  533. return -1;
  534. memcpy(alt_name, file_name, namelen);
  535. alt_name[namelen] = 0;
  536. return do_lstat(follow, alt_name, buf);
  537. }
  538. int mingw_lstat(const char *file_name, struct stat *buf)
  539. {
  540. return do_stat_internal(0, file_name, buf);
  541. }
  542. int mingw_stat(const char *file_name, struct stat *buf)
  543. {
  544. return do_stat_internal(1, file_name, buf);
  545. }
  546. int mingw_fstat(int fd, struct stat *buf)
  547. {
  548. HANDLE fh = (HANDLE)_get_osfhandle(fd);
  549. BY_HANDLE_FILE_INFORMATION fdata;
  550. if (fh == INVALID_HANDLE_VALUE) {
  551. errno = EBADF;
  552. return -1;
  553. }
  554. /* direct non-file handles to MS's fstat() */
  555. if (GetFileType(fh) != FILE_TYPE_DISK)
  556. return _fstati64(fd, buf);
  557. if (GetFileInformationByHandle(fh, &fdata)) {
  558. buf->st_ino = 0;
  559. buf->st_gid = 0;
  560. buf->st_uid = 0;
  561. buf->st_nlink = 1;
  562. buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
  563. buf->st_size = fdata.nFileSizeLow |
  564. (((off_t)fdata.nFileSizeHigh)<<32);
  565. buf->st_dev = buf->st_rdev = 0; /* not used by Git */
  566. buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
  567. buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
  568. buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
  569. return 0;
  570. }
  571. errno = EBADF;
  572. return -1;
  573. }
  574. static inline void time_t_to_filetime(time_t t, FILETIME *ft)
  575. {
  576. long long winTime = t * 10000000LL + 116444736000000000LL;
  577. ft->dwLowDateTime = winTime;
  578. ft->dwHighDateTime = winTime >> 32;
  579. }
  580. int mingw_utime (const char *file_name, const struct utimbuf *times)
  581. {
  582. FILETIME mft, aft;
  583. int fh, rc;
  584. DWORD attrs;
  585. wchar_t wfilename[MAX_PATH];
  586. if (xutftowcs_path(wfilename, file_name) < 0)
  587. return -1;
  588. /* must have write permission */
  589. attrs = GetFileAttributesW(wfilename);
  590. if (attrs != INVALID_FILE_ATTRIBUTES &&
  591. (attrs & FILE_ATTRIBUTE_READONLY)) {
  592. /* ignore errors here; open() will report them */
  593. SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
  594. }
  595. if ((fh = _wopen(wfilename, O_RDWR | O_BINARY)) < 0) {
  596. rc = -1;
  597. goto revert_attrs;
  598. }
  599. if (times) {
  600. time_t_to_filetime(times->modtime, &mft);
  601. time_t_to_filetime(times->actime, &aft);
  602. } else {
  603. GetSystemTimeAsFileTime(&mft);
  604. aft = mft;
  605. }
  606. if (!SetFileTime((HANDLE)_get_osfhandle(fh), NULL, &aft, &mft)) {
  607. errno = EINVAL;
  608. rc = -1;
  609. } else
  610. rc = 0;
  611. close(fh);
  612. revert_attrs:
  613. if (attrs != INVALID_FILE_ATTRIBUTES &&
  614. (attrs & FILE_ATTRIBUTE_READONLY)) {
  615. /* ignore errors again */
  616. SetFileAttributesW(wfilename, attrs);
  617. }
  618. return rc;
  619. }
  620. unsigned int sleep (unsigned int seconds)
  621. {
  622. Sleep(seconds*1000);
  623. return 0;
  624. }
  625. char *mingw_mktemp(char *template)
  626. {
  627. wchar_t wtemplate[MAX_PATH];
  628. if (xutftowcs_path(wtemplate, template) < 0)
  629. return NULL;
  630. if (!_wmktemp(wtemplate))
  631. return NULL;
  632. if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
  633. return NULL;
  634. return template;
  635. }
  636. int mkstemp(char *template)
  637. {
  638. char *filename = mktemp(template);
  639. if (filename == NULL)
  640. return -1;
  641. return open(filename, O_RDWR | O_CREAT, 0600);
  642. }
  643. int gettimeofday(struct timeval *tv, void *tz)
  644. {
  645. FILETIME ft;
  646. long long hnsec;
  647. GetSystemTimeAsFileTime(&ft);
  648. hnsec = filetime_to_hnsec(&ft);
  649. tv->tv_sec = hnsec / 10000000;
  650. tv->tv_usec = (hnsec % 10000000) / 10;
  651. return 0;
  652. }
  653. int pipe(int filedes[2])
  654. {
  655. HANDLE h[2];
  656. /* this creates non-inheritable handles */
  657. if (!CreatePipe(&h[0], &h[1], NULL, 8192)) {
  658. errno = err_win_to_posix(GetLastError());
  659. return -1;
  660. }
  661. filedes[0] = _open_osfhandle(HCAST(int, h[0]), O_NOINHERIT);
  662. if (filedes[0] < 0) {
  663. CloseHandle(h[0]);
  664. CloseHandle(h[1]);
  665. return -1;
  666. }
  667. filedes[1] = _open_osfhandle(HCAST(int, h[1]), O_NOINHERIT);
  668. if (filedes[1] < 0) {
  669. close(filedes[0]);
  670. CloseHandle(h[1]);
  671. return -1;
  672. }
  673. return 0;
  674. }
  675. struct tm *gmtime_r(const time_t *timep, struct tm *result)
  676. {
  677. /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
  678. memcpy(result, gmtime(timep), sizeof(struct tm));
  679. return result;
  680. }
  681. struct tm *localtime_r(const time_t *timep, struct tm *result)
  682. {
  683. /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
  684. memcpy(result, localtime(timep), sizeof(struct tm));
  685. return result;
  686. }
  687. char *mingw_getcwd(char *pointer, int len)
  688. {
  689. wchar_t wpointer[MAX_PATH];
  690. if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
  691. return NULL;
  692. if (xwcstoutf(pointer, wpointer, len) < 0)
  693. return NULL;
  694. convert_slashes(pointer);
  695. return pointer;
  696. }
  697. /*
  698. * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
  699. * (Parsing C++ Command-Line Arguments)
  700. */
  701. static const char *quote_arg(const char *arg)
  702. {
  703. /* count chars to quote */
  704. int len = 0, n = 0;
  705. int force_quotes = 0;
  706. char *q, *d;
  707. const char *p = arg;
  708. if (!*p) force_quotes = 1;
  709. while (*p) {
  710. if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
  711. force_quotes = 1;
  712. else if (*p == '"')
  713. n++;
  714. else if (*p == '\\') {
  715. int count = 0;
  716. while (*p == '\\') {
  717. count++;
  718. p++;
  719. len++;
  720. }
  721. if (*p == '"')
  722. n += count*2 + 1;
  723. continue;
  724. }
  725. len++;
  726. p++;
  727. }
  728. if (!force_quotes && n == 0)
  729. return arg;
  730. /* insert \ where necessary */
  731. d = q = xmalloc(st_add3(len, n, 3));
  732. *d++ = '"';
  733. while (*arg) {
  734. if (*arg == '"')
  735. *d++ = '\\';
  736. else if (*arg == '\\') {
  737. int count = 0;
  738. while (*arg == '\\') {
  739. count++;
  740. *d++ = *arg++;
  741. }
  742. if (*arg == '"') {
  743. while (count-- > 0)
  744. *d++ = '\\';
  745. *d++ = '\\';
  746. }
  747. }
  748. *d++ = *arg++;
  749. }
  750. *d++ = '"';
  751. *d++ = 0;
  752. return q;
  753. }
  754. static const char *parse_interpreter(const char *cmd)
  755. {
  756. static char buf[100];
  757. char *p, *opt;
  758. int n, fd;
  759. /* don't even try a .exe */
  760. n = strlen(cmd);
  761. if (n >= 4 && !strcasecmp(cmd+n-4, ".exe"))
  762. return NULL;
  763. fd = open(cmd, O_RDONLY);
  764. if (fd < 0)
  765. return NULL;
  766. n = read(fd, buf, sizeof(buf)-1);
  767. close(fd);
  768. if (n < 4) /* at least '#!/x' and not error */
  769. return NULL;
  770. if (buf[0] != '#' || buf[1] != '!')
  771. return NULL;
  772. buf[n] = '\0';
  773. p = buf + strcspn(buf, "\r\n");
  774. if (!*p)
  775. return NULL;
  776. *p = '\0';
  777. if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\')))
  778. return NULL;
  779. /* strip options */
  780. if ((opt = strchr(p+1, ' ')))
  781. *opt = '\0';
  782. return p+1;
  783. }
  784. /*
  785. * Splits the PATH into parts.
  786. */
  787. static char **get_path_split(void)
  788. {
  789. char *p, **path, *envpath = mingw_getenv("PATH");
  790. int i, n = 0;
  791. if (!envpath || !*envpath)
  792. return NULL;
  793. envpath = xstrdup(envpath);
  794. p = envpath;
  795. while (p) {
  796. char *dir = p;
  797. p = strchr(p, ';');
  798. if (p) *p++ = '\0';
  799. if (*dir) { /* not earlier, catches series of ; */
  800. ++n;
  801. }
  802. }
  803. if (!n)
  804. return NULL;
  805. ALLOC_ARRAY(path, n + 1);
  806. p = envpath;
  807. i = 0;
  808. do {
  809. if (*p)
  810. path[i++] = xstrdup(p);
  811. p = p+strlen(p)+1;
  812. } while (i < n);
  813. path[i] = NULL;
  814. free(envpath);
  815. return path;
  816. }
  817. static void free_path_split(char **path)
  818. {
  819. char **p = path;
  820. if (!path)
  821. return;
  822. while (*p)
  823. free(*p++);
  824. free(path);
  825. }
  826. /*
  827. * exe_only means that we only want to detect .exe files, but not scripts
  828. * (which do not have an extension)
  829. */
  830. static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
  831. {
  832. char path[MAX_PATH];
  833. snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
  834. if (!isexe && access(path, F_OK) == 0)
  835. return xstrdup(path);
  836. path[strlen(path)-4] = '\0';
  837. if ((!exe_only || isexe) && access(path, F_OK) == 0)
  838. if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY))
  839. return xstrdup(path);
  840. return NULL;
  841. }
  842. /*
  843. * Determines the absolute path of cmd using the split path in path.
  844. * If cmd contains a slash or backslash, no lookup is performed.
  845. */
  846. static char *path_lookup(const char *cmd, char **path, int exe_only)
  847. {
  848. char *prog = NULL;
  849. int len = strlen(cmd);
  850. int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
  851. if (strchr(cmd, '/') || strchr(cmd, '\\'))
  852. prog = xstrdup(cmd);
  853. while (!prog && *path)
  854. prog = lookup_prog(*path++, cmd, isexe, exe_only);
  855. return prog;
  856. }
  857. static int do_putenv(char **env, const char *name, int size, int free_old);
  858. /* used number of elements of environ array, including terminating NULL */
  859. static int environ_size = 0;
  860. /* allocated size of environ array, in bytes */
  861. static int environ_alloc = 0;
  862. /*
  863. * Create environment block suitable for CreateProcess. Merges current
  864. * process environment and the supplied environment changes.
  865. */
  866. static wchar_t *make_environment_block(char **deltaenv)
  867. {
  868. wchar_t *wenvblk = NULL;
  869. char **tmpenv;
  870. int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
  871. while (deltaenv && deltaenv[i])
  872. i++;
  873. /* copy the environment, leaving space for changes */
  874. ALLOC_ARRAY(tmpenv, size + i);
  875. memcpy(tmpenv, environ, size * sizeof(char*));
  876. /* merge supplied environment changes into the temporary environment */
  877. for (i = 0; deltaenv && deltaenv[i]; i++)
  878. size = do_putenv(tmpenv, deltaenv[i], size, 0);
  879. /* create environment block from temporary environment */
  880. for (i = 0; tmpenv[i]; i++) {
  881. size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
  882. ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
  883. wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
  884. }
  885. /* add final \0 terminator */
  886. wenvblk[wenvpos] = 0;
  887. free(tmpenv);
  888. return wenvblk;
  889. }
  890. struct pinfo_t {
  891. struct pinfo_t *next;
  892. pid_t pid;
  893. HANDLE proc;
  894. };
  895. static struct pinfo_t *pinfo = NULL;
  896. CRITICAL_SECTION pinfo_cs;
  897. static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
  898. const char *dir,
  899. int prepend_cmd, int fhin, int fhout, int fherr)
  900. {
  901. STARTUPINFOW si;
  902. PROCESS_INFORMATION pi;
  903. struct strbuf args;
  904. wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
  905. unsigned flags = CREATE_UNICODE_ENVIRONMENT;
  906. BOOL ret;
  907. /* Determine whether or not we are associated to a console */
  908. HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE,
  909. FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  910. FILE_ATTRIBUTE_NORMAL, NULL);
  911. if (cons == INVALID_HANDLE_VALUE) {
  912. /* There is no console associated with this process.
  913. * Since the child is a console process, Windows
  914. * would normally create a console window. But
  915. * since we'll be redirecting std streams, we do
  916. * not need the console.
  917. * It is necessary to use DETACHED_PROCESS
  918. * instead of CREATE_NO_WINDOW to make ssh
  919. * recognize that it has no console.
  920. */
  921. flags |= DETACHED_PROCESS;
  922. } else {
  923. /* There is already a console. If we specified
  924. * DETACHED_PROCESS here, too, Windows would
  925. * disassociate the child from the console.
  926. * The same is true for CREATE_NO_WINDOW.
  927. * Go figure!
  928. */
  929. CloseHandle(cons);
  930. }
  931. memset(&si, 0, sizeof(si));
  932. si.cb = sizeof(si);
  933. si.dwFlags = STARTF_USESTDHANDLES;
  934. si.hStdInput = winansi_get_osfhandle(fhin);
  935. si.hStdOutput = winansi_get_osfhandle(fhout);
  936. si.hStdError = winansi_get_osfhandle(fherr);
  937. if (xutftowcs_path(wcmd, cmd) < 0)
  938. return -1;
  939. if (dir && xutftowcs_path(wdir, dir) < 0)
  940. return -1;
  941. /* concatenate argv, quoting args as we go */
  942. strbuf_init(&args, 0);
  943. if (prepend_cmd) {
  944. char *quoted = (char *)quote_arg(cmd);
  945. strbuf_addstr(&args, quoted);
  946. if (quoted != cmd)
  947. free(quoted);
  948. }
  949. for (; *argv; argv++) {
  950. char *quoted = (char *)quote_arg(*argv);
  951. if (*args.buf)
  952. strbuf_addch(&args, ' ');
  953. strbuf_addstr(&args, quoted);
  954. if (quoted != *argv)
  955. free(quoted);
  956. }
  957. ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1));
  958. xutftowcs(wargs, args.buf, 2 * args.len + 1);
  959. strbuf_release(&args);
  960. wenvblk = make_environment_block(deltaenv);
  961. memset(&pi, 0, sizeof(pi));
  962. ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
  963. wenvblk, dir ? wdir : NULL, &si, &pi);
  964. free(wenvblk);
  965. free(wargs);
  966. if (!ret) {
  967. errno = ENOENT;
  968. return -1;
  969. }
  970. CloseHandle(pi.hThread);
  971. /*
  972. * The process ID is the human-readable identifier of the process
  973. * that we want to present in log and error messages. The handle
  974. * is not useful for this purpose. But we cannot close it, either,
  975. * because it is not possible to turn a process ID into a process
  976. * handle after the process terminated.
  977. * Keep the handle in a list for waitpid.
  978. */
  979. EnterCriticalSection(&pinfo_cs);
  980. {
  981. struct pinfo_t *info = xmalloc(sizeof(struct pinfo_t));
  982. info->pid = pi.dwProcessId;
  983. info->proc = pi.hProcess;
  984. info->next = pinfo;
  985. pinfo = info;
  986. }
  987. LeaveCriticalSection(&pinfo_cs);
  988. return (pid_t)pi.dwProcessId;
  989. }
  990. static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
  991. {
  992. return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
  993. }
  994. pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
  995. const char *dir,
  996. int fhin, int fhout, int fherr)
  997. {
  998. pid_t pid;
  999. char **path = get_path_split();
  1000. char *prog = path_lookup(cmd, path, 0);
  1001. if (!prog) {
  1002. errno = ENOENT;
  1003. pid = -1;
  1004. }
  1005. else {
  1006. const char *interpr = parse_interpreter(prog);
  1007. if (interpr) {
  1008. const char *argv0 = argv[0];
  1009. char *iprog = path_lookup(interpr, path, 1);
  1010. argv[0] = prog;
  1011. if (!iprog) {
  1012. errno = ENOENT;
  1013. pid = -1;
  1014. }
  1015. else {
  1016. pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
  1017. fhin, fhout, fherr);
  1018. free(iprog);
  1019. }
  1020. argv[0] = argv0;
  1021. }
  1022. else
  1023. pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
  1024. fhin, fhout, fherr);
  1025. free(prog);
  1026. }
  1027. free_path_split(path);
  1028. return pid;
  1029. }
  1030. static int try_shell_exec(const char *cmd, char *const *argv)
  1031. {
  1032. const char *interpr = parse_interpreter(cmd);
  1033. char **path;
  1034. char *prog;
  1035. int pid = 0;
  1036. if (!interpr)
  1037. return 0;
  1038. path = get_path_split();
  1039. prog = path_lookup(interpr, path, 1);
  1040. if (prog) {
  1041. int argc = 0;
  1042. const char **argv2;
  1043. while (argv[argc]) argc++;
  1044. ALLOC_ARRAY(argv2, argc + 1);
  1045. argv2[0] = (char *)cmd; /* full path to the script file */
  1046. memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
  1047. pid = mingw_spawnv(prog, argv2, 1);
  1048. if (pid >= 0) {
  1049. int status;
  1050. if (waitpid(pid, &status, 0) < 0)
  1051. status = 255;
  1052. exit(status);
  1053. }
  1054. pid = 1; /* indicate that we tried but failed */
  1055. free(prog);
  1056. free(argv2);
  1057. }
  1058. free_path_split(path);
  1059. return pid;
  1060. }
  1061. int mingw_execv(const char *cmd, char *const *argv)
  1062. {
  1063. /* check if git_command is a shell script */
  1064. if (!try_shell_exec(cmd, argv)) {
  1065. int pid, status;
  1066. pid = mingw_spawnv(cmd, (const char **)argv, 0);
  1067. if (pid < 0)
  1068. return -1;
  1069. if (waitpid(pid, &status, 0) < 0)
  1070. status = 255;
  1071. exit(status);
  1072. }
  1073. return -1;
  1074. }
  1075. int mingw_execvp(const char *cmd, char *const *argv)
  1076. {
  1077. char **path = get_path_split();
  1078. char *prog = path_lookup(cmd, path, 0);
  1079. if (prog) {
  1080. mingw_execv(prog, argv);
  1081. free(prog);
  1082. } else
  1083. errno = ENOENT;
  1084. free_path_split(path);
  1085. return -1;
  1086. }
  1087. int mingw_kill(pid_t pid, int sig)
  1088. {
  1089. if (pid > 0 && sig == SIGTERM) {
  1090. HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
  1091. if (TerminateProcess(h, -1)) {
  1092. CloseHandle(h);
  1093. return 0;
  1094. }
  1095. errno = err_win_to_posix(GetLastError());
  1096. CloseHandle(h);
  1097. return -1;
  1098. } else if (pid > 0 && sig == 0) {
  1099. HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
  1100. if (h) {
  1101. CloseHandle(h);
  1102. return 0;
  1103. }
  1104. }
  1105. errno = EINVAL;
  1106. return -1;
  1107. }
  1108. /*
  1109. * Compare environment entries by key (i.e. stopping at '=' or '\0').
  1110. */
  1111. static int compareenv(const void *v1, const void *v2)
  1112. {
  1113. const char *e1 = *(const char**)v1;
  1114. const char *e2 = *(const char**)v2;
  1115. for (;;) {
  1116. int c1 = *e1++;
  1117. int c2 = *e2++;
  1118. c1 = (c1 == '=') ? 0 : tolower(c1);
  1119. c2 = (c2 == '=') ? 0 : tolower(c2);
  1120. if (c1 > c2)
  1121. return 1;
  1122. if (c1 < c2)
  1123. return -1;
  1124. if (c1 == 0)
  1125. return 0;
  1126. }
  1127. }
  1128. static int bsearchenv(char **env, const char *name, size_t size)
  1129. {
  1130. unsigned low = 0, high = size;
  1131. while (low < high) {
  1132. unsigned mid = low + ((high - low) >> 1);
  1133. int cmp = compareenv(&env[mid], &name);
  1134. if (cmp < 0)
  1135. low = mid + 1;
  1136. else if (cmp > 0)
  1137. high = mid;
  1138. else
  1139. return mid;
  1140. }
  1141. return ~low; /* not found, return 1's complement of insert position */
  1142. }
  1143. /*
  1144. * If name contains '=', then sets the variable, otherwise it unsets it
  1145. * Size includes the terminating NULL. Env must have room for size + 1 entries
  1146. * (in case of insert). Returns the new size. Optionally frees removed entries.
  1147. */
  1148. static int do_putenv(char **env, const char *name, int size, int free_old)
  1149. {
  1150. int i = bsearchenv(env, name, size - 1);
  1151. /* optionally free removed / replaced entry */
  1152. if (i >= 0 && free_old)
  1153. free(env[i]);
  1154. if (strchr(name, '=')) {
  1155. /* if new value ('key=value') is specified, insert or replace entry */
  1156. if (i < 0) {
  1157. i = ~i;
  1158. memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
  1159. size++;
  1160. }
  1161. env[i] = (char*) name;
  1162. } else if (i >= 0) {
  1163. /* otherwise ('key') remove existing entry */
  1164. size--;
  1165. memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
  1166. }
  1167. return size;
  1168. }
  1169. char *mingw_getenv(const char *name)
  1170. {
  1171. char *value;
  1172. int pos = bsearchenv(environ, name, environ_size - 1);
  1173. if (pos < 0)
  1174. return NULL;
  1175. value = strchr(environ[pos], '=');
  1176. return value ? &value[1] : NULL;
  1177. }
  1178. int mingw_putenv(const char *namevalue)
  1179. {
  1180. ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
  1181. environ_size = do_putenv(environ, namevalue, environ_size, 1);
  1182. return 0;
  1183. }
  1184. /*
  1185. * Note, this isn't a complete replacement for getaddrinfo. It assumes
  1186. * that service contains a numerical port, or that it is null. It
  1187. * does a simple search using gethostbyname, and returns one IPv4 host
  1188. * if one was found.
  1189. */
  1190. static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
  1191. const struct addrinfo *hints,
  1192. struct addrinfo **res)
  1193. {
  1194. struct hostent *h = NULL;
  1195. struct addrinfo *ai;
  1196. struct sockaddr_in *sin;
  1197. if (node) {
  1198. h = gethostbyname(node);
  1199. if (!h)
  1200. return WSAGetLastError();
  1201. }
  1202. ai = xmalloc(sizeof(struct addrinfo));
  1203. *res = ai;
  1204. ai->ai_flags = 0;
  1205. ai->ai_family = AF_INET;
  1206. ai->ai_socktype = hints ? hints->ai_socktype : 0;
  1207. switch (ai->ai_socktype) {
  1208. case SOCK_STREAM:
  1209. ai->ai_protocol = IPPROTO_TCP;
  1210. break;
  1211. case SOCK_DGRAM:
  1212. ai->ai_protocol = IPPROTO_UDP;
  1213. break;
  1214. default:
  1215. ai->ai_protocol = 0;
  1216. break;
  1217. }
  1218. ai->ai_addrlen = sizeof(struct sockaddr_in);
  1219. if (hints && (hints->ai_flags & AI_CANONNAME))
  1220. ai->ai_canonname = h ? xstrdup(h->h_name) : NULL;
  1221. else
  1222. ai->ai_canonname = NULL;
  1223. sin = xcalloc(1, ai->ai_addrlen);
  1224. sin->sin_family = AF_INET;
  1225. /* Note: getaddrinfo is supposed to allow service to be a string,
  1226. * which should be looked up using getservbyname. This is
  1227. * currently not implemented */
  1228. if (service)
  1229. sin->sin_port = htons(atoi(service));
  1230. if (h)
  1231. sin->sin_addr = *(struct in_addr *)h->h_addr;
  1232. else if (hints && (hints->ai_flags & AI_PASSIVE))
  1233. sin->sin_addr.s_addr = INADDR_ANY;
  1234. else
  1235. sin->sin_addr.s_addr = INADDR_LOOPBACK;
  1236. ai->ai_addr = (struct sockaddr *)sin;
  1237. ai->ai_next = NULL;
  1238. return 0;
  1239. }
  1240. static void WSAAPI freeaddrinfo_stub(struct addrinfo *res)
  1241. {
  1242. free(res->ai_canonname);
  1243. free(res->ai_addr);
  1244. free(res);
  1245. }
  1246. static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen,
  1247. char *host, DWORD hostlen,
  1248. char *serv, DWORD servlen, int flags)
  1249. {
  1250. const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
  1251. if (sa->sa_family != AF_INET)
  1252. return EAI_FAMILY;
  1253. if (!host && !serv)
  1254. return EAI_NONAME;
  1255. if (host && hostlen > 0) {
  1256. struct hostent *ent = NULL;
  1257. if (!(flags & NI_NUMERICHOST))
  1258. ent = gethostbyaddr((const char *)&sin->sin_addr,
  1259. sizeof(sin->sin_addr), AF_INET);
  1260. if (ent)
  1261. snprintf(host, hostlen, "%s", ent->h_name);
  1262. else if (flags & NI_NAMEREQD)
  1263. return EAI_NONAME;
  1264. else
  1265. snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
  1266. }
  1267. if (serv && servlen > 0) {
  1268. struct servent *ent = NULL;
  1269. if (!(flags & NI_NUMERICSERV))
  1270. ent = getservbyport(sin->sin_port,
  1271. flags & NI_DGRAM ? "udp" : "tcp");
  1272. if (ent)
  1273. snprintf(serv, servlen, "%s", ent->s_name);
  1274. else
  1275. snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
  1276. }
  1277. return 0;
  1278. }
  1279. static HMODULE ipv6_dll = NULL;
  1280. static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res);
  1281. static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service,
  1282. const struct addrinfo *hints,
  1283. struct addrinfo **res);
  1284. static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen,
  1285. char *host, DWORD hostlen,
  1286. char *serv, DWORD servlen, int flags);
  1287. /*
  1288. * gai_strerror is an inline function in the ws2tcpip.h header, so we
  1289. * don't need to try to load that one dynamically.
  1290. */
  1291. static void socket_cleanup(void)
  1292. {
  1293. WSACleanup();
  1294. if (ipv6_dll)
  1295. FreeLibrary(ipv6_dll);
  1296. ipv6_dll = NULL;
  1297. ipv6_freeaddrinfo = freeaddrinfo_stub;
  1298. ipv6_getaddrinfo = getaddrinfo_stub;
  1299. ipv6_getnameinfo = getnameinfo_stub;
  1300. }
  1301. static void ensure_socket_initialization(void)
  1302. {
  1303. WSADATA wsa;
  1304. static int initialized = 0;
  1305. const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL };
  1306. const char **name;
  1307. if (initialized)
  1308. return;
  1309. if (WSAStartup(MAKEWORD(2,2), &wsa))
  1310. die("unable to initialize winsock subsystem, error %d",
  1311. WSAGetLastError());
  1312. for (name = libraries; *name; name++) {
  1313. ipv6_dll = LoadLibrary(*name);
  1314. if (!ipv6_dll)
  1315. continue;
  1316. ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *))
  1317. GetProcAddress(ipv6_dll, "freeaddrinfo");
  1318. ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *,
  1319. const struct addrinfo *,
  1320. struct addrinfo **))
  1321. GetProcAddress(ipv6_dll, "getaddrinfo");
  1322. ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *,
  1323. socklen_t, char *, DWORD,
  1324. char *, DWORD, int))
  1325. GetProcAddress(ipv6_dll, "getnameinfo");
  1326. if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
  1327. FreeLibrary(ipv6_dll);
  1328. ipv6_dll = NULL;
  1329. } else
  1330. break;
  1331. }
  1332. if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
  1333. ipv6_freeaddrinfo = freeaddrinfo_stub;
  1334. ipv6_getaddrinfo = getaddrinfo_stub;
  1335. ipv6_getnameinfo = getnameinfo_stub;
  1336. }
  1337. atexit(socket_cleanup);
  1338. initialized = 1;
  1339. }
  1340. #undef gethostname
  1341. int mingw_gethostname(char *name, int namelen)
  1342. {
  1343. ensure_socket_initialization();
  1344. return gethostname(name, namelen);
  1345. }
  1346. #undef gethostbyname
  1347. struct hostent *mingw_gethostbyname(const char *host)
  1348. {
  1349. ensure_socket_initialization();
  1350. return gethostbyname(host);
  1351. }
  1352. void mingw_freeaddrinfo(struct addrinfo *res)
  1353. {
  1354. ipv6_freeaddrinfo(res);
  1355. }
  1356. int mingw_getaddrinfo(const char *node, const char *service,
  1357. const struct addrinfo *hints, struct addrinfo **res)
  1358. {
  1359. ensure_socket_initialization();
  1360. return ipv6_getaddrinfo(node, service, hints, res);
  1361. }
  1362. int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
  1363. char *host, DWORD hostlen, char *serv, DWORD servlen,
  1364. int flags)
  1365. {
  1366. ensure_socket_initialization();
  1367. return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
  1368. }
  1369. int mingw_socket(int domain, int type, int protocol)
  1370. {
  1371. int sockfd;
  1372. SOCKET s;
  1373. ensure_socket_initialization();
  1374. s = WSASocket(domain, type, protocol, NULL, 0, 0);
  1375. if (s == INVALID_SOCKET) {
  1376. /*
  1377. * WSAGetLastError() values are regular BSD error codes
  1378. * biased by WSABASEERR.
  1379. * However, strerror() does not know about networking
  1380. * specific errors, which are values beginning at 38 or so.
  1381. * Therefore, we choose to leave the biased error code
  1382. * in errno so that _if_ someone looks up the code somewhere,
  1383. * then it is at least the number that are usually listed.
  1384. */
  1385. errno = WSAGetLastError();
  1386. return -1;
  1387. }
  1388. /* convert into a file descriptor */
  1389. if ((sockfd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) {
  1390. closesocket(s);
  1391. return error("unable to make a socket file descriptor: %s",
  1392. strerror(errno));
  1393. }
  1394. return sockfd;
  1395. }
  1396. #undef connect
  1397. int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
  1398. {
  1399. SOCKET s = (SOCKET)_get_osfhandle(sockfd);
  1400. return connect(s, sa, sz);
  1401. }
  1402. #undef bind
  1403. int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
  1404. {
  1405. SOCKET s = (SOCKET)_get_osfhandle(sockfd);
  1406. return bind(s, sa, sz);
  1407. }
  1408. #undef setsockopt
  1409. int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
  1410. {
  1411. SOCKET s = (SOCKET)_get_osfhandle(sockfd);
  1412. return setsockopt(s, lvl, optname, (const char*)optval, optlen);
  1413. }
  1414. #undef shutdown
  1415. int mingw_shutdown(int sockfd, int how)
  1416. {
  1417. SOCKET s = (SOCKET)_get_osfhandle(sockfd);
  1418. return shutdown(s, how);
  1419. }
  1420. #undef listen
  1421. int mingw_listen(int sockfd, int backlog)
  1422. {
  1423. SOCKET s = (SOCKET)_get_osfhandle(sockfd);
  1424. return listen(s, backlog);
  1425. }
  1426. #undef accept
  1427. int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
  1428. {
  1429. int sockfd2;
  1430. SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
  1431. SOCKET s2 = accept(s1, sa, sz);
  1432. /* convert into a file descriptor */
  1433. if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
  1434. int err = errno;
  1435. closesocket(s2);
  1436. return error("unable to make a socket file descriptor: %s",
  1437. strerror(err));
  1438. }
  1439. return sockfd2;
  1440. }
  1441. #undef rename
  1442. int mingw_rename(const char *pold, const char *pnew)
  1443. {
  1444. DWORD attrs, gle;
  1445. int tries = 0;
  1446. wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
  1447. if (xutftowcs_path(wpold, pold) < 0 || xutftowcs_path(wpnew, pnew) < 0)
  1448. return -1;
  1449. /*
  1450. * Try native rename() first to get errno right.
  1451. * It is based on MoveFile(), which cannot overwrite existing files.
  1452. */
  1453. if (!_wrename(wpold, wpnew))
  1454. return 0;
  1455. if (errno != EEXIST)
  1456. return -1;
  1457. repeat:
  1458. if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
  1459. return 0;
  1460. /* TODO: translate more errors */
  1461. gle = GetLastError();
  1462. if (gle == ERROR_ACCESS_DENIED &&
  1463. (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
  1464. if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
  1465. DWORD attrsold = GetFileAttributesW(wpold);
  1466. if (attrsold == INVALID_FILE_ATTRIBUTES ||
  1467. !(attrsold & FILE_ATTRIBUTE_DIRECTORY))
  1468. errno = EISDIR;
  1469. else if (!_wrmdir(wpnew))
  1470. goto repeat;
  1471. return -1;
  1472. }
  1473. if ((attrs & FILE_ATTRIBUTE_READONLY) &&
  1474. SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
  1475. if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
  1476. return 0;
  1477. gle = GetLastError();
  1478. /* revert file attributes on failure */
  1479. SetFileAttributesW(wpnew, attrs);
  1480. }
  1481. }
  1482. if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
  1483. /*
  1484. * We assume that some other process had the source or
  1485. * destination file open at the wrong moment and retry.
  1486. * In order to give the other process a higher chance to
  1487. * complete its operation, we give up our time slice now.
  1488. * If we have to retry again, we do sleep a bit.
  1489. */
  1490. Sleep(delay[tries]);
  1491. tries++;
  1492. goto repeat;
  1493. }
  1494. if (gle == ERROR_ACCESS_DENIED &&
  1495. ask_yes_no_if_possible("Rename from '%s' to '%s' failed. "
  1496. "Should I try again?", pold, pnew))
  1497. goto repeat;
  1498. errno = EACCES;
  1499. return -1;
  1500. }
  1501. /*
  1502. * Note that this doesn't return the actual pagesize, but
  1503. * the allocation granularity. If future Windows specific git code
  1504. * needs the real getpagesize function, we need to find another solution.
  1505. */
  1506. int mingw_getpagesize(void)
  1507. {
  1508. SYSTEM_INFO si;
  1509. GetSystemInfo(&si);
  1510. return si.dwAllocationGranularity;
  1511. }
  1512. struct passwd *getpwuid(int uid)
  1513. {
  1514. static char user_name[100];
  1515. static struct passwd p;
  1516. DWORD len = sizeof(user_name);
  1517. if (!GetUserName(user_name, &len))
  1518. return NULL;
  1519. p.pw_name = user_name;
  1520. p.pw_gecos = "unknown";
  1521. p.pw_dir = NULL;
  1522. return &p;
  1523. }
  1524. static HANDLE timer_event;
  1525. static HANDLE timer_thread;
  1526. static int timer_interval;
  1527. static int one_shot;
  1528. static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
  1529. /* The timer works like this:
  1530. * The thread, ticktack(), is a trivial routine that most of the time
  1531. * only waits to receive the signal to terminate. The main thread tells
  1532. * the thread to terminate by setting the timer_event to the signalled
  1533. * state.
  1534. * But ticktack() interrupts the wait state after the timer's interval
  1535. * length to call the signal handler.
  1536. */
  1537. static unsigned __stdcall ticktack(void *dummy)
  1538. {
  1539. while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
  1540. mingw_raise(SIGALRM);
  1541. if (one_shot)
  1542. break;
  1543. }
  1544. return 0;
  1545. }
  1546. static int start_timer_thread(void)
  1547. {
  1548. timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
  1549. if (timer_event) {
  1550. timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
  1551. if (!timer_thread )
  1552. return errno = ENOMEM,
  1553. error("cannot start timer thread");
  1554. } else
  1555. return errno = ENOMEM,
  1556. error("cannot allocate resources for timer");
  1557. return 0;
  1558. }
  1559. static void stop_timer_thread(void)
  1560. {
  1561. if (timer_event)
  1562. SetEvent(timer_event); /* tell thread to terminate */
  1563. if (timer_thread) {
  1564. int rc = WaitForSingleObject(timer_thread, 1000);
  1565. if (rc == WAIT_TIMEOUT)
  1566. error("timer thread did not terminate timely");
  1567. else if (rc != WAIT_OBJECT_0)
  1568. error("waiting for timer thread failed: %lu",
  1569. GetLastError());
  1570. CloseHandle(timer_thread);
  1571. }
  1572. if (timer_event)
  1573. CloseHandle(timer_event);
  1574. timer_event = NULL;
  1575. timer_thread = NULL;
  1576. }
  1577. static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
  1578. {
  1579. return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
  1580. }
  1581. int setitimer(int type, struct itimerval *in, struct itimerval *out)
  1582. {
  1583. static const struct timeval zero;
  1584. static int atexit_done;
  1585. if (out != NULL)
  1586. return errno = EINVAL,
  1587. error("setitimer param 3 != NULL not implemented");
  1588. if (!is_timeval_eq(&in->it_interval, &zero) &&
  1589. !is_timeval_eq(&in->it_interval, &in->it_value))
  1590. return errno = EINVAL,
  1591. error("setitimer: it_interval must be zero or eq it_value");
  1592. if (timer_thread)
  1593. stop_timer_thread();
  1594. if (is_timeval_eq(&in->it_value, &zero) &&
  1595. is_timeval_eq(&in->it_interval, &zero))
  1596. return 0;
  1597. timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
  1598. one_shot = is_timeval_eq(&in->it_interval, &zero);
  1599. if (!atexit_done) {
  1600. atexit(stop_timer_thread);
  1601. atexit_done = 1;
  1602. }
  1603. return start_timer_thread();
  1604. }
  1605. int sigaction(int sig, struct sigaction *in, struct sigaction *out)
  1606. {
  1607. if (sig != SIGALRM)
  1608. return errno = EINVAL,
  1609. error("sigaction only implemented for SIGALRM");
  1610. if (out != NULL)
  1611. return errno = EINVAL,
  1612. error("sigaction: param 3 != NULL not implemented");
  1613. timer_fn = in->sa_handler;
  1614. return 0;
  1615. }
  1616. #undef signal
  1617. sig_handler_t mingw_signal(int sig, sig_handler_t handler)
  1618. {
  1619. sig_handler_t old;
  1620. switch (sig) {
  1621. case SIGALRM:
  1622. old = timer_fn;
  1623. timer_fn = handler;
  1624. break;
  1625. case SIGINT:
  1626. old = sigint_fn;
  1627. sigint_fn = handler;
  1628. break;
  1629. default:
  1630. return signal(sig, handler);
  1631. }
  1632. return old;
  1633. }
  1634. #undef raise
  1635. int mingw_raise(int sig)
  1636. {
  1637. switch (sig) {
  1638. case SIGALRM:
  1639. if (timer_fn == SIG_DFL) {
  1640. if (isatty(STDERR_FILENO))
  1641. fputs("Alarm clock\n", stderr);
  1642. exit(128 + SIGALRM);
  1643. } else if (timer_fn != SIG_IGN)
  1644. timer_fn(SIGALRM);
  1645. return 0;
  1646. case SIGINT:
  1647. if (sigint_fn == SIG_DFL)
  1648. exit(128 + SIGINT);
  1649. else if (sigint_fn != SIG_IGN)
  1650. sigint_fn(SIGINT);
  1651. return 0;
  1652. default:
  1653. return raise(sig);
  1654. }
  1655. }
  1656. static const char *make_backslash_path(const char *path)
  1657. {
  1658. static char buf[PATH_MAX + 1];
  1659. char *c;
  1660. if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
  1661. die("Too long path: %.*s", 60, path);
  1662. for (c = buf; *c; c++) {
  1663. if (*c == '/')
  1664. *c = '\\';
  1665. }
  1666. return buf;
  1667. }
  1668. void mingw_open_html(const char *unixpath)
  1669. {
  1670. const char *htmlpath = make_backslash_path(unixpath);
  1671. typedef HINSTANCE (WINAPI *T)(HWND, const char *,
  1672. const char *, const char *, const char *, INT);
  1673. T ShellExecute;
  1674. HMODULE shell32;
  1675. int r;
  1676. shell32 = LoadLibrary("shell32.dll");
  1677. if (!shell32)
  1678. die("cannot load shell32.dll");
  1679. ShellExecute = (T)GetProcAddress(shell32, "ShellExecuteA");
  1680. if (!ShellExecute)
  1681. die("cannot run browser");
  1682. printf("Launching default browser to display HTML ...\n");
  1683. r = HCAST(int, ShellExecute(NULL, "open", htmlpath,
  1684. NULL, "\\", SW_SHOWNORMAL));
  1685. FreeLibrary(shell32);
  1686. /* see the MSDN documentation referring to the result codes here */
  1687. if (r <= 32) {
  1688. die("failed to launch browser for %.*s", MAX_PATH, unixpath);
  1689. }
  1690. }
  1691. int link(const char *oldpath, const char *newpath)
  1692. {
  1693. typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
  1694. static T create_hard_link = NULL;
  1695. wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
  1696. if (xutftowcs_path(woldpath, oldpath) < 0 ||
  1697. xutftowcs_path(wnewpath, newpath) < 0)
  1698. return -1;
  1699. if (!create_hard_link) {
  1700. create_hard_link = (T) GetProcAddress(
  1701. GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
  1702. if (!create_hard_link)
  1703. create_hard_link = (T)-1;
  1704. }
  1705. if (create_hard_link == (T)-1) {
  1706. errno = ENOSYS;
  1707. return -1;
  1708. }
  1709. if (!create_hard_link(wnewpath, woldpath, NULL)) {
  1710. errno = err_win_to_posix(GetLastError());
  1711. return -1;
  1712. }
  1713. return 0;
  1714. }
  1715. pid_

Large files files are truncated, but you can click here to view the full file