PageRenderTime 83ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/win32/win32.c

https://github.com/fizx/ruby
C | 5274 lines | 4881 code | 290 blank | 103 comment | 472 complexity | e2015b87517cbd2087bc184fc8c77f91 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0, GPL-2.0, BSD-3-Clause
  1. /*
  2. * Copyright (c) 1993, Intergraph Corporation
  3. *
  4. * You may distribute under the terms of either the GNU General Public
  5. * License or the Artistic License, as specified in the perl README file.
  6. *
  7. * Various Unix compatibility functions and NT specific functions.
  8. *
  9. * Some of this code was derived from the MSDOS port(s) and the OS/2 port.
  10. *
  11. */
  12. #include "ruby/ruby.h"
  13. #include "ruby/encoding.h"
  14. #include "dln.h"
  15. #include <fcntl.h>
  16. #include <process.h>
  17. #include <sys/stat.h>
  18. /* #include <sys/wait.h> */
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <errno.h>
  22. #include <assert.h>
  23. #include <ctype.h>
  24. #include <windows.h>
  25. #include <winbase.h>
  26. #include <wincon.h>
  27. #include <share.h>
  28. #include <shlobj.h>
  29. #include <mbstring.h>
  30. #if _MSC_VER >= 1400
  31. #include <crtdbg.h>
  32. #include <rtcapi.h>
  33. #endif
  34. #ifdef __MINGW32__
  35. #include <mswsock.h>
  36. #endif
  37. #include "ruby/win32.h"
  38. #include "win32/dir.h"
  39. #define isdirsep(x) ((x) == '/' || (x) == '\\')
  40. #undef stat
  41. #undef fclose
  42. #undef close
  43. #undef setsockopt
  44. #if defined __BORLANDC__
  45. # define _filbuf _fgetc
  46. # define _flsbuf _fputc
  47. # define enough_to_get(n) (--(n) >= 0)
  48. # define enough_to_put(n) (++(n) < 0)
  49. #else
  50. # define enough_to_get(n) (--(n) >= 0)
  51. # define enough_to_put(n) (--(n) >= 0)
  52. #endif
  53. #ifdef WIN32_DEBUG
  54. #define Debug(something) something
  55. #else
  56. #define Debug(something) /* nothing */
  57. #endif
  58. #define TO_SOCKET(x) _get_osfhandle(x)
  59. static struct ChildRecord *CreateChild(const char *, const char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
  60. static int has_redirection(const char *);
  61. int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
  62. static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
  63. #define RUBY_CRITICAL(expr) do { expr; } while (0)
  64. /* errno mapping */
  65. static struct {
  66. DWORD winerr;
  67. int err;
  68. } errmap[] = {
  69. { ERROR_INVALID_FUNCTION, EINVAL },
  70. { ERROR_FILE_NOT_FOUND, ENOENT },
  71. { ERROR_PATH_NOT_FOUND, ENOENT },
  72. { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
  73. { ERROR_ACCESS_DENIED, EACCES },
  74. { ERROR_INVALID_HANDLE, EBADF },
  75. { ERROR_ARENA_TRASHED, ENOMEM },
  76. { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
  77. { ERROR_INVALID_BLOCK, ENOMEM },
  78. { ERROR_BAD_ENVIRONMENT, E2BIG },
  79. { ERROR_BAD_FORMAT, ENOEXEC },
  80. { ERROR_INVALID_ACCESS, EINVAL },
  81. { ERROR_INVALID_DATA, EINVAL },
  82. { ERROR_INVALID_DRIVE, ENOENT },
  83. { ERROR_CURRENT_DIRECTORY, EACCES },
  84. { ERROR_NOT_SAME_DEVICE, EXDEV },
  85. { ERROR_NO_MORE_FILES, ENOENT },
  86. { ERROR_WRITE_PROTECT, EROFS },
  87. { ERROR_BAD_UNIT, ENODEV },
  88. { ERROR_NOT_READY, ENXIO },
  89. { ERROR_BAD_COMMAND, EACCES },
  90. { ERROR_CRC, EACCES },
  91. { ERROR_BAD_LENGTH, EACCES },
  92. { ERROR_SEEK, EIO },
  93. { ERROR_NOT_DOS_DISK, EACCES },
  94. { ERROR_SECTOR_NOT_FOUND, EACCES },
  95. { ERROR_OUT_OF_PAPER, EACCES },
  96. { ERROR_WRITE_FAULT, EIO },
  97. { ERROR_READ_FAULT, EIO },
  98. { ERROR_GEN_FAILURE, EACCES },
  99. { ERROR_LOCK_VIOLATION, EACCES },
  100. { ERROR_SHARING_VIOLATION, EACCES },
  101. { ERROR_WRONG_DISK, EACCES },
  102. { ERROR_SHARING_BUFFER_EXCEEDED, EACCES },
  103. { ERROR_BAD_NETPATH, ENOENT },
  104. { ERROR_NETWORK_ACCESS_DENIED, EACCES },
  105. { ERROR_BAD_NET_NAME, ENOENT },
  106. { ERROR_FILE_EXISTS, EEXIST },
  107. { ERROR_CANNOT_MAKE, EACCES },
  108. { ERROR_FAIL_I24, EACCES },
  109. { ERROR_INVALID_PARAMETER, EINVAL },
  110. { ERROR_NO_PROC_SLOTS, EAGAIN },
  111. { ERROR_DRIVE_LOCKED, EACCES },
  112. { ERROR_BROKEN_PIPE, EPIPE },
  113. { ERROR_DISK_FULL, ENOSPC },
  114. { ERROR_INVALID_TARGET_HANDLE, EBADF },
  115. { ERROR_INVALID_HANDLE, EINVAL },
  116. { ERROR_WAIT_NO_CHILDREN, ECHILD },
  117. { ERROR_CHILD_NOT_COMPLETE, ECHILD },
  118. { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
  119. { ERROR_NEGATIVE_SEEK, EINVAL },
  120. { ERROR_SEEK_ON_DEVICE, EACCES },
  121. { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
  122. { ERROR_DIRECTORY, ENOTDIR },
  123. { ERROR_NOT_LOCKED, EACCES },
  124. { ERROR_BAD_PATHNAME, ENOENT },
  125. { ERROR_MAX_THRDS_REACHED, EAGAIN },
  126. { ERROR_LOCK_FAILED, EACCES },
  127. { ERROR_ALREADY_EXISTS, EEXIST },
  128. { ERROR_INVALID_STARTING_CODESEG, ENOEXEC },
  129. { ERROR_INVALID_STACKSEG, ENOEXEC },
  130. { ERROR_INVALID_MODULETYPE, ENOEXEC },
  131. { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC },
  132. { ERROR_EXE_MARKED_INVALID, ENOEXEC },
  133. { ERROR_BAD_EXE_FORMAT, ENOEXEC },
  134. { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC },
  135. { ERROR_INVALID_MINALLOCSIZE, ENOEXEC },
  136. { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC },
  137. { ERROR_IOPL_NOT_ENABLED, ENOEXEC },
  138. { ERROR_INVALID_SEGDPL, ENOEXEC },
  139. { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC },
  140. { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC },
  141. { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC },
  142. { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC },
  143. { ERROR_FILENAME_EXCED_RANGE, ENOENT },
  144. { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
  145. #ifndef ERROR_PIPE_LOCAL
  146. #define ERROR_PIPE_LOCAL 229L
  147. #endif
  148. { ERROR_PIPE_LOCAL, EPIPE },
  149. { ERROR_BAD_PIPE, EPIPE },
  150. { ERROR_PIPE_BUSY, EAGAIN },
  151. { ERROR_NO_DATA, EPIPE },
  152. { ERROR_PIPE_NOT_CONNECTED, EPIPE },
  153. { ERROR_OPERATION_ABORTED, EINTR },
  154. { ERROR_NOT_ENOUGH_QUOTA, ENOMEM },
  155. { ERROR_MOD_NOT_FOUND, ENOENT },
  156. { WSAENAMETOOLONG, ENAMETOOLONG },
  157. { WSAENOTEMPTY, ENOTEMPTY },
  158. { WSAEINTR, EINTR },
  159. { WSAEBADF, EBADF },
  160. { WSAEACCES, EACCES },
  161. { WSAEFAULT, EFAULT },
  162. { WSAEINVAL, EINVAL },
  163. { WSAEMFILE, EMFILE },
  164. };
  165. int
  166. rb_w32_map_errno(DWORD winerr)
  167. {
  168. int i;
  169. if (winerr == 0) {
  170. return 0;
  171. }
  172. for (i = 0; i < sizeof(errmap) / sizeof(*errmap); i++) {
  173. if (errmap[i].winerr == winerr) {
  174. return errmap[i].err;
  175. }
  176. }
  177. if (winerr >= WSABASEERR) {
  178. return winerr;
  179. }
  180. return EINVAL;
  181. }
  182. #define map_errno rb_w32_map_errno
  183. static const char *NTLoginName;
  184. static OSVERSIONINFO osver;
  185. static void
  186. get_version(void)
  187. {
  188. memset(&osver, 0, sizeof(OSVERSIONINFO));
  189. osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  190. GetVersionEx(&osver);
  191. }
  192. #ifdef _M_IX86
  193. DWORD
  194. rb_w32_osid(void)
  195. {
  196. return osver.dwPlatformId;
  197. }
  198. #endif
  199. static DWORD
  200. rb_w32_osver(void)
  201. {
  202. return osver.dwMajorVersion;
  203. }
  204. #define IsWinNT() rb_w32_iswinnt()
  205. #define IsWin95() rb_w32_iswin95()
  206. #ifdef WIN95
  207. #define IfWin95(win95, winnt) (IsWin95() ? (win95) : (winnt))
  208. #else
  209. #define IfWin95(win95, winnt) (winnt)
  210. #endif
  211. HANDLE
  212. GetCurrentThreadHandle(void)
  213. {
  214. static HANDLE current_process_handle = NULL;
  215. HANDLE h;
  216. if (!current_process_handle)
  217. current_process_handle = GetCurrentProcess();
  218. if (!DuplicateHandle(current_process_handle, GetCurrentThread(),
  219. current_process_handle, &h,
  220. 0, FALSE, DUPLICATE_SAME_ACCESS))
  221. return NULL;
  222. return h;
  223. }
  224. /* simulate flock by locking a range on the file */
  225. #define LK_ERR(f,i) \
  226. do { \
  227. if (f) \
  228. i = 0; \
  229. else { \
  230. DWORD err = GetLastError(); \
  231. if (err == ERROR_LOCK_VIOLATION || err == ERROR_IO_PENDING) \
  232. errno = EWOULDBLOCK; \
  233. else if (err == ERROR_NOT_LOCKED) \
  234. i = 0; \
  235. else \
  236. errno = map_errno(err); \
  237. } \
  238. } while (0)
  239. #define LK_LEN ULONG_MAX
  240. static uintptr_t
  241. flock_winnt(uintptr_t self, int argc, uintptr_t* argv)
  242. {
  243. OVERLAPPED o;
  244. int i = -1;
  245. const HANDLE fh = (HANDLE)self;
  246. const int oper = argc;
  247. memset(&o, 0, sizeof(o));
  248. switch(oper) {
  249. case LOCK_SH: /* shared lock */
  250. LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, LK_LEN, &o), i);
  251. break;
  252. case LOCK_EX: /* exclusive lock */
  253. LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, LK_LEN, &o), i);
  254. break;
  255. case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
  256. LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i);
  257. break;
  258. case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
  259. LK_ERR(LockFileEx(fh,
  260. LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
  261. 0, LK_LEN, LK_LEN, &o), i);
  262. break;
  263. case LOCK_UN: /* unlock lock */
  264. case LOCK_UN|LOCK_NB: /* unlock is always non-blocking, I hope */
  265. LK_ERR(UnlockFileEx(fh, 0, LK_LEN, LK_LEN, &o), i);
  266. break;
  267. default: /* unknown */
  268. errno = EINVAL;
  269. break;
  270. }
  271. return i;
  272. }
  273. #ifdef WIN95
  274. static uintptr_t
  275. flock_win95(uintptr_t self, int argc, uintptr_t* argv)
  276. {
  277. int i = -1;
  278. const HANDLE fh = (HANDLE)self;
  279. const int oper = argc;
  280. switch(oper) {
  281. case LOCK_EX:
  282. do {
  283. LK_ERR(LockFile(fh, 0, 0, LK_LEN, LK_LEN), i);
  284. } while (i && errno == EWOULDBLOCK);
  285. break;
  286. case LOCK_EX|LOCK_NB:
  287. LK_ERR(LockFile(fh, 0, 0, LK_LEN, LK_LEN), i);
  288. break;
  289. case LOCK_UN:
  290. case LOCK_UN|LOCK_NB:
  291. LK_ERR(UnlockFile(fh, 0, 0, LK_LEN, LK_LEN), i);
  292. break;
  293. default:
  294. errno = EINVAL;
  295. break;
  296. }
  297. return i;
  298. }
  299. #endif
  300. #undef LK_ERR
  301. int
  302. flock(int fd, int oper)
  303. {
  304. #ifdef WIN95
  305. static asynchronous_func_t locker = NULL;
  306. if (!locker) {
  307. if (IsWinNT())
  308. locker = flock_winnt;
  309. else
  310. locker = flock_win95;
  311. }
  312. #else
  313. const asynchronous_func_t locker = flock_winnt;
  314. #endif
  315. return rb_w32_asynchronize(locker,
  316. (VALUE)_get_osfhandle(fd), oper, NULL,
  317. (DWORD)-1);
  318. }
  319. static inline WCHAR *
  320. translate_wchar(WCHAR *p, int from, int to)
  321. {
  322. for (; *p; p++) {
  323. if (*p == from)
  324. *p = to;
  325. }
  326. return p;
  327. }
  328. static inline char *
  329. translate_char(char *p, int from, int to)
  330. {
  331. while (*p) {
  332. if ((unsigned char)*p == from)
  333. *p = to;
  334. p = CharNext(p);
  335. }
  336. return p;
  337. }
  338. #ifndef CSIDL_LOCAL_APPDATA
  339. #define CSIDL_LOCAL_APPDATA 28
  340. #endif
  341. #ifndef CSIDL_COMMON_APPDATA
  342. #define CSIDL_COMMON_APPDATA 35
  343. #endif
  344. #ifndef CSIDL_WINDOWS
  345. #define CSIDL_WINDOWS 36
  346. #endif
  347. #ifndef CSIDL_SYSTEM
  348. #define CSIDL_SYSTEM 37
  349. #endif
  350. #ifndef CSIDL_PROFILE
  351. #define CSIDL_PROFILE 40
  352. #endif
  353. static BOOL
  354. get_special_folder(int n, WCHAR *env)
  355. {
  356. LPITEMIDLIST pidl;
  357. LPMALLOC alloc;
  358. BOOL f = FALSE;
  359. if (SHGetSpecialFolderLocation(NULL, n, &pidl) == 0) {
  360. f = SHGetPathFromIDListW(pidl, env);
  361. SHGetMalloc(&alloc);
  362. alloc->lpVtbl->Free(alloc, pidl);
  363. alloc->lpVtbl->Release(alloc);
  364. }
  365. return f;
  366. }
  367. static void
  368. regulate_path(WCHAR *path)
  369. {
  370. WCHAR *p = translate_wchar(path, L'\\', L'/');
  371. if (p - path == 2 && path[1] == L':') {
  372. *p++ = L'/';
  373. *p = L'\0';
  374. }
  375. }
  376. static UINT
  377. get_system_directory(WCHAR *path, UINT len)
  378. {
  379. HANDLE hKernel = GetModuleHandle("kernel32.dll");
  380. if (hKernel) {
  381. typedef UINT WINAPI wgetdir_func(WCHAR*, UINT);
  382. FARPROC ptr = GetProcAddress(hKernel, "GetSystemWindowsDirectoryW");
  383. if (ptr) {
  384. return (*(wgetdir_func *)ptr)(path, len);
  385. }
  386. }
  387. return GetWindowsDirectoryW(path, len);
  388. }
  389. #define numberof(array) (sizeof(array) / sizeof(*array))
  390. static void
  391. init_env(void)
  392. {
  393. static const WCHAR TMPDIR[] = L"TMPDIR";
  394. WCHAR env[_MAX_PATH];
  395. WCHAR *buf;
  396. DWORD len;
  397. BOOL f;
  398. if (!GetEnvironmentVariableW(L"HOME", env, numberof(env))) {
  399. f = FALSE;
  400. if (GetEnvironmentVariableW(L"HOMEDRIVE", env, numberof(env)))
  401. len = lstrlenW(env);
  402. else
  403. len = 0;
  404. if (GetEnvironmentVariableW(L"HOMEPATH", env + len, numberof(env) - len) || len) {
  405. f = TRUE;
  406. }
  407. else if (GetEnvironmentVariableW(L"USERPROFILE", env, numberof(env))) {
  408. f = TRUE;
  409. }
  410. else if (get_special_folder(CSIDL_PROFILE, env)) {
  411. f = TRUE;
  412. }
  413. else if (get_special_folder(CSIDL_PERSONAL, env)) {
  414. f = TRUE;
  415. }
  416. if (f) {
  417. regulate_path(env);
  418. buf = ALLOCA_N(WCHAR, 5 + lstrlenW(env) + 1);
  419. wsprintfW(buf, L"HOME=%s", env);
  420. _wputenv(buf);
  421. }
  422. }
  423. if (!GetEnvironmentVariableW(L"USER", env, numberof(env))) {
  424. if (!GetEnvironmentVariableW(L"USERNAME", env, numberof(env)) &&
  425. !GetUserNameW(env, (len = numberof(env), &len))) {
  426. NTLoginName = "<Unknown>";
  427. return;
  428. }
  429. buf = ALLOCA_N(WCHAR, 5 + lstrlenW(env) + 1);
  430. wsprintfW(buf, L"USER=%s", env);
  431. _wputenv(buf);
  432. }
  433. NTLoginName = strdup(rb_w32_getenv("USER"));
  434. if (!GetEnvironmentVariableW(TMPDIR, env, numberof(env)) &&
  435. !GetEnvironmentVariableW(L"TMP", env, numberof(env)) &&
  436. !GetEnvironmentVariableW(L"TEMP", env, numberof(env)) &&
  437. (get_special_folder(CSIDL_LOCAL_APPDATA, env) ||
  438. get_system_directory(env, numberof(env)))) {
  439. static const WCHAR temp[] = L"temp";
  440. WCHAR *p = translate_wchar(env, L'\\', L'/');
  441. if (*(p - 1) != L'/') *p++ = L'/';
  442. if (p - env + numberof(temp) < numberof(env)) {
  443. memcpy(p, temp, sizeof(temp));
  444. buf = ALLOCA_N(WCHAR, lstrlenW(TMPDIR) + 1 + lstrlenW(env) + 1);
  445. wsprintfW(buf, L"%s=%s", TMPDIR, env);
  446. _wputenv(buf);
  447. }
  448. }
  449. }
  450. typedef BOOL (WINAPI *cancel_io_t)(HANDLE);
  451. static cancel_io_t cancel_io = NULL;
  452. static void
  453. init_func(void)
  454. {
  455. if (!cancel_io)
  456. cancel_io = (cancel_io_t)GetProcAddress(GetModuleHandle("kernel32"),
  457. "CancelIo");
  458. }
  459. static void init_stdhandle(void);
  460. #if RT_VER >= 80
  461. static void
  462. invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, unsigned int line, uintptr_t dummy)
  463. {
  464. // nothing to do
  465. }
  466. int ruby_w32_rtc_error;
  467. static int __cdecl
  468. rtc_error_handler(int e, const char *src, int line, const char *exe, const char *fmt, ...)
  469. {
  470. va_list ap;
  471. VALUE str;
  472. if (!ruby_w32_rtc_error) return 0;
  473. str = rb_sprintf("%s:%d: ", src, line);
  474. va_start(ap, fmt);
  475. rb_str_vcatf(str, fmt, ap);
  476. va_end(ap);
  477. rb_str_cat(str, "\n", 1);
  478. rb_write_error2(RSTRING_PTR(str), RSTRING_LEN(str));
  479. return 0;
  480. }
  481. #endif
  482. static CRITICAL_SECTION select_mutex;
  483. static int NtSocketsInitialized = 0;
  484. static st_table *socklist = NULL;
  485. static char *envarea;
  486. static void
  487. exit_handler(void)
  488. {
  489. if (NtSocketsInitialized) {
  490. WSACleanup();
  491. st_free_table(socklist);
  492. socklist = NULL;
  493. NtSocketsInitialized = 0;
  494. }
  495. if (envarea) {
  496. FreeEnvironmentStrings(envarea);
  497. envarea = NULL;
  498. }
  499. DeleteCriticalSection(&select_mutex);
  500. }
  501. static void
  502. StartSockets(void)
  503. {
  504. WORD version;
  505. WSADATA retdata;
  506. //
  507. // initalize the winsock interface and insure that it's
  508. // cleaned up at exit.
  509. //
  510. version = MAKEWORD(2, 0);
  511. if (WSAStartup(version, &retdata))
  512. rb_fatal ("Unable to locate winsock library!\n");
  513. if (LOBYTE(retdata.wVersion) != 2)
  514. rb_fatal("could not find version 2 of winsock dll\n");
  515. socklist = st_init_numtable();
  516. NtSocketsInitialized = 1;
  517. }
  518. //
  519. // Initialization stuff
  520. //
  521. void
  522. rb_w32_sysinit(int *argc, char ***argv)
  523. {
  524. #if RT_VER >= 80
  525. static void set_pioinfo_extra(void);
  526. _CrtSetReportMode(_CRT_ASSERT, 0);
  527. _set_invalid_parameter_handler(invalid_parameter);
  528. _RTC_SetErrorFunc(rtc_error_handler);
  529. set_pioinfo_extra();
  530. #endif
  531. get_version();
  532. //
  533. // subvert cmd.exe's feeble attempt at command line parsing
  534. //
  535. *argc = rb_w32_cmdvector(GetCommandLine(), argv);
  536. //
  537. // Now set up the correct time stuff
  538. //
  539. tzset();
  540. init_env();
  541. init_func();
  542. init_stdhandle();
  543. InitializeCriticalSection(&select_mutex);
  544. atexit(exit_handler);
  545. // Initialize Winsock
  546. StartSockets();
  547. }
  548. char *
  549. getlogin(void)
  550. {
  551. return (char *)NTLoginName;
  552. }
  553. #define MAXCHILDNUM 256 /* max num of child processes */
  554. static struct ChildRecord {
  555. HANDLE hProcess; /* process handle */
  556. rb_pid_t pid; /* process id */
  557. } ChildRecord[MAXCHILDNUM];
  558. #define FOREACH_CHILD(v) do { \
  559. struct ChildRecord* v; \
  560. for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
  561. #define END_FOREACH_CHILD } while (0)
  562. static struct ChildRecord *
  563. FindChildSlot(rb_pid_t pid)
  564. {
  565. FOREACH_CHILD(child) {
  566. if (child->pid == pid) {
  567. return child;
  568. }
  569. } END_FOREACH_CHILD;
  570. return NULL;
  571. }
  572. static struct ChildRecord *
  573. FindChildSlotByHandle(HANDLE h)
  574. {
  575. FOREACH_CHILD(child) {
  576. if (child->hProcess == h) {
  577. return child;
  578. }
  579. } END_FOREACH_CHILD;
  580. return NULL;
  581. }
  582. static void
  583. CloseChildHandle(struct ChildRecord *child)
  584. {
  585. HANDLE h = child->hProcess;
  586. child->hProcess = NULL;
  587. child->pid = 0;
  588. CloseHandle(h);
  589. }
  590. static struct ChildRecord *
  591. FindFreeChildSlot(void)
  592. {
  593. FOREACH_CHILD(child) {
  594. if (!child->pid) {
  595. child->pid = -1; /* lock the slot */
  596. child->hProcess = NULL;
  597. return child;
  598. }
  599. } END_FOREACH_CHILD;
  600. return NULL;
  601. }
  602. /*
  603. ruby -lne 'BEGIN{$cmds = Hash.new(0); $mask = 1}'
  604. -e '$cmds[$_.downcase] |= $mask' -e '$mask <<= 1 if ARGF.eof'
  605. -e 'END{$cmds.sort.each{|n,f|puts " \"\\#{f.to_s(8)}\" #{n.dump} + 1,"}}'
  606. 98cmd ntcmd
  607. */
  608. static const char *const szInternalCmds[] = {
  609. "\2" "assoc" + 1,
  610. "\3" "break" + 1,
  611. "\3" "call" + 1,
  612. "\3" "cd" + 1,
  613. "\1" "chcp" + 1,
  614. "\3" "chdir" + 1,
  615. "\3" "cls" + 1,
  616. "\2" "color" + 1,
  617. "\3" "copy" + 1,
  618. "\1" "ctty" + 1,
  619. "\3" "date" + 1,
  620. "\3" "del" + 1,
  621. "\3" "dir" + 1,
  622. "\3" "echo" + 1,
  623. "\2" "endlocal" + 1,
  624. "\3" "erase" + 1,
  625. "\3" "exit" + 1,
  626. "\3" "for" + 1,
  627. "\2" "ftype" + 1,
  628. "\3" "goto" + 1,
  629. "\3" "if" + 1,
  630. "\1" "lfnfor" + 1,
  631. "\1" "lh" + 1,
  632. "\1" "lock" + 1,
  633. "\3" "md" + 1,
  634. "\3" "mkdir" + 1,
  635. "\2" "move" + 1,
  636. "\3" "path" + 1,
  637. "\3" "pause" + 1,
  638. "\2" "popd" + 1,
  639. "\3" "prompt" + 1,
  640. "\2" "pushd" + 1,
  641. "\3" "rd" + 1,
  642. "\3" "rem" + 1,
  643. "\3" "ren" + 1,
  644. "\3" "rename" + 1,
  645. "\3" "rmdir" + 1,
  646. "\3" "set" + 1,
  647. "\2" "setlocal" + 1,
  648. "\3" "shift" + 1,
  649. "\2" "start" + 1,
  650. "\3" "time" + 1,
  651. "\2" "title" + 1,
  652. "\1" "truename" + 1,
  653. "\3" "type" + 1,
  654. "\1" "unlock" + 1,
  655. "\3" "ver" + 1,
  656. "\3" "verify" + 1,
  657. "\3" "vol" + 1,
  658. };
  659. static int
  660. internal_match(const void *key, const void *elem)
  661. {
  662. return strcmp(key, *(const char *const *)elem);
  663. }
  664. static int
  665. is_command_com(const char *interp)
  666. {
  667. int i = strlen(interp) - 11;
  668. if ((i == 0 || i > 0 && isdirsep(interp[i-1])) &&
  669. strcasecmp(interp+i, "command.com") == 0) {
  670. return 1;
  671. }
  672. return 0;
  673. }
  674. static int internal_cmd_match(const char *cmdname, int nt);
  675. static int
  676. is_internal_cmd(const char *cmd, int nt)
  677. {
  678. char cmdname[9], *b = cmdname, c;
  679. do {
  680. if (!(c = *cmd++)) return 0;
  681. } while (isspace(c));
  682. while (isalpha(c)) {
  683. *b++ = tolower(c);
  684. if (b == cmdname + sizeof(cmdname)) return 0;
  685. c = *cmd++;
  686. }
  687. if (c == '.') c = *cmd;
  688. switch (c) {
  689. case '<': case '>': case '|':
  690. return 1;
  691. case '\0': case ' ': case '\t': case '\n':
  692. break;
  693. default:
  694. return 0;
  695. }
  696. *b = 0;
  697. return internal_cmd_match(cmdname, nt);
  698. }
  699. static int
  700. internal_cmd_match(const char *cmdname, int nt)
  701. {
  702. char **nm;
  703. nm = bsearch(cmdname, szInternalCmds,
  704. sizeof(szInternalCmds) / sizeof(*szInternalCmds),
  705. sizeof(*szInternalCmds),
  706. internal_match);
  707. if (!nm || !(nm[0][-1] & (nt ? 2 : 1)))
  708. return 0;
  709. return 1;
  710. }
  711. SOCKET
  712. rb_w32_get_osfhandle(int fh)
  713. {
  714. return _get_osfhandle(fh);
  715. }
  716. static int
  717. argv_size(char *const *argv, BOOL escape)
  718. {
  719. const char *p;
  720. char *const *t;
  721. int len, n, bs, quote;
  722. for (t = argv, len = 0; *t; t++) {
  723. for (p = *t, n = quote = bs = 0; *p; ++p) {
  724. switch (*p) {
  725. case '\\':
  726. ++bs;
  727. break;
  728. case '<': case '>': case '|': case '^':
  729. bs = 0;
  730. if (escape && !quote) n++;
  731. break;
  732. case '"':
  733. n += bs + 1; bs = 0;
  734. quote = 1;
  735. break;
  736. case ' ': case '\t':
  737. quote = 1;
  738. default:
  739. bs = 0;
  740. p = CharNext(p) - 1;
  741. break;
  742. }
  743. }
  744. len += p - *t + n + 1;
  745. if (p - *t == 0 || quote) len += 2;
  746. }
  747. return len;
  748. }
  749. static char *
  750. join_argv(char *cmd, char *const *argv, BOOL escape)
  751. {
  752. const char *p, *s;
  753. char *q, *const *t;
  754. int n, bs, quote;
  755. for (t = argv, q = cmd; p = *t; t++) {
  756. quote = 0;
  757. s = p;
  758. if (!*p || strpbrk(p, " \t\"'")) {
  759. quote = 1;
  760. *q++ = '"';
  761. }
  762. for (bs = 0; *p; ++p) {
  763. switch (*p) {
  764. case '\\':
  765. ++bs;
  766. break;
  767. case '"':
  768. memcpy(q, s, n = p - s); q += n; s = p;
  769. memset(q, '\\', ++bs); q += bs; bs = 0;
  770. break;
  771. case '<': case '>': case '|': case '^':
  772. if (escape && !quote) {
  773. memcpy(q, s, n = p - s); q += n; s = p;
  774. *q++ = '^';
  775. break;
  776. }
  777. default:
  778. bs = 0;
  779. p = CharNext(p) - 1;
  780. break;
  781. }
  782. }
  783. memcpy(q, s, n = p - s);
  784. q += n;
  785. if (quote) *q++ = '"';
  786. *q++ = ' ';
  787. }
  788. if (q > cmd) --q;
  789. *q = '\0';
  790. return cmd;
  791. }
  792. #ifdef HAVE_SYS_PARAM_H
  793. # include <sys/param.h>
  794. #else
  795. # define MAXPATHLEN 512
  796. #endif
  797. #define STRNDUPA(ptr, src, len) \
  798. (((char *)memcpy(((ptr) = ALLOCA_N(char, (len) + 1)), (src), (len)))[len] = 0)
  799. static int
  800. check_spawn_mode(int mode)
  801. {
  802. switch (mode) {
  803. case P_NOWAIT:
  804. case P_OVERLAY:
  805. return 0;
  806. default:
  807. errno = EINVAL;
  808. return -1;
  809. }
  810. }
  811. static rb_pid_t
  812. child_result(struct ChildRecord *child, int mode)
  813. {
  814. DWORD exitcode;
  815. if (!child) {
  816. return -1;
  817. }
  818. switch (mode) {
  819. case P_NOWAIT:
  820. return child->pid;
  821. case P_OVERLAY:
  822. WaitForSingleObject(child->hProcess, INFINITE);
  823. GetExitCodeProcess(child->hProcess, &exitcode);
  824. CloseChildHandle(child);
  825. _exit(exitcode);
  826. default:
  827. return -1; /* not reached */
  828. }
  829. }
  830. static struct ChildRecord *
  831. CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa,
  832. HANDLE hInput, HANDLE hOutput, HANDLE hError)
  833. {
  834. BOOL fRet;
  835. DWORD dwCreationFlags;
  836. STARTUPINFO aStartupInfo;
  837. PROCESS_INFORMATION aProcessInformation;
  838. SECURITY_ATTRIBUTES sa;
  839. struct ChildRecord *child;
  840. if (!cmd && !prog) {
  841. errno = EFAULT;
  842. return NULL;
  843. }
  844. child = FindFreeChildSlot();
  845. if (!child) {
  846. errno = EAGAIN;
  847. return NULL;
  848. }
  849. if (!psa) {
  850. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  851. sa.lpSecurityDescriptor = NULL;
  852. sa.bInheritHandle = TRUE;
  853. psa = &sa;
  854. }
  855. memset(&aStartupInfo, 0, sizeof (STARTUPINFO));
  856. memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION));
  857. aStartupInfo.cb = sizeof (STARTUPINFO);
  858. aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
  859. if (hInput) {
  860. aStartupInfo.hStdInput = hInput;
  861. }
  862. else {
  863. aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  864. }
  865. if (hOutput) {
  866. aStartupInfo.hStdOutput = hOutput;
  867. }
  868. else {
  869. aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  870. }
  871. if (hError) {
  872. aStartupInfo.hStdError = hError;
  873. }
  874. else {
  875. aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
  876. }
  877. dwCreationFlags = (NORMAL_PRIORITY_CLASS);
  878. RUBY_CRITICAL({
  879. fRet = CreateProcess(prog, (char *)cmd, psa, psa,
  880. psa->bInheritHandle, dwCreationFlags, NULL, NULL,
  881. &aStartupInfo, &aProcessInformation);
  882. errno = map_errno(GetLastError());
  883. });
  884. if (!fRet) {
  885. child->pid = 0; /* release the slot */
  886. return NULL;
  887. }
  888. CloseHandle(aProcessInformation.hThread);
  889. child->hProcess = aProcessInformation.hProcess;
  890. child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
  891. if (!IsWinNT()) {
  892. /* On Win9x, make pid positive similarly to cygwin and perl */
  893. child->pid = -child->pid;
  894. }
  895. return child;
  896. }
  897. static int
  898. is_batch(const char *cmd)
  899. {
  900. int len = strlen(cmd);
  901. if (len <= 4) return 0;
  902. cmd += len - 4;
  903. if (*cmd++ != '.') return 0;
  904. if (strcasecmp(cmd, "bat") == 0) return 1;
  905. if (strcasecmp(cmd, "cmd") == 0) return 1;
  906. return 0;
  907. }
  908. rb_pid_t
  909. rb_w32_spawn(int mode, const char *cmd, const char *prog)
  910. {
  911. char fbuf[MAXPATHLEN];
  912. char *p = NULL;
  913. const char *shell = NULL;
  914. if (check_spawn_mode(mode)) return -1;
  915. if (prog) {
  916. if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
  917. shell = prog;
  918. }
  919. else {
  920. shell = p;
  921. translate_char(p, '/', '\\');
  922. }
  923. }
  924. else {
  925. int redir = -1;
  926. int nt;
  927. while (ISSPACE(*cmd)) cmd++;
  928. if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) {
  929. char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) + sizeof(" -c ") + 2);
  930. sprintf(tmp, "%s -c \"%s\"", shell, cmd);
  931. cmd = tmp;
  932. }
  933. else if ((shell = getenv("COMSPEC")) &&
  934. (nt = !is_command_com(shell),
  935. (redir < 0 ? has_redirection(cmd) : redir) ||
  936. is_internal_cmd(cmd, nt))) {
  937. char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) + sizeof(" /c ")
  938. + (nt ? 2 : 0));
  939. sprintf(tmp, nt ? "%s /c \"%s\"" : "%s /c %s", shell, cmd);
  940. cmd = tmp;
  941. }
  942. else {
  943. int len = 0, quote = (*cmd == '"') ? '"' : (*cmd == '\'') ? '\'' : 0;
  944. for (prog = cmd + !!quote;; prog = CharNext(prog)) {
  945. if (!*prog) {
  946. len = prog - cmd;
  947. shell = cmd;
  948. break;
  949. }
  950. if ((unsigned char)*prog == quote) {
  951. len = prog++ - cmd - 1;
  952. STRNDUPA(p, cmd + 1, len);
  953. shell = p;
  954. break;
  955. }
  956. if (quote) continue;
  957. if (ISSPACE(*prog) || strchr("<>|*?\"", *prog)) {
  958. len = prog - cmd;
  959. STRNDUPA(p, cmd, len);
  960. shell = p;
  961. break;
  962. }
  963. }
  964. shell = dln_find_exe_r(shell, NULL, fbuf, sizeof(fbuf));
  965. if (!shell) {
  966. shell = p ? p : cmd;
  967. }
  968. else {
  969. len = strlen(shell);
  970. if (strchr(shell, ' ')) quote = -1;
  971. if (shell == fbuf) {
  972. p = fbuf;
  973. }
  974. else if (shell != p && strchr(shell, '/')) {
  975. STRNDUPA(p, shell, len);
  976. shell = p;
  977. }
  978. if (p) translate_char(p, '/', '\\');
  979. if (is_batch(shell)) {
  980. int alen = strlen(prog);
  981. cmd = p = ALLOCA_N(char, len + alen + (quote ? 2 : 0) + 1);
  982. if (quote) *p++ = '"';
  983. memcpy(p, shell, len);
  984. p += len;
  985. if (quote) *p++ = '"';
  986. memcpy(p, prog, alen + 1);
  987. shell = 0;
  988. }
  989. }
  990. }
  991. }
  992. return child_result(CreateChild(cmd, shell, NULL, NULL, NULL, NULL), mode);
  993. }
  994. rb_pid_t
  995. rb_w32_aspawn(int mode, const char *prog, char *const *argv)
  996. {
  997. int len, c_switch = 0;
  998. BOOL ntcmd = FALSE, tmpnt;
  999. const char *shell;
  1000. char *cmd, fbuf[MAXPATHLEN];
  1001. if (check_spawn_mode(mode)) return -1;
  1002. if (!prog) prog = argv[0];
  1003. if ((shell = getenv("COMSPEC")) &&
  1004. internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
  1005. ntcmd = tmpnt;
  1006. prog = shell;
  1007. c_switch = 1;
  1008. }
  1009. else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
  1010. if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf));
  1011. translate_char(cmd, '/', '\\');
  1012. prog = cmd;
  1013. }
  1014. else if (strchr(prog, '/')) {
  1015. len = strlen(prog);
  1016. if (len < sizeof(fbuf))
  1017. strlcpy(cmd = fbuf, prog, sizeof(fbuf));
  1018. else
  1019. STRNDUPA(cmd, prog, len);
  1020. translate_char(cmd, '/', '\\');
  1021. prog = cmd;
  1022. }
  1023. if (c_switch || is_batch(prog)) {
  1024. char *progs[2];
  1025. progs[0] = (char *)prog;
  1026. progs[1] = NULL;
  1027. len = argv_size(progs, ntcmd);
  1028. if (c_switch) len += 3;
  1029. else ++argv;
  1030. if (argv[0]) len += argv_size(argv, ntcmd);
  1031. cmd = ALLOCA_N(char, len);
  1032. join_argv(cmd, progs, ntcmd);
  1033. if (c_switch) strlcat(cmd, " /c", len);
  1034. if (argv[0]) join_argv(cmd + strlcat(cmd, " ", len), argv, ntcmd);
  1035. prog = c_switch ? shell : 0;
  1036. }
  1037. else {
  1038. len = argv_size(argv, FALSE);
  1039. cmd = ALLOCA_N(char, len);
  1040. join_argv(cmd, argv, FALSE);
  1041. }
  1042. return child_result(CreateChild(cmd, prog, NULL, NULL, NULL, NULL), mode);
  1043. }
  1044. typedef struct _NtCmdLineElement {
  1045. struct _NtCmdLineElement *next;
  1046. char *str;
  1047. int len;
  1048. int flags;
  1049. } NtCmdLineElement;
  1050. //
  1051. // Possible values for flags
  1052. //
  1053. #define NTGLOB 0x1 // element contains a wildcard
  1054. #define NTMALLOC 0x2 // string in element was malloc'ed
  1055. #define NTSTRING 0x4 // element contains a quoted string
  1056. static int
  1057. insert(const char *path, VALUE vinfo, void *enc)
  1058. {
  1059. NtCmdLineElement *tmpcurr;
  1060. NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo;
  1061. tmpcurr = (NtCmdLineElement *)malloc(sizeof(NtCmdLineElement));
  1062. if (!tmpcurr) return -1;
  1063. MEMZERO(tmpcurr, NtCmdLineElement, 1);
  1064. tmpcurr->len = strlen(path);
  1065. tmpcurr->str = strdup(path);
  1066. if (!tmpcurr->str) return -1;
  1067. tmpcurr->flags |= NTMALLOC;
  1068. **tail = tmpcurr;
  1069. *tail = &tmpcurr->next;
  1070. return 0;
  1071. }
  1072. static NtCmdLineElement **
  1073. cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail)
  1074. {
  1075. char buffer[MAXPATHLEN], *buf = buffer;
  1076. char *p;
  1077. NtCmdLineElement **last = tail;
  1078. int status;
  1079. if (patt->len >= MAXPATHLEN)
  1080. if (!(buf = malloc(patt->len + 1))) return 0;
  1081. strlcpy(buf, patt->str, patt->len + 1);
  1082. buf[patt->len] = '\0';
  1083. for (p = buf; *p; p = CharNext(p))
  1084. if (*p == '\\')
  1085. *p = '/';
  1086. status = ruby_brace_glob(buf, 0, insert, (VALUE)&tail);
  1087. if (buf != buffer)
  1088. free(buf);
  1089. if (status || last == tail) return 0;
  1090. if (patt->flags & NTMALLOC)
  1091. free(patt->str);
  1092. free(patt);
  1093. return tail;
  1094. }
  1095. //
  1096. // Check a command string to determine if it has I/O redirection
  1097. // characters that require it to be executed by a command interpreter
  1098. //
  1099. static int
  1100. has_redirection(const char *cmd)
  1101. {
  1102. char quote = '\0';
  1103. const char *ptr;
  1104. //
  1105. // Scan the string, looking for redirection characters (< or >), pipe
  1106. // character (|) or newline (\n) that are not in a quoted string
  1107. //
  1108. for (ptr = cmd; *ptr;) {
  1109. switch (*ptr) {
  1110. case '\'':
  1111. case '\"':
  1112. if (!quote)
  1113. quote = *ptr;
  1114. else if (quote == *ptr)
  1115. quote = '\0';
  1116. ptr++;
  1117. break;
  1118. case '>':
  1119. case '<':
  1120. case '|':
  1121. case '\n':
  1122. if (!quote)
  1123. return TRUE;
  1124. ptr++;
  1125. break;
  1126. case '%':
  1127. if (*++ptr != '_' && !ISALPHA(*ptr)) break;
  1128. while (*++ptr == '_' || ISALNUM(*ptr));
  1129. if (*ptr++ == '%') return TRUE;
  1130. break;
  1131. case '\\':
  1132. ptr++;
  1133. default:
  1134. ptr = CharNext(ptr);
  1135. break;
  1136. }
  1137. }
  1138. return FALSE;
  1139. }
  1140. static inline char *
  1141. skipspace(char *ptr)
  1142. {
  1143. while (ISSPACE(*ptr))
  1144. ptr++;
  1145. return ptr;
  1146. }
  1147. int
  1148. rb_w32_cmdvector(const char *cmd, char ***vec)
  1149. {
  1150. int globbing, len;
  1151. int elements, strsz, done;
  1152. int slashes, escape;
  1153. char *ptr, *base, *buffer, *cmdline;
  1154. char **vptr;
  1155. char quote;
  1156. NtCmdLineElement *curr, **tail;
  1157. NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead;
  1158. //
  1159. // just return if we don't have a command line
  1160. //
  1161. while (ISSPACE(*cmd))
  1162. cmd++;
  1163. if (!*cmd) {
  1164. *vec = NULL;
  1165. return 0;
  1166. }
  1167. ptr = cmdline = strdup(cmd);
  1168. //
  1169. // Ok, parse the command line, building a list of CmdLineElements.
  1170. // When we've finished, and it's an input command (meaning that it's
  1171. // the processes argv), we'll do globing and then build the argument
  1172. // vector.
  1173. // The outer loop does one interation for each element seen.
  1174. // The inner loop does one interation for each character in the element.
  1175. //
  1176. while (*(ptr = skipspace(ptr))) {
  1177. base = ptr;
  1178. quote = slashes = globbing = escape = 0;
  1179. for (done = 0; !done && *ptr; ) {
  1180. //
  1181. // Switch on the current character. We only care about the
  1182. // white-space characters, the wild-card characters, and the
  1183. // quote characters.
  1184. //
  1185. switch (*ptr) {
  1186. case '\\':
  1187. if (quote != '\'') slashes++;
  1188. break;
  1189. case ' ':
  1190. case '\t':
  1191. case '\n':
  1192. //
  1193. // if we're not in a string, then we're finished with this
  1194. // element
  1195. //
  1196. if (!quote) {
  1197. *ptr = 0;
  1198. done = 1;
  1199. }
  1200. break;
  1201. case '*':
  1202. case '?':
  1203. case '[':
  1204. case '{':
  1205. //
  1206. // record the fact that this element has a wildcard character
  1207. // N.B. Don't glob if inside a single quoted string
  1208. //
  1209. if (quote != '\'')
  1210. globbing++;
  1211. slashes = 0;
  1212. break;
  1213. case '\'':
  1214. case '\"':
  1215. //
  1216. // if we're already in a string, see if this is the
  1217. // terminating close-quote. If it is, we're finished with
  1218. // the string, but not neccessarily with the element.
  1219. // If we're not already in a string, start one.
  1220. //
  1221. if (!(slashes & 1)) {
  1222. if (!quote)
  1223. quote = *ptr;
  1224. else if (quote == *ptr) {
  1225. if (quote == '"' && quote == ptr[1])
  1226. ptr++;
  1227. quote = '\0';
  1228. }
  1229. }
  1230. escape++;
  1231. slashes = 0;
  1232. break;
  1233. default:
  1234. ptr = CharNext(ptr);
  1235. slashes = 0;
  1236. continue;
  1237. }
  1238. ptr++;
  1239. }
  1240. //
  1241. // when we get here, we've got a pair of pointers to the element,
  1242. // base and ptr. Base points to the start of the element while ptr
  1243. // points to the character following the element.
  1244. //
  1245. len = ptr - base;
  1246. if (done) --len;
  1247. //
  1248. // if it's an input vector element and it's enclosed by quotes,
  1249. // we can remove them.
  1250. //
  1251. if (escape) {
  1252. char *p = base, c;
  1253. slashes = quote = 0;
  1254. while (p < base + len) {
  1255. switch (c = *p) {
  1256. case '\\':
  1257. p++;
  1258. if (quote != '\'') slashes++;
  1259. break;
  1260. case '\'':
  1261. case '"':
  1262. if (!(slashes & 1) && quote && quote != c) {
  1263. p++;
  1264. slashes = 0;
  1265. break;
  1266. }
  1267. memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
  1268. base + len - p);
  1269. len -= ((slashes + 1) >> 1) + (~slashes & 1);
  1270. p -= (slashes + 1) >> 1;
  1271. if (!(slashes & 1)) {
  1272. if (quote) {
  1273. if (quote == '"' && quote == *p)
  1274. p++;
  1275. quote = '\0';
  1276. }
  1277. else
  1278. quote = c;
  1279. }
  1280. else
  1281. p++;
  1282. slashes = 0;
  1283. break;
  1284. default:
  1285. p = CharNext(p);
  1286. slashes = 0;
  1287. break;
  1288. }
  1289. }
  1290. }
  1291. curr = (NtCmdLineElement *)calloc(sizeof(NtCmdLineElement), 1);
  1292. if (!curr) goto do_nothing;
  1293. curr->str = base;
  1294. curr->len = len;
  1295. if (globbing && (tail = cmdglob(curr, cmdtail))) {
  1296. cmdtail = tail;
  1297. }
  1298. else {
  1299. *cmdtail = curr;
  1300. cmdtail = &curr->next;
  1301. }
  1302. }
  1303. //
  1304. // Almost done!
  1305. // Count up the elements, then allocate space for a vector of pointers
  1306. // (argv) and a string table for the elements.
  1307. //
  1308. for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) {
  1309. elements++;
  1310. strsz += (curr->len + 1);
  1311. }
  1312. len = (elements+1)*sizeof(char *) + strsz;
  1313. buffer = (char *)malloc(len);
  1314. if (!buffer) {
  1315. do_nothing:
  1316. while (curr = cmdhead) {
  1317. cmdhead = curr->next;
  1318. if (curr->flags & NTMALLOC) free(curr->str);
  1319. free(curr);
  1320. }
  1321. free(cmdline);
  1322. for (vptr = *vec; *vptr; ++vptr);
  1323. return vptr - *vec;
  1324. }
  1325. //
  1326. // make vptr point to the start of the buffer
  1327. // and ptr point to the area we'll consider the string table.
  1328. //
  1329. // buffer (*vec)
  1330. // |
  1331. // V ^---------------------V
  1332. // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  1333. // | | | .... | NULL | | ..... |\0 | | ..... |\0 |...
  1334. // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  1335. // |- elements+1 -| ^ 1st element ^ 2nd element
  1336. vptr = (char **) buffer;
  1337. ptr = buffer + (elements+1) * sizeof(char *);
  1338. while (curr = cmdhead) {
  1339. strlcpy(ptr, curr->str, curr->len + 1);
  1340. *vptr++ = ptr;
  1341. ptr += curr->len + 1;
  1342. cmdhead = curr->next;
  1343. if (curr->flags & NTMALLOC) free(curr->str);
  1344. free(curr);
  1345. }
  1346. *vptr = 0;
  1347. *vec = (char **) buffer;
  1348. free(cmdline);
  1349. return elements;
  1350. }
  1351. //
  1352. // UNIX compatible directory access functions for NT
  1353. //
  1354. #define PATHLEN 1024
  1355. //
  1356. // The idea here is to read all the directory names into a string table
  1357. // (separated by nulls) and when one of the other dir functions is called
  1358. // return the pointer to the current file name.
  1359. //
  1360. #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT))
  1361. #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT))
  1362. #define BitOfIsDir(n) ((n) * 2)
  1363. #define BitOfIsRep(n) ((n) * 2 + 1)
  1364. #define DIRENT_PER_CHAR (CHAR_BIT / 2)
  1365. static HANDLE
  1366. open_dir_handle(const char *filename, WIN32_FIND_DATAW *fd)
  1367. {
  1368. HANDLE fh;
  1369. static const WCHAR wildcard[] = L"\\*";
  1370. UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
  1371. WCHAR *scanname;
  1372. WCHAR *p;
  1373. int len;
  1374. //
  1375. // Create the search pattern
  1376. //
  1377. len = MultiByteToWideChar(cp, 0, filename, -1, NULL, 0);
  1378. if (len <= 0) {
  1379. errno = map_errno(GetLastError());
  1380. return INVALID_HANDLE_VALUE;
  1381. }
  1382. scanname = ALLOCA_N(WCHAR, len + sizeof(wildcard) / sizeof(WCHAR));
  1383. len = MultiByteToWideChar(cp, 0, filename, -1, scanname, len + 2);
  1384. if (len <= 0) {
  1385. errno = map_errno(GetLastError());
  1386. return INVALID_HANDLE_VALUE;
  1387. }
  1388. p = CharPrevW(scanname, scanname + len);
  1389. if (*p == L'/' || *p == L'\\' || *p == L':')
  1390. lstrcatW(scanname, wildcard + 1);
  1391. else
  1392. lstrcatW(scanname, wildcard);
  1393. //
  1394. // do the FindFirstFile call
  1395. //
  1396. fh = FindFirstFileW(scanname, fd);
  1397. if (fh == INVALID_HANDLE_VALUE) {
  1398. errno = map_errno(GetLastError());
  1399. }
  1400. return fh;
  1401. }
  1402. static DIR *
  1403. opendir_internal(HANDLE fh, WIN32_FIND_DATAW *fd)
  1404. {
  1405. DIR *p;
  1406. long len;
  1407. long idx;
  1408. WCHAR *tmpW;
  1409. char *tmp;
  1410. if (fh == INVALID_HANDLE_VALUE) {
  1411. return NULL;
  1412. }
  1413. //
  1414. // Get us a DIR structure
  1415. //
  1416. p = calloc(sizeof(DIR), 1);
  1417. if (p == NULL)
  1418. return NULL;
  1419. idx = 0;
  1420. //
  1421. // loop finding all the files that match the wildcard
  1422. // (which should be all of them in this directory!).
  1423. // the variable idx should point one past the null terminator
  1424. // of the previous string found.
  1425. //
  1426. do {
  1427. len = lstrlenW(fd->cFileName) + 1;
  1428. //
  1429. // bump the string table size by enough for the
  1430. // new name and it's null terminator
  1431. //
  1432. tmpW = realloc(p->start, (idx + len) * sizeof(WCHAR));
  1433. if (!tmpW) {
  1434. error:
  1435. rb_w32_closedir(p);
  1436. FindClose(fh);
  1437. errno = ENOMEM;
  1438. return NULL;
  1439. }
  1440. p->start = tmpW;
  1441. memcpy(&p->start[idx], fd->cFileName, len * sizeof(WCHAR));
  1442. if (p->nfiles % DIRENT_PER_CHAR == 0) {
  1443. tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1);
  1444. if (!tmp)
  1445. goto error;
  1446. p->bits = tmp;
  1447. p->bits[p->nfiles / DIRENT_PER_CHAR] = 0;
  1448. }
  1449. if (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  1450. SetBit(p->bits, BitOfIsDir(p->nfiles));
  1451. if (fd->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
  1452. SetBit(p->bits, BitOfIsRep(p->nfiles));
  1453. p->nfiles++;
  1454. idx += len;
  1455. } while (FindNextFileW(fh, fd));
  1456. FindClose(fh);
  1457. p->size = idx;
  1458. p->curr = p->start;
  1459. return p;
  1460. }
  1461. DIR *
  1462. rb_w32_opendir(const char *filename)
  1463. {
  1464. struct stati64 sbuf;
  1465. WIN32_FIND_DATAW fd;
  1466. HANDLE fh;
  1467. //
  1468. // check to see if we've got a directory
  1469. //
  1470. if (rb_w32_stati64(filename, &sbuf) < 0)
  1471. return NULL;
  1472. if (!(sbuf.st_mode & S_IFDIR) &&
  1473. (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' ||
  1474. ((1 << ((filename[0] & 0x5f) - 'A')) & GetLogicalDrives()) == 0)) {
  1475. errno = ENOTDIR;
  1476. return NULL;
  1477. }
  1478. fh = open_dir_handle(filename, &fd);
  1479. return opendir_internal(fh, &fd);
  1480. }
  1481. //
  1482. // Move to next entry
  1483. //
  1484. static void
  1485. move_to_next_entry(DIR *dirp)
  1486. {
  1487. if (dirp->curr) {
  1488. dirp->loc++;
  1489. dirp->curr += lstrlenW(dirp->curr) + 1;
  1490. if (dirp->curr >= (dirp->start + dirp->size)) {
  1491. dirp->curr = NULL;
  1492. }
  1493. }
  1494. }
  1495. static char *
  1496. win32_conv_from_wstr(const WCHAR *wstr, long *len)
  1497. {
  1498. UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
  1499. char *ptr;
  1500. *len = WideCharToMultiByte(cp, 0, wstr, -1, NULL, 0, NULL, NULL) - 1;
  1501. if (!(ptr = malloc(*len + 1))) return 0;
  1502. WideCharToMultiByte(cp, 0, wstr, -1, ptr, *len + 1, NULL, NULL);
  1503. return ptr;
  1504. }
  1505. //
  1506. // Readdir just returns the current string pointer and bumps the
  1507. // string pointer to the next entry.
  1508. //
  1509. static BOOL
  1510. win32_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *dummy)
  1511. {
  1512. if (!(entry->d_name = win32_conv_from_wstr(file, &entry->d_namlen)))
  1513. return FALSE;
  1514. return TRUE;
  1515. }
  1516. VALUE
  1517. rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
  1518. {
  1519. static rb_encoding *utf16 = (rb_encoding *)-1;
  1520. VALUE src;
  1521. VALUE opthash;
  1522. int ecflags;
  1523. VALUE ecopts;
  1524. if (utf16 == (rb_encoding *)-1) {
  1525. utf16 = rb_enc_find("UTF-16LE");
  1526. if (utf16 == rb_ascii8bit_encoding())
  1527. utf16 = NULL;
  1528. }
  1529. if (!utf16)
  1530. /* maybe miniruby */
  1531. return Qnil;
  1532. src = rb_enc_str_new((char *)wstr, lstrlenW(wstr) * sizeof(WCHAR), utf16);
  1533. opthash = rb_hash_new();
  1534. rb_hash_aset(opthash, ID2SYM(rb_intern("undef")),
  1535. ID2SYM(rb_intern("replace")));
  1536. ecflags = rb_econv_prepare_opts(opthash, &ecopts);
  1537. return rb_str_encode(src, rb_enc_from_encoding(enc), ecflags, ecopts);
  1538. }
  1539. char *
  1540. rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc)
  1541. {
  1542. VALUE str = rb_w32_conv_from_wchar(wstr, enc);
  1543. long len;
  1544. char *ptr;
  1545. if (NIL_P(str)) return win32_conv_from_wstr(wstr, lenp);
  1546. *lenp = len = RSTRING_LEN(str);
  1547. memcpy(ptr = malloc(len + 1), RSTRING_PTR(str), len);
  1548. ptr[len] = '\0';
  1549. return ptr;
  1550. }
  1551. static BOOL
  1552. ruby_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *enc)
  1553. {
  1554. if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc)))
  1555. return FALSE;
  1556. return TRUE;
  1557. }
  1558. static struct direct *
  1559. readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, struct direct *, rb_encoding *), rb_encoding *enc)
  1560. {
  1561. static int dummy = 0;
  1562. if (dirp->curr) {
  1563. //
  1564. // first set up the structure to return
  1565. //
  1566. if (dirp->dirstr.d_name)
  1567. free(dirp->dirstr.d_name);
  1568. conv(dirp->curr, &dirp->dirstr, enc);
  1569. //
  1570. // Fake inode
  1571. //
  1572. dirp->dirstr.d_ino = dummy++;
  1573. //
  1574. // Attributes
  1575. //
  1576. dirp->dirstr.d_isdir = GetBit(dirp->bits, BitOfIsDir(dirp->loc));
  1577. dirp->dirstr.d_isrep = GetBit(dirp->bits, BitOfIsRep(dirp->loc));
  1578. //
  1579. // Now set up for the next call to readdir
  1580. //
  1581. move_to_next_entry(dirp);
  1582. return &(dirp->dirstr);
  1583. } else
  1584. return NULL;
  1585. }
  1586. struct direct *
  1587. rb_w32_readdir(DIR *dirp)
  1588. {
  1589. return readdir_internal(dirp, win32_direct_conv, NULL);
  1590. }
  1591. struct direct *
  1592. rb_w32_readdir_with_enc(DIR *dirp, rb_encoding *enc)
  1593. {
  1594. if (enc == rb_ascii8bit_encoding())
  1595. return readdir_internal(dirp, win32_direct_conv, NULL);
  1596. else
  1597. return readdir_internal(dirp, ruby_direct_conv, enc);
  1598. }
  1599. //
  1600. // Telldir returns the current string pointer position
  1601. //
  1602. long
  1603. rb_w32_telldir(DIR *dirp)
  1604. {
  1605. return dirp->loc;
  1606. }
  1607. //
  1608. // Seekdir moves the string pointer to a previously saved position
  1609. // (Saved by telldir).
  1610. void
  1611. rb_w32_seekdir(DIR *dirp, long loc)
  1612. {
  1613. if (dirp->loc > loc) rb_w32_rewinddir(dirp);
  1614. while (dirp->curr && dirp->loc < loc) {
  1615. move_to_next_entry(dirp);
  1616. }
  1617. }
  1618. //
  1619. // Rewinddir resets the string pointer to the start
  1620. //
  1621. void
  1622. rb_w32_rewinddir(DIR *dirp)
  1623. {
  1624. dirp->curr = dirp->start;
  1625. dirp->loc = 0;
  1626. }
  1627. //
  1628. // This just free's the memory allocated by opendir
  1629. //
  1630. void
  1631. rb_w32_closedir(DIR *dirp)
  1632. {
  1633. if (dirp) {
  1634. if (dirp->dirstr.d_name)
  1635. free(dirp->dirstr.d_name);
  1636. if (dirp->start)
  1637. free(dirp->start);
  1638. if (dirp->bits)
  1639. free(dirp->bits);
  1640. free(dirp);
  1641. }
  1642. }
  1643. #if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__
  1644. #define MSVCRT_THREADS
  1645. #endif
  1646. #ifdef MSVCRT_THREADS
  1647. # define MTHREAD_ONLY(x) x
  1648. # define STHREAD_ONLY(x)
  1649. #elif defined(__BORLANDC__)
  1650. # define MTHREAD_ONLY(x)
  1651. # define STHREAD_ONLY(x)
  1652. #else
  1653. # define MTHREAD_ONLY(x)
  1654. # define STHREAD_ONLY(x) x
  1655. #endif
  1656. typedef struct {
  1657. intptr_t osfhnd; /* underlying OS file HANDLE */
  1658. char osfile; /* attributes of file (e.g., open in text mode?) */
  1659. char pipech; /* one char buffer for handles opened on pipes */
  1660. #ifdef MSVCRT_THREADS
  1661. int lockinitflag;
  1662. CRITICAL_SECTION lock;
  1663. #endif
  1664. #if RT_VER >= 80
  1665. char textmode;
  1666. char pipech2[2];
  1667. #endif
  1668. } ioinfo;
  1669. #if !defined _CRTIMP || defined __MINGW32__
  1670. #undef _CRTIMP
  1671. #define _CRTIMP __declspec(dllimport)
  1672. #endif
  1673. #if !defined(__BORLANDC__)
  1674. EXTERN_C _CRTIMP ioinfo * __pioinfo[];
  1675. #define IOINFO_L2E 5
  1676. #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
  1677. #define _pioinfo(i) ((ioinfo*)((char*)(__pioinfo[i >> IOINFO_L2E]) + (i & (IOINFO_ARRAY_ELTS - 1)) * (sizeof(ioinfo) + pioinfo_extra)))
  1678. #define _osfhnd(i) (_pioinfo(i)->osfhnd)
  1679. #define _osfile(i) (_pioinfo(i)->osfile)
  1680. #define _pipech(i) (_pioinfo(i)->pipech)
  1681. #if RT_VER >= 80
  1682. static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */
  1683. static void
  1684. set_pioinfo_extra(void)
  1685. {
  1686. int fd;
  1687. fd = _open("NUL", O_RDONLY);
  1688. for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra += sizeof(void *)) {
  1689. if (_osfhnd(fd) == _get_osfhandle(fd)) {
  1690. break;
  1691. }
  1692. }
  1693. _close(fd);
  1694. if (pioinfo_extra > 64) {
  1695. /* not found, maybe something wrong... */
  1696. pioinfo_extra = 0;
  1697. }
  1698. }
  1699. #else
  1700. #define pioinfo_extra 0
  1701. #endif
  1702. #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
  1703. #define _set_osflags(fh, flags) (_osfile(fh) = (flags))
  1704. #define FOPEN 0x01 /* file handle open */
  1705. #define FEOFLAG 0x02 /* end of file has been encountered */
  1706. #define FPIPE 0x08 /* file handle refers to a pipe */
  1707. #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
  1708. #define FAPPEND 0x20 /* file handle opened O_APPEND */
  1709. #define FDEV 0x40 /* file handle refers to device */
  1710. #define FTEXT 0x80 /* file handle is in text mode */
  1711. static int
  1712. rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
  1713. {
  1714. int fh;
  1715. char fileflags; /* _osfile flags */
  1716. HANDLE hF;
  1717. /* copy relevant flags from second parameter */
  1718. fileflags = FDEV;
  1719. if (flags & O_APPEND)
  1720. fileflags |= FAPPEND;
  1721. if (flags & O_TEXT)
  1722. fileflags |= FTEXT;
  1723. if (flags & O_NOINHERIT)
  1724. fileflags |= FNOINHERIT;
  1725. /* attempt to allocate a C Runtime file handle */
  1726. hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
  1727. fh = _open_osfhandle((long)hF, 0);
  1728. CloseHandle(hF);
  1729. if (fh == -1) {
  1730. errno = EMFILE; /* too many open files */
  1731. _doserrno = 0L; /* not an OS error */
  1732. }
  1733. else {
  1734. MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock)));
  1735. /* the file is open. now, set the info in _osfhnd array */
  1736. _set_osfhnd(fh, osfhandle);
  1737. fileflags |= FOPEN; /* mark as open */
  1738. _set_osflags(fh, fileflags); /* set osfile entry */
  1739. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock));
  1740. }
  1741. return fh; /* return handle */
  1742. }
  1743. static void
  1744. init_stdhandle(void)
  1745. {
  1746. int nullfd = -1;
  1747. int keep = 0;
  1748. #define open_null(fd) \
  1749. (((nullfd < 0) ? \
  1750. (nullfd = open("NUL", O_RDWR|O_BINARY)) : 0), \
  1751. ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \
  1752. (fd))
  1753. if (fileno(stdin) < 0) {
  1754. stdin->_file = open_null(0);
  1755. }
  1756. else {
  1757. setmode(fileno(stdin), O_BINARY);
  1758. }
  1759. if (fileno(stdout) < 0) {
  1760. stdout->_file = open_null(1);
  1761. }
  1762. else {
  1763. setmode(fileno(stdout), O_BINARY);
  1764. }
  1765. if (fileno(stderr) < 0) {
  1766. stderr->_file = open_null(2);
  1767. }
  1768. else {
  1769. setmode(fileno(stderr), O_BINARY);
  1770. }
  1771. if (nullfd >= 0 && !keep) close(nullfd);
  1772. setvbuf(stderr, NULL, _IONBF, 0);
  1773. }
  1774. #else
  1775. #define _set_osfhnd(fh, osfh) (void)((fh), (osfh))
  1776. #define _set_osflags(fh, flags) (void)((fh), (flags))
  1777. static void
  1778. init_stdhandle(void)
  1779. {
  1780. }
  1781. #endif
  1782. #ifdef __BORLANDC__
  1783. static int
  1784. rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
  1785. {
  1786. int fd = _open_osfhandle(osfhandle, flags);
  1787. if (fd == -1) {
  1788. errno = EMFILE; /* too many open files */
  1789. _doserrno = 0L; /* not an OS error */
  1790. }
  1791. return fd;
  1792. }
  1793. #endif
  1794. #undef getsockopt
  1795. static int
  1796. is_socket(SOCKET sock)
  1797. {
  1798. if (st_lookup(socklist, (st_data_t)sock, NULL))
  1799. return TRUE;
  1800. else
  1801. return FALSE;
  1802. }
  1803. int
  1804. rb_w32_is_socket(int fd)
  1805. {
  1806. return is_socket(TO_SOCKET(fd));
  1807. }
  1808. //
  1809. // Since the errors returned by the socket error function
  1810. // WSAGetLastError() are not known by the library routine strerror
  1811. // we have to roll our own.
  1812. //
  1813. #undef strerror
  1814. char *
  1815. rb_w32_strerror(int e)
  1816. {
  1817. static char buffer[512];
  1818. DWORD source = 0;
  1819. char *p;
  1820. #if defined __BORLANDC__ && defined ENOTEMPTY // _sys_errlist is broken
  1821. switch (e) {
  1822. case ENAMETOOLONG:
  1823. return "Filename too long";
  1824. case ENOTEMPTY:
  1825. return "Directory not empty";
  1826. }
  1827. #endif
  1828. if (e < 0 || e > sys_nerr) {
  1829. if (e < 0)
  1830. e = GetLastError();
  1831. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
  1832. FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
  1833. buffer, sizeof(buffer), NULL) == 0)
  1834. strlcpy(buffer, "Unknown Error", sizeof(buffer));
  1835. }
  1836. else
  1837. strlcpy(buffer, strerror(e), sizeof(buffer));
  1838. p = buffer;
  1839. while ((p = strpbrk(p, "\r\n")) != NULL) {
  1840. memmove(p, p + 1, strlen(p));
  1841. }
  1842. return buffer;
  1843. }
  1844. //
  1845. // various stubs
  1846. //
  1847. // Ownership
  1848. //
  1849. // Just pretend that everyone is a superuser. NT will let us know if
  1850. // we don't really have permission to do something.
  1851. //
  1852. #define ROOT_UID 0
  1853. #define ROOT_GID 0
  1854. rb_uid_t
  1855. getuid(void)
  1856. {
  1857. return ROOT_UID;
  1858. }
  1859. rb_uid_t
  1860. geteuid(void)
  1861. {
  1862. return ROOT_UID;
  1863. }
  1864. rb_gid_t
  1865. getgid(void)
  1866. {
  1867. return ROOT_GID;
  1868. }
  1869. rb_gid_t
  1870. getegid(void)
  1871. {
  1872. return ROOT_GID;
  1873. }
  1874. int
  1875. setuid(rb_uid_t uid)
  1876. {
  1877. return (uid == ROOT_UID ? 0 : -1);
  1878. }
  1879. int
  1880. setgid(rb_gid_t gid)
  1881. {
  1882. return (gid == ROOT_GID ? 0 : -1);
  1883. }
  1884. //
  1885. // File system stuff
  1886. //
  1887. int
  1888. ioctl(int i, int u, ...)
  1889. {
  1890. errno = EINVAL;
  1891. return -1;
  1892. }
  1893. #undef FD_SET
  1894. void
  1895. rb_w32_fdset(int fd, fd_set *set)
  1896. {
  1897. unsigned int i;
  1898. SOCKET s = TO_SOCKET(fd);
  1899. for (i = 0; i < set->fd_count; i++) {
  1900. if (set->fd_array[i] == s) {
  1901. return;
  1902. }
  1903. }
  1904. if (i == set->fd_count) {
  1905. if (set->fd_count < FD_SETSIZE) {
  1906. set->fd_array[i] = s;
  1907. set->fd_count++;
  1908. }
  1909. }
  1910. }
  1911. #undef FD_CLR
  1912. void
  1913. rb_w32_fdclr(int fd, fd_set *set)
  1914. {
  1915. unsigned int i;
  1916. SOCKET s = TO_SOCKET(fd);
  1917. for (i = 0; i < set->fd_count; i++) {
  1918. if (set->fd_array[i] == s) {
  1919. memmove(&set->fd_array[i], &set->fd_array[i+1],
  1920. sizeof(set->fd_array[0]) * (--set->fd_count - i));
  1921. break;
  1922. }
  1923. }
  1924. }
  1925. #undef FD_ISSET
  1926. int
  1927. rb_w32_fdisset(int fd, fd_set *set)
  1928. {
  1929. int ret;
  1930. SOCKET s = TO_SOCKET(fd);
  1931. if (s == (SOCKET)INVALID_HANDLE_VALUE)
  1932. return 0;
  1933. RUBY_CRITICAL(ret = __WSAFDIsSet(s, set));
  1934. return ret;
  1935. }
  1936. //
  1937. // Networking trampolines
  1938. // These are used to avoid socket startup/shutdown overhead in case
  1939. // the socket routines aren't used.
  1940. //
  1941. #undef select
  1942. static int
  1943. extract_fd(rb_fdset_t *dst, fd_set *src, int (*func)(SOCKET))
  1944. {
  1945. unsigned int s = 0;
  1946. if (!src || !dst) return 0;
  1947. while (s < src->fd_count) {
  1948. SOCKET fd = src->fd_array[s];
  1949. if (!func || (*func)(fd)) { /* move it to dst */
  1950. unsigned int d;
  1951. for (d = 0; d < dst->fdset->fd_count; d++) {
  1952. if (dst->fdset->fd_array[d] == fd)
  1953. break;
  1954. }
  1955. if (d == dst->fdset->fd_count) {
  1956. if ((int)dst->fdset->fd_count >= dst->capa) {
  1957. dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
  1958. dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
  1959. }
  1960. dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
  1961. }
  1962. memmove(
  1963. &src->fd_array[s],
  1964. &src->fd_array[s+1],
  1965. sizeof(src->fd_array[0]) * (--src->fd_count - s));
  1966. }
  1967. else s++;
  1968. }
  1969. return dst->fdset->fd_count;
  1970. }
  1971. static int
  1972. copy_fd(fd_set *dst, fd_set *src)
  1973. {
  1974. unsigned int s;
  1975. if (!src || !dst) return 0;
  1976. for (s = 0; s < src->fd_count; ++s) {
  1977. SOCKET fd = src->fd_array[s];
  1978. unsigned int d;
  1979. for (d = 0; d < dst->fd_count; ++d) {
  1980. if (dst->fd_array[d] == fd)
  1981. break;
  1982. }
  1983. if (d == dst->fd_count && d < FD_SETSIZE) {
  1984. dst->fd_array[dst->fd_count++] = fd;
  1985. }
  1986. }
  1987. return dst->fd_count;
  1988. }
  1989. static int
  1990. is_not_socket(SOCKET sock)
  1991. {
  1992. return !is_socket(sock);
  1993. }
  1994. static int
  1995. is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */
  1996. {
  1997. int ret;
  1998. RUBY_CRITICAL({
  1999. ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
  2000. });
  2001. return ret;
  2002. }
  2003. static int
  2004. is_readable_pipe(SOCKET sock) /* call this for pipe only */
  2005. {
  2006. int ret;
  2007. DWORD n = 0;
  2008. RUBY_CRITICAL(
  2009. if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
  2010. ret = (n > 0);
  2011. }
  2012. else {
  2013. ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */
  2014. }
  2015. );
  2016. return ret;
  2017. }
  2018. static int
  2019. is_console(SOCKET sock) /* DONT call this for SOCKET! */
  2020. {
  2021. int ret;
  2022. DWORD n = 0;
  2023. INPUT_RECORD ir;
  2024. RUBY_CRITICAL(
  2025. ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n))
  2026. );
  2027. return ret;
  2028. }
  2029. static int
  2030. is_readable_console(SOCKET sock) /* call this for console only */
  2031. {
  2032. int ret = 0;
  2033. DWORD n = 0;
  2034. INPUT_RECORD ir;
  2035. RUBY_CRITICAL(
  2036. if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
  2037. if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
  2038. ir.Event.KeyEvent.uChar.AsciiChar) {
  2039. ret = 1;
  2040. }
  2041. else {
  2042. ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
  2043. }
  2044. }
  2045. );
  2046. return ret;
  2047. }
  2048. static int
  2049. do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
  2050. struct timeval *timeout)
  2051. {
  2052. int r = 0;
  2053. if (nfds == 0) {
  2054. if (timeout)
  2055. rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
  2056. else
  2057. rb_w32_sleep(INFINITE);
  2058. }
  2059. else {
  2060. RUBY_CRITICAL(
  2061. EnterCriticalSection(&select_mutex);
  2062. r = select(nfds, rd, wr, ex, timeout);
  2063. LeaveCriticalSection(&select_mutex);
  2064. if (r == SOCKET_ERROR) {
  2065. errno = map_errno(WSAGetLastError());
  2066. r = -1;
  2067. }
  2068. );
  2069. }
  2070. return r;
  2071. }
  2072. static inline int
  2073. subtract(struct timeval *rest, const struct timeval *wait)
  2074. {
  2075. if (rest->tv_sec < wait->tv_sec) {
  2076. return 0;
  2077. }
  2078. while (rest->tv_usec < wait->tv_usec) {
  2079. if (rest->tv_sec <= wait->tv_sec) {
  2080. return 0;
  2081. }
  2082. rest->tv_sec -= 1;
  2083. rest->tv_usec += 1000 * 1000;
  2084. }
  2085. rest->tv_sec -= wait->tv_sec;
  2086. rest->tv_usec -= wait->tv_usec;
  2087. return 1;
  2088. }
  2089. static inline int
  2090. compare(const struct timeval *t1, const struct timeval *t2)
  2091. {
  2092. if (t1->tv_sec < t2->tv_sec)
  2093. return -1;
  2094. if (t1->tv_sec > t2->tv_sec)
  2095. return 1;
  2096. if (t1->tv_usec < t2->tv_usec)
  2097. return -1;
  2098. if (t1->tv_usec > t2->tv_usec)
  2099. return 1;
  2100. return 0;
  2101. }
  2102. #undef Sleep
  2103. int WSAAPI
  2104. rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
  2105. struct timeval *timeout)
  2106. {
  2107. int r;
  2108. rb_fdset_t pipe_rd;
  2109. rb_fdset_t cons_rd;
  2110. rb_fdset_t else_rd;
  2111. rb_fdset_t else_wr;
  2112. rb_fdset_t except;
  2113. int nonsock = 0;
  2114. struct timeval limit = {0, 0};
  2115. if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
  2116. errno = EINVAL;
  2117. return -1;
  2118. }
  2119. if (timeout) {
  2120. if (timeout->tv_sec < 0 ||
  2121. timeout->tv_usec < 0 ||
  2122. timeout->tv_usec >= 1000000) {
  2123. errno = EINVAL;
  2124. return -1;
  2125. }
  2126. gettimeofday(&limit, NULL);
  2127. limit.tv_sec += timeout->tv_sec;
  2128. limit.tv_usec += timeout->tv_usec;
  2129. if (limit.tv_usec >= 1000000) {
  2130. limit.tv_usec -= 1000000;
  2131. limit.tv_sec++;
  2132. }
  2133. }
  2134. if (!NtSocketsInitialized) {
  2135. StartSockets();
  2136. }
  2137. // assume else_{rd,wr} (other than socket, pipe reader, console reader)
  2138. // are always readable/writable. but this implementation still has
  2139. // problem. if pipe's buffer is full, writing to pipe will block
  2140. // until some data is read from pipe. but ruby is single threaded system,
  2141. // so whole system will be blocked forever.
  2142. rb_fd_init(&else_rd);
  2143. nonsock += extract_fd(&else_rd, rd, is_not_socket);
  2144. rb_fd_init(&pipe_rd);
  2145. extract_fd(&pipe_rd, else_rd.fdset, is_pipe); // should not call is_pipe for socket
  2146. rb_fd_init(&cons_rd);
  2147. extract_fd(&cons_rd, else_rd.fdset, is_console); // ditto
  2148. rb_fd_init(&else_wr);
  2149. nonsock += extract_fd(&else_wr, wr, is_not_socket);
  2150. rb_fd_init(&except);
  2151. extract_fd(&except, ex, is_not_socket); // drop only
  2152. r = 0;
  2153. if (rd && (int)rd->fd_count > r) r = (int)rd->fd_count;
  2154. if (wr && (int)wr->fd_count > r) r = (int)wr->fd_count;
  2155. if (ex && (int)ex->fd_count > r) r = (int)ex->fd_count;
  2156. if (nfds > r) nfds = r;
  2157. {
  2158. struct timeval rest;
  2159. struct timeval wait;
  2160. struct timeval zero;
  2161. wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms
  2162. zero.tv_sec = 0; zero.tv_usec = 0; // 0ms
  2163. for (;;) {
  2164. if (nonsock) {
  2165. // modifying {else,pipe,cons}_rd is safe because
  2166. // if they are modified, function returns immediately.
  2167. extract_fd(&else_rd, pipe_rd.fdset, is_readable_pipe);
  2168. extract_fd(&else_rd, cons_rd.fdset, is_readable_console);
  2169. }
  2170. if (else_rd.fdset->fd_count || else_wr.fdset->fd_count) {
  2171. r = do_select(nfds, rd, wr, ex, &zero); // polling
  2172. if (r < 0) break; // XXX: should I ignore error and return signaled handles?
  2173. r = copy_fd(rd, else_rd.fdset);
  2174. r += copy_fd(wr, else_wr.fdset);
  2175. if (ex)
  2176. r += ex->fd_count;
  2177. break;
  2178. }
  2179. else {
  2180. struct timeval *dowait = &wait;
  2181. fd_set orig_rd;
  2182. fd_set orig_wr;
  2183. fd_set orig_ex;
  2184. if (rd) orig_rd = *rd;
  2185. if (wr) orig_wr = *wr;
  2186. if (ex) orig_ex = *ex;
  2187. r = do_select(nfds, rd, wr, ex, &zero); // polling
  2188. if (r != 0) break; // signaled or error
  2189. if (rd) *rd = orig_rd;
  2190. if (wr) *wr = orig_wr;
  2191. if (ex) *ex = orig_ex;
  2192. if (timeout) {
  2193. struct timeval now;
  2194. gettimeofday(&now, NULL);
  2195. rest = limit;
  2196. if (!subtract(&rest, &now)) break;
  2197. if (compare(&rest, &wait) < 0) dowait = &rest;
  2198. }
  2199. Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000);
  2200. }
  2201. }
  2202. }
  2203. rb_fd_term(&except);
  2204. rb_fd_term(&else_wr);
  2205. rb_fd_term(&cons_rd);
  2206. rb_fd_term(&pipe_rd);
  2207. rb_fd_term(&else_rd);
  2208. return r;
  2209. }
  2210. #undef accept
  2211. int WSAAPI
  2212. rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
  2213. {
  2214. SOCKET r;
  2215. int fd;
  2216. if (!NtSocketsInitialized) {
  2217. StartSockets();
  2218. }
  2219. RUBY_CRITICAL({
  2220. HANDLE h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
  2221. fd = rb_w32_open_osfhandle((intptr_t)h, O_RDWR|O_BINARY|O_NOINHERIT);
  2222. if (fd != -1) {
  2223. r = accept(TO_SOCKET(s), addr, addrlen);
  2224. if (r != INVALID_SOCKET) {
  2225. MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
  2226. _set_osfhnd(fd, r);
  2227. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  2228. CloseHandle(h);
  2229. st_insert(socklist, (st_data_t)r, (st_data_t)0);
  2230. }
  2231. else {
  2232. errno = map_errno(WSAGetLastError());
  2233. close(fd);
  2234. fd = -1;
  2235. }
  2236. }
  2237. else
  2238. CloseHandle(h);
  2239. });
  2240. return fd;
  2241. }
  2242. #undef bind
  2243. int WSAAPI
  2244. rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
  2245. {
  2246. int r;
  2247. if (!NtSocketsInitialized) {
  2248. StartSockets();
  2249. }
  2250. RUBY_CRITICAL({
  2251. r = bind(TO_SOCKET(s), addr, addrlen);
  2252. if (r == SOCKET_ERROR)
  2253. errno = map_errno(WSAGetLastError());
  2254. });
  2255. return r;
  2256. }
  2257. #undef connect
  2258. int WSAAPI
  2259. rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
  2260. {
  2261. int r;
  2262. if (!NtSocketsInitialized) {
  2263. StartSockets();
  2264. }
  2265. RUBY_CRITICAL({
  2266. r = connect(TO_SOCKET(s), addr, addrlen);
  2267. if (r == SOCKET_ERROR) {
  2268. int err = WSAGetLastError();
  2269. if (err != WSAEWOULDBLOCK)
  2270. errno = map_errno(err);
  2271. else
  2272. errno = EINPROGRESS;
  2273. }
  2274. });
  2275. return r;
  2276. }
  2277. #undef getpeername
  2278. int WSAAPI
  2279. rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
  2280. {
  2281. int r;
  2282. if (!NtSocketsInitialized) {
  2283. StartSockets();
  2284. }
  2285. RUBY_CRITICAL({
  2286. r = getpeername(TO_SOCKET(s), addr, addrlen);
  2287. if (r == SOCKET_ERROR)
  2288. errno = map_errno(WSAGetLastError());
  2289. });
  2290. return r;
  2291. }
  2292. #undef getsockname
  2293. int WSAAPI
  2294. rb_w32_getsockname(int s, struct sockaddr *addr, int *addrlen)
  2295. {
  2296. int r;
  2297. if (!NtSocketsInitialized) {
  2298. StartSockets();
  2299. }
  2300. RUBY_CRITICAL({
  2301. r = getsockname(TO_SOCKET(s), addr, addrlen);
  2302. if (r == SOCKET_ERROR)
  2303. errno = map_errno(WSAGetLastError());
  2304. });
  2305. return r;
  2306. }
  2307. int WSAAPI
  2308. rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
  2309. {
  2310. int r;
  2311. if (!NtSocketsInitialized) {
  2312. StartSockets();
  2313. }
  2314. RUBY_CRITICAL({
  2315. r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
  2316. if (r == SOCKET_ERROR)
  2317. errno = map_errno(WSAGetLastError());
  2318. });
  2319. return r;
  2320. }
  2321. #undef ioctlsocket
  2322. int WSAAPI
  2323. rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
  2324. {
  2325. int r;
  2326. if (!NtSocketsInitialized) {
  2327. StartSockets();
  2328. }
  2329. RUBY_CRITICAL({
  2330. r = ioctlsocket(TO_SOCKET(s), cmd, argp);
  2331. if (r == SOCKET_ERROR)
  2332. errno = map_errno(WSAGetLastError());
  2333. });
  2334. return r;
  2335. }
  2336. #undef listen
  2337. int WSAAPI
  2338. rb_w32_listen(int s, int backlog)
  2339. {
  2340. int r;
  2341. if (!NtSocketsInitialized) {
  2342. StartSockets();
  2343. }
  2344. RUBY_CRITICAL({
  2345. r = listen(TO_SOCKET(s), backlog);
  2346. if (r == SOCKET_ERROR)
  2347. errno = map_errno(WSAGetLastError());
  2348. });
  2349. return r;
  2350. }
  2351. #undef recv
  2352. #undef recvfrom
  2353. #undef send
  2354. #undef sendto
  2355. static int
  2356. overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
  2357. struct sockaddr *addr, int *addrlen)
  2358. {
  2359. int r;
  2360. int ret;
  2361. int mode;
  2362. st_data_t data;
  2363. DWORD flg;
  2364. WSAOVERLAPPED wol;
  2365. WSABUF wbuf;
  2366. int err;
  2367. SOCKET s;
  2368. if (!NtSocketsInitialized)
  2369. StartSockets();
  2370. s = TO_SOCKET(fd);
  2371. st_lookup(socklist, (st_data_t)s, &data);
  2372. mode = (int)data;
  2373. if (!cancel_io || (mode & O_NONBLOCK)) {
  2374. RUBY_CRITICAL({
  2375. if (input) {
  2376. if (addr && addrlen)
  2377. r = recvfrom(s, buf, len, flags, addr, addrlen);
  2378. else
  2379. r = recv(s, buf, len, flags);
  2380. }
  2381. else {
  2382. if (addr && addrlen)
  2383. r = sendto(s, buf, len, flags, addr, *addrlen);
  2384. else
  2385. r = send(s, buf, len, flags);
  2386. }
  2387. if (r == SOCKET_ERROR)
  2388. errno = map_errno(WSAGetLastError());
  2389. });
  2390. }
  2391. else {
  2392. DWORD size;
  2393. wbuf.len = len;
  2394. wbuf.buf = buf;
  2395. memset(&wol, 0, sizeof(wol));
  2396. RUBY_CRITICAL({
  2397. wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  2398. if (input) {
  2399. flg = flags;
  2400. if (addr && addrlen)
  2401. ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
  2402. &wol, NULL);
  2403. else
  2404. ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL);
  2405. }
  2406. else {
  2407. if (addr && addrlen)
  2408. ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
  2409. &wol, NULL);
  2410. else
  2411. ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL);
  2412. }
  2413. });
  2414. if (ret != SOCKET_ERROR) {
  2415. r = size;
  2416. }
  2417. else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
  2418. switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
  2419. case WAIT_OBJECT_0:
  2420. RUBY_CRITICAL(
  2421. ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
  2422. );
  2423. if (ret) {
  2424. r = size;
  2425. break;
  2426. }
  2427. /* thru */
  2428. default:
  2429. errno = map_errno(WSAGetLastError());
  2430. /* thru */
  2431. case WAIT_OBJECT_0 + 1:
  2432. /* interrupted */
  2433. r = -1;
  2434. cancel_io((HANDLE)s);
  2435. break;
  2436. }
  2437. }
  2438. else {
  2439. errno = map_errno(err);
  2440. r = -1;
  2441. }
  2442. CloseHandle(wol.hEvent);
  2443. }
  2444. return r;
  2445. }
  2446. int WSAAPI
  2447. rb_w32_recv(int fd, char *buf, int len, int flags)
  2448. {
  2449. return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
  2450. }
  2451. int WSAAPI
  2452. rb_w32_recvfrom(int fd, char *buf, int len, int flags,
  2453. struct sockaddr *from, int *fromlen)
  2454. {
  2455. return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
  2456. }
  2457. int WSAAPI
  2458. rb_w32_send(int fd, const char *buf, int len, int flags)
  2459. {
  2460. return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL);
  2461. }
  2462. int WSAAPI
  2463. rb_w32_sendto(int fd, const char *buf, int len, int flags,
  2464. const struct sockaddr *to, int tolen)
  2465. {
  2466. return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
  2467. (struct sockaddr *)to, &tolen);
  2468. }
  2469. #if !defined(MSG_TRUNC) && !defined(__MINGW32__)
  2470. typedef struct {
  2471. SOCKADDR *name;
  2472. int namelen;
  2473. WSABUF *lpBuffers;
  2474. DWORD dwBufferCount;
  2475. WSABUF Control;
  2476. DWORD dwFlags;
  2477. } WSAMSG;
  2478. #endif
  2479. #ifndef WSAID_WSARECVMSG
  2480. #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
  2481. #endif
  2482. #ifndef WSAID_WSASENDMSG
  2483. #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
  2484. #endif
  2485. #define msghdr_to_wsamsg(msg, wsamsg) \
  2486. do { \
  2487. int i; \
  2488. (wsamsg)->name = (msg)->msg_name; \
  2489. (wsamsg)->namelen = (msg)->msg_namelen; \
  2490. (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
  2491. (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
  2492. for (i = 0; i < (msg)->msg_iovlen; ++i) { \
  2493. (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
  2494. (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
  2495. } \
  2496. (wsamsg)->Control.buf = (msg)->msg_control; \
  2497. (wsamsg)->Control.len = (msg)->msg_controllen; \
  2498. (wsamsg)->dwFlags = (msg)->msg_flags; \
  2499. } while (0)
  2500. int
  2501. recvmsg(int fd, struct msghdr *msg, int flags)
  2502. {
  2503. typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
  2504. static WSARecvMsg_t pWSARecvMsg = NULL;
  2505. WSAMSG wsamsg;
  2506. SOCKET s;
  2507. st_data_t data;
  2508. int mode;
  2509. DWORD len;
  2510. int ret;
  2511. if (!NtSocketsInitialized)
  2512. StartSockets();
  2513. s = TO_SOCKET(fd);
  2514. if (!pWSARecvMsg) {
  2515. static GUID guid = WSAID_WSARECVMSG;
  2516. DWORD dmy;
  2517. WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
  2518. &pWSARecvMsg, sizeof(pWSARecvMsg), &dmy, NULL, NULL);
  2519. if (!pWSARecvMsg) {
  2520. errno = ENOSYS;
  2521. return -1;
  2522. }
  2523. }
  2524. msghdr_to_wsamsg(msg, &wsamsg);
  2525. wsamsg.dwFlags |= flags;
  2526. st_lookup(socklist, (st_data_t)s, &data);
  2527. mode = (int)data;
  2528. if (!cancel_io || (mode & O_NONBLOCK)) {
  2529. RUBY_CRITICAL({
  2530. if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
  2531. errno = map_errno(WSAGetLastError());
  2532. len = -1;
  2533. }
  2534. });
  2535. }
  2536. else {
  2537. DWORD size;
  2538. int err;
  2539. WSAOVERLAPPED wol;
  2540. memset(&wol, 0, sizeof(wol));
  2541. RUBY_CRITICAL({
  2542. wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  2543. ret = pWSARecvMsg(s, &wsamsg, &len, &wol, NULL);
  2544. });
  2545. if (ret != SOCKET_ERROR) {
  2546. /* nothing to do */
  2547. }
  2548. else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
  2549. DWORD flg;
  2550. switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
  2551. case WAIT_OBJECT_0:
  2552. RUBY_CRITICAL(
  2553. ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
  2554. );
  2555. if (ret) {
  2556. len = size;
  2557. break;
  2558. }
  2559. /* thru */
  2560. default:
  2561. errno = map_errno(WSAGetLastError());
  2562. /* thru */
  2563. case WAIT_OBJECT_0 + 1:
  2564. /* interrupted */
  2565. len = -1;
  2566. cancel_io((HANDLE)s);
  2567. break;
  2568. }
  2569. }
  2570. else {
  2571. errno = map_errno(err);
  2572. len = -1;
  2573. }
  2574. CloseHandle(wol.hEvent);
  2575. }
  2576. if (ret == SOCKET_ERROR)
  2577. return -1;
  2578. /* WSAMSG to msghdr */
  2579. msg->msg_name = wsamsg.name;
  2580. msg->msg_namelen = wsamsg.namelen;
  2581. msg->msg_flags = wsamsg.dwFlags;
  2582. return len;
  2583. }
  2584. int
  2585. sendmsg(int fd, const struct msghdr *msg, int flags)
  2586. {
  2587. typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
  2588. static WSASendMsg_t pWSASendMsg = NULL;
  2589. WSAMSG wsamsg;
  2590. SOCKET s;
  2591. st_data_t data;
  2592. int mode;
  2593. DWORD len;
  2594. int ret;
  2595. if (!NtSocketsInitialized)
  2596. StartSockets();
  2597. s = TO_SOCKET(fd);
  2598. if (!pWSASendMsg) {
  2599. static GUID guid = WSAID_WSASENDMSG;
  2600. DWORD dmy;
  2601. WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
  2602. &pWSASendMsg, sizeof(pWSASendMsg), &dmy, NULL, NULL);
  2603. if (!pWSASendMsg) {
  2604. errno = ENOSYS;
  2605. return -1;
  2606. }
  2607. }
  2608. msghdr_to_wsamsg(msg, &wsamsg);
  2609. st_lookup(socklist, (st_data_t)s, &data);
  2610. mode = (int)data;
  2611. if (!cancel_io || (mode & O_NONBLOCK)) {
  2612. RUBY_CRITICAL({
  2613. if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
  2614. errno = map_errno(WSAGetLastError());
  2615. len = -1;
  2616. }
  2617. });
  2618. }
  2619. else {
  2620. DWORD size;
  2621. int err;
  2622. WSAOVERLAPPED wol;
  2623. memset(&wol, 0, sizeof(wol));
  2624. RUBY_CRITICAL({
  2625. wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  2626. ret = pWSASendMsg(s, &wsamsg, flags, &len, &wol, NULL);
  2627. });
  2628. if (ret != SOCKET_ERROR) {
  2629. /* nothing to do */
  2630. }
  2631. else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
  2632. DWORD flg;
  2633. switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
  2634. case WAIT_OBJECT_0:
  2635. RUBY_CRITICAL(
  2636. ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
  2637. );
  2638. if (ret) {
  2639. len = size;
  2640. break;
  2641. }
  2642. /* thru */
  2643. default:
  2644. errno = map_errno(WSAGetLastError());
  2645. /* thru */
  2646. case WAIT_OBJECT_0 + 1:
  2647. /* interrupted */
  2648. len = -1;
  2649. cancel_io((HANDLE)s);
  2650. break;
  2651. }
  2652. }
  2653. else {
  2654. errno = map_errno(err);
  2655. len = -1;
  2656. }
  2657. CloseHandle(wol.hEvent);
  2658. }
  2659. return len;
  2660. }
  2661. #undef setsockopt
  2662. int WSAAPI
  2663. rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
  2664. {
  2665. int r;
  2666. if (!NtSocketsInitialized) {
  2667. StartSockets();
  2668. }
  2669. RUBY_CRITICAL({
  2670. r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
  2671. if (r == SOCKET_ERROR)
  2672. errno = map_errno(WSAGetLastError());
  2673. });
  2674. return r;
  2675. }
  2676. #undef shutdown
  2677. int WSAAPI
  2678. rb_w32_shutdown(int s, int how)
  2679. {
  2680. int r;
  2681. if (!NtSocketsInitialized) {
  2682. StartSockets();
  2683. }
  2684. RUBY_CRITICAL({
  2685. r = shutdown(TO_SOCKET(s), how);
  2686. if (r == SOCKET_ERROR)
  2687. errno = map_errno(WSAGetLastError());
  2688. });
  2689. return r;
  2690. }
  2691. static SOCKET
  2692. open_ifs_socket(int af, int type, int protocol)
  2693. {
  2694. unsigned long proto_buffers_len = 0;
  2695. int error_code;
  2696. SOCKET out = INVALID_SOCKET;
  2697. if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) {
  2698. error_code = WSAGetLastError();
  2699. if (error_code == WSAENOBUFS) {
  2700. WSAPROTOCOL_INFO *proto_buffers;
  2701. int protocols_available = 0;
  2702. proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len);
  2703. if (!proto_buffers) {
  2704. WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
  2705. return INVALID_SOCKET;
  2706. }
  2707. protocols_available =
  2708. WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len);
  2709. if (protocols_available != SOCKET_ERROR) {
  2710. int i;
  2711. for (i = 0; i < protocols_available; i++) {
  2712. if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
  2713. (type != proto_buffers[i].iSocketType) ||
  2714. (protocol != 0 && protocol != proto_buffers[i].iProtocol))
  2715. continue;
  2716. if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
  2717. continue;
  2718. out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
  2719. WSA_FLAG_OVERLAPPED);
  2720. break;
  2721. }
  2722. if (out == INVALID_SOCKET)
  2723. out = WSASocket(af, type, protocol, NULL, 0, 0);
  2724. }
  2725. free(proto_buffers);
  2726. }
  2727. }
  2728. return out;
  2729. }
  2730. #undef socket
  2731. int WSAAPI
  2732. rb_w32_socket(int af, int type, int protocol)
  2733. {
  2734. SOCKET s;
  2735. int fd;
  2736. if (!NtSocketsInitialized) {
  2737. StartSockets();
  2738. }
  2739. RUBY_CRITICAL({
  2740. s = open_ifs_socket(af, type, protocol);
  2741. if (s == INVALID_SOCKET) {
  2742. errno = map_errno(WSAGetLastError());
  2743. fd = -1;
  2744. }
  2745. else {
  2746. fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
  2747. if (fd != -1)
  2748. st_insert(socklist, (st_data_t)s, (st_data_t)0);
  2749. else
  2750. closesocket(s);
  2751. }
  2752. });
  2753. return fd;
  2754. }
  2755. #undef gethostbyaddr
  2756. struct hostent * WSAAPI
  2757. rb_w32_gethostbyaddr(const char *addr, int len, int type)
  2758. {
  2759. struct hostent *r;
  2760. if (!NtSocketsInitialized) {
  2761. StartSockets();
  2762. }
  2763. RUBY_CRITICAL({
  2764. r = gethostbyaddr(addr, len, type);
  2765. if (r == NULL)
  2766. errno = map_errno(WSAGetLastError());
  2767. });
  2768. return r;
  2769. }
  2770. #undef gethostbyname
  2771. struct hostent * WSAAPI
  2772. rb_w32_gethostbyname(const char *name)
  2773. {
  2774. struct hostent *r;
  2775. if (!NtSocketsInitialized) {
  2776. StartSockets();
  2777. }
  2778. RUBY_CRITICAL({
  2779. r = gethostbyname(name);
  2780. if (r == NULL)
  2781. errno = map_errno(WSAGetLastError());
  2782. });
  2783. return r;
  2784. }
  2785. #undef gethostname
  2786. int WSAAPI
  2787. rb_w32_gethostname(char *name, int len)
  2788. {
  2789. int r;
  2790. if (!NtSocketsInitialized) {
  2791. StartSockets();
  2792. }
  2793. RUBY_CRITICAL({
  2794. r = gethostname(name, len);
  2795. if (r == SOCKET_ERROR)
  2796. errno = map_errno(WSAGetLastError());
  2797. });
  2798. return r;
  2799. }
  2800. #undef getprotobyname
  2801. struct protoent * WSAAPI
  2802. rb_w32_getprotobyname(const char *name)
  2803. {
  2804. struct protoent *r;
  2805. if (!NtSocketsInitialized) {
  2806. StartSockets();
  2807. }
  2808. RUBY_CRITICAL({
  2809. r = getprotobyname(name);
  2810. if (r == NULL)
  2811. errno = map_errno(WSAGetLastError());
  2812. });
  2813. return r;
  2814. }
  2815. #undef getprotobynumber
  2816. struct protoent * WSAAPI
  2817. rb_w32_getprotobynumber(int num)
  2818. {
  2819. struct protoent *r;
  2820. if (!NtSocketsInitialized) {
  2821. StartSockets();
  2822. }
  2823. RUBY_CRITICAL({
  2824. r = getprotobynumber(num);
  2825. if (r == NULL)
  2826. errno = map_errno(WSAGetLastError());
  2827. });
  2828. return r;
  2829. }
  2830. #undef getservbyname
  2831. struct servent * WSAAPI
  2832. rb_w32_getservbyname(const char *name, const char *proto)
  2833. {
  2834. struct servent *r;
  2835. if (!NtSocketsInitialized) {
  2836. StartSockets();
  2837. }
  2838. RUBY_CRITICAL({
  2839. r = getservbyname(name, proto);
  2840. if (r == NULL)
  2841. errno = map_errno(WSAGetLastError());
  2842. });
  2843. return r;
  2844. }
  2845. #undef getservbyport
  2846. struct servent * WSAAPI
  2847. rb_w32_getservbyport(int port, const char *proto)
  2848. {
  2849. struct servent *r;
  2850. if (!NtSocketsInitialized) {
  2851. StartSockets();
  2852. }
  2853. RUBY_CRITICAL({
  2854. r = getservbyport(port, proto);
  2855. if (r == NULL)
  2856. errno = map_errno(WSAGetLastError());
  2857. });
  2858. return r;
  2859. }
  2860. static int
  2861. socketpair_internal(int af, int type, int protocol, SOCKET *sv)
  2862. {
  2863. SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
  2864. struct sockaddr_in sock_in4;
  2865. #ifdef INET6
  2866. struct sockaddr_in6 sock_in6;
  2867. #endif
  2868. struct sockaddr *addr;
  2869. int ret = -1;
  2870. int len;
  2871. if (!NtSocketsInitialized) {
  2872. StartSockets();
  2873. }
  2874. switch (af) {
  2875. case AF_INET:
  2876. #if defined PF_INET && PF_INET != AF_INET
  2877. case PF_INET:
  2878. #endif
  2879. sock_in4.sin_family = AF_INET;
  2880. sock_in4.sin_port = 0;
  2881. sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  2882. addr = (struct sockaddr *)&sock_in4;
  2883. len = sizeof(sock_in4);
  2884. break;
  2885. #ifdef INET6
  2886. case AF_INET6:
  2887. memset(&sock_in6, 0, sizeof(sock_in6));
  2888. sock_in6.sin6_family = AF_INET6;
  2889. sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
  2890. addr = (struct sockaddr *)&sock_in6;
  2891. len = sizeof(sock_in6);
  2892. break;
  2893. #endif
  2894. default:
  2895. errno = EAFNOSUPPORT;
  2896. return -1;
  2897. }
  2898. if (type != SOCK_STREAM) {
  2899. errno = EPROTOTYPE;
  2900. return -1;
  2901. }
  2902. RUBY_CRITICAL({
  2903. do {
  2904. svr = open_ifs_socket(af, type, protocol);
  2905. if (svr == INVALID_SOCKET)
  2906. break;
  2907. if (bind(svr, addr, len) < 0)
  2908. break;
  2909. if (getsockname(svr, addr, &len) < 0)
  2910. break;
  2911. if (type == SOCK_STREAM)
  2912. listen(svr, 5);
  2913. w = open_ifs_socket(af, type, protocol);
  2914. if (w == INVALID_SOCKET)
  2915. break;
  2916. if (connect(w, addr, len) < 0)
  2917. break;
  2918. r = accept(svr, addr, &len);
  2919. if (r == INVALID_SOCKET)
  2920. break;
  2921. ret = 0;
  2922. } while (0);
  2923. if (ret < 0) {
  2924. errno = map_errno(WSAGetLastError());
  2925. if (r != INVALID_SOCKET)
  2926. closesocket(r);
  2927. if (w != INVALID_SOCKET)
  2928. closesocket(w);
  2929. }
  2930. else {
  2931. sv[0] = r;
  2932. sv[1] = w;
  2933. }
  2934. if (svr != INVALID_SOCKET)
  2935. closesocket(svr);
  2936. });
  2937. return ret;
  2938. }
  2939. int
  2940. rb_w32_socketpair(int af, int type, int protocol, int *sv)
  2941. {
  2942. SOCKET pair[2];
  2943. if (socketpair_internal(af, type, protocol, pair) < 0)
  2944. return -1;
  2945. sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
  2946. if (sv[0] == -1) {
  2947. closesocket(pair[0]);
  2948. closesocket(pair[1]);
  2949. return -1;
  2950. }
  2951. sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
  2952. if (sv[1] == -1) {
  2953. rb_w32_close(sv[0]);
  2954. closesocket(pair[1]);
  2955. return -1;
  2956. }
  2957. st_insert(socklist, (st_data_t)pair[0], (st_data_t)0);
  2958. st_insert(socklist, (st_data_t)pair[1], (st_data_t)0);
  2959. return 0;
  2960. }
  2961. //
  2962. // Networking stubs
  2963. //
  2964. void endhostent(void) {}
  2965. void endnetent(void) {}
  2966. void endprotoent(void) {}
  2967. void endservent(void) {}
  2968. struct netent *getnetent (void) {return (struct netent *) NULL;}
  2969. struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;}
  2970. struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;}
  2971. struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
  2972. struct servent *getservent (void) {return (struct servent *) NULL;}
  2973. void sethostent (int stayopen) {}
  2974. void setnetent (int stayopen) {}
  2975. void setprotoent (int stayopen) {}
  2976. void setservent (int stayopen) {}
  2977. int
  2978. fcntl(int fd, int cmd, ...)
  2979. {
  2980. SOCKET sock = TO_SOCKET(fd);
  2981. va_list va;
  2982. int arg;
  2983. int ret;
  2984. int flag = 0;
  2985. st_data_t data;
  2986. u_long ioctlArg;
  2987. if (!is_socket(sock)) {
  2988. errno = EBADF;
  2989. return -1;
  2990. }
  2991. if (cmd != F_SETFL) {
  2992. errno = EINVAL;
  2993. return -1;
  2994. }
  2995. va_start(va, cmd);
  2996. arg = va_arg(va, int);
  2997. va_end(va);
  2998. st_lookup(socklist, (st_data_t)sock, &data);
  2999. flag = (int)data;
  3000. if (arg & O_NONBLOCK) {
  3001. flag |= O_NONBLOCK;
  3002. ioctlArg = 1;
  3003. }
  3004. else {
  3005. flag &= ~O_NONBLOCK;
  3006. ioctlArg = 0;
  3007. }
  3008. RUBY_CRITICAL({
  3009. ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
  3010. if (ret == 0)
  3011. st_insert(socklist, (st_data_t)sock, (st_data_t)flag);
  3012. else
  3013. errno = map_errno(WSAGetLastError());
  3014. });
  3015. return ret;
  3016. }
  3017. #ifndef WNOHANG
  3018. #define WNOHANG -1
  3019. #endif
  3020. static rb_pid_t
  3021. poll_child_status(struct ChildRecord *child, int *stat_loc)
  3022. {
  3023. DWORD exitcode;
  3024. DWORD err;
  3025. if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
  3026. /* If an error occured, return immediatly. */
  3027. err = GetLastError();
  3028. if (err == ERROR_INVALID_PARAMETER)
  3029. errno = ECHILD;
  3030. else {
  3031. if (GetLastError() == ERROR_INVALID_HANDLE)
  3032. errno = EINVAL;
  3033. else
  3034. errno = map_errno(GetLastError());
  3035. }
  3036. CloseChildHandle(child);
  3037. return -1;
  3038. }
  3039. if (exitcode != STILL_ACTIVE) {
  3040. /* If already died, return immediatly. */
  3041. rb_pid_t pid = child->pid;
  3042. CloseChildHandle(child);
  3043. if (stat_loc) *stat_loc = exitcode << 8;
  3044. return pid;
  3045. }
  3046. return 0;
  3047. }
  3048. rb_pid_t
  3049. waitpid(rb_pid_t pid, int *stat_loc, int options)
  3050. {
  3051. DWORD timeout;
  3052. if (options == WNOHANG) {
  3053. timeout = 0;
  3054. } else {
  3055. timeout = INFINITE;
  3056. }
  3057. if (pid == -1) {
  3058. int count = 0;
  3059. int ret;
  3060. HANDLE events[MAXCHILDNUM];
  3061. FOREACH_CHILD(child) {
  3062. if (!child->pid || child->pid < 0) continue;
  3063. if ((pid = poll_child_status(child, stat_loc))) return pid;
  3064. events[count++] = child->hProcess;
  3065. } END_FOREACH_CHILD;
  3066. if (!count) {
  3067. errno = ECHILD;
  3068. return -1;
  3069. }
  3070. ret = rb_w32_wait_events_blocking(events, count, timeout);
  3071. if (ret == WAIT_TIMEOUT) return 0;
  3072. if ((ret -= WAIT_OBJECT_0) == count) {
  3073. return -1;
  3074. }
  3075. if (ret > count) {
  3076. errno = map_errno(GetLastError());
  3077. return -1;
  3078. }
  3079. return poll_child_status(FindChildSlotByHandle(events[ret]), stat_loc);
  3080. }
  3081. else {
  3082. struct ChildRecord* child = FindChildSlot(pid);
  3083. if (!child) {
  3084. errno = ECHILD;
  3085. return -1;
  3086. }
  3087. while (!(pid = poll_child_status(child, stat_loc))) {
  3088. /* wait... */
  3089. if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) {
  3090. /* still active */
  3091. pid = 0;
  3092. break;
  3093. }
  3094. }
  3095. }
  3096. return pid;
  3097. }
  3098. #include <sys/timeb.h>
  3099. static int
  3100. filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
  3101. {
  3102. ULARGE_INTEGER tmp;
  3103. unsigned LONG_LONG lt;
  3104. tmp.LowPart = ft->dwLowDateTime;
  3105. tmp.HighPart = ft->dwHighDateTime;
  3106. lt = tmp.QuadPart;
  3107. /* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC,
  3108. convert it into UNIX time (since 1970/01/01 00:00:00 UTC).
  3109. the first leap second is at 1972/06/30, so we doesn't need to think
  3110. about it. */
  3111. lt /= 10; /* to usec */
  3112. lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000;
  3113. tv->tv_sec = (long)(lt / (1000 * 1000));
  3114. tv->tv_usec = (long)(lt % (1000 * 1000));
  3115. return tv->tv_sec > 0 ? 0 : -1;
  3116. }
  3117. int _cdecl
  3118. gettimeofday(struct timeval *tv, struct timezone *tz)
  3119. {
  3120. FILETIME ft;
  3121. GetSystemTimeAsFileTime(&ft);
  3122. filetime_to_timeval(&ft, tv);
  3123. return 0;
  3124. }
  3125. char *
  3126. rb_w32_getcwd(char *buffer, int size)
  3127. {
  3128. char *p = buffer;
  3129. char *bp;
  3130. int len;
  3131. len = GetCurrentDirectory(0, NULL);
  3132. if (!len) {
  3133. errno = map_errno(GetLastError());
  3134. return NULL;
  3135. }
  3136. if (p) {
  3137. if (size < len) {
  3138. errno = ERANGE;
  3139. return NULL;
  3140. }
  3141. }
  3142. else {
  3143. p = malloc(len);
  3144. size = len;
  3145. if (!p) {
  3146. errno = ENOMEM;
  3147. return NULL;
  3148. }
  3149. }
  3150. if (!GetCurrentDirectory(size, p)) {
  3151. errno = map_errno(GetLastError());
  3152. if (!buffer)
  3153. free(p);
  3154. return NULL;
  3155. }
  3156. for (bp = p; *bp != '\0'; bp = CharNext(bp)) {
  3157. if (*bp == '\\') {
  3158. *bp = '/';
  3159. }
  3160. }
  3161. return p;
  3162. }
  3163. int
  3164. chown(const char *path, int owner, int group)
  3165. {
  3166. return 0;
  3167. }
  3168. int
  3169. kill(int pid, int sig)
  3170. {
  3171. int ret = 0;
  3172. DWORD err;
  3173. if (pid <= 0) {
  3174. errno = EINVAL;
  3175. return -1;
  3176. }
  3177. (void)IfWin95(pid = -pid, 0);
  3178. if ((unsigned int)pid == GetCurrentProcessId() &&
  3179. (sig != 0 && sig != SIGKILL)) {
  3180. if ((ret = raise(sig)) != 0) {
  3181. /* MSVCRT doesn't set errno... */
  3182. errno = EINVAL;
  3183. }
  3184. return ret;
  3185. }
  3186. switch (sig) {
  3187. case 0:
  3188. RUBY_CRITICAL({
  3189. HANDLE hProc =
  3190. OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
  3191. if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
  3192. if (GetLastError() == ERROR_INVALID_PARAMETER) {
  3193. errno = ESRCH;
  3194. }
  3195. else {
  3196. errno = EPERM;
  3197. }
  3198. ret = -1;
  3199. }
  3200. else {
  3201. CloseHandle(hProc);
  3202. }
  3203. });
  3204. break;
  3205. case SIGINT:
  3206. RUBY_CRITICAL({
  3207. if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) {
  3208. if ((err = GetLastError()) == 0)
  3209. errno = EPERM;
  3210. else
  3211. errno = map_errno(GetLastError());
  3212. ret = -1;
  3213. }
  3214. });
  3215. break;
  3216. case SIGKILL:
  3217. RUBY_CRITICAL({
  3218. HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD)pid);
  3219. if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
  3220. if (GetLastError() == ERROR_INVALID_PARAMETER) {
  3221. errno = ESRCH;
  3222. }
  3223. else {
  3224. errno = EPERM;
  3225. }
  3226. ret = -1;
  3227. }
  3228. else {
  3229. if (!TerminateProcess(hProc, 0)) {
  3230. errno = EPERM;
  3231. ret = -1;
  3232. }
  3233. CloseHandle(hProc);
  3234. }
  3235. });
  3236. break;
  3237. default:
  3238. errno = EINVAL;
  3239. ret = -1;
  3240. break;
  3241. }
  3242. return ret;
  3243. }
  3244. int
  3245. link(const char *from, const char *to)
  3246. {
  3247. static BOOL (WINAPI *pCreateHardLink)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES) = NULL;
  3248. static int myerrno = 0;
  3249. if (!pCreateHardLink && !myerrno) {
  3250. HANDLE hKernel;
  3251. hKernel = GetModuleHandle("kernel32.dll");
  3252. if (hKernel) {
  3253. pCreateHardLink = (BOOL (WINAPI *)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES))GetProcAddress(hKernel, "CreateHardLinkA");
  3254. if (!pCreateHardLink) {
  3255. myerrno = ENOSYS;
  3256. }
  3257. }
  3258. else {
  3259. myerrno = map_errno(GetLastError());
  3260. }
  3261. }
  3262. if (!pCreateHardLink) {
  3263. errno = myerrno;
  3264. return -1;
  3265. }
  3266. if (!pCreateHardLink(to, from, NULL)) {
  3267. errno = map_errno(GetLastError());
  3268. return -1;
  3269. }
  3270. return 0;
  3271. }
  3272. int
  3273. wait(int *status)
  3274. {
  3275. return waitpid(-1, status, 0);
  3276. }
  3277. char *
  3278. rb_w32_getenv(const char *name)
  3279. {
  3280. int len = strlen(name);
  3281. char *env;
  3282. if (envarea)
  3283. FreeEnvironmentStrings(envarea);
  3284. envarea = GetEnvironmentStrings();
  3285. if (!envarea) {
  3286. map_errno(GetLastError());
  3287. return NULL;
  3288. }
  3289. for (env = envarea; *env; env += strlen(env) + 1)
  3290. if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
  3291. return env + len + 1;
  3292. return NULL;
  3293. }
  3294. int
  3295. rb_w32_rename(const char *oldpath, const char *newpath)
  3296. {
  3297. int res = 0;
  3298. int oldatts;
  3299. int newatts;
  3300. oldatts = GetFileAttributes(oldpath);
  3301. newatts = GetFileAttributes(newpath);
  3302. if (oldatts == -1) {
  3303. errno = map_errno(GetLastError());
  3304. return -1;
  3305. }
  3306. RUBY_CRITICAL({
  3307. if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
  3308. SetFileAttributesA(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
  3309. if (!MoveFile(oldpath, newpath))
  3310. res = -1;
  3311. if (res) {
  3312. switch (GetLastError()) {
  3313. case ERROR_ALREADY_EXISTS:
  3314. case ERROR_FILE_EXISTS:
  3315. if (IsWinNT()) {
  3316. if (MoveFileEx(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
  3317. res = 0;
  3318. } else {
  3319. for (;;) {
  3320. if (!DeleteFile(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND)
  3321. break;
  3322. else if (MoveFile(oldpath, newpath)) {
  3323. res = 0;
  3324. break;
  3325. }
  3326. }
  3327. }
  3328. }
  3329. }
  3330. if (res)
  3331. errno = map_errno(GetLastError());
  3332. else
  3333. SetFileAttributes(newpath, oldatts);
  3334. });
  3335. return res;
  3336. }
  3337. static int
  3338. isUNCRoot(const char *path)
  3339. {
  3340. if (path[0] == '\\' && path[1] == '\\') {
  3341. const char *p;
  3342. for (p = path + 2; *p; p = CharNext(p)) {
  3343. if (*p == '\\')
  3344. break;
  3345. }
  3346. if (p[0] && p[1]) {
  3347. for (p++; *p; p = CharNext(p)) {
  3348. if (*p == '\\')
  3349. break;
  3350. }
  3351. if (!p[0] || !p[1] || (p[1] == '.' && !p[2]))
  3352. return 1;
  3353. }
  3354. }
  3355. return 0;
  3356. }
  3357. #define COPY_STAT(src, dest, size_cast) do { \
  3358. (dest).st_dev = (src).st_dev; \
  3359. (dest).st_ino = (src).st_ino; \
  3360. (dest).st_mode = (src).st_mode; \
  3361. (dest).st_nlink = (src).st_nlink; \
  3362. (dest).st_uid = (src).st_uid; \
  3363. (dest).st_gid = (src).st_gid; \
  3364. (dest).st_rdev = (src).st_rdev; \
  3365. (dest).st_size = size_cast(src).st_size; \
  3366. (dest).st_atime = (src).st_atime; \
  3367. (dest).st_mtime = (src).st_mtime; \
  3368. (dest).st_ctime = (src).st_ctime; \
  3369. } while (0)
  3370. #ifdef __BORLANDC__
  3371. #undef fstat
  3372. int
  3373. rb_w32_fstat(int fd, struct stat *st)
  3374. {
  3375. BY_HANDLE_FILE_INFORMATION info;
  3376. int ret = fstat(fd, st);
  3377. if (ret) return ret;
  3378. st->st_mode &= ~(S_IWGRP | S_IWOTH);
  3379. if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info) &&
  3380. !(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
  3381. st->st_mode |= S_IWUSR;
  3382. }
  3383. return ret;
  3384. }
  3385. int
  3386. rb_w32_fstati64(int fd, struct stati64 *st)
  3387. {
  3388. BY_HANDLE_FILE_INFORMATION info;
  3389. struct stat tmp;
  3390. int ret = fstat(fd, &tmp);
  3391. if (ret) return ret;
  3392. tmp.st_mode &= ~(S_IWGRP | S_IWOTH);
  3393. COPY_STAT(tmp, *st, +);
  3394. if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
  3395. if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
  3396. st->st_mode |= S_IWUSR;
  3397. }
  3398. st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
  3399. }
  3400. return ret;
  3401. }
  3402. #endif
  3403. static time_t
  3404. filetime_to_unixtime(const FILETIME *ft)
  3405. {
  3406. struct timeval tv;
  3407. if (filetime_to_timeval(ft, &tv) == (time_t)-1)
  3408. return 0;
  3409. else
  3410. return tv.tv_sec;
  3411. }
  3412. static unsigned
  3413. fileattr_to_unixmode(DWORD attr, const char *path)
  3414. {
  3415. unsigned mode = 0;
  3416. if (attr & FILE_ATTRIBUTE_READONLY) {
  3417. mode |= S_IREAD;
  3418. }
  3419. else {
  3420. mode |= S_IREAD | S_IWRITE | S_IWUSR;
  3421. }
  3422. if (attr & FILE_ATTRIBUTE_DIRECTORY) {
  3423. mode |= S_IFDIR | S_IEXEC;
  3424. }
  3425. else {
  3426. mode |= S_IFREG;
  3427. }
  3428. if (path && (mode & S_IFREG)) {
  3429. const char *end = path + strlen(path);
  3430. while (path < end) {
  3431. end = CharPrev(path, end);
  3432. if (*end == '.') {
  3433. if ((strcasecmp(end, ".bat") == 0) ||
  3434. (strcasecmp(end, ".cmd") == 0) ||
  3435. (strcasecmp(end, ".com") == 0) ||
  3436. (strcasecmp(end, ".exe") == 0)) {
  3437. mode |= S_IEXEC;
  3438. }
  3439. break;
  3440. }
  3441. }
  3442. }
  3443. mode |= (mode & 0700) >> 3;
  3444. mode |= (mode & 0700) >> 6;
  3445. return mode;
  3446. }
  3447. static int
  3448. check_valid_dir(const char *path)
  3449. {
  3450. WIN32_FIND_DATAW fd;
  3451. HANDLE fh = open_dir_handle(path, &fd);
  3452. if (fh == INVALID_HANDLE_VALUE)
  3453. return -1;
  3454. FindClose(fh);
  3455. return 0;
  3456. }
  3457. static int
  3458. winnt_stat(const char *path, struct stati64 *st)
  3459. {
  3460. HANDLE h;
  3461. WIN32_FIND_DATA wfd;
  3462. memset(st, 0, sizeof(*st));
  3463. st->st_nlink = 1;
  3464. if (_mbspbrk((const unsigned char *)path, (const unsigned char *)"?*")) {
  3465. errno = ENOENT;
  3466. return -1;
  3467. }
  3468. h = FindFirstFile(path, &wfd);
  3469. if (h != INVALID_HANDLE_VALUE) {
  3470. FindClose(h);
  3471. st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
  3472. st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
  3473. st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
  3474. st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
  3475. st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
  3476. }
  3477. else {
  3478. // If runtime stat(2) is called for network shares, it fails on WinNT.
  3479. // Because GetDriveType returns 1 for network shares. (Win98 returns 4)
  3480. DWORD attr = GetFileAttributes(path);
  3481. if (attr == -1) {
  3482. errno = map_errno(GetLastError());
  3483. return -1;
  3484. }
  3485. if (attr & FILE_ATTRIBUTE_DIRECTORY) {
  3486. if (check_valid_dir(path)) return -1;
  3487. }
  3488. st->st_mode = fileattr_to_unixmode(attr, path);
  3489. }
  3490. st->st_dev = st->st_rdev = (isalpha(path[0]) && path[1] == ':') ?
  3491. toupper(path[0]) - 'A' : _getdrive() - 1;
  3492. return 0;
  3493. }
  3494. #ifdef WIN95
  3495. static int
  3496. win95_stat(const char *path, struct stati64 *st)
  3497. {
  3498. int ret = stati64(path, st);
  3499. if (ret) return ret;
  3500. if (st->st_mode & S_IFDIR) {
  3501. return check_valid_dir(path);
  3502. }
  3503. return 0;
  3504. }
  3505. #else
  3506. #define win95_stat(path, st) -1
  3507. #endif
  3508. int
  3509. rb_w32_stat(const char *path, struct stat *st)
  3510. {
  3511. struct stati64 tmp;
  3512. if (rb_w32_stati64(path, &tmp)) return -1;
  3513. COPY_STAT(tmp, *st, (_off_t));
  3514. return 0;
  3515. }
  3516. int
  3517. rb_w32_stati64(const char *path, struct stati64 *st)
  3518. {
  3519. const char *p;
  3520. char *buf1, *s, *end;
  3521. int len, size;
  3522. int ret;
  3523. if (!path || !st) {
  3524. errno = EFAULT;
  3525. return -1;
  3526. }
  3527. size = strlen(path) + 2;
  3528. buf1 = ALLOCA_N(char, size);
  3529. for (p = path, s = buf1; *p; p++, s++) {
  3530. if (*p == '/')
  3531. *s = '\\';
  3532. else
  3533. *s = *p;
  3534. }
  3535. *s = '\0';
  3536. len = s - buf1;
  3537. if (!len || '\"' == *(--s)) {
  3538. errno = ENOENT;
  3539. return -1;
  3540. }
  3541. end = CharPrev(buf1, buf1 + len);
  3542. if (isUNCRoot(buf1)) {
  3543. if (*end == '.')
  3544. *end = '\0';
  3545. else if (*end != '\\')
  3546. strlcat(buf1, "\\", size);
  3547. }
  3548. else if (*end == '\\' || (buf1 + 1 == end && *end == ':'))
  3549. strlcat(buf1, ".", size);
  3550. ret = IsWinNT() ? winnt_stat(buf1, st) : win95_stat(buf1, st);
  3551. if (ret == 0) {
  3552. st->st_mode &= ~(S_IWGRP | S_IWOTH);
  3553. }
  3554. return ret;
  3555. }
  3556. int
  3557. rb_w32_access(const char *path, int mode)
  3558. {
  3559. struct stati64 stat;
  3560. if (rb_w32_stati64(path, &stat) != 0)
  3561. return -1;
  3562. mode <<= 6;
  3563. if ((stat.st_mode & mode) != mode) {
  3564. errno = EACCES;
  3565. return -1;
  3566. }
  3567. return 0;
  3568. }
  3569. static int
  3570. rb_chsize(HANDLE h, off_t size)
  3571. {
  3572. long upos, lpos, usize, lsize, uend, lend;
  3573. off_t end;
  3574. int ret = -1;
  3575. DWORD e;
  3576. if (((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
  3577. (e = GetLastError())) ||
  3578. ((lend = GetFileSize(h, (DWORD *)&uend)) == -1L && (e = GetLastError()))) {
  3579. errno = map_errno(e);
  3580. return -1;
  3581. }
  3582. end = ((off_t)uend << 32) | (unsigned long)lend;
  3583. usize = (long)(size >> 32);
  3584. lsize = (long)size;
  3585. if (SetFilePointer(h, lsize, &usize, SEEK_SET) == -1L &&
  3586. (e = GetLastError())) {
  3587. errno = map_errno(e);
  3588. }
  3589. else if (!SetEndOfFile(h)) {
  3590. errno = map_errno(GetLastError());
  3591. }
  3592. else {
  3593. ret = 0;
  3594. }
  3595. SetFilePointer(h, lpos, &upos, SEEK_SET);
  3596. return ret;
  3597. }
  3598. int
  3599. truncate(const char *path, off_t length)
  3600. {
  3601. HANDLE h;
  3602. int ret;
  3603. #ifdef WIN95
  3604. if (IsWin95()) {
  3605. int fd = open(path, O_WRONLY), e = 0;
  3606. if (fd == -1) return -1;
  3607. ret = chsize(fd, (unsigned long)length);
  3608. if (ret == -1) e = errno;
  3609. close(fd);
  3610. if (ret == -1) errno = e;
  3611. return ret;
  3612. }
  3613. #endif
  3614. h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
  3615. if (h == INVALID_HANDLE_VALUE) {
  3616. errno = map_errno(GetLastError());
  3617. return -1;
  3618. }
  3619. ret = rb_chsize(h, length);
  3620. CloseHandle(h);
  3621. return ret;
  3622. }
  3623. int
  3624. ftruncate(int fd, off_t length)
  3625. {
  3626. long h;
  3627. #ifdef WIN95
  3628. if (IsWin95()) {
  3629. return chsize(fd, (unsigned long)length);
  3630. }
  3631. #endif
  3632. h = _get_osfhandle(fd);
  3633. if (h == -1) return -1;
  3634. return rb_chsize((HANDLE)h, length);
  3635. }
  3636. #ifdef __BORLANDC__
  3637. off_t
  3638. _filelengthi64(int fd)
  3639. {
  3640. DWORD u, l;
  3641. int e;
  3642. l = GetFileSize((HANDLE)_get_osfhandle(fd), &u);
  3643. if (l == (DWORD)-1L && (e = GetLastError())) {
  3644. errno = map_errno(e);
  3645. return (off_t)-1;
  3646. }
  3647. return ((off_t)u << 32) | l;
  3648. }
  3649. off_t
  3650. _lseeki64(int fd, off_t offset, int whence)
  3651. {
  3652. long u, l;
  3653. int e;
  3654. HANDLE h = (HANDLE)_get_osfhandle(fd);
  3655. if (!h) {
  3656. errno = EBADF;
  3657. return -1;
  3658. }
  3659. u = (long)(offset >> 32);
  3660. if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L &&
  3661. (e = GetLastError())) {
  3662. errno = map_errno(e);
  3663. return -1;
  3664. }
  3665. return ((off_t)u << 32) | l;
  3666. }
  3667. #endif
  3668. int
  3669. fseeko(FILE *stream, off_t offset, int whence)
  3670. {
  3671. off_t pos;
  3672. switch (whence) {
  3673. case SEEK_CUR:
  3674. if (fgetpos(stream, (fpos_t *)&pos))
  3675. return -1;
  3676. pos += offset;
  3677. break;
  3678. case SEEK_END:
  3679. if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1)
  3680. return -1;
  3681. pos += offset;
  3682. break;
  3683. default:
  3684. pos = offset;
  3685. break;
  3686. }
  3687. return fsetpos(stream, (fpos_t *)&pos);
  3688. }
  3689. off_t
  3690. ftello(FILE *stream)
  3691. {
  3692. off_t pos;
  3693. if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1;
  3694. return pos;
  3695. }
  3696. static long
  3697. filetime_to_clock(FILETIME *ft)
  3698. {
  3699. __int64 qw = ft->dwHighDateTime;
  3700. qw <<= 32;
  3701. qw |= ft->dwLowDateTime;
  3702. qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
  3703. return (long) qw;
  3704. }
  3705. int
  3706. rb_w32_times(struct tms *tmbuf)
  3707. {
  3708. FILETIME create, exit, kernel, user;
  3709. if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
  3710. tmbuf->tms_utime = filetime_to_clock(&user);
  3711. tmbuf->tms_stime = filetime_to_clock(&kernel);
  3712. tmbuf->tms_cutime = 0;
  3713. tmbuf->tms_cstime = 0;
  3714. }
  3715. else {
  3716. tmbuf->tms_utime = clock();
  3717. tmbuf->tms_stime = 0;
  3718. tmbuf->tms_cutime = 0;
  3719. tmbuf->tms_cstime = 0;
  3720. }
  3721. return 0;
  3722. }
  3723. #define yield_once() Sleep(0)
  3724. #define yield_until(condition) do yield_once(); while (!(condition))
  3725. static void
  3726. catch_interrupt(void)
  3727. {
  3728. yield_once();
  3729. RUBY_CRITICAL(rb_w32_wait_events(NULL, 0, 0));
  3730. }
  3731. #if defined __BORLANDC__
  3732. #undef read
  3733. int
  3734. read(int fd, void *buf, size_t size)
  3735. {
  3736. int ret = _read(fd, buf, size);
  3737. if ((ret < 0) && (errno == EPIPE)) {
  3738. errno = 0;
  3739. ret = 0;
  3740. }
  3741. catch_interrupt();
  3742. return ret;
  3743. }
  3744. #endif
  3745. #undef fgetc
  3746. int
  3747. rb_w32_getc(FILE* stream)
  3748. {
  3749. int c;
  3750. if (enough_to_get(stream->FILE_COUNT)) {
  3751. c = (unsigned char)*stream->FILE_READPTR++;
  3752. }
  3753. else
  3754. {
  3755. c = _filbuf(stream);
  3756. #if defined __BORLANDC__
  3757. if ((c == EOF) && (errno == EPIPE)) {
  3758. clearerr(stream);
  3759. }
  3760. #endif
  3761. catch_interrupt();
  3762. }
  3763. return c;
  3764. }
  3765. #undef fputc
  3766. int
  3767. rb_w32_putc(int c, FILE* stream)
  3768. {
  3769. if (enough_to_put(stream->FILE_COUNT)) {
  3770. c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
  3771. }
  3772. else
  3773. {
  3774. c = _flsbuf(c, stream);
  3775. catch_interrupt();
  3776. }
  3777. return c;
  3778. }
  3779. struct asynchronous_arg_t {
  3780. /* output field */
  3781. void* stackaddr;
  3782. int errnum;
  3783. /* input field */
  3784. uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv);
  3785. uintptr_t self;
  3786. int argc;
  3787. uintptr_t* argv;
  3788. };
  3789. static DWORD WINAPI
  3790. call_asynchronous(PVOID argp)
  3791. {
  3792. DWORD ret;
  3793. struct asynchronous_arg_t *arg = argp;
  3794. arg->stackaddr = &argp;
  3795. ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
  3796. arg->errnum = errno;
  3797. return ret;
  3798. }
  3799. uintptr_t
  3800. rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self,
  3801. int argc, uintptr_t* argv, uintptr_t intrval)
  3802. {
  3803. DWORD val;
  3804. BOOL interrupted = FALSE;
  3805. HANDLE thr;
  3806. RUBY_CRITICAL({
  3807. struct asynchronous_arg_t arg;
  3808. arg.stackaddr = NULL;
  3809. arg.errnum = 0;
  3810. arg.func = func;
  3811. arg.self = self;
  3812. arg.argc = argc;
  3813. arg.argv = argv;
  3814. thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
  3815. if (thr) {
  3816. yield_until(arg.stackaddr);
  3817. if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
  3818. interrupted = TRUE;
  3819. if (TerminateThread(thr, intrval)) {
  3820. yield_once();
  3821. }
  3822. }
  3823. GetExitCodeThread(thr, &val);
  3824. CloseHandle(thr);
  3825. if (interrupted) {
  3826. /* must release stack of killed thread, why doesn't Windows? */
  3827. MEMORY_BASIC_INFORMATION m;
  3828. memset(&m, 0, sizeof(m));
  3829. if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
  3830. Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
  3831. arg.stackaddr, GetLastError()));
  3832. }
  3833. else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
  3834. Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
  3835. m.AllocationBase, GetLastError()));
  3836. }
  3837. errno = EINTR;
  3838. }
  3839. else {
  3840. errno = arg.errnum;
  3841. }
  3842. }
  3843. });
  3844. if (!thr) {
  3845. rb_fatal("failed to launch waiter thread:%ld", GetLastError());
  3846. }
  3847. return val;
  3848. }
  3849. char **
  3850. rb_w32_get_environ(void)
  3851. {
  3852. char *envtop, *env;
  3853. char **myenvtop, **myenv;
  3854. int num;
  3855. /*
  3856. * We avoid values started with `='. If you want to deal those values,
  3857. * change this function, and some functions in hash.c which recognize
  3858. * `=' as delimiter or rb_w32_getenv() and ruby_setenv().
  3859. * CygWin deals these values by changing first `=' to '!'. But we don't
  3860. * use such trick and follow cmd.exe's way that just doesn't show these
  3861. * values.
  3862. * (U.N. 2001-11-15)
  3863. */
  3864. envtop = GetEnvironmentStrings();
  3865. for (env = envtop, num = 0; *env; env += strlen(env) + 1)
  3866. if (*env != '=') num++;
  3867. myenvtop = (char **)malloc(sizeof(char *) * (num + 1));
  3868. for (env = envtop, myenv = myenvtop; *env; env += strlen(env) + 1) {
  3869. if (*env != '=') {
  3870. if (!(*myenv = strdup(env))) {
  3871. break;
  3872. }
  3873. myenv++;
  3874. }
  3875. }
  3876. *myenv = NULL;
  3877. FreeEnvironmentStrings(envtop);
  3878. return myenvtop;
  3879. }
  3880. void
  3881. rb_w32_free_environ(char **env)
  3882. {
  3883. char **t = env;
  3884. while (*t) free(*t++);
  3885. free(env);
  3886. }
  3887. rb_pid_t
  3888. rb_w32_getpid(void)
  3889. {
  3890. rb_pid_t pid;
  3891. pid = GetCurrentProcessId();
  3892. (void)IfWin95(pid = -pid, 0);
  3893. return pid;
  3894. }
  3895. rb_pid_t
  3896. rb_w32_getppid(void)
  3897. {
  3898. static long (WINAPI *pNtQueryInformationProcess)(HANDLE, int, void *, ULONG, ULONG *) = NULL;
  3899. rb_pid_t ppid = 0;
  3900. if (!IsWin95() && rb_w32_osver() >= 5) {
  3901. if (!pNtQueryInformationProcess) {
  3902. HANDLE hNtDll = GetModuleHandle("ntdll.dll");
  3903. if (hNtDll) {
  3904. pNtQueryInformationProcess = (long (WINAPI *)(HANDLE, int, void *, ULONG, ULONG *))GetProcAddress(hNtDll, "NtQueryInformationProcess");
  3905. }
  3906. }
  3907. if (pNtQueryInformationProcess) {
  3908. struct {
  3909. long ExitStatus;
  3910. void* PebBaseAddress;
  3911. ULONG AffinityMask;
  3912. ULONG BasePriority;
  3913. ULONG UniqueProcessId;
  3914. ULONG ParentProcessId;
  3915. } pbi;
  3916. ULONG len;
  3917. long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
  3918. if (!ret) {
  3919. ppid = pbi.ParentProcessId;
  3920. }
  3921. }
  3922. }
  3923. return ppid;
  3924. }
  3925. int
  3926. rb_w32_open(const char *file, int oflag, ...)
  3927. {
  3928. UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
  3929. int len;
  3930. WCHAR *wfile;
  3931. int pmode;
  3932. va_list arg;
  3933. va_start(arg, oflag);
  3934. pmode = va_arg(arg, int);
  3935. va_end(arg);
  3936. if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
  3937. return _open(file, oflag, pmode);
  3938. }
  3939. len = MultiByteToWideChar(cp, 0, file, -1, NULL, 0);
  3940. if (len <= 0) {
  3941. errno = map_errno(GetLastError());
  3942. return -1;
  3943. }
  3944. wfile = ALLOCA_N(WCHAR, len);
  3945. MultiByteToWideChar(cp, 0, file, -1, wfile, len);
  3946. if (len <= 0) {
  3947. errno = map_errno(GetLastError());
  3948. return -1;
  3949. }
  3950. return rb_w32_wopen(wfile, oflag, pmode);
  3951. }
  3952. int
  3953. rb_w32_wopen(const WCHAR *file, int oflag, ...)
  3954. {
  3955. char flags = 0;
  3956. int fd;
  3957. DWORD access;
  3958. DWORD create;
  3959. DWORD attr = FILE_ATTRIBUTE_NORMAL;
  3960. SECURITY_ATTRIBUTES sec;
  3961. HANDLE h;
  3962. if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
  3963. va_list arg;
  3964. int pmode;
  3965. va_start(arg, oflag);
  3966. pmode = va_arg(arg, int);
  3967. va_end(arg);
  3968. return _wopen(file, oflag, pmode);
  3969. }
  3970. sec.nLength = sizeof(sec);
  3971. sec.lpSecurityDescriptor = NULL;
  3972. if (oflag & O_NOINHERIT) {
  3973. sec.bInheritHandle = FALSE;
  3974. flags |= FNOINHERIT;
  3975. }
  3976. else {
  3977. sec.bInheritHandle = TRUE;
  3978. }
  3979. oflag &= ~O_NOINHERIT;
  3980. /* always open with binary mode */
  3981. oflag &= ~(O_BINARY | O_TEXT);
  3982. switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
  3983. case O_RDWR:
  3984. access = GENERIC_READ | GENERIC_WRITE;
  3985. break;
  3986. case O_RDONLY:
  3987. access = GENERIC_READ;
  3988. break;
  3989. case O_WRONLY:
  3990. access = GENERIC_WRITE;
  3991. break;
  3992. default:
  3993. errno = EINVAL;
  3994. return -1;
  3995. }
  3996. oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
  3997. switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
  3998. case O_CREAT:
  3999. create = OPEN_ALWAYS;
  4000. break;
  4001. case 0:
  4002. case O_EXCL:
  4003. create = OPEN_EXISTING;
  4004. break;
  4005. case O_CREAT | O_EXCL:
  4006. case O_CREAT | O_EXCL | O_TRUNC:
  4007. create = CREATE_NEW;
  4008. break;
  4009. case O_TRUNC:
  4010. case O_TRUNC | O_EXCL:
  4011. create = TRUNCATE_EXISTING;
  4012. break;
  4013. case O_CREAT | O_TRUNC:
  4014. create = CREATE_ALWAYS;
  4015. break;
  4016. default:
  4017. errno = EINVAL;
  4018. return -1;
  4019. }
  4020. if (oflag & O_CREAT) {
  4021. va_list arg;
  4022. int pmode;
  4023. va_start(arg, oflag);
  4024. pmode = va_arg(arg, int);
  4025. va_end(arg);
  4026. /* TODO: we need to check umask here, but it's not exported... */
  4027. if (!(pmode & S_IWRITE))
  4028. attr = FILE_ATTRIBUTE_READONLY;
  4029. }
  4030. oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
  4031. if (oflag & O_TEMPORARY) {
  4032. attr |= FILE_FLAG_DELETE_ON_CLOSE;
  4033. access |= DELETE;
  4034. }
  4035. oflag &= ~O_TEMPORARY;
  4036. if (oflag & _O_SHORT_LIVED)
  4037. attr |= FILE_ATTRIBUTE_TEMPORARY;
  4038. oflag &= ~_O_SHORT_LIVED;
  4039. switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
  4040. case 0:
  4041. break;
  4042. case O_SEQUENTIAL:
  4043. attr |= FILE_FLAG_SEQUENTIAL_SCAN;
  4044. break;
  4045. case O_RANDOM:
  4046. attr |= FILE_FLAG_RANDOM_ACCESS;
  4047. break;
  4048. default:
  4049. errno = EINVAL;
  4050. return -1;
  4051. }
  4052. oflag &= ~(O_SEQUENTIAL | O_RANDOM);
  4053. if (oflag & ~O_APPEND) {
  4054. errno = EINVAL;
  4055. return -1;
  4056. }
  4057. /* allocate a C Runtime file handle */
  4058. RUBY_CRITICAL({
  4059. h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
  4060. fd = _open_osfhandle((long)h, 0);
  4061. CloseHandle(h);
  4062. });
  4063. if (fd == -1) {
  4064. errno = EMFILE;
  4065. return -1;
  4066. }
  4067. RUBY_CRITICAL({
  4068. MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
  4069. _set_osfhnd(fd, (long)INVALID_HANDLE_VALUE);
  4070. _set_osflags(fd, 0);
  4071. /* open with FILE_FLAG_OVERLAPPED if have CancelIo */
  4072. if (cancel_io)
  4073. attr |= FILE_FLAG_OVERLAPPED;
  4074. h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec,
  4075. create, attr, NULL);
  4076. if (h == INVALID_HANDLE_VALUE) {
  4077. errno = map_errno(GetLastError());
  4078. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4079. fd = -1;
  4080. goto quit;
  4081. }
  4082. switch (GetFileType(h)) {
  4083. case FILE_TYPE_CHAR:
  4084. flags |= FDEV;
  4085. break;
  4086. case FILE_TYPE_PIPE:
  4087. flags |= FPIPE;
  4088. break;
  4089. case FILE_TYPE_UNKNOWN:
  4090. errno = map_errno(GetLastError());
  4091. CloseHandle(h);
  4092. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4093. fd = -1;
  4094. goto quit;
  4095. }
  4096. if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
  4097. flags |= FAPPEND;
  4098. _set_osfhnd(fd, (long)h);
  4099. _osfile(fd) = flags | FOPEN;
  4100. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4101. quit:
  4102. ;
  4103. });
  4104. return fd;
  4105. }
  4106. int
  4107. rb_w32_fclose(FILE *fp)
  4108. {
  4109. int fd = fileno(fp);
  4110. SOCKET sock = TO_SOCKET(fd);
  4111. int save_errno = errno;
  4112. if (fflush(fp)) return -1;
  4113. if (!is_socket(sock)) {
  4114. UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
  4115. return fclose(fp);
  4116. }
  4117. _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
  4118. fclose(fp);
  4119. errno = save_errno;
  4120. if (closesocket(sock) == SOCKET_ERROR) {
  4121. errno = map_errno(WSAGetLastError());
  4122. return -1;
  4123. }
  4124. return 0;
  4125. }
  4126. int
  4127. rb_w32_pipe(int fds[2])
  4128. {
  4129. static DWORD serial = 0;
  4130. char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
  4131. char *p;
  4132. SECURITY_ATTRIBUTES sec;
  4133. HANDLE hRead, hWrite, h;
  4134. int fdRead, fdWrite;
  4135. int ret;
  4136. /* if doesn't have CancelIo, use default pipe function */
  4137. if (!cancel_io)
  4138. return _pipe(fds, 65536L, _O_NOINHERIT);
  4139. p = strchr(name, '0');
  4140. snprintf(p, strlen(p) + 1, "%x-%lx", rb_w32_getpid(), serial++);
  4141. sec.nLength = sizeof(sec);
  4142. sec.lpSecurityDescriptor = NULL;
  4143. sec.bInheritHandle = FALSE;
  4144. RUBY_CRITICAL({
  4145. hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  4146. 0, 2, 65536, 65536, 0, &sec);
  4147. });
  4148. if (hRead == INVALID_HANDLE_VALUE) {
  4149. DWORD err = GetLastError();
  4150. if (err == ERROR_PIPE_BUSY)
  4151. errno = EMFILE;
  4152. else
  4153. errno = map_errno(GetLastError());
  4154. return -1;
  4155. }
  4156. RUBY_CRITICAL({
  4157. hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
  4158. OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
  4159. });
  4160. if (hWrite == INVALID_HANDLE_VALUE) {
  4161. errno = map_errno(GetLastError());
  4162. CloseHandle(hRead);
  4163. return -1;
  4164. }
  4165. RUBY_CRITICAL(do {
  4166. ret = 0;
  4167. h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
  4168. fdRead = _open_osfhandle((long)h, 0);
  4169. CloseHandle(h);
  4170. if (fdRead == -1) {
  4171. errno = EMFILE;
  4172. CloseHandle(hWrite);
  4173. CloseHandle(hRead);
  4174. ret = -1;
  4175. break;
  4176. }
  4177. MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock)));
  4178. _set_osfhnd(fdRead, (long)hRead);
  4179. _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
  4180. MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock)));
  4181. } while (0));
  4182. if (ret)
  4183. return ret;
  4184. RUBY_CRITICAL(do {
  4185. h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
  4186. fdWrite = _open_osfhandle((long)h, 0);
  4187. CloseHandle(h);
  4188. if (fdWrite == -1) {
  4189. errno = EMFILE;
  4190. CloseHandle(hWrite);
  4191. ret = -1;
  4192. break;
  4193. }
  4194. MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock)));
  4195. _set_osfhnd(fdWrite, (long)hWrite);
  4196. _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
  4197. MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock)));
  4198. } while (0));
  4199. if (ret) {
  4200. rb_w32_close(fdRead);
  4201. return ret;
  4202. }
  4203. fds[0] = fdRead;
  4204. fds[1] = fdWrite;
  4205. return 0;
  4206. }
  4207. int
  4208. rb_w32_close(int fd)
  4209. {
  4210. SOCKET sock = TO_SOCKET(fd);
  4211. int save_errno = errno;
  4212. st_data_t key;
  4213. if (!is_socket(sock)) {
  4214. UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
  4215. return _close(fd);
  4216. }
  4217. _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
  4218. key = (st_data_t)sock;
  4219. st_delete(socklist, &key, NULL);
  4220. sock = (SOCKET)key;
  4221. _close(fd);
  4222. errno = save_errno;
  4223. if (closesocket(sock) == SOCKET_ERROR) {
  4224. errno = map_errno(WSAGetLastError());
  4225. return -1;
  4226. }
  4227. return 0;
  4228. }
  4229. #undef read
  4230. size_t
  4231. rb_w32_read(int fd, void *buf, size_t size)
  4232. {
  4233. SOCKET sock = TO_SOCKET(fd);
  4234. DWORD read;
  4235. DWORD wait;
  4236. DWORD err;
  4237. OVERLAPPED ol, *pol = NULL;
  4238. if (is_socket(sock))
  4239. return rb_w32_recv(fd, buf, size, 0);
  4240. // validate fd by using _get_osfhandle() because we cannot access _nhandle
  4241. if (_get_osfhandle(fd) == -1) {
  4242. return -1;
  4243. }
  4244. if (_osfile(fd) & FTEXT) {
  4245. return _read(fd, buf, size);
  4246. }
  4247. MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
  4248. if (!size || _osfile(fd) & FEOFLAG) {
  4249. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4250. return 0;
  4251. }
  4252. /* if have cancel_io, use Overlapped I/O */
  4253. if (cancel_io) {
  4254. memset(&ol, 0, sizeof(ol));
  4255. if (!(_osfile(fd) & (FDEV | FPIPE))) {
  4256. LONG high = 0;
  4257. DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high,
  4258. FILE_CURRENT);
  4259. #ifndef INVALID_SET_FILE_POINTER
  4260. #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  4261. #endif
  4262. if (low == INVALID_SET_FILE_POINTER) {
  4263. errno = map_errno(GetLastError());
  4264. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4265. return -1;
  4266. }
  4267. ol.Offset = low;
  4268. ol.OffsetHigh = high;
  4269. }
  4270. ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  4271. if (!ol.hEvent) {
  4272. errno = map_errno(GetLastError());
  4273. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4274. return -1;
  4275. }
  4276. pol = &ol;
  4277. }
  4278. if (!ReadFile((HANDLE)_osfhnd(fd), buf, size, &read, pol)) {
  4279. err = GetLastError();
  4280. if (err != ERROR_IO_PENDING) {
  4281. if (err == ERROR_ACCESS_DENIED)
  4282. errno = EBADF;
  4283. else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
  4284. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4285. return 0;
  4286. }
  4287. else
  4288. errno = map_errno(err);
  4289. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4290. return -1;
  4291. }
  4292. if (pol) {
  4293. wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
  4294. if (wait != WAIT_OBJECT_0) {
  4295. if (wait == WAIT_OBJECT_0 + 1)
  4296. errno = EINTR;
  4297. else
  4298. errno = map_errno(GetLastError());
  4299. CloseHandle(ol.hEvent);
  4300. cancel_io((HANDLE)_osfhnd(fd));
  4301. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4302. return -1;
  4303. }
  4304. if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
  4305. (err = GetLastError()) != ERROR_HANDLE_EOF) {
  4306. int ret = 0;
  4307. if (err != ERROR_BROKEN_PIPE) {
  4308. errno = map_errno(err);
  4309. ret = -1;
  4310. }
  4311. CloseHandle(ol.hEvent);
  4312. cancel_io((HANDLE)_osfhnd(fd));
  4313. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4314. return ret;
  4315. }
  4316. }
  4317. }
  4318. if (pol) {
  4319. CloseHandle(ol.hEvent);
  4320. if (!(_osfile(fd) & (FDEV | FPIPE))) {
  4321. LONG high = ol.OffsetHigh;
  4322. DWORD low = ol.Offset + read;
  4323. if (low < ol.Offset)
  4324. ++high;
  4325. SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
  4326. }
  4327. }
  4328. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4329. return read;
  4330. }
  4331. #undef write
  4332. size_t
  4333. rb_w32_write(int fd, const void *buf, size_t size)
  4334. {
  4335. SOCKET sock = TO_SOCKET(fd);
  4336. DWORD written;
  4337. DWORD wait;
  4338. DWORD err;
  4339. size_t len;
  4340. size_t ret;
  4341. OVERLAPPED ol, *pol = NULL;
  4342. if (is_socket(sock))
  4343. return rb_w32_send(fd, buf, size, 0);
  4344. // validate fd by using _get_osfhandle() because we cannot access _nhandle
  4345. if (_get_osfhandle(fd) == -1) {
  4346. return -1;
  4347. }
  4348. if (_osfile(fd) & FTEXT) {
  4349. return _write(fd, buf, size);
  4350. }
  4351. MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
  4352. if (!size || _osfile(fd) & FEOFLAG) {
  4353. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4354. return 0;
  4355. }
  4356. ret = 0;
  4357. retry:
  4358. /* get rid of console writing bug */
  4359. len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size;
  4360. size -= len;
  4361. /* if have cancel_io, use Overlapped I/O */
  4362. if (cancel_io) {
  4363. memset(&ol, 0, sizeof(ol));
  4364. if (!(_osfile(fd) & (FDEV | FPIPE))) {
  4365. LONG high = 0;
  4366. DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
  4367. DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
  4368. #ifndef INVALID_SET_FILE_POINTER
  4369. #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  4370. #endif
  4371. if (low == INVALID_SET_FILE_POINTER) {
  4372. errno = map_errno(GetLastError());
  4373. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4374. return -1;
  4375. }
  4376. ol.Offset = low;
  4377. ol.OffsetHigh = high;
  4378. }
  4379. ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
  4380. if (!ol.hEvent) {
  4381. errno = map_errno(GetLastError());
  4382. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4383. return -1;
  4384. }
  4385. pol = &ol;
  4386. }
  4387. if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) {
  4388. err = GetLastError();
  4389. if (err != ERROR_IO_PENDING) {
  4390. if (err == ERROR_ACCESS_DENIED)
  4391. errno = EBADF;
  4392. else
  4393. errno = map_errno(err);
  4394. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4395. return -1;
  4396. }
  4397. if (pol) {
  4398. wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
  4399. if (wait != WAIT_OBJECT_0) {
  4400. if (wait == WAIT_OBJECT_0 + 1)
  4401. errno = EINTR;
  4402. else
  4403. errno = map_errno(GetLastError());
  4404. CloseHandle(ol.hEvent);
  4405. cancel_io((HANDLE)_osfhnd(fd));
  4406. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4407. return -1;
  4408. }
  4409. if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written,
  4410. TRUE)) {
  4411. errno = map_errno(err);
  4412. CloseHandle(ol.hEvent);
  4413. cancel_io((HANDLE)_osfhnd(fd));
  4414. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4415. return -1;
  4416. }
  4417. }
  4418. }
  4419. if (pol) {
  4420. CloseHandle(ol.hEvent);
  4421. if (!(_osfile(fd) & (FDEV | FPIPE))) {
  4422. LONG high = ol.OffsetHigh;
  4423. DWORD low = ol.Offset + written;
  4424. if (low < ol.Offset)
  4425. ++high;
  4426. SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
  4427. }
  4428. }
  4429. ret += written;
  4430. if (written == len) {
  4431. buf = (const char *)buf + len;
  4432. if (size > 0)
  4433. goto retry;
  4434. }
  4435. MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
  4436. return ret;
  4437. }
  4438. static int
  4439. unixtime_to_filetime(time_t time, FILETIME *ft)
  4440. {
  4441. struct tm *tm;
  4442. SYSTEMTIME st;
  4443. FILETIME lt;
  4444. tm = localtime(&time);
  4445. st.wYear = tm->tm_year + 1900;
  4446. st.wMonth = tm->tm_mon + 1;
  4447. st.wDayOfWeek = tm->tm_wday;
  4448. st.wDay = tm->tm_mday;
  4449. st.wHour = tm->tm_hour;
  4450. st.wMinute = tm->tm_min;
  4451. st.wSecond = tm->tm_sec;
  4452. st.wMilliseconds = 0;
  4453. if (!SystemTimeToFileTime(&st, &lt) ||
  4454. !LocalFileTimeToFileTime(&lt, ft)) {
  4455. errno = map_errno(GetLastError());
  4456. return -1;
  4457. }
  4458. return 0;
  4459. }
  4460. int
  4461. rb_w32_utime(const char *path, const struct utimbuf *times)
  4462. {
  4463. HANDLE hFile;
  4464. FILETIME atime, mtime;
  4465. struct stati64 stat;
  4466. int ret = 0;
  4467. if (rb_w32_stati64(path, &stat)) {
  4468. return -1;
  4469. }
  4470. if (times) {
  4471. if (unixtime_to_filetime(times->actime, &atime)) {
  4472. return -1;
  4473. }
  4474. if (unixtime_to_filetime(times->modtime, &mtime)) {
  4475. return -1;
  4476. }
  4477. }
  4478. else {
  4479. GetSystemTimeAsFileTime(&atime);
  4480. mtime = atime;
  4481. }
  4482. RUBY_CRITICAL({
  4483. const DWORD attr = GetFileAttributes(path);
  4484. if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
  4485. SetFileAttributes(path, attr & ~FILE_ATTRIBUTE_READONLY);
  4486. hFile = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
  4487. IsWin95() ? 0 : FILE_FLAG_BACKUP_SEMANTICS, 0);
  4488. if (hFile == INVALID_HANDLE_VALUE) {
  4489. errno = map_errno(GetLastError());
  4490. ret = -1;
  4491. }
  4492. else {
  4493. if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
  4494. errno = map_errno(GetLastError());
  4495. ret = -1;
  4496. }
  4497. CloseHandle(hFile);
  4498. }
  4499. if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
  4500. SetFileAttributes(path, attr);
  4501. });
  4502. return ret;
  4503. }
  4504. int
  4505. rb_w32_mkdir(const char *path, int mode)
  4506. {
  4507. int ret = -1;
  4508. RUBY_CRITICAL(do {
  4509. if (CreateDirectory(path, NULL) == FALSE) {
  4510. errno = map_errno(GetLastError());
  4511. break;
  4512. }
  4513. if (chmod(path, mode) == -1) {
  4514. RemoveDirectory(path);
  4515. break;
  4516. }
  4517. ret = 0;
  4518. } while (0));
  4519. return ret;
  4520. }
  4521. int
  4522. rb_w32_rmdir(const char *path)
  4523. {
  4524. int ret = 0;
  4525. RUBY_CRITICAL({
  4526. const DWORD attr = GetFileAttributes(path);
  4527. if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
  4528. SetFileAttributes(path, attr & ~FILE_ATTRIBUTE_READONLY);
  4529. }
  4530. if (RemoveDirectory(path) == FALSE) {
  4531. errno = map_errno(GetLastError());
  4532. ret = -1;
  4533. if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
  4534. SetFileAttributes(path, attr);
  4535. }
  4536. }
  4537. });
  4538. return ret;
  4539. }
  4540. int
  4541. rb_w32_unlink(const char *path)
  4542. {
  4543. int ret = 0;
  4544. RUBY_CRITICAL({
  4545. const DWORD attr = GetFileAttributes(path);
  4546. if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
  4547. SetFileAttributes(path, attr & ~FILE_ATTRIBUTE_READONLY);
  4548. }
  4549. if (DeleteFile(path) == FALSE) {
  4550. errno = map_errno(GetLastError());
  4551. ret = -1;
  4552. if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
  4553. SetFileAttributes(path, attr);
  4554. }
  4555. }
  4556. });
  4557. return ret;
  4558. }
  4559. #if !defined(__BORLANDC__)
  4560. int
  4561. rb_w32_isatty(int fd)
  4562. {
  4563. // validate fd by using _get_osfhandle() because we cannot access _nhandle
  4564. if (_get_osfhandle(fd) == -1) {
  4565. return 0;
  4566. }
  4567. if (!(_osfile(fd) & FDEV)) {
  4568. errno = ENOTTY;
  4569. return 0;
  4570. }
  4571. return 1;
  4572. }
  4573. #endif
  4574. //
  4575. // Fix bcc32's stdio bug
  4576. //
  4577. #ifdef __BORLANDC__
  4578. static int
  4579. too_many_files(void)
  4580. {
  4581. FILE *f;
  4582. for (f = _streams; f < _streams + _nfile; f++) {
  4583. if (f->fd < 0) return 0;
  4584. }
  4585. return 1;
  4586. }
  4587. #undef fopen
  4588. FILE *
  4589. rb_w32_fopen(const char *path, const char *mode)
  4590. {
  4591. FILE *f = (errno = 0, fopen(path, mode));
  4592. if (f == NULL && errno == 0) {
  4593. if (too_many_files())
  4594. errno = EMFILE;
  4595. }
  4596. return f;
  4597. }
  4598. FILE *
  4599. rb_w32_fdopen(int handle, const char *type)
  4600. {
  4601. FILE *f = (errno = 0, _fdopen(handle, (char *)type));
  4602. if (f == NULL && errno == 0) {
  4603. if (handle < 0)
  4604. errno = EBADF;
  4605. else if (too_many_files())
  4606. errno = EMFILE;
  4607. }
  4608. return f;
  4609. }
  4610. FILE *
  4611. rb_w32_fsopen(const char *path, const char *mode, int shflags)
  4612. {
  4613. FILE *f = (errno = 0, _fsopen(path, mode, shflags));
  4614. if (f == NULL && errno == 0) {
  4615. if (too_many_files())
  4616. errno = EMFILE;
  4617. }
  4618. return f;
  4619. }
  4620. #endif
  4621. #if defined(_MSC_VER) && RT_VER <= 60
  4622. extern long _ftol(double);
  4623. long
  4624. _ftol2(double d)
  4625. {
  4626. return _ftol(d);
  4627. }
  4628. long
  4629. _ftol2_sse(double d)
  4630. {
  4631. return _ftol(d);
  4632. }
  4633. #endif