config.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2006-2017 by
  4. * The Salk Institute for Biological Studies and
  5. * Pittsburgh Supercomputing Center, Carnegie Mellon University
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  20. * USA.
  21. *
  22. ******************************************************************************/
  23. /* Windows-specific includes and defines */
  24. /*
  25. This file has includes, declarations, and function definitions to make the code
  26. compile on Windows.
  27. The functions where problems may exist are noted below with their caveats.
  28. Some caveats could be addressed with additional code if necessary.
  29. Wrapped Functions: (the function is available in Windows but certain features
  30. are not available)
  31. strerror_r - return value is POSIX-like (not GCC-like) [strerror_s is used]
  32. ctime_r - must be given a fixed-sized on-stack char buffer [ctime_s is
  33. used]
  34. strftime - [adds support for many of the additional format string]
  35. gethostname - [adds special initialization during the first call]
  36. stat/fstat - [adds support for symlink detection]
  37. rename - [adds support for atomic rename]
  38. mkdir - mode argument is ignored [adds the mode argument to the
  39. declaration]
  40. Emulated functions:
  41. getrusage - only supports RUSAGE_SELF, output struct only has ru_utime and
  42. ru_stime, errno not always set, cannot include <sys/resource.h>
  43. symlink - always fails on XP
  44. alarm - return value is not correct, must use set_alarm_handler instead
  45. of sigaction
  46. */
  47. #ifndef MCELL_CONFIG_WIN_H
  48. #define MCELL_CONFIG_WIN_H
  49. #ifndef MINGW_HAS_SECURE_API
  50. #define MINGW_HAS_SECURE_API /* required for MinGW to expose _s functions */
  51. #endif
  52. #undef __USE_MINGW_ANSI_STDIO
  53. #define __USE_MINGW_ANSI_STDIO \
  54. 1 /* allows use of GNU-style printf format strings */
  55. #define PRINTF_FORMAT(arg) \
  56. __attribute__((__format__( \
  57. gnu_printf, arg, arg + 1))) /* for functions that use printf-like \ \ \ \
  58. arguments this corrects warnings */
  59. #define PRINTF_FORMAT_V(arg) __attribute__((__format__(gnu_printf, arg, 0)))
  60. #define WIN32_LEAN_AND_MEAN /* removes many unneeded Windows definitions */
  61. #undef _WIN32_WINNT
  62. #define _WIN32_WINNT 0x0502
  63. #define _CRT_SECURE_NO_WARNINGS
  64. #include <windows.h>
  65. #include <stdlib.h>
  66. #include <direct.h> /* many POSIX-like functions */
  67. #include <errno.h>
  68. #include <stdio.h> /* _snprintf */
  69. #include <time.h>
  70. typedef unsigned short u_short;
  71. typedef unsigned int u_int;
  72. typedef unsigned long u_long;
  73. // typedef int errno_t;
  74. /* Remove some windows.h definitions that may cause problems */
  75. #undef TRUE
  76. #undef FALSE
  77. #undef ERROR
  78. #undef TRANSPARENT
  79. #undef FILE_OVERWRITE
  80. #undef FILE_CREATE
  81. #ifdef _MSC_VER
  82. #define inline __inline
  83. #define getcwd _getcwd
  84. #define strdup _strdup
  85. #define va_copy(d, s) ((d) = (s))
  86. #endif
  87. /* Macro for eliminating "unused variable" or "unused parameter" warnings. */
  88. #define UNUSED(p) ((void)(p))
  89. #ifndef __GNUC__
  90. #ifndef __attribute__
  91. #define __attribute__(x) /* empty */
  92. #define __restrict__
  93. #endif
  94. #endif
  95. /* MinGW does not include this in any header but has it in the libraries */
  96. #include <string.h> /* include this to make sure we have definitions for the \ \
  97. \ \
  98. \ \ \
  99. declaration below */
  100. _CRTIMP errno_t __cdecl strerror_s(char *_Buf, size_t _SizeInBytes, int errnum);
  101. inline static int strerror_r(int errnum, char *buf, size_t buflen) {
  102. errno_t err = strerror_s(buf, buflen, errnum);
  103. if (err != 0) {
  104. errno = err;
  105. return -1;
  106. }
  107. return 0;
  108. }
  109. /* ctime_r wrapped function */
  110. inline static char *_ctime_r_helper(const time_t *timep, char *buf,
  111. size_t buflen) {
  112. #if defined(_WIN64) || defined(_MSC_VER)
  113. errno_t err = _ctime64_s(buf, buflen, timep);
  114. #else
  115. errno_t err = _ctime32_s(buf, buflen, timep);
  116. #endif
  117. if (err != 0) {
  118. errno = err;
  119. return NULL;
  120. }
  121. return buf;
  122. }
  123. #define ctime_r(timep, buf) \
  124. _ctime_r_helper(timep, buf, sizeof(buf)) // char *ctime_r(const time_t *timep,
  125. // char *buf) { }
  126. /* strftime function with many additional format codes supported on *nix
  127. * machines */
  128. inline static int _is_leap_year(int y) {
  129. return (y & 3) == 0 && ((y % 25) != 0 || (y & 15) == 0);
  130. }
  131. inline static int _iso8061_weeknum(const struct tm *timeptr) {
  132. int Y = timeptr->tm_year, M = timeptr->tm_mon;
  133. int T = timeptr->tm_mday + 4 -
  134. (timeptr->tm_wday == 0 ? 7 : timeptr->tm_wday); // nearest Thursday
  135. if (M == 12 && T > 31) {
  136. return 1;
  137. }
  138. if (M == 1 && T < 1) {
  139. --Y;
  140. M = 12;
  141. T += 31;
  142. }
  143. int D = 275 * M / 9 + T - 31 +
  144. (M > 2 ? (_is_leap_year(Y) - 2) : 0); // day of year
  145. return 1 + D / 7;
  146. }
  147. inline static int _iso8061_wn_year(const struct tm *timeptr) {
  148. int T = timeptr->tm_mday + 4 -
  149. (timeptr->tm_wday == 0 ? 7 : timeptr->tm_wday); // nearest Thursday
  150. return timeptr->tm_year + 1900 +
  151. ((timeptr->tm_mon == 11 && T > 31)
  152. ? +1
  153. : ((timeptr->tm_mon == 0 && T < 1) ? -1 : 0));
  154. }
  155. inline static void _strnlwr(char *str, size_t count) {
  156. for (char *end = str + count; str < end; ++str) {
  157. *str = tolower(*str);
  158. }
  159. }
  160. inline static void _strnupr(char *str, size_t count) {
  161. for (char *end = str + count; str < end; ++str) {
  162. *str = toupper(*str);
  163. }
  164. }
  165. inline static void _strnchcase(char *str, size_t count) {
  166. for (char *end = str + count; str < end; ++str) {
  167. *str = isupper(*str) ? tolower(*str) : toupper(*str);
  168. }
  169. }
  170. __attribute__((__format__(
  171. gnu_strftime, 3,
  172. 0))) inline static size_t _win_strftime(char *strDest, size_t maxsize,
  173. const char *format,
  174. const struct tm *timeptr) {
  175. /* TODO: verify against *nix version, including edge cases */
  176. struct tm t = *timeptr;
  177. const char *f2, *f1 = format;
  178. char *out = strDest, *out_end = strDest + maxsize;
  179. char fbuf[3] = "%%", buf[64];
  180. while ((f2 = strchr(f1, '%')) != NULL) {
  181. if (f2 - f1 > out_end - out) {
  182. return 0;
  183. }
  184. strncpy(out, f1, f2 - f1);
  185. out += f2 - f1;
  186. ++f2;
  187. /* Flag */
  188. char flag;
  189. if (*f2 == '_' || *f2 == '-' || *f2 == '0' || *f2 == '^' || *f2 == '#') {
  190. flag = *(f2++);
  191. } else {
  192. flag = 0;
  193. }
  194. /* Width */
  195. size_t width = 0;
  196. while (isdigit(*f2)) {
  197. width = 10 * (width - '0') + *(f2++);
  198. }
  199. if ((ptrdiff_t)width > out_end - out) {
  200. return 0;
  201. }
  202. /* Modifier */
  203. /* TODO: support modifiers, currently they are read but never used */
  204. // char modifier = 0;
  205. if (*f2 == 'E') {
  206. f2++;
  207. // if (*f2 == 'c' || *f2 == 'C' || *f2 == 'x' || *f2 == 'X' || *f2 == 'y'
  208. // || *f2 == 'Y')
  209. // modifier = 'E'; /* E only before: c, C, x, X, y, Y */
  210. } else if (*f2 == 'O') {
  211. f2++;
  212. // if (*f2 == 'd' || *f2 == 'e' || *f2 == 'H' || *f2 == 'I' || *f2 == 'm'
  213. // || *f2 == 'M' || *f2 == 'S' || *f2 == 'u' || *f2 == 'U' || *f2 == 'V'
  214. // || *f2 == 'w' || *f2 == 'W' || *f2 == 'Y')
  215. // modifier = 'O'; /* O only before: d, e, H, I, m, M, S, u, U, V, w,
  216. // W, y */
  217. }
  218. /* Get content */
  219. size_t count;
  220. int is_numeric = 0, is_num_space_padded = 0;
  221. switch (*f2) {
  222. /* single character formats */
  223. case 0:
  224. buf[0] = '%';
  225. count = 1;
  226. break;
  227. case 'n':
  228. buf[0] = '\n';
  229. count = 1;
  230. break;
  231. case 't':
  232. buf[0] = '\t';
  233. count = 1;
  234. break;
  235. /* simple format equivalences */
  236. case 'h':
  237. count = strftime(buf, ARRAYSIZE(buf), "%b", timeptr);
  238. break;
  239. case 'D':
  240. count = strftime(buf, ARRAYSIZE(buf), "%m/%d/%y", timeptr);
  241. break;
  242. case 'F':
  243. count = strftime(buf, ARRAYSIZE(buf), "%Y-%m-%d", timeptr);
  244. break;
  245. case 'r':
  246. count = strftime(buf, ARRAYSIZE(buf), "%I:%M:%S %p", timeptr);
  247. break; /* TODO: this is actually supposed to be locale dependent? */
  248. case 'R':
  249. count = strftime(buf, ARRAYSIZE(buf), "%H:%M", timeptr);
  250. break;
  251. case 'T':
  252. count = strftime(buf, ARRAYSIZE(buf), "%H:%M:%S", timeptr);
  253. break;
  254. case '+':
  255. count = strftime(buf, ARRAYSIZE(buf), "%a %b %d %H:%M:%S %Z %Y", timeptr);
  256. break;
  257. /* lower-case conversions */
  258. case 'P':
  259. _strnlwr(buf, count = strftime(buf, ARRAYSIZE(buf), "%p", timeptr));
  260. break;
  261. /* pad with leading spaces instead of 0s */
  262. case 'e':
  263. count = strftime(buf, ARRAYSIZE(buf), "%d", timeptr);
  264. is_num_space_padded = 1;
  265. is_numeric = 1;
  266. break;
  267. case 'k':
  268. count = strftime(buf, ARRAYSIZE(buf), "%H", timeptr);
  269. is_num_space_padded = 1;
  270. is_numeric = 1;
  271. break;
  272. case 'l':
  273. count = strftime(buf, ARRAYSIZE(buf), "%I", timeptr);
  274. is_num_space_padded = 1;
  275. is_numeric = 1;
  276. break;
  277. /* sprintf conversions */
  278. case 'C':
  279. count = _snprintf(buf, ARRAYSIZE(buf), "%02u",
  280. (timeptr->tm_year + 1900) / 100);
  281. is_numeric = 1;
  282. break;
  283. case 'u':
  284. count = _snprintf(buf, ARRAYSIZE(buf), "%1u",
  285. timeptr->tm_wday == 0 ? 7 : timeptr->tm_wday);
  286. is_numeric = 1;
  287. break;
  288. #if defined(_WIN64) || defined(_MSC_VER)
  289. case 's':
  290. count = _snprintf(buf, ARRAYSIZE(buf), "%08Iu", mktime(&t));
  291. is_numeric = 1;
  292. break;
  293. #else
  294. case 's':
  295. count = _snprintf(buf, ARRAYSIZE(buf), "%04Iu", mktime(&t));
  296. is_numeric = 1;
  297. break;
  298. #endif
  299. /* ISO 8601 week formats */
  300. case 'V':
  301. count = _snprintf(buf, ARRAYSIZE(buf), "%02u", _iso8061_weeknum(timeptr));
  302. is_numeric = 1;
  303. break;
  304. case 'G':
  305. count = _snprintf(buf, ARRAYSIZE(buf), "%04u", _iso8061_wn_year(timeptr));
  306. is_numeric = 1;
  307. break;
  308. case 'g':
  309. count = _snprintf(buf, ARRAYSIZE(buf), "%02u",
  310. _iso8061_wn_year(timeptr) % 100);
  311. is_numeric = 1;
  312. break;
  313. /* supported by Windows natively (or a character that can't be converted,
  314. * which will be converted to empty string) */
  315. /* make sure is_numeric is set appropriately */
  316. case 'd':
  317. case 'H':
  318. case 'I':
  319. case 'j':
  320. case 'm':
  321. case 'M':
  322. case 'S':
  323. case 'U':
  324. case 'w':
  325. case 'W':
  326. case 'y':
  327. case 'Y':
  328. is_numeric = 1;
  329. fbuf[1] = *f2;
  330. count = strftime(buf, ARRAYSIZE(buf), fbuf, timeptr);
  331. break;
  332. default:
  333. fbuf[1] = *f2;
  334. count = strftime(buf, ARRAYSIZE(buf), fbuf, timeptr);
  335. break;
  336. /* TODO: not sure if Windows' %z is the same as POSIX */
  337. }
  338. /* Write output */
  339. size_t trim = 0;
  340. char padding =
  341. (flag == '_')
  342. ? ' '
  343. : ((flag == '0')
  344. ? '0'
  345. : (is_numeric ? (is_num_space_padded ? ' ' : '0') : ' '));
  346. if (is_numeric) {
  347. if (flag == '-') {
  348. while (trim < count - 1 && buf[trim] == '0') {
  349. ++trim;
  350. }
  351. count -= trim;
  352. } else if (padding == ' ') {
  353. for (size_t i = 0; i < count - 1 && buf[i] == '0'; ++i) {
  354. buf[i] = ' ';
  355. }
  356. }
  357. } else if (flag == '^') {
  358. _strnupr(buf, count);
  359. } /* convert alphabetic characters in result string to upper case */
  360. else if (flag == '#') {
  361. _strnchcase(buf, count);
  362. } /* swap the case of the result string */
  363. if ((ptrdiff_t)count > out_end - out) {
  364. return 0;
  365. }
  366. if (count < width) {
  367. memset(out, padding, width - count);
  368. out += width - count;
  369. }
  370. strncpy(out, buf + trim, count);
  371. out += count;
  372. f1 = f2 + 1;
  373. }
  374. /* copy remaining */
  375. size_t len = strlen(f1);
  376. strncpy(out, f1, len);
  377. out[len] = 0;
  378. return out - strDest + len;
  379. }
  380. #define strftime _win_strftime
  381. /* gethostname wrapped function */
  382. #define WSADESCRIPTION_LEN 256
  383. #define WSASYS_STATUS_LEN 128
  384. #define SOCKET_ERROR -1
  385. typedef struct WSAData {
  386. WORD wVersion;
  387. WORD wHighVersion;
  388. #ifdef _WIN64
  389. unsigned short iMaxSockets;
  390. unsigned short iMaxUdpDg;
  391. char *lpVendorInfo;
  392. char szDescription[WSADESCRIPTION_LEN + 1];
  393. char szSystemStatus[WSASYS_STATUS_LEN + 1];
  394. #else
  395. char szDescription[WSADESCRIPTION_LEN + 1];
  396. char szSystemStatus[WSASYS_STATUS_LEN + 1];
  397. unsigned short iMaxSockets;
  398. unsigned short iMaxUdpDg;
  399. char *lpVendorInfo;
  400. #endif
  401. } WSADATA, *LPWSADATA;
  402. typedef int(WINAPI *FUNC_WSAStartup)(WORD wVersionRequested,
  403. LPWSADATA lpWSAData);
  404. typedef int(WINAPI *FUNC_WSAGetLastError)(void);
  405. typedef int(WINAPI *FUNC_gethostname)(char *name, int namelen);
  406. static FUNC_WSAStartup WSAStartup = NULL;
  407. static FUNC_WSAGetLastError WSAGetLastError = NULL;
  408. static FUNC_gethostname win32gethostname = NULL;
  409. inline static int gethostname(char *name, size_t len) {
  410. if (len > INT_MAX) {
  411. errno = EINVAL;
  412. return -1;
  413. }
  414. /* dynamically load the necessary function and initialize the Winsock DLL */
  415. if (win32gethostname == NULL) {
  416. HMODULE ws2 = LoadLibraryA("ws2_32");
  417. WSADATA wsaData;
  418. WSAStartup = (FUNC_WSAStartup)GetProcAddress(ws2, "WSAStartup");
  419. WSAGetLastError =
  420. (FUNC_WSAGetLastError)GetProcAddress(ws2, "WSAGetLastError");
  421. win32gethostname = (FUNC_gethostname)GetProcAddress(ws2, "gethostname");
  422. if (ws2 == NULL || WSAStartup == NULL || WSAGetLastError == NULL ||
  423. win32gethostname == NULL || WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
  424. if (ws2) {
  425. FreeLibrary(ws2);
  426. }
  427. win32gethostname = NULL;
  428. errno = EPERM;
  429. return -1;
  430. }
  431. }
  432. /* call the Win32 gethostname() */
  433. if (win32gethostname(name, (int)len) == SOCKET_ERROR) {
  434. /* error */
  435. switch (WSAGetLastError()) {
  436. case WSAEFAULT:
  437. errno = name ? ENAMETOOLONG : EFAULT;
  438. break;
  439. case WSANOTINITIALISED:
  440. case WSAENETDOWN:
  441. case WSAEINPROGRESS:
  442. errno = EAGAIN;
  443. break;
  444. }
  445. return -1;
  446. }
  447. return 0;
  448. }
  449. /* getrusage emulated function, normally in <sys/resources.h> */
  450. #ifndef _TIMEVAL_DEFINED
  451. #define _TIMEVAL_DEFINED
  452. struct timeval {
  453. long tv_sec;
  454. long tv_usec;
  455. };
  456. #endif
  457. struct rusage {
  458. struct timeval ru_utime; /* user CPU time used */
  459. struct timeval ru_stime; /* system CPU time used */
  460. };
  461. #define RUSAGE_SELF 0
  462. inline static int getrusage(int who, struct rusage *usage) {
  463. if (who != RUSAGE_SELF) {
  464. errno = EINVAL;
  465. return -1;
  466. }
  467. if (usage == NULL) {
  468. errno = EFAULT;
  469. return -1;
  470. }
  471. FILETIME ftCreation, ftExit, ftKernel, ftUser;
  472. if (GetProcessTimes(GetCurrentProcess(), &ftCreation, &ftExit, &ftKernel,
  473. &ftUser) == 0) {
  474. /* error */
  475. /* FIXME: set errno based on GetLastError() */
  476. return -1;
  477. }
  478. ULONGLONG user =
  479. (((ULONGLONG)ftUser.dwHighDateTime) << 32) + ftUser.dwLowDateTime;
  480. ULONGLONG kernel =
  481. (((ULONGLONG)ftKernel.dwHighDateTime) << 32) + ftKernel.dwLowDateTime;
  482. /* Value is in 100 nanosecond intervals */
  483. /* t / 10000000 => timeval.sec */
  484. /* (t % 10000000) / 10 => timeval.usec */
  485. usage->ru_utime.tv_usec = (long)((user % 10000000) / 10);
  486. usage->ru_utime.tv_sec = (long)(user / 10000000);
  487. usage->ru_stime.tv_usec = (long)((kernel % 10000000) / 10);
  488. usage->ru_stime.tv_sec = (long)(kernel / 10000000);
  489. return 0;
  490. }
  491. /* symlink emulated function, normally in <unistd.h> */
  492. #define SYMBOLIC_LINK_FLAG_FILE 0x0
  493. #define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
  494. typedef BOOLEAN(WINAPI *FUNC_CreateSymbolicLink)(LPCSTR lpSymlinkFileName,
  495. LPCSTR lpTargetFileName,
  496. DWORD dwFlags);
  497. static FUNC_CreateSymbolicLink CreateSymbolicLink = NULL;
  498. inline static int _win_is_dir(const char *path) {
  499. DWORD attr = GetFileAttributesA(path);
  500. return attr != INVALID_FILE_ATTRIBUTES &&
  501. (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
  502. }
  503. inline static int symlink(const char *oldpath, const char *newpath) {
  504. /* dynamically load the CreateSymbolicLink function */
  505. if (CreateSymbolicLink == NULL) {
  506. /* requires Windows Vista or newer */
  507. CreateSymbolicLink = (FUNC_CreateSymbolicLink)GetProcAddress(
  508. GetModuleHandleA("kernel32"), "CreateSymbolicLinkA");
  509. if (CreateSymbolicLink == NULL) {
  510. errno = EPERM;
  511. return -1;
  512. }
  513. }
  514. if (!CreateSymbolicLink(newpath, oldpath, _win_is_dir(oldpath))) {
  515. /* error */
  516. char buf[MAX_PATH + 1];
  517. switch (GetLastError()) {
  518. case ERROR_INVALID_FUNCTION:
  519. errno = EPERM;
  520. break;
  521. case ERROR_INVALID_REPARSE_DATA: /* when oldpath == "" */
  522. case ERROR_PATH_NOT_FOUND:
  523. errno = strlen(getcwd(buf, sizeof(buf))) + strlen(newpath) >= MAX_PATH
  524. ? ENAMETOOLONG
  525. : ENOENT;
  526. break; /* or ENOTDIR or ELOOP(?) */
  527. case ERROR_ACCESS_DENIED:
  528. errno = _win_is_dir(newpath) ? EEXIST : EACCES;
  529. break; /* reports ERROR_ACCESS_DENIED when newpath already exists as a
  530. directory */
  531. case ERROR_NOT_ENOUGH_MEMORY:
  532. errno = ENOMEM;
  533. break;
  534. case ERROR_WRITE_PROTECT:
  535. errno = EROFS;
  536. break;
  537. case ERROR_INVALID_PARAMETER:
  538. errno = EFAULT;
  539. break;
  540. case ERROR_DISK_FULL:
  541. errno = ENOSPC;
  542. break;
  543. case ERROR_ALREADY_EXISTS:
  544. errno = EEXIST;
  545. break;
  546. default:
  547. errno = EIO;
  548. break;
  549. }
  550. return -1;
  551. }
  552. return 0;
  553. }
  554. /* stat and fstat wrapped function */
  555. /* adds S_IFLNK support to stat(path, &s) - necessary since Windows' stat does
  556. * not set S_IFLNK (or even define S_IFLNK) */
  557. #include <sys/stat.h>
  558. #ifndef FSCTL_GET_REPARSE_POINT
  559. #define FSCTL_GET_REPARSE_POINT \
  560. (0x00000009 << 16) | (42 << 2) | 0 | \
  561. (0 << 14) // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED,
  562. // FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER
  563. #endif
  564. #define S_IFLNK 0120000
  565. #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
  566. inline static int _is_symlink(const char *path) {
  567. HANDLE hFile = CreateFileA(
  568. path, GENERIC_READ,
  569. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
  570. OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
  571. NULL);
  572. if (hFile == INVALID_HANDLE_VALUE) {
  573. return 0;
  574. }
  575. DWORD *data = (DWORD *)malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE), size;
  576. if (data == NULL) {
  577. CloseHandle(hFile);
  578. return 0;
  579. }
  580. BOOL success = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, data,
  581. MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size, NULL);
  582. DWORD tag = *data;
  583. free(data);
  584. CloseHandle(hFile);
  585. return success && tag == IO_REPARSE_TAG_SYMLINK;
  586. }
  587. #ifdef stat
  588. /*
  589. we have a version of MinGW that uses a #define to map stat to _stat64
  590. this introduces a ton of problems
  591. to make this work we need to do something similar
  592. since the stat structure is "changing" we also need an fstat...
  593. */
  594. #undef stat
  595. #undef fstat
  596. #define stat _win_stat
  597. #define fstat _win_fstat
  598. struct stat { // equivalent to _stat64
  599. _dev_t st_dev;
  600. _ino_t st_ino;
  601. unsigned short st_mode;
  602. short st_nlink;
  603. short st_uid;
  604. short st_gid;
  605. _dev_t st_rdev;
  606. __MINGW_EXTENSION __int64 st_size;
  607. __time64_t st_atime;
  608. __time64_t st_mtime;
  609. __time64_t st_ctime;
  610. };
  611. inline static int stat(const char *path, struct stat *buf) {
  612. int retval = _stat64(path, (struct _stat64 *)buf);
  613. if (retval == 0 && _is_symlink(path)) {
  614. buf->st_mode |= S_IFLNK;
  615. }
  616. return retval;
  617. }
  618. inline static int fstat(int fd, struct stat *buf) {
  619. return _fstat64(fd, (struct _stat64 *)buf);
  620. }
  621. #else
  622. // we just use the normal forwarding setup
  623. // no need to treat fstat special
  624. inline static int _win_stat(const char *path, struct stat *buf) {
  625. int retval = stat(path, buf);
  626. if (retval == 0 && _is_symlink(path)) {
  627. buf->st_mode |= S_IFLNK;
  628. }
  629. return retval;
  630. }
  631. #define stat(path, buf) _win_stat(path, buf)
  632. #endif
  633. /* alarm emulated function, normally in <unistd.h> */
  634. /* sigaction(SIGALRM, ...) replaced by set_alarm_handler() */
  635. #define SIGALRM 14
  636. typedef void(__cdecl *ALARM_CB)(int);
  637. static ALARM_CB _alarm_cb = NULL;
  638. static HANDLE _timer = NULL;
  639. inline static void _win_alarm_cb(PVOID lpParameter, BOOLEAN TimerOrWaitFired) {
  640. _timer = NULL;
  641. _alarm_cb(SIGALRM);
  642. }
  643. inline static void set_alarm_handler(ALARM_CB handler) { _alarm_cb = handler; }
  644. inline static unsigned alarm(unsigned seconds) {
  645. unsigned retval = 0;
  646. if (_timer) {
  647. retval = 1; /* fixme: get actual time left in the timer and return that */
  648. DeleteTimerQueueTimer(NULL, _timer, NULL);
  649. _timer = NULL;
  650. }
  651. if (!CreateTimerQueueTimer(&_timer, NULL, (WAITORTIMERCALLBACK)_win_alarm_cb,
  652. NULL, seconds * 1000, 0, WT_EXECUTEONLYONCE)) {
  653. retval = (unsigned)-1;
  654. }
  655. return retval;
  656. }
  657. /* atomic rename wrapped function */
  658. /* Windows rename is not atomic, but there is ReplaceFile (only when actually
  659. * replacing though) */
  660. inline static int _win_rename(const char *old, const char *new) {
  661. DWORD dwAttrib = GetFileAttributes(new);
  662. if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
  663. !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
  664. /* new file exists */
  665. if (ReplaceFile(new, old, NULL, REPLACEFILE_WRITE_THROUGH, NULL, NULL)) {
  666. return 0;
  667. }
  668. /* fixme: set errno based on GetLastError() [possibly doing some filtering
  669. * before] */
  670. errno = EACCES;
  671. return -1;
  672. } else {
  673. return rename(old, new);
  674. }
  675. }
  676. #define rename _win_rename
  677. /* mkdir wrapped function */
  678. inline static int _win_mkdir(const char *pathname, mode_t mode) {
  679. /* TODO: do something with the mode argument */
  680. UNUSED(mode);
  681. return mkdir(pathname);
  682. }
  683. #define mkdir _win_mkdir
  684. #endif