PageRenderTime 94ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/win32/win32.c

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