Ruby  3.1.4p223 (2023-03-30 revision HEAD)
win32.c
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 /*
13  The parts licensed under above copyright notice are marked as "Artistic or
14  GPL".
15  Another parts are licensed under Ruby's License.
16 
17  Copyright (C) 1993-2011 Yukihiro Matsumoto
18  Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
19  Copyright (C) 2000 Information-technology Promotion Agency, Japan
20  */
21 
22 #undef __STRICT_ANSI__
23 
24 #include "ruby/ruby.h"
25 #include "ruby/encoding.h"
26 #include "ruby/io.h"
27 #include "ruby/util.h"
28 #include <fcntl.h>
29 #include <process.h>
30 #include <sys/stat.h>
31 /* #include <sys/wait.h> */
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <assert.h>
36 #include <ctype.h>
37 
38 #include <windows.h>
39 #include <winbase.h>
40 #include <wincon.h>
41 #include <share.h>
42 #include <shlobj.h>
43 #include <mbstring.h>
44 #include <shlwapi.h>
45 #if defined _MSC_VER && _MSC_VER >= 1400
46 #include <crtdbg.h>
47 #include <rtcapi.h>
48 #endif
49 #ifdef __MINGW32__
50 #include <mswsock.h>
51 #endif
52 #include "ruby/win32.h"
53 #include "ruby/vm.h"
54 #include "win32/dir.h"
55 #include "win32/file.h"
56 #include "id.h"
57 #include "internal.h"
58 #include "internal/enc.h"
59 #include "internal/object.h"
60 #include "internal/static_assert.h"
61 #include "ruby/internal/stdbool.h"
62 #include "encindex.h"
63 #define isdirsep(x) ((x) == '/' || (x) == '\\')
64 
65 #if defined _MSC_VER && _MSC_VER <= 1200
66 # define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags))
67 #endif
68 
69 static int w32_wopen(const WCHAR *file, int oflag, int perm);
70 static int w32_stati128(const char *path, struct stati128 *st, UINT cp, BOOL lstat);
71 static char *w32_getenv(const char *name, UINT cp);
72 
73 #undef getenv
74 /*
75  * Do not remove the macros to substitute functions in dln_find.c.
76  */
77 #define DLN_FIND_EXTRA_ARG_DECL ,UINT cp
78 #define DLN_FIND_EXTRA_ARG ,cp
79 #define rb_w32_stati128(path, st) w32_stati128(path, st, cp, FALSE)
80 #define getenv(name) w32_getenv(name, cp) /* Necessarily For dln.c */
81 #undef CharNext
82 #define CharNext(p) CharNextExA(cp, (p), 0)
83 #define dln_find_exe_r rb_w32_udln_find_exe_r
84 #define dln_find_file_r rb_w32_udln_find_file_r
85 #include "dln.h"
86 #include "dln_find.c"
87 #undef MAXPATHLEN
88 #undef rb_w32_stati128
89 #undef dln_find_exe_r
90 #undef dln_find_file_r
91 #define dln_find_exe_r(fname, path, buf, size) rb_w32_udln_find_exe_r(fname, path, buf, size, cp)
92 #define dln_find_file_r(fname, path, buf, size) rb_w32_udln_find_file_r(fname, path, buf, size, cp)
93 #undef CharNext /* no default cp version */
94 #undef getenv
95 
96 #ifndef PATH_MAX
97 # if defined MAX_PATH
98 # define PATH_MAX MAX_PATH
99 # elif defined HAVE_SYS_PARAM_H
100 # include <sys/param.h>
101 # define PATH_MAX MAXPATHLEN
102 # endif
103 #endif
104 #define ENV_MAX 512
105 
106 #undef stat
107 #undef fclose
108 #undef close
109 #undef setsockopt
110 #undef dup2
111 #undef strdup
112 
113 #if RUBY_MSVCRT_VERSION >= 140
114 # define _filbuf _fgetc_nolock
115 # define _flsbuf _fputc_nolock
116 #endif
117 #define enough_to_get(n) (--(n) >= 0)
118 #define enough_to_put(n) (--(n) >= 0)
119 
120 #ifdef WIN32_DEBUG
121 #define Debug(something) something
122 #else
123 #define Debug(something) /* nothing */
124 #endif
125 
126 #define TO_SOCKET(x) _get_osfhandle(x)
127 
128 int rb_w32_reparse_symlink_p(const WCHAR *path);
129 
130 static int has_redirection(const char *, UINT);
131 int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
132 static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
133 static int wstati128(const WCHAR *path, struct stati128 *st, BOOL lstat);
134 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
135 int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc);
136 static FARPROC get_proc_address(const char *module, const char *func, HANDLE *mh);
137 
138 #define RUBY_CRITICAL if (0) {} else /* just remark */
139 
140 /* errno mapping */
141 static const struct {
142  DWORD winerr;
143  int err;
144 } errmap[] = {
145  { ERROR_INVALID_FUNCTION, EINVAL },
146  { ERROR_FILE_NOT_FOUND, ENOENT },
147  { ERROR_PATH_NOT_FOUND, ENOENT },
148  { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
149  { ERROR_ACCESS_DENIED, EACCES },
150  { ERROR_INVALID_HANDLE, EBADF },
151  { ERROR_ARENA_TRASHED, ENOMEM },
152  { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
153  { ERROR_INVALID_BLOCK, ENOMEM },
154  { ERROR_BAD_ENVIRONMENT, E2BIG },
155  { ERROR_BAD_FORMAT, ENOEXEC },
156  { ERROR_INVALID_ACCESS, EINVAL },
157  { ERROR_INVALID_DATA, EINVAL },
158  { ERROR_INVALID_DRIVE, ENOENT },
159  { ERROR_CURRENT_DIRECTORY, EACCES },
160  { ERROR_NOT_SAME_DEVICE, EXDEV },
161  { ERROR_NO_MORE_FILES, ENOENT },
162  { ERROR_WRITE_PROTECT, EROFS },
163  { ERROR_BAD_UNIT, ENODEV },
164  { ERROR_NOT_READY, ENXIO },
165  { ERROR_BAD_COMMAND, EACCES },
166  { ERROR_CRC, EACCES },
167  { ERROR_BAD_LENGTH, EACCES },
168  { ERROR_SEEK, EIO },
169  { ERROR_NOT_DOS_DISK, EACCES },
170  { ERROR_SECTOR_NOT_FOUND, EACCES },
171  { ERROR_OUT_OF_PAPER, EACCES },
172  { ERROR_WRITE_FAULT, EIO },
173  { ERROR_READ_FAULT, EIO },
174  { ERROR_GEN_FAILURE, EACCES },
175  { ERROR_LOCK_VIOLATION, EACCES },
176  { ERROR_SHARING_VIOLATION, EACCES },
177  { ERROR_WRONG_DISK, EACCES },
178  { ERROR_SHARING_BUFFER_EXCEEDED, EACCES },
179  { ERROR_BAD_NETPATH, ENOENT },
180  { ERROR_NETWORK_ACCESS_DENIED, EACCES },
181  { ERROR_BAD_NET_NAME, ENOENT },
182  { ERROR_FILE_EXISTS, EEXIST },
183  { ERROR_CANNOT_MAKE, EACCES },
184  { ERROR_FAIL_I24, EACCES },
185  { ERROR_INVALID_PARAMETER, EINVAL },
186  { ERROR_NO_PROC_SLOTS, EAGAIN },
187  { ERROR_DRIVE_LOCKED, EACCES },
188  { ERROR_BROKEN_PIPE, EPIPE },
189  { ERROR_DISK_FULL, ENOSPC },
190  { ERROR_INVALID_TARGET_HANDLE, EBADF },
191  { ERROR_INVALID_HANDLE, EINVAL },
192  { ERROR_WAIT_NO_CHILDREN, ECHILD },
193  { ERROR_CHILD_NOT_COMPLETE, ECHILD },
194  { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
195  { ERROR_NEGATIVE_SEEK, EINVAL },
196  { ERROR_SEEK_ON_DEVICE, EACCES },
197  { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
198  { ERROR_DIRECTORY, ENOTDIR },
199  { ERROR_NOT_LOCKED, EACCES },
200  { ERROR_BAD_PATHNAME, ENOENT },
201  { ERROR_MAX_THRDS_REACHED, EAGAIN },
202  { ERROR_LOCK_FAILED, EACCES },
203  { ERROR_ALREADY_EXISTS, EEXIST },
204  { ERROR_INVALID_STARTING_CODESEG, ENOEXEC },
205  { ERROR_INVALID_STACKSEG, ENOEXEC },
206  { ERROR_INVALID_MODULETYPE, ENOEXEC },
207  { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC },
208  { ERROR_EXE_MARKED_INVALID, ENOEXEC },
209  { ERROR_BAD_EXE_FORMAT, ENOEXEC },
210  { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC },
211  { ERROR_INVALID_MINALLOCSIZE, ENOEXEC },
212  { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC },
213  { ERROR_IOPL_NOT_ENABLED, ENOEXEC },
214  { ERROR_INVALID_SEGDPL, ENOEXEC },
215  { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC },
216  { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC },
217  { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC },
218  { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC },
219  { ERROR_FILENAME_EXCED_RANGE, ENOENT },
220  { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
221 #ifndef ERROR_PIPE_LOCAL
222 #define ERROR_PIPE_LOCAL 229L
223 #endif
224  { ERROR_PIPE_LOCAL, EPIPE },
225  { ERROR_BAD_PIPE, EPIPE },
226  { ERROR_PIPE_BUSY, EAGAIN },
227  { ERROR_NO_DATA, EPIPE },
228  { ERROR_PIPE_NOT_CONNECTED, EPIPE },
229  { ERROR_OPERATION_ABORTED, EINTR },
230  { ERROR_NOT_ENOUGH_QUOTA, ENOMEM },
231  { ERROR_MOD_NOT_FOUND, ENOENT },
232  { ERROR_PRIVILEGE_NOT_HELD, EACCES, },
233  { ERROR_CANT_RESOLVE_FILENAME, ELOOP, },
234  { WSAEINTR, EINTR },
235  { WSAEBADF, EBADF },
236  { WSAEACCES, EACCES },
237  { WSAEFAULT, EFAULT },
238  { WSAEINVAL, EINVAL },
239  { WSAEMFILE, EMFILE },
240  { WSAEWOULDBLOCK, EWOULDBLOCK },
241  { WSAEINPROGRESS, EINPROGRESS },
242  { WSAEALREADY, EALREADY },
243  { WSAENOTSOCK, ENOTSOCK },
244  { WSAEDESTADDRREQ, EDESTADDRREQ },
245  { WSAEMSGSIZE, EMSGSIZE },
246  { WSAEPROTOTYPE, EPROTOTYPE },
247  { WSAENOPROTOOPT, ENOPROTOOPT },
248  { WSAEPROTONOSUPPORT, EPROTONOSUPPORT },
249  { WSAESOCKTNOSUPPORT, ESOCKTNOSUPPORT },
250  { WSAEOPNOTSUPP, EOPNOTSUPP },
251  { WSAEPFNOSUPPORT, EPFNOSUPPORT },
252  { WSAEAFNOSUPPORT, EAFNOSUPPORT },
253  { WSAEADDRINUSE, EADDRINUSE },
254  { WSAEADDRNOTAVAIL, EADDRNOTAVAIL },
255  { WSAENETDOWN, ENETDOWN },
256  { WSAENETUNREACH, ENETUNREACH },
257  { WSAENETRESET, ENETRESET },
258  { WSAECONNABORTED, ECONNABORTED },
259  { WSAECONNRESET, ECONNRESET },
260  { WSAENOBUFS, ENOBUFS },
261  { WSAEISCONN, EISCONN },
262  { WSAENOTCONN, ENOTCONN },
263  { WSAESHUTDOWN, ESHUTDOWN },
264  { WSAETOOMANYREFS, ETOOMANYREFS },
265  { WSAETIMEDOUT, ETIMEDOUT },
266  { WSAECONNREFUSED, ECONNREFUSED },
267  { WSAELOOP, ELOOP },
268  { WSAENAMETOOLONG, ENAMETOOLONG },
269  { WSAEHOSTDOWN, EHOSTDOWN },
270  { WSAEHOSTUNREACH, EHOSTUNREACH },
271  { WSAEPROCLIM, EPROCLIM },
272  { WSAENOTEMPTY, ENOTEMPTY },
273  { WSAEUSERS, EUSERS },
274  { WSAEDQUOT, EDQUOT },
275  { WSAESTALE, ESTALE },
276  { WSAEREMOTE, EREMOTE },
277 };
278 
279 /* License: Ruby's */
280 int
281 rb_w32_map_errno(DWORD winerr)
282 {
283  int i;
284 
285  if (winerr == 0) {
286  return 0;
287  }
288 
289  for (i = 0; i < (int)(sizeof(errmap) / sizeof(*errmap)); i++) {
290  if (errmap[i].winerr == winerr) {
291  return errmap[i].err;
292  }
293  }
294 
295  if (winerr >= WSABASEERR) {
296  return winerr;
297  }
298  return EINVAL;
299 }
300 
301 #define map_errno rb_w32_map_errno
302 
303 static const char *NTLoginName;
304 
305 static OSVERSIONINFO osver;
306 
307 /* License: Artistic or GPL */
308 static void
309 get_version(void)
310 {
311  memset(&osver, 0, sizeof(OSVERSIONINFO));
312  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
313  GetVersionEx(&osver);
314 }
315 
316 #ifdef _M_IX86
317 /* License: Artistic or GPL */
318 DWORD
319 rb_w32_osid(void)
320 {
321  return osver.dwPlatformId;
322 }
323 #endif
324 
325 /* License: Artistic or GPL */
326 DWORD
327 rb_w32_osver(void)
328 {
329  return osver.dwMajorVersion;
330 }
331 
332 /* simulate flock by locking a range on the file */
333 
334 /* License: Artistic or GPL */
335 #define LK_ERR(f,i) \
336  do { \
337  if (f) \
338  i = 0; \
339  else { \
340  DWORD err = GetLastError(); \
341  if (err == ERROR_LOCK_VIOLATION || err == ERROR_IO_PENDING) \
342  errno = EWOULDBLOCK; \
343  else if (err == ERROR_NOT_LOCKED) \
344  i = 0; \
345  else \
346  errno = map_errno(err); \
347  } \
348  } while (0)
349 #define LK_LEN ULONG_MAX
350 
351 /* License: Artistic or GPL */
352 static uintptr_t
353 flock_winnt(uintptr_t self, int argc, uintptr_t* argv)
354 {
355  OVERLAPPED o;
356  int i = -1;
357  const HANDLE fh = (HANDLE)self;
358  const int oper = argc;
359 
360  memset(&o, 0, sizeof(o));
361 
362  switch (oper) {
363  case LOCK_SH: /* shared lock */
364  LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, LK_LEN, &o), i);
365  break;
366  case LOCK_EX: /* exclusive lock */
367  LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, LK_LEN, &o), i);
368  break;
369  case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
370  LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i);
371  break;
372  case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
373  LK_ERR(LockFileEx(fh,
374  LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
375  0, LK_LEN, LK_LEN, &o), i);
376  break;
377  case LOCK_UN: /* unlock lock */
378  case LOCK_UN|LOCK_NB: /* unlock is always non-blocking, I hope */
379  LK_ERR(UnlockFileEx(fh, 0, LK_LEN, LK_LEN, &o), i);
380  break;
381  default: /* unknown */
382  errno = EINVAL;
383  break;
384  }
385  return i;
386 }
387 
388 #undef LK_ERR
389 
390 /* License: Artistic or GPL */
391 int
392 flock(int fd, int oper)
393 {
394  const asynchronous_func_t locker = flock_winnt;
395 
396  return rb_w32_asynchronize(locker,
397  (VALUE)_get_osfhandle(fd), oper, NULL,
398  (DWORD)-1);
399 }
400 
401 /* License: Ruby's */
402 static inline WCHAR *
403 translate_wchar(WCHAR *p, int from, int to)
404 {
405  for (; *p; p++) {
406  if (*p == from)
407  *p = to;
408  }
409  return p;
410 }
411 
412 /* License: Ruby's */
413 static inline char *
414 translate_char(char *p, int from, int to, UINT cp)
415 {
416  while (*p) {
417  if ((unsigned char)*p == from)
418  *p = to;
419  p = CharNextExA(cp, p, 0);
420  }
421  return p;
422 }
423 
424 #ifndef CSIDL_LOCAL_APPDATA
425 #define CSIDL_LOCAL_APPDATA 28
426 #endif
427 #ifndef CSIDL_COMMON_APPDATA
428 #define CSIDL_COMMON_APPDATA 35
429 #endif
430 #ifndef CSIDL_WINDOWS
431 #define CSIDL_WINDOWS 36
432 #endif
433 #ifndef CSIDL_SYSTEM
434 #define CSIDL_SYSTEM 37
435 #endif
436 #ifndef CSIDL_PROFILE
437 #define CSIDL_PROFILE 40
438 #endif
439 
440 /* License: Ruby's */
441 static BOOL
442 get_special_folder(int n, WCHAR *buf, size_t len)
443 {
444  LPITEMIDLIST pidl;
445  LPMALLOC alloc;
446  BOOL f = FALSE;
447  typedef BOOL (WINAPI *get_path_func)(LPITEMIDLIST, WCHAR*, DWORD, int);
448  static get_path_func func = (get_path_func)-1;
449 
450  if (func == (get_path_func)-1) {
451  func = (get_path_func)
452  get_proc_address("shell32", "SHGetPathFromIDListEx", NULL);
453  }
454  if (!func && len < MAX_PATH) return FALSE;
455 
456  if (SHGetSpecialFolderLocation(NULL, n, &pidl) == 0) {
457  if (func) {
458  f = func(pidl, buf, len, 0);
459  }
460  else {
461  f = SHGetPathFromIDListW(pidl, buf);
462  }
463  SHGetMalloc(&alloc);
464  alloc->lpVtbl->Free(alloc, pidl);
465  alloc->lpVtbl->Release(alloc);
466  }
467  return f;
468 }
469 
470 /* License: Ruby's */
471 static void
472 regulate_path(WCHAR *path)
473 {
474  WCHAR *p = translate_wchar(path, L'\\', L'/');
475  if (p - path == 2 && path[1] == L':') {
476  *p++ = L'/';
477  *p = L'\0';
478  }
479 }
480 
481 /* License: Ruby's */
482 static FARPROC
483 get_proc_address(const char *module, const char *func, HANDLE *mh)
484 {
485  HANDLE h;
486  FARPROC ptr;
487 
488  if (mh)
489  h = LoadLibrary(module);
490  else
491  h = GetModuleHandle(module);
492  if (!h)
493  return NULL;
494 
495  ptr = GetProcAddress(h, func);
496  if (mh) {
497  if (ptr)
498  *mh = h;
499  else
500  FreeLibrary(h);
501  }
502  return ptr;
503 }
504 
505 /* License: Ruby's */
506 VALUE
507 rb_w32_special_folder(int type)
508 {
509  WCHAR path[PATH_MAX];
510 
511  if (!get_special_folder(type, path, numberof(path))) return Qnil;
512  regulate_path(path);
513  return rb_w32_conv_from_wchar(path, rb_filesystem_encoding());
514 }
515 
516 #if defined _MSC_VER && _MSC_VER <= 1200
517 /* License: Ruby's */
518 #define GetSystemWindowsDirectoryW GetWindowsDirectoryW
519 #endif
520 
521 /* License: Ruby's */
522 UINT
523 rb_w32_system_tmpdir(WCHAR *path, UINT len)
524 {
525  static const WCHAR temp[] = L"temp";
526  WCHAR *p;
527 
528  if (!get_special_folder(CSIDL_LOCAL_APPDATA, path, len)) {
529  if (GetSystemWindowsDirectoryW(path, len)) return 0;
530  }
531  p = translate_wchar(path, L'\\', L'/');
532  if (*(p - 1) != L'/') *p++ = L'/';
533  if ((UINT)(p - path + numberof(temp)) >= len) return 0;
534  memcpy(p, temp, sizeof(temp));
535  return (UINT)(p - path + numberof(temp) - 1);
536 }
537 
538 /*
539  Return user's home directory using environment variables combinations.
540  Memory allocated by this function should be manually freed
541  afterwards with xfree.
542 
543  Try:
544  HOME, HOMEDRIVE + HOMEPATH and USERPROFILE environment variables
545  Special Folders - Profile and Personal
546 */
547 WCHAR *
548 rb_w32_home_dir(void)
549 {
550  WCHAR *buffer = NULL;
551  size_t buffer_len = MAX_PATH, len = 0;
552  enum {
553  HOME_NONE, ENV_HOME, ENV_DRIVEPATH, ENV_USERPROFILE
554  } home_type = HOME_NONE;
555 
556  if ((len = GetEnvironmentVariableW(L"HOME", NULL, 0)) != 0) {
557  buffer_len = len;
558  home_type = ENV_HOME;
559  }
560  else if ((len = GetEnvironmentVariableW(L"HOMEDRIVE", NULL, 0)) != 0) {
561  buffer_len = len;
562  if ((len = GetEnvironmentVariableW(L"HOMEPATH", NULL, 0)) != 0) {
563  buffer_len += len;
564  home_type = ENV_DRIVEPATH;
565  }
566  }
567  else if ((len = GetEnvironmentVariableW(L"USERPROFILE", NULL, 0)) != 0) {
568  buffer_len = len;
569  home_type = ENV_USERPROFILE;
570  }
571 
572  /* allocate buffer */
573  buffer = ALLOC_N(WCHAR, buffer_len);
574 
575  switch (home_type) {
576  case ENV_HOME:
577  GetEnvironmentVariableW(L"HOME", buffer, buffer_len);
578  break;
579  case ENV_DRIVEPATH:
580  len = GetEnvironmentVariableW(L"HOMEDRIVE", buffer, buffer_len);
581  GetEnvironmentVariableW(L"HOMEPATH", buffer + len, buffer_len - len);
582  break;
583  case ENV_USERPROFILE:
584  GetEnvironmentVariableW(L"USERPROFILE", buffer, buffer_len);
585  break;
586  default:
587  if (!get_special_folder(CSIDL_PROFILE, buffer, buffer_len) &&
588  !get_special_folder(CSIDL_PERSONAL, buffer, buffer_len)) {
589  xfree(buffer);
590  return NULL;
591  }
592  REALLOC_N(buffer, WCHAR, lstrlenW(buffer) + 1);
593  break;
594  }
595 
596  /* sanitize backslashes with forwardslashes */
597  regulate_path(buffer);
598 
599  return buffer;
600 }
601 
602 /* License: Ruby's */
603 static void
604 init_env(void)
605 {
606  static const WCHAR TMPDIR[] = L"TMPDIR";
607  struct {WCHAR name[6], eq, val[ENV_MAX];} wk;
608  DWORD len;
609  BOOL f;
610 #define env wk.val
611 #define set_env_val(vname) do { \
612  typedef char wk_name_offset[(numberof(wk.name) - (numberof(vname) - 1)) * 2 + 1]; \
613  WCHAR *const buf = wk.name + sizeof(wk_name_offset) / 2; \
614  MEMCPY(buf, vname, WCHAR, numberof(vname) - 1); \
615  _wputenv(buf); \
616  } while (0)
617 
618  wk.eq = L'=';
619 
620  if (!GetEnvironmentVariableW(L"HOME", env, numberof(env))) {
621  f = FALSE;
622  if (GetEnvironmentVariableW(L"HOMEDRIVE", env, numberof(env)))
623  len = lstrlenW(env);
624  else
625  len = 0;
626  if (GetEnvironmentVariableW(L"HOMEPATH", env + len, numberof(env) - len) || len) {
627  f = TRUE;
628  }
629  else if (GetEnvironmentVariableW(L"USERPROFILE", env, numberof(env))) {
630  f = TRUE;
631  }
632  else if (get_special_folder(CSIDL_PROFILE, env, numberof(env))) {
633  f = TRUE;
634  }
635  else if (get_special_folder(CSIDL_PERSONAL, env, numberof(env))) {
636  f = TRUE;
637  }
638  if (f) {
639  regulate_path(env);
640  set_env_val(L"HOME");
641  }
642  }
643 
644  if (!GetEnvironmentVariableW(L"USER", env, numberof(env))) {
645  if (!GetEnvironmentVariableW(L"USERNAME", env, numberof(env)) &&
646  !GetUserNameW(env, (len = numberof(env), &len))) {
647  NTLoginName = "<Unknown>";
648  }
649  else {
650  set_env_val(L"USER");
651  NTLoginName = rb_w32_wstr_to_mbstr(CP_UTF8, env, -1, NULL);
652  }
653  }
654  else {
655  NTLoginName = rb_w32_wstr_to_mbstr(CP_UTF8, env, -1, NULL);
656  }
657 
658  if (!GetEnvironmentVariableW(TMPDIR, env, numberof(env)) &&
659  !GetEnvironmentVariableW(L"TMP", env, numberof(env)) &&
660  !GetEnvironmentVariableW(L"TEMP", env, numberof(env)) &&
661  rb_w32_system_tmpdir(env, numberof(env))) {
662  set_env_val(TMPDIR);
663  }
664 
665 #undef env
666 #undef set_env_val
667 }
668 
669 static void init_stdhandle(void);
670 
671 #if RUBY_MSVCRT_VERSION >= 80
672 /* License: Ruby's */
673 static void
674 invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, unsigned int line, uintptr_t dummy)
675 {
676  // nothing to do
677 }
678 
679 int ruby_w32_rtc_error;
680 
681 /* License: Ruby's */
682 static int __cdecl
683 rtc_error_handler(int e, const char *src, int line, const char *exe, const char *fmt, ...)
684 {
685  va_list ap;
686  VALUE str;
687 
688  if (!ruby_w32_rtc_error) return 0;
689  str = rb_sprintf("%s:%d: ", src, line);
690  va_start(ap, fmt);
691  rb_str_vcatf(str, fmt, ap);
692  va_end(ap);
693  rb_str_cat(str, "\n", 1);
695  return 0;
696 }
697 #endif
698 
699 static CRITICAL_SECTION select_mutex;
700 
701 static CRITICAL_SECTION socklist_mutex;
702 static st_table *socklist = NULL;
703 
704 static CRITICAL_SECTION conlist_mutex;
705 static st_table *conlist = NULL;
706 #define conlist_disabled ((st_table *)-1)
707 
708 #define thread_exclusive(obj) \
709  for (bool exclusive_for_##obj = (EnterCriticalSection(&obj##_mutex), true); \
710  exclusive_for_##obj; \
711  exclusive_for_##obj = (LeaveCriticalSection(&obj##_mutex), false))
712 
713 static CRITICAL_SECTION uenvarea_mutex;
714 static char *uenvarea;
715 
716 /* License: Ruby's */
717 struct constat {
718  struct {
719  int state, seq[16], reverse;
720  WORD attr;
721  COORD saved;
722  } vt100;
723 };
724 enum {constat_init = -2, constat_esc = -1, constat_seq = 0};
725 
726 /* License: Ruby's */
727 static int
728 free_conlist(st_data_t key, st_data_t val, st_data_t arg)
729 {
730  xfree((struct constat *)val);
731  return ST_DELETE;
732 }
733 
734 /* License: Ruby's */
735 static void
736 constat_delete(HANDLE h)
737 {
738  thread_exclusive(conlist) {
739  if (conlist && conlist != conlist_disabled) {
740  st_data_t key = (st_data_t)h, val;
741  st_delete(conlist, &key, &val);
742  xfree((struct constat *)val);
743  }
744  }
745 }
746 
747 /* License: Ruby's */
748 static void
749 exit_handler(void)
750 {
751  WSACleanup();
752  DeleteCriticalSection(&select_mutex);
753  DeleteCriticalSection(&socklist_mutex);
754  DeleteCriticalSection(&conlist_mutex);
755  thread_exclusive(uenvarea) {
756  if (uenvarea) {
757  free(uenvarea);
758  uenvarea = NULL;
759  }
760  }
761  DeleteCriticalSection(&uenvarea_mutex);
762 }
763 
764 /* License: Ruby's */
765 static void
766 vm_exit_handler(ruby_vm_t *vm)
767 {
768  EnterCriticalSection(&socklist_mutex);
769  if (socklist) {
770  st_free_table(socklist);
771  socklist = NULL;
772  }
773  LeaveCriticalSection(&socklist_mutex);
774 
775  EnterCriticalSection(&conlist_mutex);
776  if (conlist && conlist != conlist_disabled) {
777  st_foreach(conlist, free_conlist, 0);
778  st_free_table(conlist);
779  conlist = NULL;
780  }
781  LeaveCriticalSection(&conlist_mutex);
782 }
783 
784 #define ATOMIC_LONG_CAS(var, oldval, newval) InterlockedCompareExchange(&(var), (newval), (oldval))
785 
786 /* License: Ruby's */
787 static void
788 install_vm_exit_handler(void)
789 {
790  static LONG installed = 0;
791  LONG i;
792 
793  while ((i = ATOMIC_LONG_CAS(installed, 0, -1)) != 1) {
794  if (i != 0) {
795  Sleep(1);
796  continue;
797  }
798  ruby_vm_at_exit(vm_exit_handler);
799  ATOMIC_LONG_CAS(installed, -1, 1);
800  break;
801  }
802 }
803 
804 /* License: Artistic or GPL */
805 static void
806 StartSockets(void)
807 {
808  WORD version;
809  WSADATA retdata;
810 
811  //
812  // initialize the winsock interface and insure that it's
813  // cleaned up at exit.
814  //
815  version = MAKEWORD(2, 0);
816  if (WSAStartup(version, &retdata))
817  rb_fatal("Unable to locate winsock library!");
818  if (LOBYTE(retdata.wVersion) != 2)
819  rb_fatal("could not find version 2 of winsock dll");
820 
821  InitializeCriticalSection(&select_mutex);
822  InitializeCriticalSection(&socklist_mutex);
823  InitializeCriticalSection(&conlist_mutex);
824 
825  atexit(exit_handler);
826 }
827 
828 #define MAKE_SOCKDATA(af, fl) ((int)((((int)af)<<4)|((fl)&0xFFFF)))
829 #define GET_FAMILY(v) ((int)(((v)>>4)&0xFFFF))
830 #define GET_FLAGS(v) ((int)((v)&0xFFFF))
831 
832 /* License: Ruby's */
833 static inline int
834 socklist_insert(SOCKET sock, int flag)
835 {
836  int ret;
837 
838  thread_exclusive(socklist) {
839  if (!socklist) {
840  socklist = st_init_numtable();
841  install_vm_exit_handler();
842  }
843  ret = st_insert(socklist, (st_data_t)sock, (st_data_t)flag);
844  }
845 
846  return ret;
847 }
848 
849 /* License: Ruby's */
850 static inline int
851 socklist_lookup(SOCKET sock, int *flagp)
852 {
853  st_data_t data;
854  int ret = 0;
855 
856  thread_exclusive(socklist) {
857  if (!socklist) continue;
858  ret = st_lookup(socklist, (st_data_t)sock, (st_data_t *)&data);
859  if (ret && flagp)
860  *flagp = (int)data;
861  }
862 
863  return ret;
864 }
865 
866 /* License: Ruby's */
867 static inline int
868 socklist_delete(SOCKET *sockp, int *flagp)
869 {
870  st_data_t key;
871  st_data_t data;
872  int ret = 0;
873 
874  thread_exclusive(socklist) {
875  if (!socklist) continue;
876  key = (st_data_t)*sockp;
877  if (flagp)
878  data = (st_data_t)*flagp;
879  ret = st_delete(socklist, &key, &data);
880  if (ret) {
881  *sockp = (SOCKET)key;
882  if (flagp)
883  *flagp = (int)data;
884  }
885  }
886 
887  return ret;
888 }
889 
890 #if RUBY_MSVCRT_VERSION >= 80
891 # ifdef __MINGW32__
892 # define _CrtSetReportMode(type,mode) ((void)0)
893 # define _RTC_SetErrorFunc(func) ((void)0)
894 # endif
895 static void set_pioinfo_extra(void);
896 #endif
897 static int w32_cmdvector(const WCHAR *, char ***, UINT, rb_encoding *);
898 //
899 // Initialization stuff
900 //
901 /* License: Ruby's */
902 void
903 rb_w32_sysinit(int *argc, char ***argv)
904 {
905 #if RUBY_MSVCRT_VERSION >= 80
906 
907  _CrtSetReportMode(_CRT_ASSERT, 0);
908  _set_invalid_parameter_handler(invalid_parameter);
909  _RTC_SetErrorFunc(rtc_error_handler);
910  set_pioinfo_extra();
911 #endif
912  SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
913 
914  get_version();
915 
916  //
917  // subvert cmd.exe's feeble attempt at command line parsing
918  //
919  *argc = w32_cmdvector(GetCommandLineW(), argv, CP_UTF8, &OnigEncodingUTF_8);
920 
921  //
922  // Now set up the correct time stuff
923  //
924 
925  tzset();
926 
927  InitializeCriticalSection(&uenvarea_mutex);
928  init_env();
929 
930  init_stdhandle();
931 
932  // Initialize Winsock
933  StartSockets();
934 }
935 
936 char *
937 getlogin(void)
938 {
939  return (char *)NTLoginName;
940 }
941 
942 #define MAXCHILDNUM 256 /* max num of child processes */
943 
944 /* License: Ruby's */
945 static struct ChildRecord {
946  HANDLE hProcess; /* process handle */
947  rb_pid_t pid; /* process id */
948 } ChildRecord[MAXCHILDNUM];
949 
950 /* License: Ruby's */
951 #define FOREACH_CHILD(v) do { \
952  struct ChildRecord* v; \
953  for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
954 #define END_FOREACH_CHILD } while (0)
955 
956 /* License: Ruby's */
957 static struct ChildRecord *
958 FindChildSlot(rb_pid_t pid)
959 {
960 
961  FOREACH_CHILD(child) {
962  if (child->pid == pid) {
963  return child;
964  }
965  } END_FOREACH_CHILD;
966  return NULL;
967 }
968 
969 /* License: Ruby's */
970 static struct ChildRecord *
971 FindChildSlotByHandle(HANDLE h)
972 {
973 
974  FOREACH_CHILD(child) {
975  if (child->hProcess == h) {
976  return child;
977  }
978  } END_FOREACH_CHILD;
979  return NULL;
980 }
981 
982 /* License: Ruby's */
983 static void
984 CloseChildHandle(struct ChildRecord *child)
985 {
986  HANDLE h = child->hProcess;
987  child->hProcess = NULL;
988  child->pid = 0;
989  CloseHandle(h);
990 }
991 
992 /* License: Ruby's */
993 static struct ChildRecord *
994 FindFreeChildSlot(void)
995 {
996  FOREACH_CHILD(child) {
997  if (!child->pid) {
998  child->pid = -1; /* lock the slot */
999  child->hProcess = NULL;
1000  return child;
1001  }
1002  } END_FOREACH_CHILD;
1003  return NULL;
1004 }
1005 
1006 
1007 /*
1008  ruby -lne 'BEGIN{$cmds = Hash.new(0); $mask = 1}'
1009  -e '$cmds[$_.downcase] |= $mask' -e '$mask <<= 1 if ARGF.eof'
1010  -e 'END{$cmds.sort.each{|n,f|puts " \"\\#{f.to_s(8)}\" #{n.dump} + 1,"}}'
1011  98cmd ntcmd
1012  */
1013 #define InternalCmdsMax 8
1014 static const char szInternalCmds[][InternalCmdsMax+2] = {
1015  "\2" "assoc",
1016  "\3" "break",
1017  "\3" "call",
1018  "\3" "cd",
1019  "\1" "chcp",
1020  "\3" "chdir",
1021  "\3" "cls",
1022  "\2" "color",
1023  "\3" "copy",
1024  "\1" "ctty",
1025  "\3" "date",
1026  "\3" "del",
1027  "\3" "dir",
1028  "\3" "echo",
1029  "\2" "endlocal",
1030  "\3" "erase",
1031  "\3" "exit",
1032  "\3" "for",
1033  "\2" "ftype",
1034  "\3" "goto",
1035  "\3" "if",
1036  "\1" "lfnfor",
1037  "\1" "lh",
1038  "\1" "lock",
1039  "\3" "md",
1040  "\3" "mkdir",
1041  "\2" "move",
1042  "\3" "path",
1043  "\3" "pause",
1044  "\2" "popd",
1045  "\3" "prompt",
1046  "\2" "pushd",
1047  "\3" "rd",
1048  "\3" "rem",
1049  "\3" "ren",
1050  "\3" "rename",
1051  "\3" "rmdir",
1052  "\3" "set",
1053  "\2" "setlocal",
1054  "\3" "shift",
1055  "\2" "start",
1056  "\3" "time",
1057  "\2" "title",
1058  "\1" "truename",
1059  "\3" "type",
1060  "\1" "unlock",
1061  "\3" "ver",
1062  "\3" "verify",
1063  "\3" "vol",
1064 };
1065 
1066 /* License: Ruby's */
1067 static int
1068 internal_match(const void *key, const void *elem)
1069 {
1070  return strncmp(key, ((const char *)elem) + 1, InternalCmdsMax);
1071 }
1072 
1073 /* License: Ruby's */
1074 static int
1075 is_command_com(const char *interp)
1076 {
1077  int i = strlen(interp) - 11;
1078 
1079  if ((i == 0 || (i > 0 && isdirsep(interp[i-1]))) &&
1080  strcasecmp(interp+i, "command.com") == 0) {
1081  return 1;
1082  }
1083  return 0;
1084 }
1085 
1086 static int internal_cmd_match(const char *cmdname, int nt);
1087 
1088 /* License: Ruby's */
1089 static int
1090 is_internal_cmd(const char *cmd, int nt)
1091 {
1092  char cmdname[9], *b = cmdname, c;
1093 
1094  do {
1095  if (!(c = *cmd++)) return 0;
1096  } while (isspace(c));
1097  if (c == '@')
1098  return 1;
1099  while (isalpha(c)) {
1100  *b++ = tolower(c);
1101  if (b == cmdname + sizeof(cmdname)) return 0;
1102  c = *cmd++;
1103  }
1104  if (c == '.') c = *cmd;
1105  switch (c) {
1106  case '<': case '>': case '|':
1107  return 1;
1108  case '\0': case ' ': case '\t': case '\n':
1109  break;
1110  default:
1111  return 0;
1112  }
1113  *b = 0;
1114  return internal_cmd_match(cmdname, nt);
1115 }
1116 
1117 /* License: Ruby's */
1118 static int
1119 internal_cmd_match(const char *cmdname, int nt)
1120 {
1121  char *nm;
1122 
1123  nm = bsearch(cmdname, szInternalCmds,
1124  sizeof(szInternalCmds) / sizeof(*szInternalCmds),
1125  sizeof(*szInternalCmds),
1126  internal_match);
1127  if (!nm || !(nm[0] & (nt ? 2 : 1)))
1128  return 0;
1129  return 1;
1130 }
1131 
1132 /* License: Ruby's */
1133 SOCKET
1134 rb_w32_get_osfhandle(int fh)
1135 {
1136  return _get_osfhandle(fh);
1137 }
1138 
1139 /* License: Ruby's */
1140 static int
1141 join_argv(char *cmd, char *const *argv, BOOL escape, UINT cp, int backslash)
1142 {
1143  const char *p, *s;
1144  char *q, *const *t;
1145  int len, n, bs, quote;
1146 
1147  for (t = argv, q = cmd, len = 0; (p = *t) != 0; t++) {
1148  quote = 0;
1149  s = p;
1150  if (!*p || strpbrk(p, " \t\"'")) {
1151  quote = 1;
1152  len++;
1153  if (q) *q++ = '"';
1154  }
1155  for (bs = 0; *p; ++p) {
1156  switch (*p) {
1157  case '\\':
1158  ++bs;
1159  break;
1160  case '"':
1161  len += n = p - s;
1162  if (q) {
1163  memcpy(q, s, n);
1164  q += n;
1165  }
1166  s = p;
1167  len += ++bs;
1168  if (q) {
1169  memset(q, '\\', bs);
1170  q += bs;
1171  }
1172  bs = 0;
1173  break;
1174  case '<': case '>': case '|': case '^':
1175  if (escape && !quote) {
1176  len += (n = p - s) + 1;
1177  if (q) {
1178  memcpy(q, s, n);
1179  q += n;
1180  *q++ = '^';
1181  }
1182  s = p;
1183  break;
1184  }
1185  default:
1186  bs = 0;
1187  p = CharNextExA(cp, p, 0) - 1;
1188  break;
1189  }
1190  }
1191  len += (n = p - s) + 1;
1192  if (quote) len++;
1193  if (q) {
1194  memcpy(q, s, n);
1195  if (backslash > 0) {
1196  --backslash;
1197  q[n] = 0;
1198  translate_char(q, '/', '\\', cp);
1199  }
1200  q += n;
1201  if (quote) *q++ = '"';
1202  *q++ = ' ';
1203  }
1204  }
1205  if (q > cmd) --len;
1206  if (q) {
1207  if (q > cmd) --q;
1208  *q = '\0';
1209  }
1210  return len;
1211 }
1212 
1213 /* License: Ruby's */
1214 #define STRNDUPV(ptr, v, src, len) \
1215  (((char *)memcpy(((ptr) = ALLOCV((v), (len) + 1)), (src), (len)))[len] = 0)
1216 
1217 /* License: Ruby's */
1218 static int
1219 check_spawn_mode(int mode)
1220 {
1221  switch (mode) {
1222  case P_NOWAIT:
1223  case P_OVERLAY:
1224  return 0;
1225  default:
1226  errno = EINVAL;
1227  return -1;
1228  }
1229 }
1230 
1231 /* License: Ruby's */
1232 static rb_pid_t
1233 child_result(struct ChildRecord *child, int mode)
1234 {
1235  DWORD exitcode;
1236 
1237  if (!child) {
1238  return -1;
1239  }
1240 
1241  if (mode == P_OVERLAY) {
1242  WaitForSingleObject(child->hProcess, INFINITE);
1243  GetExitCodeProcess(child->hProcess, &exitcode);
1244  CloseChildHandle(child);
1245  _exit(exitcode);
1246  }
1247  return child->pid;
1248 }
1249 
1250 /* License: Ruby's */
1251 static int
1252 CreateChild(struct ChildRecord *child, const WCHAR *cmd, const WCHAR *prog, HANDLE hInput, HANDLE hOutput, HANDLE hError, DWORD dwCreationFlags)
1253 {
1254  BOOL fRet;
1255  STARTUPINFOW aStartupInfo;
1256  PROCESS_INFORMATION aProcessInformation;
1257  SECURITY_ATTRIBUTES sa;
1258 
1259  if (!cmd && !prog) {
1260  errno = EFAULT;
1261  return FALSE;
1262  }
1263 
1264  if (!child) {
1265  errno = EAGAIN;
1266  return FALSE;
1267  }
1268 
1269  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1270  sa.lpSecurityDescriptor = NULL;
1271  sa.bInheritHandle = TRUE;
1272 
1273  memset(&aStartupInfo, 0, sizeof(aStartupInfo));
1274  memset(&aProcessInformation, 0, sizeof(aProcessInformation));
1275  aStartupInfo.cb = sizeof(aStartupInfo);
1276  aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
1277  if (hInput) {
1278  aStartupInfo.hStdInput = hInput;
1279  }
1280  else {
1281  aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1282  }
1283  if (hOutput) {
1284  aStartupInfo.hStdOutput = hOutput;
1285  }
1286  else {
1287  aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1288  }
1289  if (hError) {
1290  aStartupInfo.hStdError = hError;
1291  }
1292  else {
1293  aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1294  }
1295 
1296  dwCreationFlags |= NORMAL_PRIORITY_CLASS;
1297 
1298  if (lstrlenW(cmd) > 32767) {
1299  child->pid = 0; /* release the slot */
1300  errno = E2BIG;
1301  return FALSE;
1302  }
1303 
1304  RUBY_CRITICAL {
1305  fRet = CreateProcessW(prog, (WCHAR *)cmd, &sa, &sa,
1306  sa.bInheritHandle, dwCreationFlags, NULL, NULL,
1307  &aStartupInfo, &aProcessInformation);
1308  errno = map_errno(GetLastError());
1309  }
1310 
1311  if (!fRet) {
1312  child->pid = 0; /* release the slot */
1313  return FALSE;
1314  }
1315 
1316  CloseHandle(aProcessInformation.hThread);
1317 
1318  child->hProcess = aProcessInformation.hProcess;
1319  child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
1320 
1321  return TRUE;
1322 }
1323 
1324 /* License: Ruby's */
1325 static int
1326 is_batch(const char *cmd)
1327 {
1328  int len = strlen(cmd);
1329  if (len <= 4) return 0;
1330  cmd += len - 4;
1331  if (*cmd++ != '.') return 0;
1332  if (strcasecmp(cmd, "bat") == 0) return 1;
1333  if (strcasecmp(cmd, "cmd") == 0) return 1;
1334  return 0;
1335 }
1336 
1337 #define filecp rb_w32_filecp
1338 #define mbstr_to_wstr rb_w32_mbstr_to_wstr
1339 #define wstr_to_mbstr rb_w32_wstr_to_mbstr
1340 #define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen)
1341 #define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen)
1342 #define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen)
1343 #define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen)
1344 #define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen)
1345 #define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen)
1346 
1347 /* License: Ruby's */
1348 MJIT_FUNC_EXPORTED HANDLE
1349 rb_w32_start_process(const char *abspath, char *const *argv, int out_fd)
1350 {
1351  /* NOTE: This function is used by MJIT worker, so it can be used parallelly with
1352  Ruby's main thread. So functions touching things shared with main thread can't
1353  be used, like `ALLOCV` that may trigger GC or `FindFreeChildSlot` that finds
1354  a slot from shared memory without atomic locks. */
1355  struct ChildRecord child;
1356  char *cmd;
1357  size_t len;
1358  WCHAR *wcmd = NULL, *wprog = NULL;
1359  HANDLE outHandle = NULL;
1360 
1361  if (out_fd) {
1362  outHandle = (HANDLE)rb_w32_get_osfhandle(out_fd);
1363  }
1364 
1365  len = join_argv(NULL, argv, FALSE, filecp(), 1);
1366  cmd = alloca(sizeof(char) * len);
1367  join_argv(cmd, argv, FALSE, filecp(), 1);
1368 
1369  if (!(wcmd = mbstr_to_wstr(filecp(), cmd, -1, NULL))) {
1370  errno = E2BIG;
1371  return NULL;
1372  }
1373  if (!(wprog = mbstr_to_wstr(filecp(), abspath, -1, NULL))) {
1374  errno = E2BIG;
1375  return NULL;
1376  }
1377 
1378  if (!CreateChild(&child, wcmd, wprog, NULL, outHandle, outHandle, 0)) {
1379  return NULL;
1380  }
1381 
1382  free(wcmd);
1383  free(wprog);
1384  return child.hProcess;
1385 }
1386 
1387 /* License: Artistic or GPL */
1388 static rb_pid_t
1389 w32_spawn(int mode, const char *cmd, const char *prog, UINT cp)
1390 {
1391  char fbuf[PATH_MAX];
1392  char *p = NULL;
1393  const char *shell = NULL;
1394  WCHAR *wcmd = NULL, *wshell = NULL;
1395  int e = 0;
1396  rb_pid_t ret = -1;
1397  VALUE v = 0;
1398  VALUE v2 = 0;
1399  int sep = 0;
1400  char *cmd_sep = NULL;
1401 
1402  if (check_spawn_mode(mode)) return -1;
1403 
1404  if (prog) {
1405  if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
1406  shell = prog;
1407  }
1408  else {
1409  shell = p;
1410  translate_char(p, '/', '\\', cp);
1411  }
1412  }
1413  else {
1414  int redir = -1;
1415  int nt;
1416  while (ISSPACE(*cmd)) cmd++;
1417  if ((shell = w32_getenv("RUBYSHELL", cp)) && (redir = has_redirection(cmd, cp))) {
1418  size_t shell_len = strlen(shell);
1419  char *tmp = ALLOCV(v, shell_len + strlen(cmd) + sizeof(" -c ") + 2);
1420  memcpy(tmp, shell, shell_len + 1);
1421  translate_char(tmp, '/', '\\', cp);
1422  sprintf(tmp + shell_len, " -c \"%s\"", cmd);
1423  cmd = tmp;
1424  }
1425  else if ((shell = w32_getenv("COMSPEC", cp)) &&
1426  (nt = !is_command_com(shell),
1427  (redir < 0 ? has_redirection(cmd, cp) : redir) ||
1428  is_internal_cmd(cmd, nt))) {
1429  char *tmp = ALLOCV(v, strlen(shell) + strlen(cmd) + sizeof(" /c ") + (nt ? 2 : 0));
1430  sprintf(tmp, nt ? "%s /c \"%s\"" : "%s /c %s", shell, cmd);
1431  cmd = tmp;
1432  }
1433  else {
1434  int len = 0, quote = (*cmd == '"') ? '"' : (*cmd == '\'') ? '\'' : 0;
1435  int slash = 0;
1436  for (prog = cmd + !!quote;; prog = CharNextExA(cp, prog, 0)) {
1437  if (*prog == '/') slash = 1;
1438  if (!*prog) {
1439  len = prog - cmd;
1440  if (slash) {
1441  STRNDUPV(p, v2, cmd, len);
1442  cmd = p;
1443  }
1444  shell = cmd;
1445  break;
1446  }
1447  if ((unsigned char)*prog == quote) {
1448  len = prog++ - cmd - 1;
1449  STRNDUPV(p, v2, cmd + 1, len);
1450  shell = p;
1451  break;
1452  }
1453  if (quote) continue;
1454  if (ISSPACE(*prog) || strchr("<>|*?\"", *prog)) {
1455  len = prog - cmd;
1456  STRNDUPV(p, v2, cmd, len + (slash ? strlen(prog) : 0));
1457  if (slash) {
1458  cmd = p;
1459  sep = *(cmd_sep = &p[len]);
1460  *cmd_sep = '\0';
1461  }
1462  shell = p;
1463  break;
1464  }
1465  }
1466  shell = dln_find_exe_r(shell, NULL, fbuf, sizeof(fbuf));
1467  if (p && slash) translate_char(p, '/', '\\', cp);
1468  if (!shell) {
1469  shell = p ? p : cmd;
1470  }
1471  else {
1472  len = strlen(shell);
1473  if (strchr(shell, ' ')) quote = -1;
1474  if (shell == fbuf) {
1475  p = fbuf;
1476  }
1477  else if (shell != p && strchr(shell, '/')) {
1478  STRNDUPV(p, v2, shell, len);
1479  shell = p;
1480  }
1481  if (p) translate_char(p, '/', '\\', cp);
1482  if (is_batch(shell)) {
1483  int alen = strlen(prog);
1484  cmd = p = ALLOCV(v, len + alen + (quote ? 2 : 0) + 1);
1485  if (quote) *p++ = '"';
1486  memcpy(p, shell, len);
1487  p += len;
1488  if (quote) *p++ = '"';
1489  memcpy(p, prog, alen + 1);
1490  shell = 0;
1491  }
1492  }
1493  }
1494  }
1495 
1496  if (!e && shell && !(wshell = mbstr_to_wstr(cp, shell, -1, NULL))) e = E2BIG;
1497  if (cmd_sep) *cmd_sep = sep;
1498  if (!e && cmd && !(wcmd = mbstr_to_wstr(cp, cmd, -1, NULL))) e = E2BIG;
1499  if (v2) ALLOCV_END(v2);
1500  if (v) ALLOCV_END(v);
1501 
1502  if (!e) {
1503  struct ChildRecord *child = FindFreeChildSlot();
1504  if (CreateChild(child, wcmd, wshell, NULL, NULL, NULL, 0)) {
1505  ret = child_result(child, mode);
1506  }
1507  }
1508  free(wshell);
1509  free(wcmd);
1510  if (e) errno = e;
1511  return ret;
1512 }
1513 
1514 /* License: Ruby's */
1515 rb_pid_t
1516 rb_w32_spawn(int mode, const char *cmd, const char *prog)
1517 {
1518  /* assume ACP */
1519  return w32_spawn(mode, cmd, prog, filecp());
1520 }
1521 
1522 /* License: Ruby's */
1523 rb_pid_t
1524 rb_w32_uspawn(int mode, const char *cmd, const char *prog)
1525 {
1526  return w32_spawn(mode, cmd, prog, CP_UTF8);
1527 }
1528 
1529 /* License: Artistic or GPL */
1530 static rb_pid_t
1531 w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags, UINT cp)
1532 {
1533  int c_switch = 0;
1534  size_t len;
1535  BOOL ntcmd = FALSE, tmpnt;
1536  const char *shell;
1537  char *cmd, fbuf[PATH_MAX];
1538  WCHAR *wcmd = NULL, *wprog = NULL;
1539  int e = 0;
1540  rb_pid_t ret = -1;
1541  VALUE v = 0;
1542 
1543  if (check_spawn_mode(mode)) return -1;
1544 
1545  if (!prog) prog = argv[0];
1546  if ((shell = w32_getenv("COMSPEC", cp)) &&
1547  internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
1548  ntcmd = tmpnt;
1549  prog = shell;
1550  c_switch = 1;
1551  }
1552  else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
1553  if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf));
1554  translate_char(cmd, '/', '\\', cp);
1555  prog = cmd;
1556  }
1557  else if (strchr(prog, '/')) {
1558  len = strlen(prog);
1559  if (len < sizeof(fbuf))
1560  strlcpy(cmd = fbuf, prog, sizeof(fbuf));
1561  else
1562  STRNDUPV(cmd, v, prog, len);
1563  translate_char(cmd, '/', '\\', cp);
1564  prog = cmd;
1565  }
1566  if (c_switch || is_batch(prog)) {
1567  char *progs[2];
1568  progs[0] = (char *)prog;
1569  progs[1] = NULL;
1570  len = join_argv(NULL, progs, ntcmd, cp, 1);
1571  if (c_switch) len += 3;
1572  else ++argv;
1573  if (argv[0]) len += join_argv(NULL, argv, ntcmd, cp, 0);
1574  cmd = ALLOCV(v, len);
1575  join_argv(cmd, progs, ntcmd, cp, 1);
1576  if (c_switch) strlcat(cmd, " /c", len);
1577  if (argv[0]) join_argv(cmd + strlcat(cmd, " ", len), argv, ntcmd, cp, 0);
1578  prog = c_switch ? shell : 0;
1579  }
1580  else {
1581  len = join_argv(NULL, argv, FALSE, cp, 1);
1582  cmd = ALLOCV(v, len);
1583  join_argv(cmd, argv, FALSE, cp, 1);
1584  }
1585 
1586  if (!e && cmd && !(wcmd = mbstr_to_wstr(cp, cmd, -1, NULL))) e = E2BIG;
1587  if (v) ALLOCV_END(v);
1588  if (!e && prog && !(wprog = mbstr_to_wstr(cp, prog, -1, NULL))) e = E2BIG;
1589 
1590  if (!e) {
1591  struct ChildRecord *child = FindFreeChildSlot();
1592  if (CreateChild(child, wcmd, wprog, NULL, NULL, NULL, flags)) {
1593  ret = child_result(child, mode);
1594  }
1595  }
1596  free(wprog);
1597  free(wcmd);
1598  if (e) errno = e;
1599  return ret;
1600 }
1601 
1602 /* License: Ruby's */
1603 rb_pid_t
1604 rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
1605 {
1606  /* assume ACP */
1607  return w32_aspawn_flags(mode, prog, argv, flags, filecp());
1608 }
1609 
1610 /* License: Ruby's */
1611 rb_pid_t
1612 rb_w32_uaspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
1613 {
1614  return w32_aspawn_flags(mode, prog, argv, flags, CP_UTF8);
1615 }
1616 
1617 /* License: Ruby's */
1618 rb_pid_t
1619 rb_w32_aspawn(int mode, const char *prog, char *const *argv)
1620 {
1621  return w32_aspawn_flags(mode, prog, argv, 0, filecp());
1622 }
1623 
1624 /* License: Ruby's */
1625 rb_pid_t
1626 rb_w32_uaspawn(int mode, const char *prog, char *const *argv)
1627 {
1628  return rb_w32_uaspawn_flags(mode, prog, argv, 0);
1629 }
1630 
1631 /* License: Artistic or GPL */
1632 typedef struct _NtCmdLineElement {
1633  struct _NtCmdLineElement *next;
1634  char *str;
1635  long len;
1636  int flags;
1638 
1639 //
1640 // Possible values for flags
1641 //
1642 
1643 #define NTGLOB 0x1 // element contains a wildcard
1644 #define NTMALLOC 0x2 // string in element was malloc'ed
1645 #define NTSTRING 0x4 // element contains a quoted string
1646 
1647 /* License: Ruby's */
1648 static int
1649 insert(const char *path, VALUE vinfo, void *enc)
1650 {
1651  NtCmdLineElement *tmpcurr;
1652  NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo;
1653 
1654  tmpcurr = (NtCmdLineElement *)malloc(sizeof(NtCmdLineElement));
1655  if (!tmpcurr) return -1;
1656  MEMZERO(tmpcurr, NtCmdLineElement, 1);
1657  tmpcurr->len = strlen(path);
1658  tmpcurr->str = strdup(path);
1659  if (!tmpcurr->str) return -1;
1660  tmpcurr->flags |= NTMALLOC;
1661  **tail = tmpcurr;
1662  *tail = &tmpcurr->next;
1663 
1664  return 0;
1665 }
1666 
1667 /* License: Artistic or GPL */
1668 static NtCmdLineElement **
1669 cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail, UINT cp, rb_encoding *enc)
1670 {
1671  char buffer[PATH_MAX], *buf = buffer;
1672  NtCmdLineElement **last = tail;
1673  int status;
1674 
1675  if (patt->len >= PATH_MAX)
1676  if (!(buf = malloc(patt->len + 1))) return 0;
1677 
1678  memcpy(buf, patt->str, patt->len);
1679  buf[patt->len] = '\0';
1680  translate_char(buf, '\\', '/', cp);
1681  status = ruby_brace_glob_with_enc(buf, 0, insert, (VALUE)&tail, enc);
1682  if (buf != buffer)
1683  free(buf);
1684 
1685  if (status || last == tail) return 0;
1686  if (patt->flags & NTMALLOC)
1687  free(patt->str);
1688  free(patt);
1689  return tail;
1690 }
1691 
1692 //
1693 // Check a command string to determine if it has I/O redirection
1694 // characters that require it to be executed by a command interpreter
1695 //
1696 
1697 /* License: Artistic or GPL */
1698 static int
1699 has_redirection(const char *cmd, UINT cp)
1700 {
1701  char quote = '\0';
1702  const char *ptr;
1703 
1704  //
1705  // Scan the string, looking for redirection characters (< or >), pipe
1706  // character (|) or newline (\n) that are not in a quoted string
1707  //
1708 
1709  for (ptr = cmd; *ptr;) {
1710  switch (*ptr) {
1711  case '\'':
1712  case '\"':
1713  if (!quote)
1714  quote = *ptr;
1715  else if (quote == *ptr)
1716  quote = '\0';
1717  ptr++;
1718  break;
1719 
1720  case '>':
1721  case '<':
1722  case '|':
1723  case '&':
1724  case '\n':
1725  if (!quote)
1726  return TRUE;
1727  ptr++;
1728  break;
1729 
1730  case '%':
1731  if (*++ptr != '_' && !ISALPHA(*ptr)) break;
1732  while (*++ptr == '_' || ISALNUM(*ptr));
1733  if (*ptr++ == '%') return TRUE;
1734  break;
1735 
1736  case '\\':
1737  ptr++;
1738  default:
1739  ptr = CharNextExA(cp, ptr, 0);
1740  break;
1741  }
1742  }
1743  return FALSE;
1744 }
1745 
1746 /* License: Ruby's */
1747 static inline WCHAR *
1748 skipspace(WCHAR *ptr)
1749 {
1750  while (ISSPACE(*ptr))
1751  ptr++;
1752  return ptr;
1753 }
1754 
1755 /* License: Artistic or GPL */
1756 static int
1757 w32_cmdvector(const WCHAR *cmd, char ***vec, UINT cp, rb_encoding *enc)
1758 {
1759  int globbing, len;
1760  int elements, strsz, done;
1761  int slashes, escape;
1762  WCHAR *ptr, *base, *cmdline;
1763  char *cptr, *buffer;
1764  char **vptr;
1765  WCHAR quote;
1766  NtCmdLineElement *curr, **tail;
1767  NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead;
1768 
1769  //
1770  // just return if we don't have a command line
1771  //
1772  while (ISSPACE(*cmd))
1773  cmd++;
1774  if (!*cmd) {
1775  *vec = NULL;
1776  return 0;
1777  }
1778 
1779  ptr = cmdline = wcsdup(cmd);
1780 
1781  //
1782  // Ok, parse the command line, building a list of CmdLineElements.
1783  // When we've finished, and it's an input command (meaning that it's
1784  // the processes argv), we'll do globing and then build the argument
1785  // vector.
1786  // The outer loop does one iteration for each element seen.
1787  // The inner loop does one iteration for each character in the element.
1788  //
1789 
1790  while (*(ptr = skipspace(ptr))) {
1791  base = ptr;
1792  quote = slashes = globbing = escape = 0;
1793  for (done = 0; !done && *ptr; ) {
1794  //
1795  // Switch on the current character. We only care about the
1796  // white-space characters, the wild-card characters, and the
1797  // quote characters.
1798  //
1799 
1800  switch (*ptr) {
1801  case L'\\':
1802  if (quote != L'\'') slashes++;
1803  break;
1804 
1805  case L' ':
1806  case L'\t':
1807  case L'\n':
1808  //
1809  // if we're not in a string, then we're finished with this
1810  // element
1811  //
1812 
1813  if (!quote) {
1814  *ptr = 0;
1815  done = 1;
1816  }
1817  break;
1818 
1819  case L'*':
1820  case L'?':
1821  case L'[':
1822  case L'{':
1823  //
1824  // record the fact that this element has a wildcard character
1825  // N.B. Don't glob if inside a single quoted string
1826  //
1827 
1828  if (quote != L'\'')
1829  globbing++;
1830  slashes = 0;
1831  break;
1832 
1833  case L'\'':
1834  case L'\"':
1835  //
1836  // if we're already in a string, see if this is the
1837  // terminating close-quote. If it is, we're finished with
1838  // the string, but not necessarily with the element.
1839  // If we're not already in a string, start one.
1840  //
1841 
1842  if (!(slashes & 1)) {
1843  if (!quote)
1844  quote = *ptr;
1845  else if (quote == *ptr) {
1846  if (quote == L'"' && quote == ptr[1])
1847  ptr++;
1848  quote = L'\0';
1849  }
1850  }
1851  escape++;
1852  slashes = 0;
1853  break;
1854 
1855  default:
1856  ptr = CharNextW(ptr);
1857  slashes = 0;
1858  continue;
1859  }
1860  ptr++;
1861  }
1862 
1863  //
1864  // when we get here, we've got a pair of pointers to the element,
1865  // base and ptr. Base points to the start of the element while ptr
1866  // points to the character following the element.
1867  //
1868 
1869  len = ptr - base;
1870  if (done) --len;
1871 
1872  //
1873  // if it's an input vector element and it's enclosed by quotes,
1874  // we can remove them.
1875  //
1876 
1877  if (escape) {
1878  WCHAR *p = base, c;
1879  slashes = quote = 0;
1880  while (p < base + len) {
1881  switch (c = *p) {
1882  case L'\\':
1883  p++;
1884  if (quote != L'\'') slashes++;
1885  break;
1886 
1887  case L'\'':
1888  case L'"':
1889  if (!(slashes & 1) && quote && quote != c) {
1890  p++;
1891  slashes = 0;
1892  break;
1893  }
1894  memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
1895  sizeof(WCHAR) * (base + len - p));
1896  len -= ((slashes + 1) >> 1) + (~slashes & 1);
1897  p -= (slashes + 1) >> 1;
1898  if (!(slashes & 1)) {
1899  if (quote) {
1900  if (quote == L'"' && quote == *p)
1901  p++;
1902  quote = L'\0';
1903  }
1904  else
1905  quote = c;
1906  }
1907  else
1908  p++;
1909  slashes = 0;
1910  break;
1911 
1912  default:
1913  p = CharNextW(p);
1914  slashes = 0;
1915  break;
1916  }
1917  }
1918  }
1919 
1920  curr = (NtCmdLineElement *)calloc(sizeof(NtCmdLineElement), 1);
1921  if (!curr) goto do_nothing;
1922  curr->str = rb_w32_wstr_to_mbstr(cp, base, len, &curr->len);
1923  curr->flags |= NTMALLOC;
1924 
1925  if (globbing && (tail = cmdglob(curr, cmdtail, cp, enc))) {
1926  cmdtail = tail;
1927  }
1928  else {
1929  *cmdtail = curr;
1930  cmdtail = &curr->next;
1931  }
1932  }
1933 
1934  //
1935  // Almost done!
1936  // Count up the elements, then allocate space for a vector of pointers
1937  // (argv) and a string table for the elements.
1938  //
1939 
1940  for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) {
1941  elements++;
1942  strsz += (curr->len + 1);
1943  }
1944 
1945  len = (elements+1)*sizeof(char *) + strsz;
1946  buffer = (char *)malloc(len);
1947  if (!buffer) {
1948  do_nothing:
1949  while ((curr = cmdhead) != 0) {
1950  cmdhead = curr->next;
1951  if (curr->flags & NTMALLOC) free(curr->str);
1952  free(curr);
1953  }
1954  free(cmdline);
1955  for (vptr = *vec; *vptr; ++vptr);
1956  return vptr - *vec;
1957  }
1958 
1959  //
1960  // make vptr point to the start of the buffer
1961  // and cptr point to the area we'll consider the string table.
1962  //
1963  // buffer (*vec)
1964  // |
1965  // V ^---------------------V
1966  // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1967  // | | | .... | NULL | | ..... |\0 | | ..... |\0 |...
1968  // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
1969  // |- elements+1 -| ^ 1st element ^ 2nd element
1970 
1971  vptr = (char **) buffer;
1972 
1973  cptr = buffer + (elements+1) * sizeof(char *);
1974 
1975  while ((curr = cmdhead) != 0) {
1976  memcpy(cptr, curr->str, curr->len);
1977  cptr[curr->len] = '\0';
1978  *vptr++ = cptr;
1979  cptr += curr->len + 1;
1980  cmdhead = curr->next;
1981  if (curr->flags & NTMALLOC) free(curr->str);
1982  free(curr);
1983  }
1984  *vptr = 0;
1985 
1986  *vec = (char **) buffer;
1987  free(cmdline);
1988  return elements;
1989 }
1990 
1991 //
1992 // UNIX compatible directory access functions for NT
1993 //
1994 
1995 typedef DWORD (WINAPI *get_final_path_func)(HANDLE, WCHAR*, DWORD, DWORD);
1996 static get_final_path_func get_final_path;
1997 
1998 static DWORD WINAPI
1999 get_final_path_fail(HANDLE f, WCHAR *buf, DWORD len, DWORD flag)
2000 {
2001  return 0;
2002 }
2003 
2004 static DWORD WINAPI
2005 get_final_path_unknown(HANDLE f, WCHAR *buf, DWORD len, DWORD flag)
2006 {
2007  /* Since Windows Vista and Windows Server 2008 */
2008  get_final_path_func func = (get_final_path_func)
2009  get_proc_address("kernel32", "GetFinalPathNameByHandleW", NULL);
2010  if (!func) func = get_final_path_fail;
2011  get_final_path = func;
2012  return func(f, buf, len, flag);
2013 }
2014 
2015 static get_final_path_func get_final_path = get_final_path_unknown;
2016 
2017 /* License: Ruby's */
2018 /* TODO: better name */
2019 static HANDLE
2020 open_special(const WCHAR *path, DWORD access, DWORD flags)
2021 {
2022  const DWORD share_mode =
2023  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2024  return CreateFileW(path, access, share_mode, NULL, OPEN_EXISTING,
2025  FILE_FLAG_BACKUP_SEMANTICS|flags, NULL);
2026 }
2027 
2028 //
2029 // The idea here is to read all the directory names into a string table
2030 // (separated by nulls) and when one of the other dir functions is called
2031 // return the pointer to the current file name.
2032 //
2033 
2034 /* License: Ruby's */
2035 #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT))
2036 #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT))
2037 
2038 #define BitOfIsDir(n) ((n) * 2)
2039 #define BitOfIsRep(n) ((n) * 2 + 1)
2040 #define DIRENT_PER_CHAR (CHAR_BIT / 2)
2041 
2042 static const WCHAR namespace_prefix[] = {L'\\', L'\\', L'?', L'\\'};
2043 
2044 enum {FINAL_PATH_MAX = PATH_MAX + numberof(namespace_prefix)};
2045 
2046 /* License: Artistic or GPL */
2047 static HANDLE
2048 open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
2049 {
2050  HANDLE fh;
2051  WCHAR fullname[FINAL_PATH_MAX + rb_strlen_lit("\\*")];
2052  WCHAR *p;
2053  int len = 0;
2054 
2055  //
2056  // Create the search pattern
2057  //
2058 
2059  fh = open_special(filename, 0, 0);
2060  if (fh != INVALID_HANDLE_VALUE) {
2061  len = get_final_path(fh, fullname, FINAL_PATH_MAX, 0);
2062  CloseHandle(fh);
2063  if (len >= FINAL_PATH_MAX) {
2064  errno = ENAMETOOLONG;
2065  return INVALID_HANDLE_VALUE;
2066  }
2067  }
2068  if (!len) {
2069  len = lstrlenW(filename);
2070  if (len >= PATH_MAX) {
2071  errno = ENAMETOOLONG;
2072  return INVALID_HANDLE_VALUE;
2073  }
2074  MEMCPY(fullname, filename, WCHAR, len);
2075  }
2076  p = &fullname[len-1];
2077  if (!(isdirsep(*p) || *p == L':')) *++p = L'\\';
2078  *++p = L'*';
2079  *++p = L'\0';
2080 
2081  //
2082  // do the FindFirstFile call
2083  //
2084  fh = FindFirstFileW(fullname, fd);
2085  if (fh == INVALID_HANDLE_VALUE) {
2086  errno = map_errno(GetLastError());
2087  }
2088  return fh;
2089 }
2090 
2091 /* License: Artistic or GPL */
2092 static DIR *
2093 w32_wopendir(const WCHAR *wpath)
2094 {
2095  struct stati128 sbuf;
2096  WIN32_FIND_DATAW fd;
2097  HANDLE fh;
2098  DIR *p;
2099  long pathlen;
2100  long len;
2101  long altlen;
2102  long idx;
2103  WCHAR *tmpW;
2104  char *tmp;
2105 
2106  //
2107  // check to see if we've got a directory
2108  //
2109  if (wstati128(wpath, &sbuf, FALSE) < 0) {
2110  return NULL;
2111  }
2112  if (!(sbuf.st_mode & S_IFDIR) &&
2113  (!ISALPHA(wpath[0]) || wpath[1] != L':' || wpath[2] != L'\0' ||
2114  ((1 << ((wpath[0] & 0x5f) - 'A')) & GetLogicalDrives()) == 0)) {
2115  errno = ENOTDIR;
2116  return NULL;
2117  }
2118  fh = open_dir_handle(wpath, &fd);
2119  if (fh == INVALID_HANDLE_VALUE) {
2120  return NULL;
2121  }
2122 
2123  //
2124  // Get us a DIR structure
2125  //
2126  p = calloc(sizeof(DIR), 1);
2127  if (p == NULL)
2128  return NULL;
2129 
2130  pathlen = lstrlenW(wpath);
2131  idx = 0;
2132 
2133  //
2134  // loop finding all the files that match the wildcard
2135  // (which should be all of them in this directory!).
2136  // the variable idx should point one past the null terminator
2137  // of the previous string found.
2138  //
2139  do {
2140  len = lstrlenW(fd.cFileName) + 1;
2141  altlen = lstrlenW(fd.cAlternateFileName) + 1;
2142 
2143  //
2144  // bump the string table size by enough for the
2145  // new name and it's null terminator
2146  //
2147  tmpW = realloc(p->start, (idx + len + altlen) * sizeof(WCHAR));
2148  if (!tmpW) {
2149  error:
2150  rb_w32_closedir(p);
2151  FindClose(fh);
2152  errno = ENOMEM;
2153  return NULL;
2154  }
2155 
2156  p->start = tmpW;
2157  memcpy(&p->start[idx], fd.cFileName, len * sizeof(WCHAR));
2158  memcpy(&p->start[idx + len], fd.cAlternateFileName, altlen * sizeof(WCHAR));
2159 
2160  if (p->nfiles % DIRENT_PER_CHAR == 0) {
2161  tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1);
2162  if (!tmp)
2163  goto error;
2164  p->bits = tmp;
2165  p->bits[p->nfiles / DIRENT_PER_CHAR] = 0;
2166  }
2167  if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2168  SetBit(p->bits, BitOfIsDir(p->nfiles));
2169  if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
2170  WCHAR *tmppath = malloc((pathlen + len + 1) * sizeof(WCHAR));
2171  memcpy(tmppath, wpath, pathlen * sizeof(WCHAR));
2172  tmppath[pathlen] = L'\\';
2173  memcpy(tmppath + pathlen + 1, fd.cFileName, len * sizeof(WCHAR));
2174  if (rb_w32_reparse_symlink_p(tmppath))
2175  SetBit(p->bits, BitOfIsRep(p->nfiles));
2176  free(tmppath);
2177  }
2178 
2179  p->nfiles++;
2180  idx += len + altlen;
2181  } while (FindNextFileW(fh, &fd));
2182  FindClose(fh);
2183  p->size = idx;
2184  p->curr = p->start;
2185  return p;
2186 }
2187 
2188 /* License: Ruby's */
2189 UINT
2190 filecp(void)
2191 {
2192  UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
2193  return cp;
2194 }
2195 
2196 /* License: Ruby's */
2197 char *
2198 rb_w32_wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen)
2199 {
2200  char *ptr;
2201  int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL);
2202  if (!(ptr = malloc(len))) return 0;
2203  WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, NULL, NULL);
2204  if (plen) {
2205  /* exclude NUL only if NUL-terminated string */
2206  if (clen == -1) --len;
2207  *plen = len;
2208  }
2209  return ptr;
2210 }
2211 
2212 /* License: Ruby's */
2213 WCHAR *
2214 rb_w32_mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen)
2215 {
2216  /* This is used by MJIT worker. Do not trigger GC or call Ruby method here. */
2217  WCHAR *ptr;
2218  int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0);
2219  if (!(ptr = malloc(sizeof(WCHAR) * len))) return 0;
2220  MultiByteToWideChar(cp, 0, str, clen, ptr, len);
2221  if (plen) {
2222  /* exclude NUL only if NUL-terminated string */
2223  if (clen == -1) --len;
2224  *plen = len;
2225  }
2226  return ptr;
2227 }
2228 
2229 /* License: Ruby's */
2230 DIR *
2231 rb_w32_opendir(const char *filename)
2232 {
2233  DIR *ret;
2234  WCHAR *wpath = filecp_to_wstr(filename, NULL);
2235  if (!wpath)
2236  return NULL;
2237  ret = w32_wopendir(wpath);
2238  free(wpath);
2239  return ret;
2240 }
2241 
2242 /* License: Ruby's */
2243 DIR *
2244 rb_w32_uopendir(const char *filename)
2245 {
2246  DIR *ret;
2247  WCHAR *wpath = utf8_to_wstr(filename, NULL);
2248  if (!wpath)
2249  return NULL;
2250  ret = w32_wopendir(wpath);
2251  free(wpath);
2252  return ret;
2253 }
2254 
2255 //
2256 // Move to next entry
2257 //
2258 
2259 /* License: Artistic or GPL */
2260 static void
2261 move_to_next_entry(DIR *dirp)
2262 {
2263  if (dirp->curr) {
2264  dirp->loc++;
2265  dirp->curr += lstrlenW(dirp->curr) + 1;
2266  dirp->curr += lstrlenW(dirp->curr) + 1;
2267  if (dirp->curr >= (dirp->start + dirp->size)) {
2268  dirp->curr = NULL;
2269  }
2270  }
2271 }
2272 
2273 //
2274 // Readdir just returns the current string pointer and bumps the
2275 // string pointer to the next entry.
2276 //
2277 /* License: Ruby's */
2278 static BOOL
2279 win32_direct_conv(const WCHAR *file, const WCHAR *alt, struct direct *entry, const void *enc)
2280 {
2281  UINT cp = *((UINT *)enc);
2282  if (!(entry->d_name = wstr_to_mbstr(cp, file, -1, &entry->d_namlen)))
2283  return FALSE;
2284  if (alt && *alt) {
2285  long altlen = 0;
2286  entry->d_altname = wstr_to_mbstr(cp, alt, -1, &altlen);
2287  entry->d_altlen = altlen;
2288  }
2289  return TRUE;
2290 }
2291 
2292 /* License: Ruby's */
2293 VALUE
2294 rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
2295 {
2296  VALUE src;
2297  long len = lstrlenW(wstr);
2298  int encindex = rb_enc_to_index(enc);
2299 
2300  if (encindex == ENCINDEX_UTF_16LE) {
2301  return rb_enc_str_new((char *)wstr, len * sizeof(WCHAR), enc);
2302  }
2303  else {
2304 #if SIZEOF_INT < SIZEOF_LONG
2305 # error long should equal to int on Windows
2306 #endif
2307  int clen = rb_long2int(len);
2308  len = WideCharToMultiByte(CP_UTF8, 0, wstr, clen, NULL, 0, NULL, NULL);
2309  src = rb_enc_str_new(0, len, rb_enc_from_index(ENCINDEX_UTF_8));
2310  WideCharToMultiByte(CP_UTF8, 0, wstr, clen, RSTRING_PTR(src), len, NULL, NULL);
2311  }
2312  switch (encindex) {
2313  case ENCINDEX_ASCII:
2314  case ENCINDEX_US_ASCII:
2315  /* assume UTF-8 */
2316  case ENCINDEX_UTF_8:
2317  /* do nothing */
2318  return src;
2319  }
2320  return rb_str_conv_enc_opts(src, NULL, enc, ECONV_UNDEF_REPLACE, Qnil);
2321 }
2322 
2323 /* License: Ruby's */
2324 char *
2325 rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc)
2326 {
2327  VALUE str = rb_w32_conv_from_wchar(wstr, enc);
2328  long len;
2329  char *ptr;
2330 
2331  if (NIL_P(str)) return wstr_to_utf8(wstr, lenp);
2332  *lenp = len = RSTRING_LEN(str);
2333  memcpy(ptr = malloc(len + 1), RSTRING_PTR(str), len);
2334  ptr[len] = '\0';
2335  return ptr;
2336 }
2337 
2338 /* License: Ruby's */
2339 static BOOL
2340 ruby_direct_conv(const WCHAR *file, const WCHAR *alt, struct direct *entry, const void *enc)
2341 {
2342  if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc)))
2343  return FALSE;
2344  if (alt && *alt) {
2345  long altlen = 0;
2346  entry->d_altname = rb_w32_conv_from_wstr(alt, &altlen, enc);
2347  entry->d_altlen = altlen;
2348  }
2349  return TRUE;
2350 }
2351 
2352 /* License: Artistic or GPL */
2353 static struct direct *
2354 readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, const WCHAR *, struct direct *, const void *), const void *enc)
2355 {
2356  static long dummy_ino = 0;
2357 
2358  if (dirp->curr) {
2359 
2360  //
2361  // first set up the structure to return
2362  //
2363  if (dirp->dirstr.d_name)
2364  free(dirp->dirstr.d_name);
2365  if (dirp->dirstr.d_altname)
2366  free(dirp->dirstr.d_altname);
2367  dirp->dirstr.d_altname = 0;
2368  dirp->dirstr.d_altlen = 0;
2369  conv(dirp->curr, dirp->curr + lstrlenW(dirp->curr) + 1, &dirp->dirstr, enc);
2370 
2371  //
2372  // Fake inode
2373  //
2374  dirp->dirstr.d_ino = (ino_t)(InterlockedIncrement(&dummy_ino) - 1);
2375 
2376  //
2377  // Attributes
2378  //
2379  /* ignore FILE_ATTRIBUTE_DIRECTORY as unreliable for reparse points */
2380  if (GetBit(dirp->bits, BitOfIsRep(dirp->loc)))
2381  dirp->dirstr.d_type = DT_LNK;
2382  else if (GetBit(dirp->bits, BitOfIsDir(dirp->loc)))
2383  dirp->dirstr.d_type = DT_DIR;
2384  else
2385  dirp->dirstr.d_type = DT_REG;
2386 
2387  //
2388  // Now set up for the next call to readdir
2389  //
2390 
2391  move_to_next_entry(dirp);
2392 
2393  return &(dirp->dirstr);
2394 
2395  }
2396  else
2397  return NULL;
2398 }
2399 
2400 /* License: Ruby's */
2401 struct direct *
2402 rb_w32_readdir(DIR *dirp, rb_encoding *enc)
2403 {
2404  int idx = rb_enc_to_index(enc);
2405  if (idx == ENCINDEX_ASCII) {
2406  const UINT cp = filecp();
2407  return readdir_internal(dirp, win32_direct_conv, &cp);
2408  }
2409  else if (idx == ENCINDEX_UTF_8) {
2410  const UINT cp = CP_UTF8;
2411  return readdir_internal(dirp, win32_direct_conv, &cp);
2412  }
2413  else
2414  return readdir_internal(dirp, ruby_direct_conv, enc);
2415 }
2416 
2417 /* License: Ruby's */
2418 struct direct *
2419 rb_w32_ureaddir(DIR *dirp)
2420 {
2421  const UINT cp = CP_UTF8;
2422  return readdir_internal(dirp, win32_direct_conv, &cp);
2423 }
2424 
2425 //
2426 // Telldir returns the current string pointer position
2427 //
2428 
2429 /* License: Artistic or GPL */
2430 long
2431 rb_w32_telldir(DIR *dirp)
2432 {
2433  return dirp->loc;
2434 }
2435 
2436 //
2437 // Seekdir moves the string pointer to a previously saved position
2438 // (Saved by telldir).
2439 
2440 /* License: Ruby's */
2441 void
2442 rb_w32_seekdir(DIR *dirp, long loc)
2443 {
2444  if (dirp->loc > loc) rb_w32_rewinddir(dirp);
2445 
2446  while (dirp->curr && dirp->loc < loc) {
2447  move_to_next_entry(dirp);
2448  }
2449 }
2450 
2451 //
2452 // Rewinddir resets the string pointer to the start
2453 //
2454 
2455 /* License: Artistic or GPL */
2456 void
2457 rb_w32_rewinddir(DIR *dirp)
2458 {
2459  dirp->curr = dirp->start;
2460  dirp->loc = 0;
2461 }
2462 
2463 //
2464 // This just free's the memory allocated by opendir
2465 //
2466 
2467 /* License: Artistic or GPL */
2468 void
2469 rb_w32_closedir(DIR *dirp)
2470 {
2471  if (dirp) {
2472  if (dirp->dirstr.d_name)
2473  free(dirp->dirstr.d_name);
2474  if (dirp->dirstr.d_altname)
2475  free(dirp->dirstr.d_altname);
2476  if (dirp->start)
2477  free(dirp->start);
2478  if (dirp->bits)
2479  free(dirp->bits);
2480  free(dirp);
2481  }
2482 }
2483 
2484 #if RUBY_MSVCRT_VERSION >= 140
2485 typedef struct {
2486  union
2487  {
2488  FILE _public_file;
2489  char* _ptr;
2490  };
2491 
2492  char* _base;
2493  int _cnt;
2494  long _flags;
2495  long _file;
2496  int _charbuf;
2497  int _bufsiz;
2498  char* _tmpfname;
2499  CRITICAL_SECTION _lock;
2500 } vcruntime_file;
2501 #define FILE_COUNT(stream) ((vcruntime_file*)stream)->_cnt
2502 #define FILE_READPTR(stream) ((vcruntime_file*)stream)->_ptr
2503 #define FILE_FILENO(stream) ((vcruntime_file*)stream)->_file
2504 #else
2505 #define FILE_COUNT(stream) stream->_cnt
2506 #define FILE_READPTR(stream) stream->_ptr
2507 #define FILE_FILENO(stream) stream->_file
2508 #endif
2509 
2510 /* License: Ruby's */
2511 #if RUBY_MSVCRT_VERSION >= 140
2512 typedef char lowio_text_mode;
2513 typedef char lowio_pipe_lookahead[3];
2514 
2515 typedef struct {
2516  CRITICAL_SECTION lock;
2517  intptr_t osfhnd; // underlying OS file HANDLE
2518  __int64 startpos; // File position that matches buffer start
2519  unsigned char osfile; // Attributes of file (e.g., open in text mode?)
2520  lowio_text_mode textmode;
2521  lowio_pipe_lookahead _pipe_lookahead;
2522 
2523  uint8_t unicode : 1; // Was the file opened as unicode?
2524  uint8_t utf8translations : 1; // Buffer contains translations other than CRLF
2525  uint8_t dbcsBufferUsed : 1; // Is the dbcsBuffer in use?
2526  char dbcsBuffer; // Buffer for the lead byte of DBCS when converting from DBCS to Unicode
2527 } ioinfo;
2528 #else
2529 typedef struct {
2530  intptr_t osfhnd; /* underlying OS file HANDLE */
2531  char osfile; /* attributes of file (e.g., open in text mode?) */
2532  char pipech; /* one char buffer for handles opened on pipes */
2533  int lockinitflag;
2534  CRITICAL_SECTION lock;
2535 #if RUBY_MSVCRT_VERSION >= 80
2536  char textmode;
2537  char pipech2[2];
2538 #endif
2539 } ioinfo;
2540 #endif
2541 
2542 #if !defined _CRTIMP || defined __MINGW32__
2543 #undef _CRTIMP
2544 #define _CRTIMP __declspec(dllimport)
2545 #endif
2546 
2547 #if RUBY_MSVCRT_VERSION >= 140
2548 static ioinfo ** __pioinfo = NULL;
2549 #define IOINFO_L2E 6
2550 #else
2551 EXTERN_C _CRTIMP ioinfo * __pioinfo[];
2552 #define IOINFO_L2E 5
2553 #endif
2554 static inline ioinfo* _pioinfo(int);
2555 
2556 
2557 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
2558 #define _osfhnd(i) (_pioinfo(i)->osfhnd)
2559 #define _osfile(i) (_pioinfo(i)->osfile)
2560 #define rb_acrt_lowio_lock_fh(i) EnterCriticalSection(&_pioinfo(i)->lock)
2561 #define rb_acrt_lowio_unlock_fh(i) LeaveCriticalSection(&_pioinfo(i)->lock)
2562 
2563 #if RUBY_MSVCRT_VERSION >= 80
2564 static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */
2565 
2566 /* License: Ruby's */
2567 static void
2568 set_pioinfo_extra(void)
2569 {
2570 #if RUBY_MSVCRT_VERSION >= 140
2571 # define FUNCTION_RET 0xc3 /* ret */
2572 # ifdef _DEBUG
2573 # define UCRTBASE "ucrtbased.dll"
2574 # else
2575 # define UCRTBASE "ucrtbase.dll"
2576 # endif
2577  /* get __pioinfo addr with _isatty */
2578  char *p = (char*)get_proc_address(UCRTBASE, "_isatty", NULL);
2579  char *pend = p;
2580  /* _osfile(fh) & FDEV */
2581 
2582 # ifdef _WIN64
2583  int32_t rel;
2584  char *rip;
2585  /* add rsp, _ */
2586 # define FUNCTION_BEFORE_RET_MARK "\x48\x83\xc4"
2587 # define FUNCTION_SKIP_BYTES 1
2588 # ifdef _DEBUG
2589  /* lea rcx,[__pioinfo's addr in RIP-relative 32bit addr] */
2590 # define PIOINFO_MARK "\x48\x8d\x0d"
2591 # else
2592  /* lea rdx,[__pioinfo's addr in RIP-relative 32bit addr] */
2593 # define PIOINFO_MARK "\x48\x8d\x15"
2594 # endif
2595 
2596 # else /* x86 */
2597  /* pop ebp */
2598 # define FUNCTION_BEFORE_RET_MARK "\x5d"
2599 # define FUNCTION_SKIP_BYTES 0
2600  /* mov eax,dword ptr [eax*4+100EB430h] */
2601 # define PIOINFO_MARK "\x8B\x04\x85"
2602 # endif
2603  if (p) {
2604  for (pend += 10; pend < p + 300; pend++) {
2605  // find end of function
2606  if (memcmp(pend, FUNCTION_BEFORE_RET_MARK, sizeof(FUNCTION_BEFORE_RET_MARK) - 1) == 0 &&
2607  (*(pend + (sizeof(FUNCTION_BEFORE_RET_MARK) - 1) + FUNCTION_SKIP_BYTES) & FUNCTION_RET) == FUNCTION_RET) {
2608  // search backwards from end of function
2609  for (pend -= (sizeof(PIOINFO_MARK) - 1); pend > p; pend--) {
2610  if (memcmp(pend, PIOINFO_MARK, sizeof(PIOINFO_MARK) - 1) == 0) {
2611  p = pend;
2612  goto found;
2613  }
2614  }
2615  break;
2616  }
2617  }
2618  }
2619  fprintf(stderr, "unexpected " UCRTBASE "\n");
2620  _exit(1);
2621 
2622  found:
2623  p += sizeof(PIOINFO_MARK) - 1;
2624 #ifdef _WIN64
2625  rel = *(int32_t*)(p);
2626  rip = p + sizeof(int32_t);
2627  __pioinfo = (ioinfo**)(rip + rel);
2628 #else
2629  __pioinfo = *(ioinfo***)(p);
2630 #endif
2631 #endif
2632  int fd;
2633 
2634  fd = _open("NUL", O_RDONLY);
2635  for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra += sizeof(void *)) {
2636  if (_osfhnd(fd) == _get_osfhandle(fd)) {
2637  break;
2638  }
2639  }
2640  _close(fd);
2641 
2642  if (pioinfo_extra > 64) {
2643  /* not found, maybe something wrong... */
2644  pioinfo_extra = 0;
2645  }
2646 }
2647 #else
2648 #define pioinfo_extra 0
2649 #endif
2650 
2651 static inline ioinfo*
2652 _pioinfo(int fd)
2653 {
2654  const size_t sizeof_ioinfo = sizeof(ioinfo) + pioinfo_extra;
2655  return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
2656  (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
2657 }
2658 
2659 #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
2660 #define _set_osflags(fh, flags) (_osfile(fh) = (flags))
2661 
2662 #define FOPEN 0x01 /* file handle open */
2663 #define FEOFLAG 0x02 /* end of file has been encountered */
2664 #define FPIPE 0x08 /* file handle refers to a pipe */
2665 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2666 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2667 #define FDEV 0x40 /* file handle refers to device */
2668 #define FTEXT 0x80 /* file handle is in text mode */
2669 
2670 static int is_socket(SOCKET);
2671 static int is_console(SOCKET);
2672 
2673 /* License: Ruby's */
2674 int
2675 rb_w32_io_cancelable_p(int fd)
2676 {
2677  return is_socket(TO_SOCKET(fd)) || !is_console(TO_SOCKET(fd));
2678 }
2679 
2680 /* License: Ruby's */
2681 static int
2682 rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
2683 {
2684  int fh;
2685  char fileflags; /* _osfile flags */
2686  HANDLE hF;
2687 
2688  /* copy relevant flags from second parameter */
2689  fileflags = FDEV;
2690 
2691  if (flags & O_APPEND)
2692  fileflags |= FAPPEND;
2693 
2694  if (flags & O_TEXT)
2695  fileflags |= FTEXT;
2696 
2697  if (flags & O_NOINHERIT)
2698  fileflags |= FNOINHERIT;
2699 
2700  /* attempt to allocate a C Runtime file handle */
2701  hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2702  fh = _open_osfhandle((intptr_t)hF, 0);
2703  CloseHandle(hF);
2704  if (fh == -1) {
2705  errno = EMFILE; /* too many open files */
2706  _doserrno = 0L; /* not an OS error */
2707  }
2708  else {
2709 
2710  rb_acrt_lowio_lock_fh(fh);
2711  /* the file is open. now, set the info in _osfhnd array */
2712  _set_osfhnd(fh, osfhandle);
2713 
2714  fileflags |= FOPEN; /* mark as open */
2715 
2716  _set_osflags(fh, fileflags); /* set osfile entry */
2717  rb_acrt_lowio_unlock_fh(fh);
2718  }
2719  return fh; /* return handle */
2720 }
2721 
2722 /* License: Ruby's */
2723 static void
2724 init_stdhandle(void)
2725 {
2726  int nullfd = -1;
2727  int keep = 0;
2728 #define open_null(fd) \
2729  (((nullfd < 0) ? \
2730  (nullfd = open("NUL", O_RDWR)) : 0), \
2731  ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \
2732  (fd))
2733 
2734  if (fileno(stdin) < 0) {
2735  FILE_FILENO(stdin) = open_null(0);
2736  }
2737  else {
2738  setmode(fileno(stdin), O_BINARY);
2739  }
2740  if (fileno(stdout) < 0) {
2741  FILE_FILENO(stdout) = open_null(1);
2742  }
2743  if (fileno(stderr) < 0) {
2744  FILE_FILENO(stderr) = open_null(2);
2745  }
2746  if (nullfd >= 0 && !keep) close(nullfd);
2747  setvbuf(stderr, NULL, _IONBF, 0);
2748 
2749  {
2750  HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
2751  DWORD m;
2752  if (GetConsoleMode(h, &m)) {
2753 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
2754 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
2755 #endif
2756  SetConsoleMode(h, m | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
2757  }
2758  }
2759 }
2760 
2761 #undef getsockopt
2762 
2763 /* License: Ruby's */
2764 static int
2765 is_socket(SOCKET sock)
2766 {
2767  if (socklist_lookup(sock, NULL))
2768  return TRUE;
2769  else
2770  return FALSE;
2771 }
2772 
2773 /* License: Ruby's */
2774 int
2775 rb_w32_is_socket(int fd)
2776 {
2777  return is_socket(TO_SOCKET(fd));
2778 }
2779 
2780 //
2781 // Since the errors returned by the socket error function
2782 // WSAGetLastError() are not known by the library routine strerror
2783 // we have to roll our own.
2784 //
2785 
2786 #undef strerror
2787 
2788 /* License: Artistic or GPL */
2789 char *
2790 rb_w32_strerror(int e)
2791 {
2792  static char buffer[512];
2793  DWORD source = 0;
2794  char *p;
2795 
2796  if (e < 0 || e > sys_nerr) {
2797  if (e < 0)
2798  e = GetLastError();
2799 #if WSAEWOULDBLOCK != EWOULDBLOCK
2800  else if (e >= EADDRINUSE && e <= EWOULDBLOCK) {
2801  static int s = -1;
2802  int i;
2803  if (s < 0)
2804  for (s = 0; s < (int)(sizeof(errmap)/sizeof(*errmap)); s++)
2805  if (errmap[s].winerr == WSAEWOULDBLOCK)
2806  break;
2807  for (i = s; i < (int)(sizeof(errmap)/sizeof(*errmap)); i++)
2808  if (errmap[i].err == e) {
2809  e = errmap[i].winerr;
2810  break;
2811  }
2812  }
2813 #endif
2814  if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2815  FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
2816  MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
2817  buffer, sizeof(buffer), NULL) == 0 &&
2818  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2819  FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
2820  buffer, sizeof(buffer), NULL) == 0)
2821  strlcpy(buffer, "Unknown Error", sizeof(buffer));
2822  }
2823  else
2824  strlcpy(buffer, strerror(e), sizeof(buffer));
2825 
2826  p = buffer;
2827  while ((p = strpbrk(p, "\r\n")) != NULL) {
2828  memmove(p, p + 1, strlen(p));
2829  }
2830  return buffer;
2831 }
2832 
2833 //
2834 // various stubs
2835 //
2836 
2837 
2838 // Ownership
2839 //
2840 // Just pretend that everyone is a superuser. NT will let us know if
2841 // we don't really have permission to do something.
2842 //
2843 
2844 #define ROOT_UID 0
2845 #define ROOT_GID 0
2846 
2847 /* License: Artistic or GPL */
2848 rb_uid_t
2849 getuid(void)
2850 {
2851  return ROOT_UID;
2852 }
2853 
2854 /* License: Artistic or GPL */
2855 rb_uid_t
2856 geteuid(void)
2857 {
2858  return ROOT_UID;
2859 }
2860 
2861 /* License: Artistic or GPL */
2862 rb_gid_t
2863 getgid(void)
2864 {
2865  return ROOT_GID;
2866 }
2867 
2868 /* License: Artistic or GPL */
2869 rb_gid_t
2870 getegid(void)
2871 {
2872  return ROOT_GID;
2873 }
2874 
2875 /* License: Artistic or GPL */
2876 int
2877 setuid(rb_uid_t uid)
2878 {
2879  return (uid == ROOT_UID ? 0 : -1);
2880 }
2881 
2882 /* License: Artistic or GPL */
2883 int
2884 setgid(rb_gid_t gid)
2885 {
2886  return (gid == ROOT_GID ? 0 : -1);
2887 }
2888 
2889 //
2890 // File system stuff
2891 //
2892 
2893 /* License: Artistic or GPL */
2894 int
2895 ioctl(int i, int u, ...)
2896 {
2897  errno = EINVAL;
2898  return -1;
2899 }
2900 
2901 void
2902 rb_w32_fdset(int fd, fd_set *set)
2903 {
2904  FD_SET(fd, set);
2905 }
2906 
2907 #undef FD_CLR
2908 
2909 /* License: Ruby's */
2910 void
2911 rb_w32_fdclr(int fd, fd_set *set)
2912 {
2913  unsigned int i;
2914  SOCKET s = TO_SOCKET(fd);
2915 
2916  for (i = 0; i < set->fd_count; i++) {
2917  if (set->fd_array[i] == s) {
2918  memmove(&set->fd_array[i], &set->fd_array[i+1],
2919  sizeof(set->fd_array[0]) * (--set->fd_count - i));
2920  break;
2921  }
2922  }
2923 }
2924 
2925 #undef FD_ISSET
2926 
2927 /* License: Ruby's */
2928 int
2929 rb_w32_fdisset(int fd, fd_set *set)
2930 {
2931  int ret;
2932  SOCKET s = TO_SOCKET(fd);
2933  if (s == (SOCKET)INVALID_HANDLE_VALUE)
2934  return 0;
2935  RUBY_CRITICAL {ret = __WSAFDIsSet(s, set);}
2936  return ret;
2937 }
2938 
2939 /* License: Ruby's */
2940 void
2941 rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
2942 {
2943  max = min(src->fd_count, (UINT)max);
2944  if ((UINT)dst->capa < (UINT)max) {
2945  dst->capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2946  dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
2947  }
2948 
2949  memcpy(dst->fdset->fd_array, src->fd_array,
2950  max * sizeof(src->fd_array[0]));
2951  dst->fdset->fd_count = src->fd_count;
2952 }
2953 
2954 /* License: Ruby's */
2955 void
2957 {
2958  if ((UINT)dst->capa < src->fdset->fd_count) {
2959  dst->capa = (src->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2960  dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
2961  }
2962 
2963  memcpy(dst->fdset->fd_array, src->fdset->fd_array,
2964  src->fdset->fd_count * sizeof(src->fdset->fd_array[0]));
2965  dst->fdset->fd_count = src->fdset->fd_count;
2966 }
2967 
2968 //
2969 // Networking trampolines
2970 // These are used to avoid socket startup/shutdown overhead in case
2971 // the socket routines aren't used.
2972 //
2973 
2974 #undef select
2975 
2976 /* License: Ruby's */
2977 static int
2978 extract_fd(rb_fdset_t *dst, fd_set *src, int (*func)(SOCKET))
2979 {
2980  unsigned int s = 0;
2981  unsigned int m = 0;
2982  if (!src) return 0;
2983 
2984  while (s < src->fd_count) {
2985  SOCKET fd = src->fd_array[s];
2986 
2987  if (!func || (*func)(fd)) {
2988  if (dst) { /* move it to dst */
2989  unsigned int d;
2990 
2991  for (d = 0; d < dst->fdset->fd_count; d++) {
2992  if (dst->fdset->fd_array[d] == fd)
2993  break;
2994  }
2995  if (d == dst->fdset->fd_count) {
2996  if ((int)dst->fdset->fd_count >= dst->capa) {
2997  dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2998  dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
2999  }
3000  dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
3001  }
3002  memmove(
3003  &src->fd_array[s],
3004  &src->fd_array[s+1],
3005  sizeof(src->fd_array[0]) * (--src->fd_count - s));
3006  }
3007  else {
3008  m++;
3009  s++;
3010  }
3011  }
3012  else s++;
3013  }
3014 
3015  return dst ? dst->fdset->fd_count : m;
3016 }
3017 
3018 /* License: Ruby's */
3019 static int
3020 copy_fd(fd_set *dst, fd_set *src)
3021 {
3022  unsigned int s;
3023  if (!src || !dst) return 0;
3024 
3025  for (s = 0; s < src->fd_count; ++s) {
3026  SOCKET fd = src->fd_array[s];
3027  unsigned int d;
3028  for (d = 0; d < dst->fd_count; ++d) {
3029  if (dst->fd_array[d] == fd)
3030  break;
3031  }
3032  if (d == dst->fd_count && d < FD_SETSIZE) {
3033  dst->fd_array[dst->fd_count++] = fd;
3034  }
3035  }
3036 
3037  return dst->fd_count;
3038 }
3039 
3040 /* License: Ruby's */
3041 static int
3042 is_not_socket(SOCKET sock)
3043 {
3044  return !is_socket(sock);
3045 }
3046 
3047 /* License: Ruby's */
3048 static int
3049 is_pipe(SOCKET sock) /* DONT call this for SOCKET! it claims it is PIPE. */
3050 {
3051  int ret;
3052 
3053  RUBY_CRITICAL {
3054  ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
3055  }
3056 
3057  return ret;
3058 }
3059 
3060 /* License: Ruby's */
3061 static int
3062 is_readable_pipe(SOCKET sock) /* call this for pipe only */
3063 {
3064  int ret;
3065  DWORD n = 0;
3066 
3067  RUBY_CRITICAL {
3068  if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
3069  ret = (n > 0);
3070  }
3071  else {
3072  ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */
3073  }
3074  }
3075 
3076  return ret;
3077 }
3078 
3079 /* License: Ruby's */
3080 static int
3081 is_console(SOCKET sock) /* DONT call this for SOCKET! */
3082 {
3083  int ret;
3084  DWORD n = 0;
3085  INPUT_RECORD ir;
3086 
3087  RUBY_CRITICAL {
3088  ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n));
3089  }
3090 
3091  return ret;
3092 }
3093 
3094 /* License: Ruby's */
3095 static int
3096 is_readable_console(SOCKET sock) /* call this for console only */
3097 {
3098  int ret = 0;
3099  DWORD n = 0;
3100  INPUT_RECORD ir;
3101 
3102  RUBY_CRITICAL {
3103  if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
3104  if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
3105  ir.Event.KeyEvent.uChar.AsciiChar) {
3106  ret = 1;
3107  }
3108  else {
3109  ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
3110  }
3111  }
3112  }
3113 
3114  return ret;
3115 }
3116 
3117 /* License: Ruby's */
3118 static int
3119 is_invalid_handle(SOCKET sock)
3120 {
3121  return (HANDLE)sock == INVALID_HANDLE_VALUE;
3122 }
3123 
3124 /* License: Artistic or GPL */
3125 static int
3126 do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
3127  struct timeval *timeout)
3128 {
3129  int r = 0;
3130 
3131  if (nfds == 0) {
3132  if (timeout)
3133  rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
3134  else
3135  rb_w32_sleep(INFINITE);
3136  }
3137  else {
3138  RUBY_CRITICAL {
3139  thread_exclusive(select) {
3140  r = select(nfds, rd, wr, ex, timeout);
3141  }
3142  if (r == SOCKET_ERROR) {
3143  errno = map_errno(WSAGetLastError());
3144  r = -1;
3145  }
3146  }
3147  }
3148 
3149  return r;
3150 }
3151 
3152 /*
3153  * rest -= wait
3154  * return 0 if rest is smaller than wait.
3155  */
3156 /* License: Ruby's */
3157 int
3158 rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait)
3159 {
3160  if (rest->tv_sec < wait->tv_sec) {
3161  return 0;
3162  }
3163  while (rest->tv_usec < wait->tv_usec) {
3164  if (rest->tv_sec <= wait->tv_sec) {
3165  return 0;
3166  }
3167  rest->tv_sec -= 1;
3168  rest->tv_usec += 1000 * 1000;
3169  }
3170  rest->tv_sec -= wait->tv_sec;
3171  rest->tv_usec -= wait->tv_usec;
3172  return rest->tv_sec != 0 || rest->tv_usec != 0;
3173 }
3174 
3175 /* License: Ruby's */
3176 static inline int
3177 compare(const struct timeval *t1, const struct timeval *t2)
3178 {
3179  if (t1->tv_sec < t2->tv_sec)
3180  return -1;
3181  if (t1->tv_sec > t2->tv_sec)
3182  return 1;
3183  if (t1->tv_usec < t2->tv_usec)
3184  return -1;
3185  if (t1->tv_usec > t2->tv_usec)
3186  return 1;
3187  return 0;
3188 }
3189 
3190 #undef Sleep
3191 
3192 int rb_w32_check_interrupt(void *); /* @internal */
3193 
3194 /* @internal */
3195 /* License: Ruby's */
3196 int
3197 rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
3198  struct timeval *timeout, void *th)
3199 {
3200  int r;
3201  rb_fdset_t pipe_rd;
3202  rb_fdset_t cons_rd;
3203  rb_fdset_t else_rd;
3204  rb_fdset_t else_wr;
3205  rb_fdset_t except;
3206  int nonsock = 0;
3207  struct timeval limit = {0, 0};
3208 
3209  if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
3210  errno = EINVAL;
3211  return -1;
3212  }
3213 
3214  if (timeout) {
3215  if (timeout->tv_sec < 0 ||
3216  timeout->tv_usec < 0 ||
3217  timeout->tv_usec >= 1000000) {
3218  errno = EINVAL;
3219  return -1;
3220  }
3221  gettimeofday(&limit, NULL);
3222  limit.tv_sec += timeout->tv_sec;
3223  limit.tv_usec += timeout->tv_usec;
3224  if (limit.tv_usec >= 1000000) {
3225  limit.tv_usec -= 1000000;
3226  limit.tv_sec++;
3227  }
3228  }
3229 
3230  // assume else_{rd,wr} (other than socket, pipe reader, console reader)
3231  // are always readable/writable. but this implementation still has
3232  // problem. if pipe's buffer is full, writing to pipe will block
3233  // until some data is read from pipe. but ruby is single threaded system,
3234  // so whole system will be blocked forever.
3235 
3236  rb_fd_init(&else_rd);
3237  nonsock += extract_fd(&else_rd, rd, is_not_socket);
3238 
3239  rb_fd_init(&else_wr);
3240  nonsock += extract_fd(&else_wr, wr, is_not_socket);
3241 
3242  // check invalid handles
3243  if (extract_fd(NULL, else_rd.fdset, is_invalid_handle) > 0 ||
3244  extract_fd(NULL, else_wr.fdset, is_invalid_handle) > 0) {
3245  rb_fd_term(&else_wr);
3246  rb_fd_term(&else_rd);
3247  errno = EBADF;
3248  return -1;
3249  }
3250 
3251  rb_fd_init(&pipe_rd);
3252  extract_fd(&pipe_rd, else_rd.fdset, is_pipe); // should not call is_pipe for socket
3253 
3254  rb_fd_init(&cons_rd);
3255  extract_fd(&cons_rd, else_rd.fdset, is_console); // ditto
3256 
3257  rb_fd_init(&except);
3258  extract_fd(&except, ex, is_not_socket); // drop only
3259 
3260  r = 0;
3261  if (rd && (int)rd->fd_count > r) r = (int)rd->fd_count;
3262  if (wr && (int)wr->fd_count > r) r = (int)wr->fd_count;
3263  if (ex && (int)ex->fd_count > r) r = (int)ex->fd_count;
3264  if (nfds > r) nfds = r;
3265 
3266  {
3267  struct timeval rest;
3268  const struct timeval wait = {0, 10 * 1000}; // 10ms
3269  struct timeval zero = {0, 0}; // 0ms
3270  for (;;) {
3271  if (th && rb_w32_check_interrupt(th) != WAIT_TIMEOUT) {
3272  r = -1;
3273  break;
3274  }
3275  if (nonsock) {
3276  // modifying {else,pipe,cons}_rd is safe because
3277  // if they are modified, function returns immediately.
3278  extract_fd(&else_rd, pipe_rd.fdset, is_readable_pipe);
3279  extract_fd(&else_rd, cons_rd.fdset, is_readable_console);
3280  }
3281 
3282  if (else_rd.fdset->fd_count || else_wr.fdset->fd_count) {
3283  r = do_select(nfds, rd, wr, ex, &zero); // polling
3284  if (r < 0) break; // XXX: should I ignore error and return signaled handles?
3285  r += copy_fd(rd, else_rd.fdset);
3286  r += copy_fd(wr, else_wr.fdset);
3287  if (ex)
3288  r += ex->fd_count;
3289  break;
3290  }
3291  else {
3292  const struct timeval *dowait = &wait;
3293 
3294  fd_set orig_rd;
3295  fd_set orig_wr;
3296  fd_set orig_ex;
3297 
3298  FD_ZERO(&orig_rd);
3299  FD_ZERO(&orig_wr);
3300  FD_ZERO(&orig_ex);
3301 
3302  if (rd) copy_fd(&orig_rd, rd);
3303  if (wr) copy_fd(&orig_wr, wr);
3304  if (ex) copy_fd(&orig_ex, ex);
3305  r = do_select(nfds, rd, wr, ex, &zero); // polling
3306  if (r != 0) break; // signaled or error
3307  if (rd) copy_fd(rd, &orig_rd);
3308  if (wr) copy_fd(wr, &orig_wr);
3309  if (ex) copy_fd(ex, &orig_ex);
3310 
3311  if (timeout) {
3312  struct timeval now;
3313  gettimeofday(&now, NULL);
3314  rest = limit;
3315  if (!rb_w32_time_subtract(&rest, &now)) break;
3316  if (compare(&rest, &wait) < 0) dowait = &rest;
3317  }
3318  Sleep(dowait->tv_sec * 1000 + (dowait->tv_usec + 999) / 1000);
3319  }
3320  }
3321  }
3322 
3323  rb_fd_term(&except);
3324  rb_fd_term(&cons_rd);
3325  rb_fd_term(&pipe_rd);
3326  rb_fd_term(&else_wr);
3327  rb_fd_term(&else_rd);
3328 
3329  return r;
3330 }
3331 
3332 /* License: Ruby's */
3333 int WSAAPI
3334 rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
3335  struct timeval *timeout)
3336 {
3337  return rb_w32_select_with_thread(nfds, rd, wr, ex, timeout, 0);
3338 }
3339 
3340 /* License: Ruby's */
3341 static FARPROC
3342 get_wsa_extension_function(SOCKET s, GUID guid)
3343 {
3344  DWORD dmy;
3345  FARPROC ptr = NULL;
3346 
3347  WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
3348  &ptr, sizeof(ptr), &dmy, NULL, NULL);
3349  if (!ptr)
3350  errno = ENOSYS;
3351  return ptr;
3352 }
3353 
3354 #undef accept
3355 
3356 /* License: Artistic or GPL */
3357 int WSAAPI
3358 rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
3359 {
3360  SOCKET r;
3361  int fd;
3362 
3363  RUBY_CRITICAL {
3364  r = accept(TO_SOCKET(s), addr, addrlen);
3365  if (r != INVALID_SOCKET) {
3366  SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
3367  fd = rb_w32_open_osfhandle((intptr_t)r, O_RDWR|O_BINARY|O_NOINHERIT);
3368  if (fd != -1)
3369  socklist_insert(r, 0);
3370  else
3371  closesocket(r);
3372  }
3373  else {
3374  errno = map_errno(WSAGetLastError());
3375  fd = -1;
3376  }
3377  }
3378  return fd;
3379 }
3380 
3381 #undef bind
3382 
3383 /* License: Artistic or GPL */
3384 int WSAAPI
3385 rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
3386 {
3387  int r;
3388 
3389  RUBY_CRITICAL {
3390  r = bind(TO_SOCKET(s), addr, addrlen);
3391  if (r == SOCKET_ERROR)
3392  errno = map_errno(WSAGetLastError());
3393  }
3394  return r;
3395 }
3396 
3397 #undef connect
3398 
3399 /* License: Artistic or GPL */
3400 int WSAAPI
3401 rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
3402 {
3403  int r;
3404  RUBY_CRITICAL {
3405  r = connect(TO_SOCKET(s), addr, addrlen);
3406  if (r == SOCKET_ERROR) {
3407  int err = WSAGetLastError();
3408  if (err != WSAEWOULDBLOCK)
3409  errno = map_errno(err);
3410  else
3411  errno = EINPROGRESS;
3412  }
3413  }
3414  return r;
3415 }
3416 
3417 
3418 #undef getpeername
3419 
3420 /* License: Artistic or GPL */
3421 int WSAAPI
3422 rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
3423 {
3424  int r;
3425  RUBY_CRITICAL {
3426  r = getpeername(TO_SOCKET(s), addr, addrlen);
3427  if (r == SOCKET_ERROR)
3428  errno = map_errno(WSAGetLastError());
3429  }
3430  return r;
3431 }
3432 
3433 #undef getsockname
3434 
3435 /* License: Artistic or GPL */
3436 int WSAAPI
3437 rb_w32_getsockname(int fd, struct sockaddr *addr, int *addrlen)
3438 {
3439  int sock;
3440  int r;
3441  RUBY_CRITICAL {
3442  sock = TO_SOCKET(fd);
3443  r = getsockname(sock, addr, addrlen);
3444  if (r == SOCKET_ERROR) {
3445  DWORD wsaerror = WSAGetLastError();
3446  if (wsaerror == WSAEINVAL) {
3447  int flags;
3448  if (socklist_lookup(sock, &flags)) {
3449  int af = GET_FAMILY(flags);
3450  if (af) {
3451  memset(addr, 0, *addrlen);
3452  addr->sa_family = af;
3453  return 0;
3454  }
3455  }
3456  }
3457  errno = map_errno(wsaerror);
3458  }
3459  }
3460  return r;
3461 }
3462 
3463 #undef getsockopt
3464 
3465 /* License: Artistic or GPL */
3466 int WSAAPI
3467 rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
3468 {
3469  int r;
3470  RUBY_CRITICAL {
3471  r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
3472  if (r == SOCKET_ERROR)
3473  errno = map_errno(WSAGetLastError());
3474  }
3475  return r;
3476 }
3477 
3478 #undef ioctlsocket
3479 
3480 /* License: Artistic or GPL */
3481 int WSAAPI
3482 rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
3483 {
3484  int r;
3485  RUBY_CRITICAL {
3486  r = ioctlsocket(TO_SOCKET(s), cmd, argp);
3487  if (r == SOCKET_ERROR)
3488  errno = map_errno(WSAGetLastError());
3489  }
3490  return r;
3491 }
3492 
3493 #undef listen
3494 
3495 /* License: Artistic or GPL */
3496 int WSAAPI
3497 rb_w32_listen(int s, int backlog)
3498 {
3499  int r;
3500  RUBY_CRITICAL {
3501  r = listen(TO_SOCKET(s), backlog);
3502  if (r == SOCKET_ERROR)
3503  errno = map_errno(WSAGetLastError());
3504  }
3505  return r;
3506 }
3507 
3508 #undef recv
3509 #undef recvfrom
3510 #undef send
3511 #undef sendto
3512 
3513 /* License: Ruby's */
3514 static int
3515 finish_overlapped_socket(BOOL input, SOCKET s, WSAOVERLAPPED *wol, int result, DWORD *len, DWORD size)
3516 {
3517  DWORD flg;
3518  int err;
3519 
3520  if (result != SOCKET_ERROR)
3521  *len = size;
3522  else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
3523  switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) {
3524  case WAIT_OBJECT_0:
3525  RUBY_CRITICAL {
3526  result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg);
3527  }
3528  if (result) {
3529  result = 0;
3530  *len = size;
3531  break;
3532  }
3533  result = SOCKET_ERROR;
3534  /* thru */
3535  default:
3536  if ((err = WSAGetLastError()) == WSAECONNABORTED && !input)
3537  errno = EPIPE;
3538  else if (err == WSAEMSGSIZE && input) {
3539  result = 0;
3540  *len = size;
3541  break;
3542  }
3543  else
3544  errno = map_errno(err);
3545  /* thru */
3546  case WAIT_OBJECT_0 + 1:
3547  /* interrupted */
3548  *len = -1;
3549  CancelIo((HANDLE)s);
3550  break;
3551  }
3552  }
3553  else {
3554  if (err == WSAECONNABORTED && !input)
3555  errno = EPIPE;
3556  else
3557  errno = map_errno(err);
3558  *len = -1;
3559  }
3560  CloseHandle(wol->hEvent);
3561 
3562  return result;
3563 }
3564 
3565 /* License: Artistic or GPL */
3566 static int
3567 overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
3568  struct sockaddr *addr, int *addrlen)
3569 {
3570  int r;
3571  int ret;
3572  int mode = 0;
3573  DWORD flg;
3574  WSAOVERLAPPED wol;
3575  WSABUF wbuf;
3576  SOCKET s;
3577 
3578  s = TO_SOCKET(fd);
3579  socklist_lookup(s, &mode);
3580  if (GET_FLAGS(mode) & O_NONBLOCK) {
3581  RUBY_CRITICAL {
3582  if (input) {
3583  if (addr && addrlen)
3584  r = recvfrom(s, buf, len, flags, addr, addrlen);
3585  else
3586  r = recv(s, buf, len, flags);
3587  if (r == SOCKET_ERROR)
3588  errno = map_errno(WSAGetLastError());
3589  }
3590  else {
3591  if (addr && addrlen)
3592  r = sendto(s, buf, len, flags, addr, *addrlen);
3593  else
3594  r = send(s, buf, len, flags);
3595  if (r == SOCKET_ERROR) {
3596  DWORD err = WSAGetLastError();
3597  if (err == WSAECONNABORTED)
3598  errno = EPIPE;
3599  else
3600  errno = map_errno(err);
3601  }
3602  }
3603  }
3604  }
3605  else {
3606  DWORD size;
3607  DWORD rlen;
3608  wbuf.len = len;
3609  wbuf.buf = buf;
3610  memset(&wol, 0, sizeof(wol));
3611  RUBY_CRITICAL {
3612  wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3613  if (input) {
3614  flg = flags;
3615  if (addr && addrlen)
3616  ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
3617  &wol, NULL);
3618  else
3619  ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL);
3620  }
3621  else {
3622  if (addr && addrlen)
3623  ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
3624  &wol, NULL);
3625  else
3626  ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL);
3627  }
3628  }
3629 
3630  finish_overlapped_socket(input, s, &wol, ret, &rlen, size);
3631  r = (int)rlen;
3632  }
3633 
3634  return r;
3635 }
3636 
3637 /* License: Ruby's */
3638 int WSAAPI
3639 rb_w32_recv(int fd, char *buf, int len, int flags)
3640 {
3641  return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
3642 }
3643 
3644 /* License: Ruby's */
3645 int WSAAPI
3646 rb_w32_recvfrom(int fd, char *buf, int len, int flags,
3647  struct sockaddr *from, int *fromlen)
3648 {
3649  return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
3650 }
3651 
3652 /* License: Ruby's */
3653 int WSAAPI
3654 rb_w32_send(int fd, const char *buf, int len, int flags)
3655 {
3656  return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL);
3657 }
3658 
3659 /* License: Ruby's */
3660 int WSAAPI
3661 rb_w32_sendto(int fd, const char *buf, int len, int flags,
3662  const struct sockaddr *to, int tolen)
3663 {
3664  return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
3665  (struct sockaddr *)to, &tolen);
3666 }
3667 
3668 #if !defined(MSG_TRUNC) && !defined(__MINGW32__)
3669 /* License: Ruby's */
3670 typedef struct {
3671  SOCKADDR *name;
3672  int namelen;
3673  WSABUF *lpBuffers;
3674  DWORD dwBufferCount;
3675  WSABUF Control;
3676  DWORD dwFlags;
3677 } WSAMSG;
3678 #endif
3679 #ifndef WSAID_WSARECVMSG
3680 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
3681 #endif
3682 #ifndef WSAID_WSASENDMSG
3683 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
3684 #endif
3685 
3686 /* License: Ruby's */
3687 #define msghdr_to_wsamsg(msg, wsamsg) \
3688  do { \
3689  int i; \
3690  (wsamsg)->name = (msg)->msg_name; \
3691  (wsamsg)->namelen = (msg)->msg_namelen; \
3692  (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
3693  (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
3694  for (i = 0; i < (msg)->msg_iovlen; ++i) { \
3695  (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
3696  (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
3697  } \
3698  (wsamsg)->Control.buf = (msg)->msg_control; \
3699  (wsamsg)->Control.len = (msg)->msg_controllen; \
3700  (wsamsg)->dwFlags = (msg)->msg_flags; \
3701  } while (0)
3702 
3703 /* License: Ruby's */
3704 int
3705 recvmsg(int fd, struct msghdr *msg, int flags)
3706 {
3707  typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3708  static WSARecvMsg_t pWSARecvMsg = NULL;
3709  WSAMSG wsamsg;
3710  SOCKET s;
3711  int mode = 0;
3712  DWORD len;
3713  int ret;
3714 
3715  s = TO_SOCKET(fd);
3716 
3717  if (!pWSARecvMsg) {
3718  static const GUID guid = WSAID_WSARECVMSG;
3719  pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, guid);
3720  if (!pWSARecvMsg)
3721  return -1;
3722  }
3723 
3724  msghdr_to_wsamsg(msg, &wsamsg);
3725  wsamsg.dwFlags |= flags;
3726 
3727  socklist_lookup(s, &mode);
3728  if (GET_FLAGS(mode) & O_NONBLOCK) {
3729  RUBY_CRITICAL {
3730  if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
3731  errno = map_errno(WSAGetLastError());
3732  len = -1;
3733  }
3734  }
3735  }
3736  else {
3737  DWORD size;
3738  WSAOVERLAPPED wol;
3739  memset(&wol, 0, sizeof(wol));
3740  RUBY_CRITICAL {
3741  wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3742  ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL);
3743  }
3744 
3745  ret = finish_overlapped_socket(TRUE, s, &wol, ret, &len, size);
3746  }
3747  if (ret == SOCKET_ERROR)
3748  return -1;
3749 
3750  /* WSAMSG to msghdr */
3751  msg->msg_name = wsamsg.name;
3752  msg->msg_namelen = wsamsg.namelen;
3753  msg->msg_flags = wsamsg.dwFlags;
3754 
3755  return len;
3756 }
3757 
3758 /* License: Ruby's */
3759 int
3760 sendmsg(int fd, const struct msghdr *msg, int flags)
3761 {
3762  typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3763  static WSASendMsg_t pWSASendMsg = NULL;
3764  WSAMSG wsamsg;
3765  SOCKET s;
3766  int mode = 0;
3767  DWORD len;
3768  int ret;
3769 
3770  s = TO_SOCKET(fd);
3771 
3772  if (!pWSASendMsg) {
3773  static const GUID guid = WSAID_WSASENDMSG;
3774  pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, guid);
3775  if (!pWSASendMsg)
3776  return -1;
3777  }
3778 
3779  msghdr_to_wsamsg(msg, &wsamsg);
3780 
3781  socklist_lookup(s, &mode);
3782  if (GET_FLAGS(mode) & O_NONBLOCK) {
3783  RUBY_CRITICAL {
3784  if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
3785  errno = map_errno(WSAGetLastError());
3786  len = -1;
3787  }
3788  }
3789  }
3790  else {
3791  DWORD size;
3792  WSAOVERLAPPED wol;
3793  memset(&wol, 0, sizeof(wol));
3794  RUBY_CRITICAL {
3795  wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3796  ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL);
3797  }
3798 
3799  finish_overlapped_socket(FALSE, s, &wol, ret, &len, size);
3800  }
3801 
3802  return len;
3803 }
3804 
3805 #undef setsockopt
3806 
3807 /* License: Artistic or GPL */
3808 int WSAAPI
3809 rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
3810 {
3811  int r;
3812  RUBY_CRITICAL {
3813  r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
3814  if (r == SOCKET_ERROR)
3815  errno = map_errno(WSAGetLastError());
3816  }
3817  return r;
3818 }
3819 
3820 #undef shutdown
3821 
3822 /* License: Artistic or GPL */
3823 int WSAAPI
3824 rb_w32_shutdown(int s, int how)
3825 {
3826  int r;
3827  RUBY_CRITICAL {
3828  r = shutdown(TO_SOCKET(s), how);
3829  if (r == SOCKET_ERROR)
3830  errno = map_errno(WSAGetLastError());
3831  }
3832  return r;
3833 }
3834 
3835 /* License: Ruby's */
3836 static SOCKET
3837 open_ifs_socket(int af, int type, int protocol)
3838 {
3839  unsigned long proto_buffers_len = 0;
3840  int error_code;
3841  SOCKET out = INVALID_SOCKET;
3842 
3843  if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) {
3844  error_code = WSAGetLastError();
3845  if (error_code == WSAENOBUFS) {
3846  WSAPROTOCOL_INFO *proto_buffers;
3847  int protocols_available = 0;
3848 
3849  proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len);
3850  if (!proto_buffers) {
3851  WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
3852  return INVALID_SOCKET;
3853  }
3854 
3855  protocols_available =
3856  WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len);
3857  if (protocols_available != SOCKET_ERROR) {
3858  int i;
3859  for (i = 0; i < protocols_available; i++) {
3860  if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
3861  (type != proto_buffers[i].iSocketType) ||
3862  (protocol != 0 && protocol != proto_buffers[i].iProtocol))
3863  continue;
3864 
3865  if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
3866  continue;
3867 
3868  out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
3869  WSA_FLAG_OVERLAPPED);
3870  break;
3871  }
3872  if (out == INVALID_SOCKET)
3873  out = WSASocket(af, type, protocol, NULL, 0, 0);
3874  if (out != INVALID_SOCKET)
3875  SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0);
3876  }
3877 
3878  free(proto_buffers);
3879  }
3880  }
3881 
3882  return out;
3883 }
3884 
3885 #undef socket
3886 
3887 /* License: Artistic or GPL */
3888 int WSAAPI
3889 rb_w32_socket(int af, int type, int protocol)
3890 {
3891  SOCKET s;
3892  int fd;
3893 
3894  RUBY_CRITICAL {
3895  s = open_ifs_socket(af, type, protocol);
3896  if (s == INVALID_SOCKET) {
3897  errno = map_errno(WSAGetLastError());
3898  fd = -1;
3899  }
3900  else {
3901  fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
3902  if (fd != -1)
3903  socklist_insert(s, MAKE_SOCKDATA(af, 0));
3904  else
3905  closesocket(s);
3906  }
3907  }
3908  return fd;
3909 }
3910 
3911 #undef gethostbyaddr
3912 
3913 /* License: Artistic or GPL */
3914 struct hostent * WSAAPI
3915 rb_w32_gethostbyaddr(const char *addr, int len, int type)
3916 {
3917  struct hostent *r;
3918  RUBY_CRITICAL {
3919  r = gethostbyaddr(addr, len, type);
3920  if (r == NULL)
3921  errno = map_errno(WSAGetLastError());
3922  }
3923  return r;
3924 }
3925 
3926 #undef gethostbyname
3927 
3928 /* License: Artistic or GPL */
3929 struct hostent * WSAAPI
3930 rb_w32_gethostbyname(const char *name)
3931 {
3932  struct hostent *r;
3933  RUBY_CRITICAL {
3934  r = gethostbyname(name);
3935  if (r == NULL)
3936  errno = map_errno(WSAGetLastError());
3937  }
3938  return r;
3939 }
3940 
3941 #undef gethostname
3942 
3943 /* License: Artistic or GPL */
3944 int WSAAPI
3945 rb_w32_gethostname(char *name, int len)
3946 {
3947  int r;
3948  RUBY_CRITICAL {
3949  r = gethostname(name, len);
3950  if (r == SOCKET_ERROR)
3951  errno = map_errno(WSAGetLastError());
3952  }
3953  return r;
3954 }
3955 
3956 #undef getprotobyname
3957 
3958 /* License: Artistic or GPL */
3959 struct protoent * WSAAPI
3960 rb_w32_getprotobyname(const char *name)
3961 {
3962  struct protoent *r;
3963  RUBY_CRITICAL {
3964  r = getprotobyname(name);
3965  if (r == NULL)
3966  errno = map_errno(WSAGetLastError());
3967  }
3968  return r;
3969 }
3970 
3971 #undef getprotobynumber
3972 
3973 /* License: Artistic or GPL */
3974 struct protoent * WSAAPI
3975 rb_w32_getprotobynumber(int num)
3976 {
3977  struct protoent *r;
3978  RUBY_CRITICAL {
3979  r = getprotobynumber(num);
3980  if (r == NULL)
3981  errno = map_errno(WSAGetLastError());
3982  }
3983  return r;
3984 }
3985 
3986 #undef getservbyname
3987 
3988 /* License: Artistic or GPL */
3989 struct servent * WSAAPI
3990 rb_w32_getservbyname(const char *name, const char *proto)
3991 {
3992  struct servent *r;
3993  RUBY_CRITICAL {
3994  r = getservbyname(name, proto);
3995  if (r == NULL)
3996  errno = map_errno(WSAGetLastError());
3997  }
3998  return r;
3999 }
4000 
4001 #undef getservbyport
4002 
4003 /* License: Artistic or GPL */
4004 struct servent * WSAAPI
4005 rb_w32_getservbyport(int port, const char *proto)
4006 {
4007  struct servent *r;
4008  RUBY_CRITICAL {
4009  r = getservbyport(port, proto);
4010  if (r == NULL)
4011  errno = map_errno(WSAGetLastError());
4012  }
4013  return r;
4014 }
4015 
4016 /* License: Ruby's */
4017 static int
4018 socketpair_internal(int af, int type, int protocol, SOCKET *sv)
4019 {
4020  SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
4021  struct sockaddr_in sock_in4;
4022 #ifdef INET6
4023  struct sockaddr_in6 sock_in6;
4024 #endif
4025  struct sockaddr *addr;
4026  int ret = -1;
4027  int len;
4028 
4029  switch (af) {
4030  case AF_INET:
4031 #if defined PF_INET && PF_INET != AF_INET
4032  case PF_INET:
4033 #endif
4034  sock_in4.sin_family = AF_INET;
4035  sock_in4.sin_port = 0;
4036  sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4037  addr = (struct sockaddr *)&sock_in4;
4038  len = sizeof(sock_in4);
4039  break;
4040 #ifdef INET6
4041  case AF_INET6:
4042  memset(&sock_in6, 0, sizeof(sock_in6));
4043  sock_in6.sin6_family = AF_INET6;
4044  sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
4045  addr = (struct sockaddr *)&sock_in6;
4046  len = sizeof(sock_in6);
4047  break;
4048 #endif
4049  default:
4050  errno = EAFNOSUPPORT;
4051  return -1;
4052  }
4053  if (type != SOCK_STREAM) {
4054  errno = EPROTOTYPE;
4055  return -1;
4056  }
4057 
4058  sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
4059  sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
4060  RUBY_CRITICAL {
4061  do {
4062  svr = open_ifs_socket(af, type, protocol);
4063  if (svr == INVALID_SOCKET)
4064  break;
4065  if (bind(svr, addr, len) < 0)
4066  break;
4067  if (getsockname(svr, addr, &len) < 0)
4068  break;
4069  if (type == SOCK_STREAM)
4070  listen(svr, 5);
4071 
4072  w = open_ifs_socket(af, type, protocol);
4073  if (w == INVALID_SOCKET)
4074  break;
4075  if (connect(w, addr, len) < 0)
4076  break;
4077 
4078  r = accept(svr, addr, &len);
4079  if (r == INVALID_SOCKET)
4080  break;
4081  SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
4082 
4083  ret = 0;
4084  } while (0);
4085 
4086  if (ret < 0) {
4087  errno = map_errno(WSAGetLastError());
4088  if (r != INVALID_SOCKET)
4089  closesocket(r);
4090  if (w != INVALID_SOCKET)
4091  closesocket(w);
4092  }
4093  else {
4094  sv[0] = r;
4095  sv[1] = w;
4096  }
4097  if (svr != INVALID_SOCKET)
4098  closesocket(svr);
4099  }
4100 
4101  return ret;
4102 }
4103 
4104 /* License: Ruby's */
4105 int
4106 socketpair(int af, int type, int protocol, int *sv)
4107 {
4108  SOCKET pair[2];
4109 
4110  if (socketpair_internal(af, type, protocol, pair) < 0)
4111  return -1;
4112  sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
4113  if (sv[0] == -1) {
4114  closesocket(pair[0]);
4115  closesocket(pair[1]);
4116  return -1;
4117  }
4118  sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
4119  if (sv[1] == -1) {
4120  rb_w32_close(sv[0]);
4121  closesocket(pair[1]);
4122  return -1;
4123  }
4124  socklist_insert(pair[0], MAKE_SOCKDATA(af, 0));
4125  socklist_insert(pair[1], MAKE_SOCKDATA(af, 0));
4126 
4127  return 0;
4128 }
4129 
4130 #if !defined(_MSC_VER) || _MSC_VER >= 1400
4131 /* License: Ruby's */
4132 static void
4133 str2guid(const char *str, GUID *guid)
4134 {
4135 #define hex2byte(str) \
4136  ((isdigit(*(str)) ? *(str) - '0' : toupper(*(str)) - 'A' + 10) << 4 | (isdigit(*((str) + 1)) ? *((str) + 1) - '0' : toupper(*((str) + 1)) - 'A' + 10))
4137  char *end;
4138  int i;
4139  if (*str == '{') str++;
4140  guid->Data1 = (long)strtoul(str, &end, 16);
4141  str += 9;
4142  guid->Data2 = (unsigned short)strtoul(str, &end, 16);
4143  str += 5;
4144  guid->Data3 = (unsigned short)strtoul(str, &end, 16);
4145  str += 5;
4146  guid->Data4[0] = hex2byte(str);
4147  str += 2;
4148  guid->Data4[1] = hex2byte(str);
4149  str += 3;
4150  for (i = 0; i < 6; i++) {
4151  guid->Data4[i + 2] = hex2byte(str);
4152  str += 2;
4153  }
4154 }
4155 
4156 /* License: Ruby's */
4157 #ifndef HAVE_TYPE_NET_LUID
4158  typedef struct {
4159  uint64_t Value;
4160  struct {
4161  uint64_t Reserved :24;
4162  uint64_t NetLuidIndex :24;
4163  uint64_t IfType :16;
4164  } Info;
4165  } NET_LUID;
4166 #endif
4167 typedef DWORD (WINAPI *cigl_t)(const GUID *, NET_LUID *);
4168 typedef DWORD (WINAPI *cilnA_t)(const NET_LUID *, char *, size_t);
4169 static cigl_t pConvertInterfaceGuidToLuid = (cigl_t)-1;
4170 static cilnA_t pConvertInterfaceLuidToNameA = (cilnA_t)-1;
4171 
4172 int
4173 getifaddrs(struct ifaddrs **ifap)
4174 {
4175  ULONG size = 0;
4176  ULONG ret;
4177  IP_ADAPTER_ADDRESSES *root, *addr;
4178  struct ifaddrs *prev;
4179 
4180  ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
4181  if (ret != ERROR_BUFFER_OVERFLOW) {
4182  errno = map_errno(ret);
4183  return -1;
4184  }
4185  root = ruby_xmalloc(size);
4186  ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, root, &size);
4187  if (ret != ERROR_SUCCESS) {
4188  errno = map_errno(ret);
4189  ruby_xfree(root);
4190  return -1;
4191  }
4192 
4193  if (pConvertInterfaceGuidToLuid == (cigl_t)-1)
4194  pConvertInterfaceGuidToLuid =
4195  (cigl_t)get_proc_address("iphlpapi.dll",
4196  "ConvertInterfaceGuidToLuid", NULL);
4197  if (pConvertInterfaceLuidToNameA == (cilnA_t)-1)
4198  pConvertInterfaceLuidToNameA =
4199  (cilnA_t)get_proc_address("iphlpapi.dll",
4200  "ConvertInterfaceLuidToNameA", NULL);
4201 
4202  for (prev = NULL, addr = root; addr; addr = addr->Next) {
4203  struct ifaddrs *ifa = ruby_xcalloc(1, sizeof(*ifa));
4204  char name[IFNAMSIZ];
4205  GUID guid;
4206  NET_LUID luid;
4207 
4208  if (prev)
4209  prev->ifa_next = ifa;
4210  else
4211  *ifap = ifa;
4212 
4213  str2guid(addr->AdapterName, &guid);
4214  if (pConvertInterfaceGuidToLuid && pConvertInterfaceLuidToNameA &&
4215  pConvertInterfaceGuidToLuid(&guid, &luid) == NO_ERROR &&
4216  pConvertInterfaceLuidToNameA(&luid, name, sizeof(name)) == NO_ERROR) {
4217  ifa->ifa_name = ruby_strdup(name);
4218  }
4219  else {
4220  ifa->ifa_name = ruby_strdup(addr->AdapterName);
4221  }
4222 
4223  if (addr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
4224  ifa->ifa_flags |= IFF_LOOPBACK;
4225  if (addr->OperStatus == IfOperStatusUp) {
4226  ifa->ifa_flags |= IFF_UP;
4227 
4228  if (addr->FirstUnicastAddress) {
4229  IP_ADAPTER_UNICAST_ADDRESS *cur;
4230  int added = 0;
4231  for (cur = addr->FirstUnicastAddress; cur; cur = cur->Next) {
4232  if (cur->Flags & IP_ADAPTER_ADDRESS_TRANSIENT ||
4233  cur->DadState == IpDadStateDeprecated) {
4234  continue;
4235  }
4236  if (added) {
4237  prev = ifa;
4238  ifa = ruby_xcalloc(1, sizeof(*ifa));
4239  prev->ifa_next = ifa;
4240  ifa->ifa_name = ruby_strdup(prev->ifa_name);
4241  ifa->ifa_flags = prev->ifa_flags;
4242  }
4243  ifa->ifa_addr = ruby_xmalloc(cur->Address.iSockaddrLength);
4244  memcpy(ifa->ifa_addr, cur->Address.lpSockaddr,
4245  cur->Address.iSockaddrLength);
4246  added = 1;
4247  }
4248  }
4249  }
4250 
4251  prev = ifa;
4252  }
4253 
4254  ruby_xfree(root);
4255  return 0;
4256 }
4257 
4258 /* License: Ruby's */
4259 void
4260 freeifaddrs(struct ifaddrs *ifp)
4261 {
4262  while (ifp) {
4263  struct ifaddrs *next = ifp->ifa_next;
4264  if (ifp->ifa_addr) ruby_xfree(ifp->ifa_addr);
4265  if (ifp->ifa_name) ruby_xfree(ifp->ifa_name);
4266  ruby_xfree(ifp);
4267  ifp = next;
4268  }
4269 }
4270 #endif
4271 
4272 #if 0 // Have never been used
4273 //
4274 // Networking stubs
4275 //
4276 
4277 void endhostent(void) {}
4278 void endnetent(void) {}
4279 void endprotoent(void) {}
4280 void endservent(void) {}
4281 
4282 struct netent *getnetent (void) {return (struct netent *) NULL;}
4283 
4284 struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;}
4285 
4286 struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;}
4287 
4288 struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
4289 
4290 struct servent *getservent (void) {return (struct servent *) NULL;}
4291 
4292 void sethostent (int stayopen) {}
4293 
4294 void setnetent (int stayopen) {}
4295 
4296 void setprotoent (int stayopen) {}
4297 
4298 void setservent (int stayopen) {}
4299 #endif
4300 
4301 /* License: Ruby's */
4302 static int
4303 setfl(SOCKET sock, int arg)
4304 {
4305  int ret;
4306  int af = 0;
4307  int flag = 0;
4308  u_long ioctlArg;
4309 
4310  socklist_lookup(sock, &flag);
4311  af = GET_FAMILY(flag);
4312  flag = GET_FLAGS(flag);
4313  if (arg & O_NONBLOCK) {
4314  flag |= O_NONBLOCK;
4315  ioctlArg = 1;
4316  }
4317  else {
4318  flag &= ~O_NONBLOCK;
4319  ioctlArg = 0;
4320  }
4321  RUBY_CRITICAL {
4322  ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
4323  if (ret == 0)
4324  socklist_insert(sock, MAKE_SOCKDATA(af, flag));
4325  else
4326  errno = map_errno(WSAGetLastError());
4327  }
4328 
4329  return ret;
4330 }
4331 
4332 /* License: Ruby's */
4333 static int
4334 dupfd(HANDLE hDup, int flags, int minfd)
4335 {
4336  int save_errno;
4337  int ret;
4338  int fds[32];
4339  int filled = 0;
4340 
4341  do {
4342  ret = _open_osfhandle((intptr_t)hDup, flags | FOPEN);
4343  if (ret == -1) {
4344  goto close_fds_and_return;
4345  }
4346  if (ret >= minfd) {
4347  goto close_fds_and_return;
4348  }
4349  fds[filled++] = ret;
4350  } while (filled < (int)numberof(fds));
4351 
4352  ret = dupfd(hDup, flags, minfd);
4353 
4354  close_fds_and_return:
4355  save_errno = errno;
4356  while (filled > 0) {
4357  int fd = fds[--filled];
4358  _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
4359  close(fd);
4360  }
4361  errno = save_errno;
4362 
4363  return ret;
4364 }
4365 
4366 /* License: Ruby's */
4367 int
4368 fcntl(int fd, int cmd, ...)
4369 {
4370  va_list va;
4371  int arg;
4372  DWORD flag;
4373 
4374  switch (cmd) {
4375  case F_SETFL: {
4376  SOCKET sock = TO_SOCKET(fd);
4377  if (!is_socket(sock)) {
4378  errno = EBADF;
4379  return -1;
4380  }
4381 
4382  va_start(va, cmd);
4383  arg = va_arg(va, int);
4384  va_end(va);
4385  return setfl(sock, arg);
4386  }
4387  case F_DUPFD: case F_DUPFD_CLOEXEC: {
4388  int ret;
4389  HANDLE hDup;
4390  flag = _osfile(fd);
4391  if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
4392  GetCurrentProcess(), &hDup, 0L,
4393  cmd == F_DUPFD && !(flag & FNOINHERIT),
4394  DUPLICATE_SAME_ACCESS))) {
4395  errno = map_errno(GetLastError());
4396  return -1;
4397  }
4398 
4399  va_start(va, cmd);
4400  arg = va_arg(va, int);
4401  va_end(va);
4402 
4403  if (cmd != F_DUPFD)
4404  flag |= FNOINHERIT;
4405  else
4406  flag &= ~FNOINHERIT;
4407  if ((ret = dupfd(hDup, flag, arg)) == -1)
4408  CloseHandle(hDup);
4409  return ret;
4410  }
4411  case F_GETFD: {
4412  SIGNED_VALUE h = _get_osfhandle(fd);
4413  if (h == -1) return -1;
4414  if (!GetHandleInformation((HANDLE)h, &flag)) {
4415  errno = map_errno(GetLastError());
4416  return -1;
4417  }
4418  return (flag & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
4419  }
4420  case F_SETFD: {
4421  SIGNED_VALUE h = _get_osfhandle(fd);
4422  if (h == -1) return -1;
4423  va_start(va, cmd);
4424  arg = va_arg(va, int);
4425  va_end(va);
4426  if (!SetHandleInformation((HANDLE)h, HANDLE_FLAG_INHERIT,
4427  (arg & FD_CLOEXEC) ? 0 : HANDLE_FLAG_INHERIT)) {
4428  errno = map_errno(GetLastError());
4429  return -1;
4430  }
4431  if (arg & FD_CLOEXEC)
4432  _osfile(fd) |= FNOINHERIT;
4433  else
4434  _osfile(fd) &= ~FNOINHERIT;
4435  return 0;
4436  }
4437  default:
4438  errno = EINVAL;
4439  return -1;
4440  }
4441 }
4442 
4443 /* License: Ruby's */
4444 int
4445 rb_w32_set_nonblock2(int fd, int nonblock)
4446 {
4447  SOCKET sock = TO_SOCKET(fd);
4448  if (is_socket(sock)) {
4449  return setfl(sock, nonblock ? O_NONBLOCK : 0);
4450  }
4451  else if (is_pipe(sock)) {
4452  DWORD state;
4453  if (!GetNamedPipeHandleState((HANDLE)sock, &state, NULL, NULL, NULL, NULL, 0)) {
4454  errno = map_errno(GetLastError());
4455  return -1;
4456  }
4457  if (nonblock) {
4458  state |= PIPE_NOWAIT;
4459  }
4460  else {
4461  state &= ~PIPE_NOWAIT;
4462  }
4463  if (!SetNamedPipeHandleState((HANDLE)sock, &state, NULL, NULL)) {
4464  errno = map_errno(GetLastError());
4465  return -1;
4466  }
4467  return 0;
4468  }
4469  else {
4470  errno = EBADF;
4471  return -1;
4472  }
4473 }
4474 
4475 int
4476 rb_w32_set_nonblock(int fd)
4477 {
4478  return rb_w32_set_nonblock2(fd, TRUE);
4479 }
4480 
4481 #ifndef WNOHANG
4482 #define WNOHANG -1
4483 #endif
4484 
4485 /* License: Ruby's */
4486 static rb_pid_t
4487 poll_child_status(struct ChildRecord *child, int *stat_loc)
4488 {
4489  DWORD exitcode;
4490  DWORD err;
4491 
4492  if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
4493  /* If an error occurred, return immediately. */
4494  err = GetLastError();
4495  switch (err) {
4496  case ERROR_INVALID_PARAMETER:
4497  errno = ECHILD;
4498  break;
4499  case ERROR_INVALID_HANDLE:
4500  errno = EINVAL;
4501  break;
4502  default:
4503  errno = map_errno(err);
4504  break;
4505  }
4506  error_exit:
4507  CloseChildHandle(child);
4508  return -1;
4509  }
4510  if (exitcode != STILL_ACTIVE) {
4511  rb_pid_t pid;
4512  /* If already died, wait process's real termination. */
4513  if (rb_w32_wait_events_blocking(&child->hProcess, 1, INFINITE) != WAIT_OBJECT_0) {
4514  goto error_exit;
4515  }
4516  pid = child->pid;
4517  CloseChildHandle(child);
4518  if (stat_loc) {
4519  *stat_loc = exitcode << 8;
4520  if (exitcode & 0xC0000000) {
4521  static const struct {
4522  DWORD status;
4523  int sig;
4524  } table[] = {
4525  {STATUS_ACCESS_VIOLATION, SIGSEGV},
4526  {STATUS_ILLEGAL_INSTRUCTION, SIGILL},
4527  {STATUS_PRIVILEGED_INSTRUCTION, SIGILL},
4528  {STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE},
4529  {STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE},
4530  {STATUS_FLOAT_INEXACT_RESULT, SIGFPE},
4531  {STATUS_FLOAT_INVALID_OPERATION, SIGFPE},
4532  {STATUS_FLOAT_OVERFLOW, SIGFPE},
4533  {STATUS_FLOAT_STACK_CHECK, SIGFPE},
4534  {STATUS_FLOAT_UNDERFLOW, SIGFPE},
4535 #ifdef STATUS_FLOAT_MULTIPLE_FAULTS
4536  {STATUS_FLOAT_MULTIPLE_FAULTS, SIGFPE},
4537 #endif
4538 #ifdef STATUS_FLOAT_MULTIPLE_TRAPS
4539  {STATUS_FLOAT_MULTIPLE_TRAPS, SIGFPE},
4540 #endif
4541  {STATUS_CONTROL_C_EXIT, SIGINT},
4542  };
4543  int i;
4544  for (i = 0; i < (int)numberof(table); i++) {
4545  if (table[i].status == exitcode) {
4546  *stat_loc |= table[i].sig;
4547  break;
4548  }
4549  }
4550  // if unknown status, assume SEGV
4551  if (i >= (int)numberof(table))
4552  *stat_loc |= SIGSEGV;
4553  }
4554  }
4555  return pid;
4556  }
4557  return 0;
4558 }
4559 
4560 /* License: Artistic or GPL */
4561 rb_pid_t
4562 waitpid(rb_pid_t pid, int *stat_loc, int options)
4563 {
4564  DWORD timeout;
4565 
4566  /* Artistic or GPL part start */
4567  if (options == WNOHANG) {
4568  timeout = 0;
4569  }
4570  else {
4571  timeout = INFINITE;
4572  }
4573  /* Artistic or GPL part end */
4574 
4575  if (pid == -1) {
4576  int count = 0;
4577  int ret;
4578  HANDLE events[MAXCHILDNUM];
4579  struct ChildRecord* cause;
4580 
4581  FOREACH_CHILD(child) {
4582  if (!child->pid || child->pid < 0) continue;
4583  if ((pid = poll_child_status(child, stat_loc))) return pid;
4584  events[count++] = child->hProcess;
4585  } END_FOREACH_CHILD;
4586  if (!count) {
4587  errno = ECHILD;
4588  return -1;
4589  }
4590 
4591  ret = rb_w32_wait_events_blocking(events, count, timeout);
4592  if (ret == WAIT_TIMEOUT) return 0;
4593  if ((ret -= WAIT_OBJECT_0) == count) {
4594  return -1;
4595  }
4596  if (ret > count) {
4597  errno = map_errno(GetLastError());
4598  return -1;
4599  }
4600 
4601  cause = FindChildSlotByHandle(events[ret]);
4602  if (!cause) {
4603  errno = ECHILD;
4604  return -1;
4605  }
4606  return poll_child_status(cause, stat_loc);
4607  }
4608  else {
4609  struct ChildRecord* child = FindChildSlot(pid);
4610  int retried = 0;
4611  if (!child) {
4612  errno = ECHILD;
4613  return -1;
4614  }
4615 
4616  while (!(pid = poll_child_status(child, stat_loc))) {
4617  /* wait... */
4618  int ret = rb_w32_wait_events_blocking(&child->hProcess, 1, timeout);
4619  if (ret == WAIT_OBJECT_0 + 1) return -1; /* maybe EINTR */
4620  if (ret != WAIT_OBJECT_0) {
4621  /* still active */
4622  if (options & WNOHANG) {
4623  pid = 0;
4624  break;
4625  }
4626  ++retried;
4627  }
4628  }
4629  if (pid == -1 && retried) pid = 0;
4630  }
4631 
4632  return pid;
4633 }
4634 
4635 #include <sys/timeb.h>
4636 
4637 static int have_precisetime = -1;
4638 
4639 static void
4640 get_systemtime(FILETIME *ft)
4641 {
4642  typedef void (WINAPI *get_time_func)(FILETIME *ft);
4643  static get_time_func func = (get_time_func)-1;
4644 
4645  if (func == (get_time_func)-1) {
4646  /* GetSystemTimePreciseAsFileTime is available since Windows 8 and Windows Server 2012. */
4647  func = (get_time_func)get_proc_address("kernel32", "GetSystemTimePreciseAsFileTime", NULL);
4648  if (func == NULL) {
4649  func = GetSystemTimeAsFileTime;
4650  have_precisetime = 0;
4651  }
4652  else
4653  have_precisetime = 1;
4654  }
4655  if (!ft) return;
4656  func(ft);
4657 }
4658 
4659 /* License: Ruby's */
4660 /* split FILETIME value into UNIX time and sub-seconds in NT ticks */
4661 static time_t
4662 filetime_split(const FILETIME* ft, long *subsec)
4663 {
4664  ULARGE_INTEGER tmp;
4665  unsigned LONG_LONG lt;
4666  const unsigned LONG_LONG subsec_unit = (unsigned LONG_LONG)10 * 1000 * 1000;
4667 
4668  tmp.LowPart = ft->dwLowDateTime;
4669  tmp.HighPart = ft->dwHighDateTime;
4670  lt = tmp.QuadPart;
4671 
4672  /* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC,
4673  convert it into UNIX time (since 1970/01/01 00:00:00 UTC).
4674  the first leap second is at 1972/06/30, so we doesn't need to think
4675  about it. */
4676  lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * subsec_unit;
4677 
4678  *subsec = (long)(lt % subsec_unit);
4679  return (time_t)(lt / subsec_unit);
4680 }
4681 
4682 /* License: Ruby's */
4683 int __cdecl
4684 gettimeofday(struct timeval *tv, struct timezone *tz)
4685 {
4686  FILETIME ft;
4687  long subsec;
4688 
4689  get_systemtime(&ft);
4690  tv->tv_sec = filetime_split(&ft, &subsec);
4691  tv->tv_usec = subsec / 10;
4692 
4693  return 0;
4694 }
4695 
4696 /* License: Ruby's */
4697 int
4698 clock_gettime(clockid_t clock_id, struct timespec *sp)
4699 {
4700  switch (clock_id) {
4701  case CLOCK_REALTIME:
4702  {
4703  FILETIME ft;
4704  long subsec;
4705 
4706  get_systemtime(&ft);
4707  sp->tv_sec = filetime_split(&ft, &subsec);
4708  sp->tv_nsec = subsec * 100;
4709  return 0;
4710  }
4711  case CLOCK_MONOTONIC:
4712  {
4713  LARGE_INTEGER freq;
4714  LARGE_INTEGER count;
4715  if (!QueryPerformanceFrequency(&freq)) {
4716  errno = map_errno(GetLastError());
4717  return -1;
4718  }
4719  if (!QueryPerformanceCounter(&count)) {
4720  errno = map_errno(GetLastError());
4721  return -1;
4722  }
4723  sp->tv_sec = count.QuadPart / freq.QuadPart;
4724  if (freq.QuadPart < 1000000000)
4725  sp->tv_nsec = (count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
4726  else
4727  sp->tv_nsec = (long)((count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
4728  return 0;
4729  }
4730  default:
4731  errno = EINVAL;
4732  return -1;
4733  }
4734 }
4735 
4736 /* License: Ruby's */
4737 int
4738 clock_getres(clockid_t clock_id, struct timespec *sp)
4739 {
4740  switch (clock_id) {
4741  case CLOCK_REALTIME:
4742  {
4743  sp->tv_sec = 0;
4744  sp->tv_nsec = 1000;
4745  return 0;
4746  }
4747  case CLOCK_MONOTONIC:
4748  {
4749  LARGE_INTEGER freq;
4750  if (!QueryPerformanceFrequency(&freq)) {
4751  errno = map_errno(GetLastError());
4752  return -1;
4753  }
4754  sp->tv_sec = 0;
4755  sp->tv_nsec = (long)(1000000000.0 / freq.QuadPart);
4756  return 0;
4757  }
4758  default:
4759  errno = EINVAL;
4760  return -1;
4761  }
4762 }
4763 
4764 /* License: Ruby's */
4765 static char *
4766 w32_getcwd(char *buffer, int size, UINT cp, void *alloc(int, void *), void *arg)
4767 {
4768  WCHAR *p;
4769  int wlen, len;
4770 
4771  len = GetCurrentDirectoryW(0, NULL);
4772  if (!len) {
4773  errno = map_errno(GetLastError());
4774  return NULL;
4775  }
4776 
4777  if (buffer && size < len) {
4778  errno = ERANGE;
4779  return NULL;
4780  }
4781 
4782  p = ALLOCA_N(WCHAR, len);
4783  if (!GetCurrentDirectoryW(len, p)) {
4784  errno = map_errno(GetLastError());
4785  return NULL;
4786  }
4787 
4788  wlen = translate_wchar(p, L'\\', L'/') - p + 1;
4789  len = WideCharToMultiByte(cp, 0, p, wlen, NULL, 0, NULL, NULL);
4790  if (buffer) {
4791  if (size < len) {
4792  errno = ERANGE;
4793  return NULL;
4794  }
4795  }
4796  else {
4797  buffer = (*alloc)(len, arg);
4798  if (!buffer) {
4799  errno = ENOMEM;
4800  return NULL;
4801  }
4802  }
4803  WideCharToMultiByte(cp, 0, p, wlen, buffer, len, NULL, NULL);
4804 
4805  return buffer;
4806 }
4807 
4808 /* License: Ruby's */
4809 static void *
4810 getcwd_alloc(int size, void *dummy)
4811 {
4812  return malloc(size);
4813 }
4814 
4815 /* License: Ruby's */
4816 char *
4817 rb_w32_getcwd(char *buffer, int size)
4818 {
4819  return w32_getcwd(buffer, size, filecp(), getcwd_alloc, NULL);
4820 }
4821 
4822 /* License: Ruby's */
4823 char *
4824 rb_w32_ugetcwd(char *buffer, int size)
4825 {
4826  return w32_getcwd(buffer, size, CP_UTF8, getcwd_alloc, NULL);
4827 }
4828 
4829 /* License: Ruby's */
4830 static void *
4831 getcwd_value(int size, void *arg)
4832 {
4833  VALUE str = *(VALUE *)arg = rb_utf8_str_new(0, size - 1);
4834  return RSTRING_PTR(str);
4835 }
4836 
4837 /* License: Ruby's */
4838 VALUE
4839 rb_dir_getwd_ospath(void)
4840 {
4841  VALUE cwd = Qnil;
4842  w32_getcwd(NULL, 0, CP_UTF8, getcwd_value, &cwd);
4843  return cwd;
4844 }
4845 
4846 /* License: Artistic or GPL */
4847 int
4848 chown(const char *path, int owner, int group)
4849 {
4850  return 0;
4851 }
4852 
4853 /* License: Artistic or GPL */
4854 int
4855 rb_w32_uchown(const char *path, int owner, int group)
4856 {
4857  return 0;
4858 }
4859 
4860 int
4861 lchown(const char *path, int owner, int group)
4862 {
4863  return 0;
4864 }
4865 
4866 int
4867 rb_w32_ulchown(const char *path, int owner, int group)
4868 {
4869  return 0;
4870 }
4871 
4872 /* License: Ruby's */
4873 int
4874 kill(int pid, int sig)
4875 {
4876  int ret = 0;
4877  DWORD err;
4878 
4879  if (pid < 0 || (pid == 0 && sig != SIGINT)) {
4880  errno = EINVAL;
4881  return -1;
4882  }
4883 
4884  if ((unsigned int)pid == GetCurrentProcessId() &&
4885  (sig != 0 && sig != SIGKILL)) {
4886  if ((ret = raise(sig)) != 0) {
4887  /* MSVCRT doesn't set errno... */
4888  errno = EINVAL;
4889  }
4890  return ret;
4891  }
4892 
4893  switch (sig) {
4894  case 0:
4895  RUBY_CRITICAL {
4896  HANDLE hProc =
4897  OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
4898  if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
4899  if (GetLastError() == ERROR_INVALID_PARAMETER) {
4900  errno = ESRCH;
4901  }
4902  else {
4903  errno = EPERM;
4904  }
4905  ret = -1;
4906  }
4907  else {
4908  CloseHandle(hProc);
4909  }
4910  }
4911  break;
4912 
4913  case SIGINT:
4914  RUBY_CRITICAL {
4915  DWORD ctrlEvent = CTRL_C_EVENT;
4916  if (pid != 0) {
4917  /* CTRL+C signal cannot be generated for process groups.
4918  * Instead, we use CTRL+BREAK signal. */
4919  ctrlEvent = CTRL_BREAK_EVENT;
4920  }
4921  if (!GenerateConsoleCtrlEvent(ctrlEvent, (DWORD)pid)) {
4922  if ((err = GetLastError()) == 0)
4923  errno = EPERM;
4924  else
4925  errno = map_errno(GetLastError());
4926  ret = -1;
4927  }
4928  }
4929  break;
4930 
4931  case SIGKILL:
4932  RUBY_CRITICAL {
4933  HANDLE hProc;
4934  struct ChildRecord* child = FindChildSlot(pid);
4935  if (child) {
4936  hProc = child->hProcess;
4937  }
4938  else {
4939  hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
4940  }
4941  if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
4942  if (GetLastError() == ERROR_INVALID_PARAMETER) {
4943  errno = ESRCH;
4944  }
4945  else {
4946  errno = EPERM;
4947  }
4948  ret = -1;
4949  }
4950  else {
4951  DWORD status;
4952  if (!GetExitCodeProcess(hProc, &status)) {
4953  errno = map_errno(GetLastError());
4954  ret = -1;
4955  }
4956  else if (status == STILL_ACTIVE) {
4957  if (!TerminateProcess(hProc, 0)) {
4958  errno = EPERM;
4959  ret = -1;
4960  }
4961  }
4962  else {
4963  errno = ESRCH;
4964  ret = -1;
4965  }
4966  if (!child) {
4967  CloseHandle(hProc);
4968  }
4969  }
4970  }
4971  break;
4972 
4973  default:
4974  errno = EINVAL;
4975  ret = -1;
4976  break;
4977  }
4978 
4979  return ret;
4980 }
4981 
4982 /* License: Ruby's */
4983 static int
4984 wlink(const WCHAR *from, const WCHAR *to)
4985 {
4986  if (!CreateHardLinkW(to, from, NULL)) {
4987  errno = map_errno(GetLastError());
4988  return -1;
4989  }
4990 
4991  return 0;
4992 }
4993 
4994 /* License: Ruby's */
4995 int
4996 rb_w32_ulink(const char *from, const char *to)
4997 {
4998  WCHAR *wfrom;
4999  WCHAR *wto;
5000  int ret;
5001 
5002  if (!(wfrom = utf8_to_wstr(from, NULL)))
5003  return -1;
5004  if (!(wto = utf8_to_wstr(to, NULL))) {
5005  free(wfrom);
5006  return -1;
5007  }
5008  ret = wlink(wfrom, wto);
5009  free(wto);
5010  free(wfrom);
5011  return ret;
5012 }
5013 
5014 /* License: Ruby's */
5015 int
5016 link(const char *from, const char *to)
5017 {
5018  WCHAR *wfrom;
5019  WCHAR *wto;
5020  int ret;
5021 
5022  if (!(wfrom = filecp_to_wstr(from, NULL)))
5023  return -1;
5024  if (!(wto = filecp_to_wstr(to, NULL))) {
5025  free(wfrom);
5026  return -1;
5027  }
5028  ret = wlink(wfrom, wto);
5029  free(wto);
5030  free(wfrom);
5031  return ret;
5032 }
5033 
5034 /* License: Public Domain, copied from mingw headers */
5035 #ifndef FILE_DEVICE_FILE_SYSTEM
5036 # define FILE_DEVICE_FILE_SYSTEM 0x00000009
5037 #endif
5038 #ifndef FSCTL_GET_REPARSE_POINT
5039 # define FSCTL_GET_REPARSE_POINT ((0x9<<16)|(42<<2))
5040 #endif
5041 #ifndef IO_REPARSE_TAG_SYMLINK
5042 # define IO_REPARSE_TAG_SYMLINK 0xA000000CL
5043 #endif
5044 
5045 /* License: Ruby's */
5046 static int
5047 reparse_symlink(const WCHAR *path, rb_w32_reparse_buffer_t *rp, size_t size)
5048 {
5049  HANDLE f;
5050  DWORD ret;
5051  int e = 0;
5052 
5053  f = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5054  if (f == INVALID_HANDLE_VALUE) {
5055  return GetLastError();
5056  }
5057 
5058  if (!DeviceIoControl(f, FSCTL_GET_REPARSE_POINT, NULL, 0,
5059  rp, size, &ret, NULL)) {
5060  e = GetLastError();
5061  }
5062  else if (rp->ReparseTag != IO_REPARSE_TAG_SYMLINK &&
5063  rp->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
5064  e = ERROR_INVALID_PARAMETER;
5065  }
5066  CloseHandle(f);
5067  return e;
5068 }
5069 
5070 /* License: Ruby's */
5071 int
5072 rb_w32_reparse_symlink_p(const WCHAR *path)
5073 {
5074  VALUE wtmp = 0;
5075  rb_w32_reparse_buffer_t rbuf, *rp = &rbuf;
5076  WCHAR *wbuf;
5077  DWORD len;
5078  int e;
5079 
5080  e = rb_w32_read_reparse_point(path, rp, sizeof(rbuf), &wbuf, &len);
5081  if (e == ERROR_MORE_DATA) {
5082  size_t size = rb_w32_reparse_buffer_size(len + 1);
5083  rp = ALLOCV(wtmp, size);
5084  e = rb_w32_read_reparse_point(path, rp, size, &wbuf, &len);
5085  ALLOCV_END(wtmp);
5086  }
5087  switch (e) {
5088  case 0:
5089  case ERROR_MORE_DATA:
5090  return TRUE;
5091  }
5092  return FALSE;
5093 }
5094 
5095 /* License: Ruby's */
5096 int
5097 rb_w32_read_reparse_point(const WCHAR *path, rb_w32_reparse_buffer_t *rp,
5098  size_t bufsize, WCHAR **result, DWORD *len)
5099 {
5100  int e = reparse_symlink(path, rp, bufsize);
5101  DWORD ret = 0;
5102 
5103  if (!e || e == ERROR_MORE_DATA) {
5104  void *name;
5105  if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
5106  name = ((char *)rp->SymbolicLinkReparseBuffer.PathBuffer +
5107  rp->SymbolicLinkReparseBuffer.PrintNameOffset);
5108  ret = rp->SymbolicLinkReparseBuffer.PrintNameLength;
5109  *len = ret / sizeof(WCHAR);
5110  }
5111  else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
5112  static const WCHAR volume[] = L"Volume{";
5113  enum {volume_prefix_len = rb_strlen_lit("\\??\\")};
5114  name = ((char *)rp->MountPointReparseBuffer.PathBuffer +
5115  rp->MountPointReparseBuffer.SubstituteNameOffset +
5116  volume_prefix_len * sizeof(WCHAR));
5117  ret = rp->MountPointReparseBuffer.SubstituteNameLength;
5118  *len = ret / sizeof(WCHAR);
5119  ret -= volume_prefix_len * sizeof(WCHAR);
5120  if (ret > sizeof(volume) - 1 * sizeof(WCHAR) &&
5121  memcmp(name, volume, sizeof(volume) - 1 * sizeof(WCHAR)) == 0)
5122  return -1;
5123  }
5124  else {
5125  return -1;
5126  }
5127  *result = name;
5128  if (e) {
5129  if ((char *)name + ret + sizeof(WCHAR) > (char *)rp + bufsize)
5130  return e;
5131  /* SubstituteName is not used */
5132  }
5133  ((WCHAR *)name)[ret/sizeof(WCHAR)] = L'\0';
5134  translate_wchar(name, L'\\', L'/');
5135  return 0;
5136  }
5137  else {
5138  return e;
5139  }
5140 }
5141 
5142 /* License: Ruby's */
5143 static ssize_t
5144 w32_readlink(UINT cp, const char *path, char *buf, size_t bufsize)
5145 {
5146  VALUE wtmp;
5147  DWORD len = MultiByteToWideChar(cp, 0, path, -1, NULL, 0);
5148  size_t size = rb_w32_reparse_buffer_size(len);
5149  WCHAR *wname, *wpath = ALLOCV(wtmp, size + sizeof(WCHAR) * len);
5150  rb_w32_reparse_buffer_t *rp = (void *)(wpath + len);
5151  ssize_t ret;
5152  int e;
5153 
5154  MultiByteToWideChar(cp, 0, path, -1, wpath, len);
5155  e = rb_w32_read_reparse_point(wpath, rp, size, &wname, &len);
5156  if (e && e != ERROR_MORE_DATA) {
5157  ALLOCV_END(wtmp);
5158  errno = map_errno(e);
5159  return -1;
5160  }
5161  len = lstrlenW(wname) + 1;
5162  ret = WideCharToMultiByte(cp, 0, wname, len, buf, bufsize, NULL, NULL);
5163  ALLOCV_END(wtmp);
5164  if (e) {
5165  ret = bufsize;
5166  }
5167  else if (!ret) {
5168  e = GetLastError();
5169  errno = map_errno(e);
5170  ret = -1;
5171  }
5172  return ret;
5173 }
5174 
5175 /* License: Ruby's */
5176 ssize_t
5177 rb_w32_ureadlink(const char *path, char *buf, size_t bufsize)
5178 {
5179  return w32_readlink(CP_UTF8, path, buf, bufsize);
5180 }
5181 
5182 /* License: Ruby's */
5183 ssize_t
5184 readlink(const char *path, char *buf, size_t bufsize)
5185 {
5186  return w32_readlink(filecp(), path, buf, bufsize);
5187 }
5188 
5189 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5190 #define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1)
5191 #endif
5192 #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
5193 #define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
5194 #endif
5195 
5196 /* License: Ruby's */
5197 static int
5198 w32_symlink(UINT cp, const char *src, const char *link)
5199 {
5200  int atts, len1, len2;
5201  VALUE buf;
5202  WCHAR *wsrc, *wlink;
5203  DWORD flag = 0;
5204  BOOLEAN ret;
5205  int e;
5206 
5207  typedef BOOLEAN (WINAPI *create_symbolic_link_func)(WCHAR*, WCHAR*, DWORD);
5208  static create_symbolic_link_func create_symbolic_link =
5209  (create_symbolic_link_func)-1;
5210  static DWORD create_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
5211 
5212  if (create_symbolic_link == (create_symbolic_link_func)-1) {
5213  /* Since Windows Vista and Windows Server 2008 */
5214  create_symbolic_link = (create_symbolic_link_func)
5215  get_proc_address("kernel32", "CreateSymbolicLinkW", NULL);
5216  }
5217  if (!create_symbolic_link) {
5218  errno = ENOSYS;
5219  return -1;
5220  }
5221 
5222  if (!*link) {
5223  errno = ENOENT;
5224  return -1;
5225  }
5226  if (!*src) {
5227  errno = EINVAL;
5228  return -1;
5229  }
5230  len1 = MultiByteToWideChar(cp, 0, src, -1, NULL, 0);
5231  len2 = MultiByteToWideChar(cp, 0, link, -1, NULL, 0);
5232  wsrc = ALLOCV_N(WCHAR, buf, len1+len2);
5233  wlink = wsrc + len1;
5234  MultiByteToWideChar(cp, 0, src, -1, wsrc, len1);
5235  MultiByteToWideChar(cp, 0, link, -1, wlink, len2);
5236  translate_wchar(wsrc, L'/', L'\\');
5237 
5238  atts = GetFileAttributesW(wsrc);
5239  if (atts != -1 && atts & FILE_ATTRIBUTE_DIRECTORY)
5240  flag = SYMBOLIC_LINK_FLAG_DIRECTORY;
5241  ret = create_symbolic_link(wlink, wsrc, flag |= create_flag);
5242  if (!ret &&
5243  (e = GetLastError()) == ERROR_INVALID_PARAMETER &&
5244  (flag & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) {
5245  create_flag = 0;
5246  flag &= ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
5247  ret = create_symbolic_link(wlink, wsrc, flag);
5248  if (!ret) e = GetLastError();
5249  }
5250  ALLOCV_END(buf);
5251 
5252  if (!ret) {
5253  errno = map_errno(e);
5254  return -1;
5255  }
5256  return 0;
5257 }
5258 
5259 /* License: Ruby's */
5260 int
5261 rb_w32_usymlink(const char *src, const char *link)
5262 {
5263  return w32_symlink(CP_UTF8, src, link);
5264 }
5265 
5266 /* License: Ruby's */
5267 int
5268 symlink(const char *src, const char *link)
5269 {
5270  return w32_symlink(filecp(), src, link);
5271 }
5272 
5273 /* License: Ruby's */
5274 rb_pid_t
5275 wait(int *status)
5276 {
5277  return waitpid(-1, status, 0);
5278 }
5279 
5280 /* License: Ruby's */
5281 static char *
5282 w32_getenv(const char *name, UINT cp)
5283 {
5284  WCHAR *wenvarea, *wenv;
5285  int len = strlen(name);
5286  char *env, *found = NULL;
5287  int wlen;
5288 
5289  if (len == 0) return NULL;
5290 
5291  if (!NTLoginName) {
5292  /* initialized in init_env, uenvarea_mutex should have been
5293  * initialized before it */
5294  return getenv(name);
5295  }
5296 
5297  thread_exclusive(uenvarea) {
5298  if (uenvarea) {
5299  free(uenvarea);
5300  uenvarea = NULL;
5301  }
5302  wenvarea = GetEnvironmentStringsW();
5303  if (!wenvarea) {
5304  map_errno(GetLastError());
5305  continue;
5306  }
5307  for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
5308  wlen += lstrlenW(wenv) + 1;
5309  uenvarea = wstr_to_mbstr(cp, wenvarea, wlen, NULL);
5310  FreeEnvironmentStringsW(wenvarea);
5311  if (!uenvarea)
5312  continue;
5313 
5314  for (env = uenvarea; *env; env += strlen(env) + 1) {
5315  if (strncasecmp(env, name, len) == 0 && *(env + len) == '=') {
5316  found = env + len + 1;
5317  break;
5318  }
5319  }
5320  }
5321 
5322  return found;
5323 }
5324 
5325 /* License: Ruby's */
5326 char *
5327 rb_w32_ugetenv(const char *name)
5328 {
5329  return w32_getenv(name, CP_UTF8);
5330 }
5331 
5332 /* License: Ruby's */
5333 char *
5334 rb_w32_getenv(const char *name)
5335 {
5336  return w32_getenv(name, CP_ACP);
5337 }
5338 
5339 /* License: Ruby's */
5340 static DWORD
5341 get_attr_vsn(const WCHAR *path, DWORD *atts, DWORD *vsn)
5342 {
5343  BY_HANDLE_FILE_INFORMATION st = {0};
5344  DWORD e = 0;
5345  HANDLE h = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5346 
5347  if (h == INVALID_HANDLE_VALUE) {
5348  e = GetLastError();
5349  ASSUME(e);
5350  return e;
5351  }
5352  if (!GetFileInformationByHandle(h, &st)) {
5353  e = GetLastError();
5354  ASSUME(e);
5355  }
5356  else {
5357  *atts = st.dwFileAttributes;
5358  *vsn = st.dwVolumeSerialNumber;
5359  }
5360  CloseHandle(h);
5361  return e;
5362 }
5363 
5364 /* License: Artistic or GPL */
5365 static int
5366 wrename(const WCHAR *oldpath, const WCHAR *newpath)
5367 {
5368  int res = 0;
5369  DWORD oldatts = 0, newatts = (DWORD)-1;
5370  DWORD oldvsn = 0, newvsn = 0, e;
5371 
5372  e = get_attr_vsn(oldpath, &oldatts, &oldvsn);
5373  if (e) {
5374  errno = map_errno(e);
5375  return -1;
5376  }
5377  if (oldatts & FILE_ATTRIBUTE_REPARSE_POINT) {
5378  HANDLE fh = open_special(oldpath, 0, 0);
5379  if (fh == INVALID_HANDLE_VALUE) {
5380  e = GetLastError();
5381  if (e == ERROR_CANT_RESOLVE_FILENAME) {
5382  errno = ELOOP;
5383  return -1;
5384  }
5385  }
5386  CloseHandle(fh);
5387  }
5388  get_attr_vsn(newpath, &newatts, &newvsn);
5389 
5390  RUBY_CRITICAL {
5391  if (newatts != (DWORD)-1 && newatts & FILE_ATTRIBUTE_READONLY)
5392  SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
5393 
5394  if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
5395  res = -1;
5396 
5397  if (res) {
5398  DWORD e = GetLastError();
5399  if ((e == ERROR_ACCESS_DENIED) && (oldatts & FILE_ATTRIBUTE_DIRECTORY) &&
5400  oldvsn != newvsn)
5401  errno = EXDEV;
5402  else
5403  errno = map_errno(e);
5404  }
5405  else
5406  SetFileAttributesW(newpath, oldatts);
5407  }
5408 
5409  return res;
5410 }
5411 
5412 /* License: Ruby's */
5413 int rb_w32_urename(const char *from, const char *to)
5414 {
5415  WCHAR *wfrom;
5416  WCHAR *wto;
5417  int ret = -1;
5418 
5419  if (!(wfrom = utf8_to_wstr(from, NULL)))
5420  return -1;
5421  if (!(wto = utf8_to_wstr(to, NULL))) {
5422  free(wfrom);
5423  return -1;
5424  }
5425  ret = wrename(wfrom, wto);
5426  free(wto);
5427  free(wfrom);
5428  return ret;
5429 }
5430 
5431 /* License: Ruby's */
5432 int rb_w32_rename(const char *from, const char *to)
5433 {
5434  WCHAR *wfrom;
5435  WCHAR *wto;
5436  int ret = -1;
5437 
5438  if (!(wfrom = filecp_to_wstr(from, NULL)))
5439  return -1;
5440  if (!(wto = filecp_to_wstr(to, NULL))) {
5441  free(wfrom);
5442  return -1;
5443  }
5444  ret = wrename(wfrom, wto);
5445  free(wto);
5446  free(wfrom);
5447  return ret;
5448 }
5449 
5450 /* License: Ruby's */
5451 static int
5452 isUNCRoot(const WCHAR *path)
5453 {
5454  if (path[0] == L'\\' && path[1] == L'\\') {
5455  const WCHAR *p = path + 2;
5456  if (p[0] == L'?' && p[1] == L'\\') {
5457  p += 2;
5458  }
5459  for (; *p; p++) {
5460  if (*p == L'\\')
5461  break;
5462  }
5463  if (p[0] && p[1]) {
5464  for (p++; *p; p++) {
5465  if (*p == L'\\')
5466  break;
5467  }
5468  if (!p[0] || !p[1] || (p[1] == L'.' && !p[2]))
5469  return 1;
5470  }
5471  }
5472  return 0;
5473 }
5474 
5475 #define COPY_STAT(src, dest, size_cast) do { \
5476  (dest).st_dev = (src).st_dev; \
5477  (dest).st_ino = (src).st_ino; \
5478  (dest).st_mode = (src).st_mode; \
5479  (dest).st_nlink = (src).st_nlink; \
5480  (dest).st_uid = (src).st_uid; \
5481  (dest).st_gid = (src).st_gid; \
5482  (dest).st_rdev = (src).st_rdev; \
5483  (dest).st_size = size_cast(src).st_size; \
5484  (dest).st_atime = (src).st_atime; \
5485  (dest).st_mtime = (src).st_mtime; \
5486  (dest).st_ctime = (src).st_ctime; \
5487  } while (0)
5488 
5489 static time_t filetime_to_unixtime(const FILETIME *ft);
5490 static long filetime_to_nsec(const FILETIME *ft);
5491 static WCHAR *name_for_stat(WCHAR *buf, const WCHAR *path);
5492 static DWORD stati128_handle(HANDLE h, struct stati128 *st);
5493 
5494 #undef fstat
5495 /* License: Ruby's */
5496 int
5497 rb_w32_fstat(int fd, struct stat *st)
5498 {
5499  BY_HANDLE_FILE_INFORMATION info;
5500  int ret = fstat(fd, st);
5501 
5502  if (ret) return ret;
5503  if (GetEnvironmentVariableW(L"TZ", NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) return ret;
5504  if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
5505  st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5506  st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5507  st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5508  }
5509  return ret;
5510 }
5511 
5512 /* License: Ruby's */
5513 int
5514 rb_w32_fstati128(int fd, struct stati128 *st)
5515 {
5516  struct stat tmp;
5517  int ret = fstat(fd, &tmp);
5518 
5519  if (ret) return ret;
5520  COPY_STAT(tmp, *st, +);
5521  stati128_handle((HANDLE)_get_osfhandle(fd), st);
5522  return ret;
5523 }
5524 
5525 #if !defined FILE_INVALID_FILE_ID && !defined __MINGW32__
5526 typedef struct {
5527  BYTE Identifier[16];
5528 } FILE_ID_128;
5529 #endif
5530 
5531 #if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < 0x602
5532 #define FileIdInfo 0x12
5533 
5534 typedef struct {
5535  unsigned LONG_LONG VolumeSerialNumber;
5536  FILE_ID_128 FileId;
5537 } FILE_ID_INFO;
5538 #endif
5539 
5540 static DWORD
5541 get_ino(HANDLE h, FILE_ID_INFO *id)
5542 {
5543  typedef BOOL (WINAPI *gfibhe_t)(HANDLE, int, void *, DWORD);
5544  static gfibhe_t pGetFileInformationByHandleEx = (gfibhe_t)-1;
5545 
5546  if (pGetFileInformationByHandleEx == (gfibhe_t)-1)
5547  /* Since Windows Vista and Windows Server 2008 */
5548  pGetFileInformationByHandleEx = (gfibhe_t)get_proc_address("kernel32", "GetFileInformationByHandleEx", NULL);
5549 
5550  if (pGetFileInformationByHandleEx) {
5551  if (pGetFileInformationByHandleEx(h, FileIdInfo, id, sizeof(*id)))
5552  return 0;
5553  else
5554  return GetLastError();
5555  }
5556  return ERROR_INVALID_PARAMETER;
5557 }
5558 
5559 /* License: Ruby's */
5560 static DWORD
5561 stati128_handle(HANDLE h, struct stati128 *st)
5562 {
5563  BY_HANDLE_FILE_INFORMATION info;
5564  DWORD attr = (DWORD)-1;
5565 
5566  if (GetFileInformationByHandle(h, &info)) {
5567  FILE_ID_INFO fii;
5568  st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
5569  st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5570  st->st_atimensec = filetime_to_nsec(&info.ftLastAccessTime);
5571  st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5572  st->st_mtimensec = filetime_to_nsec(&info.ftLastWriteTime);
5573  st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5574  st->st_ctimensec = filetime_to_nsec(&info.ftCreationTime);
5575  st->st_nlink = info.nNumberOfLinks;
5576  attr = info.dwFileAttributes;
5577  if (!get_ino(h, &fii)) {
5578  st->st_ino = *((unsigned __int64 *)&fii.FileId);
5579  st->st_inohigh = *((__int64 *)&fii.FileId + 1);
5580  }
5581  else {
5582  st->st_ino = ((__int64)info.nFileIndexHigh << 32) | info.nFileIndexLow;
5583  st->st_inohigh = 0;
5584  }
5585  }
5586  return attr;
5587 }
5588 
5589 /* License: Ruby's */
5590 static time_t
5591 filetime_to_unixtime(const FILETIME *ft)
5592 {
5593  long subsec;
5594  time_t t = filetime_split(ft, &subsec);
5595 
5596  if (t < 0) return 0;
5597  return t;
5598 }
5599 
5600 /* License: Ruby's */
5601 static long
5602 filetime_to_nsec(const FILETIME *ft)
5603 {
5604  if (have_precisetime <= 0)
5605  return 0;
5606  else {
5607  ULARGE_INTEGER tmp;
5608  tmp.LowPart = ft->dwLowDateTime;
5609  tmp.HighPart = ft->dwHighDateTime;
5610  return (long)(tmp.QuadPart % 10000000) * 100;
5611  }
5612 }
5613 
5614 /* License: Ruby's */
5615 static unsigned
5616 fileattr_to_unixmode(DWORD attr, const WCHAR *path, unsigned mode)
5617 {
5618  if (attr & FILE_ATTRIBUTE_READONLY) {
5619  mode |= S_IREAD;
5620  }
5621  else {
5622  mode |= S_IREAD | S_IWRITE | S_IWUSR;
5623  }
5624 
5625  if (mode & S_IFMT) {
5626  /* format is already set */
5627  }
5628  else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5629  if (rb_w32_reparse_symlink_p(path))
5630  mode |= S_IFLNK | S_IEXEC;
5631  else
5632  mode |= S_IFDIR | S_IEXEC;
5633  }
5634  else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5635  mode |= S_IFDIR | S_IEXEC;
5636  }
5637  else {
5638  mode |= S_IFREG;
5639  }
5640 
5641  if (path && (mode & S_IFREG)) {
5642  const WCHAR *end = path + lstrlenW(path);
5643  while (path < end) {
5644  end = CharPrevW(path, end);
5645  if (*end == L'.') {
5646  if ((_wcsicmp(end, L".bat") == 0) ||
5647  (_wcsicmp(end, L".cmd") == 0) ||
5648  (_wcsicmp(end, L".com") == 0) ||
5649  (_wcsicmp(end, L".exe") == 0)) {
5650  mode |= S_IEXEC;
5651  }
5652  break;
5653  }
5654  if (!iswalnum(*end)) break;
5655  }
5656  }
5657 
5658  mode |= (mode & 0500) >> 3;
5659  mode |= (mode & 0500) >> 6;
5660 
5661  return mode;
5662 }
5663 
5664 /* License: Ruby's */
5665 static int
5666 check_valid_dir(const WCHAR *path)
5667 {
5668  WIN32_FIND_DATAW fd;
5669  HANDLE fh;
5670  WCHAR full[PATH_MAX];
5671  WCHAR *dmy;
5672  WCHAR *p, *q;
5673 
5674  /* GetFileAttributes() determines "..." as directory. */
5675  /* We recheck it by FindFirstFile(). */
5676  if (!(p = wcsstr(path, L"...")))
5677  return 0;
5678  q = p + wcsspn(p, L".");
5679  if ((p == path || wcschr(L":/\\", *(p - 1))) &&
5680  (!*q || wcschr(L":/\\", *q))) {
5681  errno = ENOENT;
5682  return -1;
5683  }
5684 
5685  /* if the specified path is the root of a drive and the drive is empty, */
5686  /* FindFirstFile() returns INVALID_HANDLE_VALUE. */
5687  if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) {
5688  errno = map_errno(GetLastError());
5689  return -1;
5690  }
5691  if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
5692  return 0;
5693 
5694  fh = open_dir_handle(path, &fd);
5695  if (fh == INVALID_HANDLE_VALUE)
5696  return -1;
5697  FindClose(fh);
5698  return 0;
5699 }
5700 
5701 /* License: Ruby's */
5702 static int
5703 stat_by_find(const WCHAR *path, struct stati128 *st)
5704 {
5705  HANDLE h;
5706  WIN32_FIND_DATAW wfd;
5707  /* GetFileAttributesEx failed; check why. */
5708  int e = GetLastError();
5709 
5710  if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
5711  || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
5712  errno = map_errno(e);
5713  return -1;
5714  }
5715 
5716  /* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
5717  h = FindFirstFileW(path, &wfd);
5718  if (h == INVALID_HANDLE_VALUE) {
5719  errno = map_errno(GetLastError());
5720  return -1;
5721  }
5722  FindClose(h);
5723  st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path, 0);
5724  st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
5725  st->st_atimensec = filetime_to_nsec(&wfd.ftLastAccessTime);
5726  st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
5727  st->st_mtimensec = filetime_to_nsec(&wfd.ftLastWriteTime);
5728  st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
5729  st->st_ctimensec = filetime_to_nsec(&wfd.ftCreationTime);
5730  st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
5731  st->st_nlink = 1;
5732  return 0;
5733 }
5734 
5735 /* License: Ruby's */
5736 static int
5737 path_drive(const WCHAR *path)
5738 {
5739  return (iswalpha(path[0]) && path[1] == L':') ?
5740  towupper(path[0]) - L'A' : _getdrive() - 1;
5741 }
5742 
5743 /* License: Ruby's */
5744 static int
5745 winnt_stat(const WCHAR *path, struct stati128 *st, BOOL lstat)
5746 {
5747  DWORD flags = lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0;
5748  HANDLE f;
5749  WCHAR finalname[PATH_MAX];
5750 
5751  memset(st, 0, sizeof(*st));
5752  f = open_special(path, 0, flags);
5753  if (f != INVALID_HANDLE_VALUE) {
5754  DWORD attr = stati128_handle(f, st);
5755  const DWORD len = get_final_path(f, finalname, numberof(finalname), 0);
5756  unsigned mode = 0;
5757  switch (GetFileType(f)) {
5758  case FILE_TYPE_CHAR:
5759  mode = S_IFCHR;
5760  break;
5761  case FILE_TYPE_PIPE:
5762  mode = S_IFIFO;
5763  break;
5764  }
5765  CloseHandle(f);
5766  if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5767  /* TODO: size in which encoding? */
5768  if (rb_w32_reparse_symlink_p(path))
5769  st->st_size = 0;
5770  else
5771  attr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
5772  }
5773  if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5774  if (check_valid_dir(path)) return -1;
5775  }
5776  st->st_mode = fileattr_to_unixmode(attr, path, mode);
5777  if (len) {
5778  finalname[min(len, numberof(finalname)-1)] = L'\0';
5779  path = finalname;
5780  if (wcsncmp(path, namespace_prefix, numberof(namespace_prefix)) == 0)
5781  path += numberof(namespace_prefix);
5782  }
5783  }
5784  else {
5785  if (stat_by_find(path, st)) return -1;
5786  }
5787 
5788  st->st_dev = st->st_rdev = path_drive(path);
5789 
5790  return 0;
5791 }
5792 
5793 /* License: Ruby's */
5794 int
5795 rb_w32_stat(const char *path, struct stat *st)
5796 {
5797  struct stati128 tmp;
5798 
5799  if (w32_stati128(path, &tmp, filecp(), FALSE)) return -1;
5800  COPY_STAT(tmp, *st, (_off_t));
5801  return 0;
5802 }
5803 
5804 /* License: Ruby's */
5805 static int
5806 wstati128(const WCHAR *path, struct stati128 *st, BOOL lstat)
5807 {
5808  WCHAR *buf1;
5809  int ret, size;
5810  VALUE v;
5811 
5812  if (!path || !st) {
5813  errno = EFAULT;
5814  return -1;
5815  }
5816  size = lstrlenW(path) + 2;
5817  buf1 = ALLOCV_N(WCHAR, v, size);
5818  if (!(path = name_for_stat(buf1, path)))
5819  return -1;
5820  ret = winnt_stat(path, st, lstat);
5821  if (v)
5822  ALLOCV_END(v);
5823 
5824  return ret;
5825 }
5826 
5827 /* License: Ruby's */
5828 static WCHAR *
5829 name_for_stat(WCHAR *buf1, const WCHAR *path)
5830 {
5831  const WCHAR *p;
5832  WCHAR *s, *end;
5833  int len;
5834 
5835  for (p = path, s = buf1; *p; p++, s++) {
5836  if (*p == L'/')
5837  *s = L'\\';
5838  else
5839  *s = *p;
5840  }
5841  *s = '\0';
5842  len = s - buf1;
5843  if (!len || L'\"' == *(--s)) {
5844  errno = ENOENT;
5845  return NULL;
5846  }
5847  end = buf1 + len - 1;
5848 
5849  if (isUNCRoot(buf1)) {
5850  if (*end == L'.')
5851  *end = L'\0';
5852  else if (*end != L'\\')
5853  lstrcatW(buf1, L"\\");
5854  }
5855  else if (*end == L'\\' || (buf1 + 1 == end && *end == L':'))
5856  lstrcatW(buf1, L".");
5857 
5858  return buf1;
5859 }
5860 
5861 /* License: Ruby's */
5862 int
5863 rb_w32_ustati128(const char *path, struct stati128 *st)
5864 {
5865  return w32_stati128(path, st, CP_UTF8, FALSE);
5866 }
5867 
5868 /* License: Ruby's */
5869 int
5870 rb_w32_stati128(const char *path, struct stati128 *st)
5871 {
5872  return w32_stati128(path, st, filecp(), FALSE);
5873 }
5874 
5875 /* License: Ruby's */
5876 static int
5877 w32_stati128(const char *path, struct stati128 *st, UINT cp, BOOL lstat)
5878 {
5879  WCHAR *wpath;
5880  int ret;
5881 
5882  if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
5883  return -1;
5884  ret = wstati128(wpath, st, lstat);
5885  free(wpath);
5886  return ret;
5887 }
5888 
5889 /* License: Ruby's */
5890 int
5891 rb_w32_ulstati128(const char *path, struct stati128 *st)
5892 {
5893  return w32_stati128(path, st, CP_UTF8, TRUE);
5894 }
5895 
5896 /* License: Ruby's */
5897 int
5898 rb_w32_lstati128(const char *path, struct stati128 *st)
5899 {
5900  return w32_stati128(path, st, filecp(), TRUE);
5901 }
5902 
5903 /* License: Ruby's */
5904 off_t
5905 rb_w32_lseek(int fd, off_t ofs, int whence)
5906 {
5907  SOCKET sock = TO_SOCKET(fd);
5908  if (is_socket(sock) || is_pipe(sock)) {
5909  errno = ESPIPE;
5910  return -1;
5911  }
5912  return _lseeki64(fd, ofs, whence);
5913 }
5914 
5915 /* License: Ruby's */
5916 static int
5917 w32_access(const char *path, int mode, UINT cp)
5918 {
5919  struct stati128 stat;
5920  if (w32_stati128(path, &stat, cp, FALSE) != 0)
5921  return -1;
5922  mode <<= 6;
5923  if ((stat.st_mode & mode) != mode) {
5924  errno = EACCES;
5925  return -1;
5926  }
5927  return 0;
5928 }
5929 
5930 /* License: Ruby's */
5931 int
5932 rb_w32_access(const char *path, int mode)
5933 {
5934  return w32_access(path, mode, filecp());
5935 }
5936 
5937 /* License: Ruby's */
5938 int
5939 rb_w32_uaccess(const char *path, int mode)
5940 {
5941  return w32_access(path, mode, CP_UTF8);
5942 }
5943 
5944 /* License: Ruby's */
5945 static int
5946 rb_chsize(HANDLE h, off_t size)
5947 {
5948  long upos, lpos, usize, lsize;
5949  int ret = -1;
5950  DWORD e;
5951 
5952  if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
5953  (e = GetLastError())) {
5954  errno = map_errno(e);
5955  return -1;
5956  }
5957  usize = (long)(size >> 32);
5958  lsize = (long)size;
5959  if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L &&
5960  (e = GetLastError())) {
5961  errno = map_errno(e);
5962  }
5963  else if (!SetEndOfFile(h)) {
5964  errno = map_errno(GetLastError());
5965  }
5966  else {
5967  ret = 0;
5968  }
5969  SetFilePointer(h, lpos, &upos, SEEK_SET);
5970  return ret;
5971 }
5972 
5973 /* License: Ruby's */
5974 static int
5975 w32_truncate(const char *path, off_t length, UINT cp)
5976 {
5977  HANDLE h;
5978  int ret;
5979  WCHAR *wpath;
5980 
5981  if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
5982  return -1;
5983  h = CreateFileW(wpath, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
5984  if (h == INVALID_HANDLE_VALUE) {
5985  errno = map_errno(GetLastError());
5986  free(wpath);
5987  return -1;
5988  }
5989  free(wpath);
5990  ret = rb_chsize(h, length);
5991  CloseHandle(h);
5992  return ret;
5993 }
5994 
5995 /* License: Ruby's */
5996 int
5997 rb_w32_utruncate(const char *path, off_t length)
5998 {
5999  return w32_truncate(path, length, CP_UTF8);
6000 }
6001 
6002 /* License: Ruby's */
6003 int
6004 rb_w32_truncate(const char *path, off_t length)
6005 {
6006  return w32_truncate(path, length, filecp());
6007 }
6008 
6009 /* License: Ruby's */
6010 int
6011 rb_w32_ftruncate(int fd, off_t length)
6012 {
6013  HANDLE h;
6014 
6015  h = (HANDLE)_get_osfhandle(fd);
6016  if (h == (HANDLE)-1) return -1;
6017  return rb_chsize(h, length);
6018 }
6019 
6020 /* License: Ruby's */
6021 static long
6022 filetime_to_clock(FILETIME *ft)
6023 {
6024  __int64 qw = ft->dwHighDateTime;
6025  qw <<= 32;
6026  qw |= ft->dwLowDateTime;
6027  qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
6028  return (long) qw;
6029 }
6030 
6031 /* License: Ruby's */
6032 int
6033 rb_w32_times(struct tms *tmbuf)
6034 {
6035  FILETIME create, exit, kernel, user;
6036 
6037  if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
6038  tmbuf->tms_utime = filetime_to_clock(&user);
6039  tmbuf->tms_stime = filetime_to_clock(&kernel);
6040  tmbuf->tms_cutime = 0;
6041  tmbuf->tms_cstime = 0;
6042  }
6043  else {
6044  tmbuf->tms_utime = clock();
6045  tmbuf->tms_stime = 0;
6046  tmbuf->tms_cutime = 0;
6047  tmbuf->tms_cstime = 0;
6048  }
6049  return 0;
6050 }
6051 
6052 
6053 /* License: Ruby's */
6054 #define yield_once() Sleep(0)
6055 #define yield_until(condition) do yield_once(); while (!(condition))
6056 
6057 /* License: Ruby's */
6059  /* output field */
6060  void* stackaddr;
6061  int errnum;
6062 
6063  /* input field */
6064  uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv);
6065  uintptr_t self;
6066  int argc;
6067  uintptr_t* argv;
6068 };
6069 
6070 /* License: Ruby's */
6071 static DWORD WINAPI
6072 call_asynchronous(PVOID argp)
6073 {
6074  DWORD ret;
6075  struct asynchronous_arg_t *arg = argp;
6076  arg->stackaddr = &argp;
6077  ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
6078  arg->errnum = errno;
6079  return ret;
6080 }
6081 
6082 /* License: Ruby's */
6083 uintptr_t
6084 rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self,
6085  int argc, uintptr_t* argv, uintptr_t intrval)
6086 {
6087  DWORD val;
6088  BOOL interrupted = FALSE;
6089  HANDLE thr;
6090 
6091  RUBY_CRITICAL {
6092  struct asynchronous_arg_t arg;
6093 
6094  arg.stackaddr = NULL;
6095  arg.errnum = 0;
6096  arg.func = func;
6097  arg.self = self;
6098  arg.argc = argc;
6099  arg.argv = argv;
6100 
6101  thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
6102 
6103  if (thr) {
6104  yield_until(arg.stackaddr);
6105 
6106  if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
6107  interrupted = TRUE;
6108 
6109  if (TerminateThread(thr, intrval)) {
6110  yield_once();
6111  }
6112  }
6113 
6114  GetExitCodeThread(thr, &val);
6115  CloseHandle(thr);
6116 
6117  if (interrupted) {
6118  /* must release stack of killed thread, why doesn't Windows? */
6119  MEMORY_BASIC_INFORMATION m;
6120 
6121  memset(&m, 0, sizeof(m));
6122  if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
6123  Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
6124  arg.stackaddr, GetLastError()));
6125  }
6126  else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
6127  Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
6128  m.AllocationBase, GetLastError()));
6129  }
6130  errno = EINTR;
6131  }
6132  else {
6133  errno = arg.errnum;
6134  }
6135  }
6136  }
6137 
6138  if (!thr) {
6139  rb_fatal("failed to launch waiter thread:%ld", GetLastError());
6140  }
6141 
6142  return val;
6143 }
6144 
6145 /* License: Ruby's */
6146 char **
6147 rb_w32_get_environ(void)
6148 {
6149  WCHAR *envtop, *env;
6150  char **myenvtop, **myenv;
6151  int num;
6152 
6153  /*
6154  * We avoid values started with `='. If you want to deal those values,
6155  * change this function, and some functions in hash.c which recognize
6156  * `=' as delimiter or rb_w32_getenv() and ruby_setenv().
6157  * CygWin deals these values by changing first `=' to '!'. But we don't
6158  * use such trick and follow cmd.exe's way that just doesn't show these
6159  * values.
6160  *
6161  * This function returns UTF-8 strings.
6162  */
6163  envtop = GetEnvironmentStringsW();
6164  for (env = envtop, num = 0; *env; env += lstrlenW(env) + 1)
6165  if (*env != '=') num++;
6166 
6167  myenvtop = (char **)malloc(sizeof(char *) * (num + 1));
6168  for (env = envtop, myenv = myenvtop; *env; env += lstrlenW(env) + 1) {
6169  if (*env != '=') {
6170  if (!(*myenv = wstr_to_utf8(env, NULL))) {
6171  break;
6172  }
6173  myenv++;
6174  }
6175  }
6176  *myenv = NULL;
6177  FreeEnvironmentStringsW(envtop);
6178 
6179  return myenvtop;
6180 }
6181 
6182 /* License: Ruby's */
6183 void
6184 rb_w32_free_environ(char **env)
6185 {
6186  char **t = env;
6187 
6188  while (*t) free(*t++);
6189  free(env);
6190 }
6191 
6192 /* License: Ruby's */
6193 rb_pid_t
6194 rb_w32_getpid(void)
6195 {
6196  return GetCurrentProcessId();
6197 }
6198 
6199 
6200 /* License: Ruby's */
6201 rb_pid_t
6202 rb_w32_getppid(void)
6203 {
6204  typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *);
6205  static query_func *pNtQueryInformationProcess = (query_func *)-1;
6206  rb_pid_t ppid = 0;
6207 
6208  if (pNtQueryInformationProcess == (query_func *)-1)
6209  pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL);
6210  if (pNtQueryInformationProcess) {
6211  struct {
6212  long ExitStatus;
6213  void* PebBaseAddress;
6214  uintptr_t AffinityMask;
6215  uintptr_t BasePriority;
6216  uintptr_t UniqueProcessId;
6217  uintptr_t ParentProcessId;
6218  } pbi;
6219  ULONG len;
6220  long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
6221  if (!ret) {
6222  ppid = pbi.ParentProcessId;
6223  }
6224  }
6225 
6226  return ppid;
6227 }
6228 
6229 STATIC_ASSERT(std_handle, (STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)==(STD_ERROR_HANDLE-STD_OUTPUT_HANDLE));
6230 
6231 /* License: Ruby's */
6232 #define set_new_std_handle(newfd, handle) do { \
6233  if ((unsigned)(newfd) > 2) break; \
6234  SetStdHandle(STD_INPUT_HANDLE+(STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)*(newfd), \
6235  (handle)); \
6236  } while (0)
6237 #define set_new_std_fd(newfd) set_new_std_handle(newfd, (HANDLE)rb_w32_get_osfhandle(newfd))
6238 
6239 /* License: Ruby's */
6240 int
6241 rb_w32_dup2(int oldfd, int newfd)
6242 {
6243  int ret;
6244 
6245  if (oldfd == newfd) return newfd;
6246  ret = dup2(oldfd, newfd);
6247  if (ret < 0) return ret;
6248  set_new_std_fd(newfd);
6249  return newfd;
6250 }
6251 
6252 /* License: Ruby's */
6253 int
6254 rb_w32_uopen(const char *file, int oflag, ...)
6255 {
6256  WCHAR *wfile;
6257  int ret;
6258  int pmode;
6259 
6260  va_list arg;
6261  va_start(arg, oflag);
6262  pmode = va_arg(arg, int);
6263  va_end(arg);
6264 
6265  if (!(wfile = utf8_to_wstr(file, NULL)))
6266  return -1;
6267  ret = w32_wopen(wfile, oflag, pmode);
6268  free(wfile);
6269  return ret;
6270 }
6271 
6272 /* License: Ruby's */
6273 static int
6274 check_if_wdir(const WCHAR *wfile)
6275 {
6276  DWORD attr = GetFileAttributesW(wfile);
6277  if (attr == (DWORD)-1L ||
6278  !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
6279  check_valid_dir(wfile)) {
6280  return FALSE;
6281  }
6282  errno = EISDIR;
6283  return TRUE;
6284 }
6285 
6286 /* License: Ruby's */
6287 int
6288 rb_w32_open(const char *file, int oflag, ...)
6289 {
6290  WCHAR *wfile;
6291  int ret;
6292  int pmode;
6293 
6294  va_list arg;
6295  va_start(arg, oflag);
6296  pmode = va_arg(arg, int);
6297  va_end(arg);
6298 
6299  if (!(wfile = filecp_to_wstr(file, NULL)))
6300  return -1;
6301  ret = w32_wopen(wfile, oflag, pmode);
6302  free(wfile);
6303  return ret;
6304 }
6305 
6306 /* License: Ruby's */
6307 int
6308 rb_w32_wopen(const WCHAR *file, int oflag, ...)
6309 {
6310  int pmode = 0;
6311 
6312  if (oflag & O_CREAT) {
6313  va_list arg;
6314  va_start(arg, oflag);
6315  pmode = va_arg(arg, int);
6316  va_end(arg);
6317  }
6318 
6319  return w32_wopen(file, oflag, pmode);
6320 }
6321 
6322 static int
6323 w32_wopen(const WCHAR *file, int oflag, int pmode)
6324 {
6325  char flags = 0;
6326  int fd;
6327  DWORD access;
6328  DWORD create;
6329  DWORD attr = FILE_ATTRIBUTE_NORMAL;
6330  SECURITY_ATTRIBUTES sec;
6331  HANDLE h;
6332  int share_delete;
6333 
6334  share_delete = oflag & O_SHARE_DELETE ? FILE_SHARE_DELETE : 0;
6335  oflag &= ~O_SHARE_DELETE;
6336  if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
6337  fd = _wopen(file, oflag, pmode);
6338  if (fd == -1) {
6339  switch (errno) {
6340  case EACCES:
6341  check_if_wdir(file);
6342  break;
6343  case EINVAL:
6344  errno = map_errno(GetLastError());
6345  break;
6346  }
6347  }
6348  return fd;
6349  }
6350 
6351  sec.nLength = sizeof(sec);
6352  sec.lpSecurityDescriptor = NULL;
6353  if (oflag & O_NOINHERIT) {
6354  sec.bInheritHandle = FALSE;
6355  flags |= FNOINHERIT;
6356  }
6357  else {
6358  sec.bInheritHandle = TRUE;
6359  }
6360  oflag &= ~O_NOINHERIT;
6361 
6362  /* always open with binary mode */
6363  oflag &= ~(O_BINARY | O_TEXT);
6364 
6365  switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
6366  case O_RDWR:
6367  access = GENERIC_READ | GENERIC_WRITE;
6368  break;
6369  case O_RDONLY:
6370  access = GENERIC_READ;
6371  break;
6372  case O_WRONLY:
6373  access = GENERIC_WRITE;
6374  break;
6375  default:
6376  errno = EINVAL;
6377  return -1;
6378  }
6379  oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
6380 
6381  switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
6382  case O_CREAT:
6383  create = OPEN_ALWAYS;
6384  break;
6385  case 0:
6386  case O_EXCL:
6387  create = OPEN_EXISTING;
6388  break;
6389  case O_CREAT | O_EXCL:
6390  case O_CREAT | O_EXCL | O_TRUNC:
6391  create = CREATE_NEW;
6392  break;
6393  case O_TRUNC:
6394  case O_TRUNC | O_EXCL:
6395  create = TRUNCATE_EXISTING;
6396  break;
6397  case O_CREAT | O_TRUNC:
6398  create = CREATE_ALWAYS;
6399  break;
6400  default:
6401  errno = EINVAL;
6402  return -1;
6403  }
6404  if (oflag & O_CREAT) {
6405  /* TODO: we need to check umask here, but it's not exported... */
6406  if (!(pmode & S_IWRITE))
6407  attr = FILE_ATTRIBUTE_READONLY;
6408  }
6409  oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
6410 
6411  if (oflag & O_TEMPORARY) {
6412  attr |= FILE_FLAG_DELETE_ON_CLOSE;
6413  access |= DELETE;
6414  }
6415  oflag &= ~O_TEMPORARY;
6416 
6417  if (oflag & _O_SHORT_LIVED)
6418  attr |= FILE_ATTRIBUTE_TEMPORARY;
6419  oflag &= ~_O_SHORT_LIVED;
6420 
6421  switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
6422  case 0:
6423  break;
6424  case O_SEQUENTIAL:
6425  attr |= FILE_FLAG_SEQUENTIAL_SCAN;
6426  break;
6427  case O_RANDOM:
6428  attr |= FILE_FLAG_RANDOM_ACCESS;
6429  break;
6430  default:
6431  errno = EINVAL;
6432  return -1;
6433  }
6434  oflag &= ~(O_SEQUENTIAL | O_RANDOM);
6435 
6436  if (oflag & ~O_APPEND) {
6437  errno = EINVAL;
6438  return -1;
6439  }
6440 
6441  /* allocate a C Runtime file handle */
6442  RUBY_CRITICAL {
6443  h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
6444  fd = _open_osfhandle((intptr_t)h, 0);
6445  CloseHandle(h);
6446  }
6447  if (fd == -1) {
6448  errno = EMFILE;
6449  return -1;
6450  }
6451  RUBY_CRITICAL {
6452  rb_acrt_lowio_lock_fh(fd);
6453  _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
6454  _set_osflags(fd, 0);
6455 
6456  h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE | share_delete, &sec, create, attr, NULL);
6457  if (h == INVALID_HANDLE_VALUE) {
6458  DWORD e = GetLastError();
6459  if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
6460  errno = map_errno(e);
6461  rb_acrt_lowio_unlock_fh(fd);
6462  fd = -1;
6463  goto quit;
6464  }
6465 
6466  switch (GetFileType(h)) {
6467  case FILE_TYPE_CHAR:
6468  flags |= FDEV;
6469  break;
6470  case FILE_TYPE_PIPE:
6471  flags |= FPIPE;
6472  break;
6473  case FILE_TYPE_UNKNOWN:
6474  errno = map_errno(GetLastError());
6475  CloseHandle(h);
6476  rb_acrt_lowio_unlock_fh(fd);
6477  fd = -1;
6478  goto quit;
6479  }
6480  if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
6481  flags |= FAPPEND;
6482 
6483  _set_osfhnd(fd, (intptr_t)h);
6484  _set_osflags(fd, flags | FOPEN);
6485 
6486  rb_acrt_lowio_unlock_fh(fd);
6487  quit:
6488  ;
6489  }
6490 
6491  return fd;
6492 }
6493 
6494 /* License: Ruby's */
6495 int
6496 rb_w32_fclose(FILE *fp)
6497 {
6498  int fd = fileno(fp);
6499  SOCKET sock = TO_SOCKET(fd);
6500  int save_errno = errno;
6501 
6502  if (fflush(fp)) return -1;
6503  if (!is_socket(sock)) {
6504  UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
6505  return fclose(fp);
6506  }
6507  _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
6508  fclose(fp);
6509  errno = save_errno;
6510  if (closesocket(sock) == SOCKET_ERROR) {
6511  errno = map_errno(WSAGetLastError());
6512  return -1;
6513  }
6514  return 0;
6515 }
6516 
6517 /* License: Ruby's */
6518 int
6519 rb_w32_pipe(int fds[2])
6520 {
6521  static long serial = 0;
6522  static const char prefix[] = "\\\\.\\pipe\\ruby";
6523  enum {
6524  width_of_prefix = (int)sizeof(prefix) - 1,
6525  width_of_pid = (int)sizeof(rb_pid_t) * 2,
6526  width_of_serial = (int)sizeof(serial) * 2,
6527  width_of_ids = width_of_pid + 1 + width_of_serial + 1
6528  };
6529  char name[sizeof(prefix) + width_of_ids];
6530  SECURITY_ATTRIBUTES sec;
6531  HANDLE hRead, hWrite, h;
6532  int fdRead, fdWrite;
6533  int ret;
6534 
6535  memcpy(name, prefix, width_of_prefix);
6536  snprintf(name + width_of_prefix, width_of_ids, "%.*"PRI_PIDT_PREFIX"x-%.*lx",
6537  width_of_pid, rb_w32_getpid(), width_of_serial, InterlockedIncrement(&serial)-1);
6538 
6539  sec.nLength = sizeof(sec);
6540  sec.lpSecurityDescriptor = NULL;
6541  sec.bInheritHandle = FALSE;
6542 
6543  RUBY_CRITICAL {
6544  hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
6545  0, 2, 65536, 65536, 0, &sec);
6546  }
6547  if (hRead == INVALID_HANDLE_VALUE) {
6548  DWORD err = GetLastError();
6549  if (err == ERROR_PIPE_BUSY)
6550  errno = EMFILE;
6551  else
6552  errno = map_errno(GetLastError());
6553  return -1;
6554  }
6555 
6556  RUBY_CRITICAL {
6557  hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
6558  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
6559  }
6560  if (hWrite == INVALID_HANDLE_VALUE) {
6561  errno = map_errno(GetLastError());
6562  CloseHandle(hRead);
6563  return -1;
6564  }
6565 
6566  RUBY_CRITICAL do {
6567  ret = 0;
6568  h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
6569  fdRead = _open_osfhandle((intptr_t)h, 0);
6570  CloseHandle(h);
6571  if (fdRead == -1) {
6572  errno = EMFILE;
6573  CloseHandle(hWrite);
6574  CloseHandle(hRead);
6575  ret = -1;
6576  break;
6577  }
6578 
6579  rb_acrt_lowio_lock_fh(fdRead);
6580  _set_osfhnd(fdRead, (intptr_t)hRead);
6581  _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
6582  rb_acrt_lowio_unlock_fh(fdRead);
6583  } while (0);
6584  if (ret)
6585  return ret;
6586 
6587  RUBY_CRITICAL do {
6588  h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
6589  fdWrite = _open_osfhandle((intptr_t)h, 0);
6590  CloseHandle(h);
6591  if (fdWrite == -1) {
6592  errno = EMFILE;
6593  CloseHandle(hWrite);
6594  ret = -1;
6595  break;
6596  }
6597  rb_acrt_lowio_lock_fh(fdWrite);
6598  _set_osfhnd(fdWrite, (intptr_t)hWrite);
6599  _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
6600  rb_acrt_lowio_unlock_fh(fdWrite);
6601  } while (0);
6602  if (ret) {
6603  rb_w32_close(fdRead);
6604  return ret;
6605  }
6606 
6607  fds[0] = fdRead;
6608  fds[1] = fdWrite;
6609 
6610  return 0;
6611 }
6612 
6613 /* License: Ruby's */
6614 static int
6615 console_emulator_p(void)
6616 {
6617 #ifdef _WIN32_WCE
6618  return FALSE;
6619 #else
6620  const void *const func = WriteConsoleW;
6621  HMODULE k;
6622  MEMORY_BASIC_INFORMATION m;
6623 
6624  memset(&m, 0, sizeof(m));
6625  if (!VirtualQuery(func, &m, sizeof(m))) {
6626  return FALSE;
6627  }
6628  k = GetModuleHandle("kernel32.dll");
6629  if (!k) return FALSE;
6630  return (HMODULE)m.AllocationBase != k;
6631 #endif
6632 }
6633 
6634 /* License: Ruby's */
6635 static struct constat *
6636 constat_handle(HANDLE h)
6637 {
6638  st_data_t data;
6639  struct constat *p = NULL;
6640  thread_exclusive(conlist) {
6641  if (!conlist) {
6642  if (console_emulator_p()) {
6643  conlist = conlist_disabled;
6644  continue;
6645  }
6646  conlist = st_init_numtable();
6647  install_vm_exit_handler();
6648  }
6649  else if (conlist == conlist_disabled) {
6650  continue;
6651  }
6652  if (st_lookup(conlist, (st_data_t)h, &data)) {
6653  p = (struct constat *)data;
6654  }
6655  else {
6656  CONSOLE_SCREEN_BUFFER_INFO csbi;
6657  p = ALLOC(struct constat);
6658  p->vt100.state = constat_init;
6659  p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6660  p->vt100.reverse = 0;
6661  p->vt100.saved.X = p->vt100.saved.Y = 0;
6662  if (GetConsoleScreenBufferInfo(h, &csbi)) {
6663  p->vt100.attr = csbi.wAttributes;
6664  }
6665  st_insert(conlist, (st_data_t)h, (st_data_t)p);
6666  }
6667  }
6668  return p;
6669 }
6670 
6671 /* License: Ruby's */
6672 static void
6673 constat_reset(HANDLE h)
6674 {
6675  st_data_t data;
6676  struct constat *p;
6677  thread_exclusive(conlist) {
6678  if (!conlist || conlist == conlist_disabled) continue;
6679  if (!st_lookup(conlist, (st_data_t)h, &data)) continue;
6680  p = (struct constat *)data;
6681  p->vt100.state = constat_init;
6682  }
6683 }
6684 
6685 #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
6686 #define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
6687 
6688 #define constat_attr_color_reverse(attr) \
6689  ((attr) & ~(FOREGROUND_MASK | BACKGROUND_MASK)) | \
6690  (((attr) & FOREGROUND_MASK) << 4) | \
6691  (((attr) & BACKGROUND_MASK) >> 4)
6692 
6693 /* License: Ruby's */
6694 static WORD
6695 constat_attr(int count, const int *seq, WORD attr, WORD default_attr, int *reverse)
6696 {
6697  int rev = *reverse;
6698  WORD bold;
6699 
6700  if (!count) return attr;
6701  if (rev) attr = constat_attr_color_reverse(attr);
6702  bold = attr & FOREGROUND_INTENSITY;
6703  attr &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
6704 
6705  while (count-- > 0) {
6706  switch (*seq++) {
6707  case 0:
6708  attr = default_attr;
6709  rev = 0;
6710  bold = 0;
6711  break;
6712  case 1:
6713  bold = FOREGROUND_INTENSITY;
6714  break;
6715  case 4:
6716 #ifndef COMMON_LVB_UNDERSCORE
6717 #define COMMON_LVB_UNDERSCORE 0x8000
6718 #endif
6719  attr |= COMMON_LVB_UNDERSCORE;
6720  break;
6721  case 7:
6722  rev = 1;
6723  break;
6724 
6725  case 30:
6726  attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
6727  break;
6728  case 17:
6729  case 31:
6730  attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN)) | FOREGROUND_RED;
6731  break;
6732  case 18:
6733  case 32:
6734  attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_RED)) | FOREGROUND_GREEN;
6735  break;
6736  case 19:
6737  case 33:
6738  attr = (attr & ~FOREGROUND_BLUE) | FOREGROUND_GREEN | FOREGROUND_RED;
6739  break;
6740  case 20:
6741  case 34:
6742  attr = (attr & ~(FOREGROUND_GREEN | FOREGROUND_RED)) | FOREGROUND_BLUE;
6743  break;
6744  case 21:
6745  case 35:
6746  attr = (attr & ~FOREGROUND_GREEN) | FOREGROUND_BLUE | FOREGROUND_RED;
6747  break;
6748  case 22:
6749  case 36:
6750  attr = (attr & ~FOREGROUND_RED) | FOREGROUND_BLUE | FOREGROUND_GREEN;
6751  break;
6752  case 23:
6753  case 37:
6754  attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6755  break;
6756 
6757  case 40:
6758  attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
6759  break;
6760  case 41:
6761  attr = (attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN)) | BACKGROUND_RED;
6762  break;
6763  case 42:
6764  attr = (attr & ~(BACKGROUND_BLUE | BACKGROUND_RED)) | BACKGROUND_GREEN;
6765  break;
6766  case 43:
6767  attr = (attr & ~BACKGROUND_BLUE) | BACKGROUND_GREEN | BACKGROUND_RED;
6768  break;
6769  case 44:
6770  attr = (attr & ~(BACKGROUND_GREEN | BACKGROUND_RED)) | BACKGROUND_BLUE;
6771  break;
6772  case 45:
6773  attr = (attr & ~BACKGROUND_GREEN) | BACKGROUND_BLUE | BACKGROUND_RED;
6774  break;
6775  case 46:
6776  attr = (attr & ~BACKGROUND_RED) | BACKGROUND_BLUE | BACKGROUND_GREEN;
6777  break;
6778  case 47:
6779  attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
6780  break;
6781  }
6782  }
6783  attr |= bold;
6784  if (rev) attr = constat_attr_color_reverse(attr);
6785  *reverse = rev;
6786  return attr;
6787 }
6788 
6789 /* License: Ruby's */
6790 static void
6791 constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
6792 {
6793  DWORD written;
6794 
6795  FillConsoleOutputAttribute(handle, attr, len, pos, &written);
6796  FillConsoleOutputCharacterW(handle, L' ', len, pos, &written);
6797 }
6798 
6799 /* License: Ruby's */
6800 static void
6801 constat_apply(HANDLE handle, struct constat *s, WCHAR w)
6802 {
6803  CONSOLE_SCREEN_BUFFER_INFO csbi;
6804  const int *seq = s->vt100.seq;
6805  int count = s->vt100.state;
6806  int arg0, arg1 = 1;
6807  COORD pos;
6808 
6809  if (!GetConsoleScreenBufferInfo(handle, &csbi)) return;
6810  arg0 = (count > 0 && seq[0] > 0);
6811  if (arg0) arg1 = seq[0];
6812  switch (w) {
6813  case L'm':
6814  SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr, &s->vt100.reverse));
6815  break;
6816  case L'F':
6817  csbi.dwCursorPosition.X = 0;
6818  case L'A':
6819  csbi.dwCursorPosition.Y -= arg1;
6820  if (csbi.dwCursorPosition.Y < csbi.srWindow.Top)
6821  csbi.dwCursorPosition.Y = csbi.srWindow.Top;
6822  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6823  break;
6824  case L'E':
6825  csbi.dwCursorPosition.X = 0;
6826  case L'B':
6827  case L'e':
6828  csbi.dwCursorPosition.Y += arg1;
6829  if (csbi.dwCursorPosition.Y > csbi.srWindow.Bottom)
6830  csbi.dwCursorPosition.Y = csbi.srWindow.Bottom;
6831  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6832  break;
6833  case L'C':
6834  csbi.dwCursorPosition.X += arg1;
6835  if (csbi.dwCursorPosition.X >= csbi.srWindow.Right)
6836  csbi.dwCursorPosition.X = csbi.srWindow.Right;
6837  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6838  break;
6839  case L'D':
6840  csbi.dwCursorPosition.X -= arg1;
6841  if (csbi.dwCursorPosition.X < csbi.srWindow.Left)
6842  csbi.dwCursorPosition.X = csbi.srWindow.Left;
6843  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6844  break;
6845  case L'G':
6846  case L'`':
6847  arg1 += csbi.srWindow.Left;
6848  if (arg1 > csbi.srWindow.Right)
6849  arg1 = csbi.srWindow.Right;
6850  csbi.dwCursorPosition.X = arg1;
6851  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6852  break;
6853  case L'd':
6854  arg1 += csbi.srWindow.Top;
6855  if (arg1 > csbi.srWindow.Bottom)
6856  arg1 = csbi.srWindow.Bottom;
6857  csbi.dwCursorPosition.Y = arg1;
6858  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6859  break;
6860  case L'H':
6861  case L'f':
6862  pos.Y = arg1 + csbi.srWindow.Top - 1;
6863  if (pos.Y > csbi.srWindow.Bottom) pos.Y = csbi.srWindow.Bottom;
6864  if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1;
6865  pos.X = arg1 + csbi.srWindow.Left - 1;
6866  if (pos.X > csbi.srWindow.Right) pos.X = csbi.srWindow.Right;
6867  SetConsoleCursorPosition(handle, pos);
6868  break;
6869  case L'J':
6870  switch (arg0 ? arg1 : 0) {
6871  case 0: /* erase after cursor */
6872  constat_clear(handle, csbi.wAttributes,
6873  (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.dwCursorPosition.Y + 1)
6874  - csbi.dwCursorPosition.X),
6875  csbi.dwCursorPosition);
6876  break;
6877  case 1: /* erase before *and* cursor */
6878  pos.X = 0;
6879  pos.Y = csbi.srWindow.Top;
6880  constat_clear(handle, csbi.wAttributes,
6881  (csbi.dwSize.X * (csbi.dwCursorPosition.Y - csbi.srWindow.Top)
6882  + csbi.dwCursorPosition.X + 1),
6883  pos);
6884  break;
6885  case 2: /* erase entire screen */
6886  pos.X = 0;
6887  pos.Y = csbi.srWindow.Top;
6888  constat_clear(handle, csbi.wAttributes,
6889  (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1)),
6890  pos);
6891  break;
6892  case 3: /* erase entire screen */
6893  pos.X = 0;
6894  pos.Y = 0;
6895  constat_clear(handle, csbi.wAttributes,
6896  (csbi.dwSize.X * csbi.dwSize.Y),
6897  pos);
6898  break;
6899  }
6900  break;
6901  case L'K':
6902  switch (arg0 ? arg1 : 0) {
6903  case 0: /* erase after cursor */
6904  constat_clear(handle, csbi.wAttributes,
6905  (csbi.dwSize.X - csbi.dwCursorPosition.X),
6906  csbi.dwCursorPosition);
6907  break;
6908  case 1: /* erase before *and* cursor */
6909  pos.X = 0;
6910  pos.Y = csbi.dwCursorPosition.Y;
6911  constat_clear(handle, csbi.wAttributes,
6912  csbi.dwCursorPosition.X + 1, pos);
6913  break;
6914  case 2: /* erase entire line */
6915  pos.X = 0;
6916  pos.Y = csbi.dwCursorPosition.Y;
6917  constat_clear(handle, csbi.wAttributes,
6918  csbi.dwSize.X, pos);
6919  break;
6920  }
6921  break;
6922  case L's':
6923  s->vt100.saved = csbi.dwCursorPosition;
6924  break;
6925  case L'u':
6926  SetConsoleCursorPosition(handle, s->vt100.saved);
6927  break;
6928  case L'h':
6929  if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
6930  CONSOLE_CURSOR_INFO cci;
6931  GetConsoleCursorInfo(handle, &cci);
6932  cci.bVisible = TRUE;
6933  SetConsoleCursorInfo(handle, &cci);
6934  }
6935  break;
6936  case L'l':
6937  if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
6938  CONSOLE_CURSOR_INFO cci;
6939  GetConsoleCursorInfo(handle, &cci);
6940  cci.bVisible = FALSE;
6941  SetConsoleCursorInfo(handle, &cci);
6942  }
6943  break;
6944  }
6945 }
6946 
6947 /* get rid of console writing bug; assume WriteConsole and WriteFile
6948  * on a console share the same limit. */
6949 static const long MAXSIZE_CONSOLE_WRITING = 31366;
6950 
6951 /* License: Ruby's */
6952 static long
6953 constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
6954 {
6955  const WCHAR *ptr = *ptrp;
6956  long rest, len = *lenp;
6957  while (len-- > 0) {
6958  WCHAR wc = *ptr++;
6959  if (wc == 0x1b) {
6960  rest = *lenp - len - 1;
6961  if (s->vt100.state == constat_esc) {
6962  rest++; /* reuse this ESC */
6963  }
6964  s->vt100.state = constat_init;
6965  if (len > 0 && *ptr != L'[') continue;
6966  s->vt100.state = constat_esc;
6967  }
6968  else if (s->vt100.state == constat_esc) {
6969  if (wc != L'[') {
6970  /* TODO: supply dropped ESC at beginning */
6971  s->vt100.state = constat_init;
6972  continue;
6973  }
6974  rest = *lenp - len - 1;
6975  if (rest > 0) --rest;
6976  s->vt100.state = constat_seq;
6977  s->vt100.seq[0] = 0;
6978  }
6979  else if (s->vt100.state >= constat_seq) {
6980  if (wc >= L'0' && wc <= L'9') {
6981  if (s->vt100.state < (int)numberof(s->vt100.seq)) {
6982  int *seq = &s->vt100.seq[s->vt100.state];
6983  *seq = (*seq * 10) + (wc - L'0');
6984  }
6985  }
6986  else if (s->vt100.state == constat_seq && s->vt100.seq[0] == 0 && wc == L'?') {
6987  s->vt100.seq[s->vt100.state++] = -1;
6988  }
6989  else {
6990  do {
6991  if (++s->vt100.state < (int)numberof(s->vt100.seq)) {
6992  s->vt100.seq[s->vt100.state] = 0;
6993  }
6994  else {
6995  s->vt100.state = (int)numberof(s->vt100.seq);
6996  }
6997  } while (0);
6998  if (wc != L';') {
6999  constat_apply(h, s, wc);
7000  s->vt100.state = constat_init;
7001  }
7002  }
7003  rest = 0;
7004  }
7005  else if ((rest = *lenp - len) < MAXSIZE_CONSOLE_WRITING) {
7006  continue;
7007  }
7008  *ptrp = ptr;
7009  *lenp = len;
7010  return rest;
7011  }
7012  len = *lenp;
7013  *ptrp = ptr;
7014  *lenp = 0;
7015  return len;
7016 }
7017 
7018 
7019 /* License: Ruby's */
7020 int
7021 rb_w32_close(int fd)
7022 {
7023  SOCKET sock = TO_SOCKET(fd);
7024  int save_errno = errno;
7025 
7026  if (!is_socket(sock)) {
7027  UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
7028  constat_delete((HANDLE)sock);
7029  return _close(fd);
7030  }
7031  _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
7032  socklist_delete(&sock, NULL);
7033  _close(fd);
7034  errno = save_errno;
7035  if (closesocket(sock) == SOCKET_ERROR) {
7036  errno = map_errno(WSAGetLastError());
7037  return -1;
7038  }
7039  return 0;
7040 }
7041 
7042 static int
7043 setup_overlapped(OVERLAPPED *ol, int fd, int iswrite)
7044 {
7045  memset(ol, 0, sizeof(*ol));
7046  if (!(_osfile(fd) & (FDEV | FPIPE))) {
7047  LONG high = 0;
7048  /* On mode:a, it can write only FILE_END.
7049  * On mode:a+, though it can write only FILE_END,
7050  * it can read from everywhere.
7051  */
7052  DWORD method = ((_osfile(fd) & FAPPEND) && iswrite) ? FILE_END : FILE_CURRENT;
7053  DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
7054 #ifndef INVALID_SET_FILE_POINTER
7055 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
7056 #endif
7057  if (low == INVALID_SET_FILE_POINTER) {
7058  DWORD err = GetLastError();
7059  if (err != NO_ERROR) {
7060  errno = map_errno(err);
7061  return -1;
7062  }
7063  }
7064  ol->Offset = low;
7065  ol->OffsetHigh = high;
7066  }
7067  ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
7068  if (!ol->hEvent) {
7069  errno = map_errno(GetLastError());
7070  return -1;
7071  }
7072  return 0;
7073 }
7074 
7075 static void
7076 finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
7077 {
7078  CloseHandle(ol->hEvent);
7079 
7080  if (!(_osfile(fd) & (FDEV | FPIPE))) {
7081  LONG high = ol->OffsetHigh;
7082  DWORD low = ol->Offset + size;
7083  if (low < ol->Offset)
7084  ++high;
7085  SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
7086  }
7087 }
7088 
7089 #undef read
7090 /* License: Ruby's */
7091 ssize_t
7092 rb_w32_read(int fd, void *buf, size_t size)
7093 {
7094  SOCKET sock = TO_SOCKET(fd);
7095  DWORD read;
7096  DWORD wait;
7097  DWORD err;
7098  size_t len;
7099  size_t ret;
7100  OVERLAPPED ol;
7101  BOOL isconsole;
7102  BOOL islineinput = FALSE;
7103  int start = 0;
7104 
7105  if (is_socket(sock))
7106  return rb_w32_recv(fd, buf, size, 0);
7107 
7108  // validate fd by using _get_osfhandle() because we cannot access _nhandle
7109  if (_get_osfhandle(fd) == -1) {
7110  return -1;
7111  }
7112 
7113  if (_osfile(fd) & FTEXT) {
7114  return _read(fd, buf, size);
7115  }
7116 
7117  rb_acrt_lowio_lock_fh(fd);
7118 
7119  if (!size || _osfile(fd) & FEOFLAG) {
7120  _set_osflags(fd, _osfile(fd) & ~FEOFLAG);
7121  rb_acrt_lowio_unlock_fh(fd);
7122  return 0;
7123  }
7124 
7125  ret = 0;
7126  isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
7127  if (isconsole) {
7128  DWORD mode;
7129  GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
7130  islineinput = (mode & ENABLE_LINE_INPUT) != 0;
7131  }
7132  retry:
7133  /* get rid of console reading bug */
7134  if (isconsole) {
7135  constat_reset((HANDLE)_osfhnd(fd));
7136  if (start)
7137  len = 1;
7138  else {
7139  len = 0;
7140  start = 1;
7141  }
7142  }
7143  else
7144  len = size;
7145  size -= len;
7146 
7147  if (setup_overlapped(&ol, fd, FALSE)) {
7148  rb_acrt_lowio_unlock_fh(fd);
7149  return -1;
7150  }
7151 
7152  if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, &ol)) {
7153  err = GetLastError();
7154  if (err == ERROR_NO_DATA && (_osfile(fd) & FPIPE)) {
7155  DWORD state;
7156  if (GetNamedPipeHandleState((HANDLE)_osfhnd(fd), &state, NULL, NULL, NULL, NULL, 0) && (state & PIPE_NOWAIT)) {
7157  errno = EWOULDBLOCK;
7158  }
7159  else {
7160  errno = map_errno(err);
7161  }
7162  rb_acrt_lowio_unlock_fh(fd);
7163  return -1;
7164  }
7165  else if (err != ERROR_IO_PENDING) {
7166  CloseHandle(ol.hEvent);
7167  if (err == ERROR_ACCESS_DENIED)
7168  errno = EBADF;
7169  else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
7170  rb_acrt_lowio_unlock_fh(fd);
7171  return 0;
7172  }
7173  else
7174  errno = map_errno(err);
7175 
7176  rb_acrt_lowio_unlock_fh(fd);
7177  return -1;
7178  }
7179 
7180  wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
7181  if (wait != WAIT_OBJECT_0) {
7182  if (wait == WAIT_OBJECT_0 + 1)
7183  errno = EINTR;
7184  else
7185  errno = map_errno(GetLastError());
7186  CloseHandle(ol.hEvent);
7187  CancelIo((HANDLE)_osfhnd(fd));
7188  rb_acrt_lowio_unlock_fh(fd);
7189  return -1;
7190  }
7191 
7192  if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
7193  (err = GetLastError()) != ERROR_HANDLE_EOF) {
7194  int ret = 0;
7195  if (err != ERROR_BROKEN_PIPE) {
7196  errno = map_errno(err);
7197  ret = -1;
7198  }
7199  CloseHandle(ol.hEvent);
7200  CancelIo((HANDLE)_osfhnd(fd));
7201  rb_acrt_lowio_unlock_fh(fd);
7202  return ret;
7203  }
7204  }
7205  else {
7206  err = GetLastError();
7207  errno = map_errno(err);
7208  }
7209 
7210  finish_overlapped(&ol, fd, read);
7211 
7212  ret += read;
7213  if (read >= len) {
7214  buf = (char *)buf + read;
7215  if (err != ERROR_OPERATION_ABORTED &&
7216  !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0)
7217  goto retry;
7218  }
7219  if (read == 0)
7220  _set_osflags(fd, _osfile(fd) | FEOFLAG);
7221 
7222 
7223  rb_acrt_lowio_unlock_fh(fd);
7224 
7225  return ret;
7226 }
7227 
7228 #undef write
7229 /* License: Ruby's */
7230 ssize_t
7231 rb_w32_write(int fd, const void *buf, size_t size)
7232 {
7233  SOCKET sock = TO_SOCKET(fd);
7234  DWORD written;
7235  DWORD wait;
7236  DWORD err;
7237  size_t len;
7238  size_t ret;
7239  OVERLAPPED ol;
7240 
7241  if (is_socket(sock))
7242  return rb_w32_send(fd, buf, size, 0);
7243 
7244  // validate fd by using _get_osfhandle() because we cannot access _nhandle
7245  if (_get_osfhandle(fd) == -1) {
7246  return -1;
7247  }
7248 
7249  if ((_osfile(fd) & FTEXT) &&
7250  (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) {
7251  ssize_t w = _write(fd, buf, size);
7252  if (w == (ssize_t)-1 && errno == EINVAL) {
7253  errno = map_errno(GetLastError());
7254  }
7255  return w;
7256  }
7257 
7258  rb_acrt_lowio_lock_fh(fd);
7259 
7260  if (!size || _osfile(fd) & FEOFLAG) {
7261  rb_acrt_lowio_unlock_fh(fd);
7262  return 0;
7263  }
7264 
7265  ret = 0;
7266  retry:
7267  len = (_osfile(fd) & FDEV) ? min(MAXSIZE_CONSOLE_WRITING, size) : size;
7268  size -= len;
7269  retry2:
7270 
7271  if (setup_overlapped(&ol, fd, TRUE)) {
7272  rb_acrt_lowio_unlock_fh(fd);
7273  return -1;
7274  }
7275 
7276  if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, &ol)) {
7277  err = GetLastError();
7278  if (err != ERROR_IO_PENDING) {
7279  CloseHandle(ol.hEvent);
7280  if (err == ERROR_ACCESS_DENIED)
7281  errno = EBADF;
7282  else
7283  errno = map_errno(err);
7284 
7285  rb_acrt_lowio_unlock_fh(fd);
7286  return -1;
7287  }
7288 
7289  wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
7290  if (wait != WAIT_OBJECT_0) {
7291  if (wait == WAIT_OBJECT_0 + 1)
7292  errno = EINTR;
7293  else
7294  errno = map_errno(GetLastError());
7295  CloseHandle(ol.hEvent);
7296  CancelIo((HANDLE)_osfhnd(fd));
7297  rb_acrt_lowio_unlock_fh(fd);
7298  return -1;
7299  }
7300 
7301  if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written, TRUE)) {
7302  errno = map_errno(GetLastError());
7303  CloseHandle(ol.hEvent);
7304  CancelIo((HANDLE)_osfhnd(fd));
7305  rb_acrt_lowio_unlock_fh(fd);
7306  return -1;
7307  }
7308  }
7309 
7310  finish_overlapped(&ol, fd, written);
7311 
7312  ret += written;
7313  if (written == len) {
7314  buf = (const char *)buf + len;
7315  if (size > 0)
7316  goto retry;
7317  }
7318  if (ret == 0) {
7319  size_t newlen = len / 2;
7320  if (newlen > 0) {
7321  size += len - newlen;
7322  len = newlen;
7323  goto retry2;
7324  }
7325  ret = -1;
7326  errno = EWOULDBLOCK;
7327  }
7328 
7329  rb_acrt_lowio_unlock_fh(fd);
7330 
7331  return ret;
7332 }
7333 
7334 /* License: Ruby's */
7335 long
7336 rb_w32_write_console(uintptr_t strarg, int fd)
7337 {
7338  HANDLE handle;
7339  DWORD dwMode, reslen;
7340  VALUE str = strarg;
7341  int encindex;
7342  WCHAR *wbuffer = 0;
7343  const WCHAR *ptr, *next;
7344  struct constat *s;
7345  long len;
7346 
7347  handle = (HANDLE)_osfhnd(fd);
7348  if (!GetConsoleMode(handle, &dwMode))
7349  return -1L;
7350 
7351  s = constat_handle(handle);
7352  if (!s) return -1L;
7353  encindex = ENCODING_GET(str);
7354  switch (encindex) {
7355  default:
7356  if (!rb_econv_has_convpath_p(rb_enc_name(rb_enc_from_index(encindex)), "UTF-8"))
7357  return -1L;
7358  str = rb_str_conv_enc_opts(str, NULL, rb_enc_from_index(ENCINDEX_UTF_8),
7360  /* fall through */
7361  case ENCINDEX_US_ASCII:
7362  case ENCINDEX_ASCII:
7363  /* assume UTF-8 */
7364  case ENCINDEX_UTF_8:
7365  ptr = wbuffer = mbstr_to_wstr(CP_UTF8, RSTRING_PTR(str), RSTRING_LEN(str), &len);
7366  if (!ptr) return -1L;
7367  break;
7368  case ENCINDEX_UTF_16LE:
7369  ptr = (const WCHAR *)RSTRING_PTR(str);
7370  len = RSTRING_LEN(str) / sizeof(WCHAR);
7371  break;
7372  }
7373  reslen = 0;
7374  if (dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) {
7375  if (!WriteConsoleW(handle, ptr, len, &reslen, NULL))
7376  reslen = (DWORD)-1L;
7377  }
7378  else {
7379  while (len > 0) {
7380  long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
7381  reslen += next - ptr;
7382  if (curlen > 0) {
7383  DWORD written;
7384  if (!WriteConsoleW(handle, ptr, curlen, &written, NULL)) {
7385  reslen = (DWORD)-1L;
7386  break;
7387  }
7388  }
7389  ptr = next;
7390  }
7391  }
7392  RB_GC_GUARD(str);
7393  if (wbuffer) free(wbuffer);
7394  return (long)reslen;
7395 }
7396 
7397 #if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7398 /* License: Ruby's */
7399 static int
7400 unixtime_to_filetime(time_t time, FILETIME *ft)
7401 {
7402  ULARGE_INTEGER tmp;
7403 
7404  tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
7405  ft->dwLowDateTime = tmp.LowPart;
7406  ft->dwHighDateTime = tmp.HighPart;
7407  return 0;
7408 }
7409 #endif
7410 
7411 /* License: Ruby's */
7412 static int
7413 timespec_to_filetime(const struct timespec *ts, FILETIME *ft)
7414 {
7415  ULARGE_INTEGER tmp;
7416 
7417  tmp.QuadPart = ((LONG_LONG)ts->tv_sec + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
7418  tmp.QuadPart += ts->tv_nsec / 100;
7419  ft->dwLowDateTime = tmp.LowPart;
7420  ft->dwHighDateTime = tmp.HighPart;
7421  return 0;
7422 }
7423 
7424 /* License: Ruby's */
7425 static int
7426 wutimensat(int dirfd, const WCHAR *path, const struct timespec *times, int flags)
7427 {
7428  HANDLE hFile;
7429  FILETIME atime, mtime;
7430  struct stati128 stat;
7431  int ret = 0;
7432 
7433  /* TODO: When path is absolute, dirfd should be ignored. */
7434  if (dirfd != AT_FDCWD) {
7435  errno = ENOSYS;
7436  return -1;
7437  }
7438 
7439  if (flags != 0) {
7440  errno = EINVAL; /* AT_SYMLINK_NOFOLLOW isn't supported. */
7441  return -1;
7442  }
7443 
7444  if (wstati128(path, &stat, FALSE)) {
7445  return -1;
7446  }
7447 
7448  if (times) {
7449  if (timespec_to_filetime(&times[0], &atime)) {
7450  return -1;
7451  }
7452  if (timespec_to_filetime(&times[1], &mtime)) {
7453  return -1;
7454  }
7455  }
7456  else {
7457  get_systemtime(&atime);
7458  mtime = atime;
7459  }
7460 
7461  RUBY_CRITICAL {
7462  const DWORD attr = GetFileAttributesW(path);
7463  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7464  SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7465  hFile = open_special(path, GENERIC_WRITE, 0);
7466  if (hFile == INVALID_HANDLE_VALUE) {
7467  errno = map_errno(GetLastError());
7468  ret = -1;
7469  }
7470  else {
7471  if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
7472  errno = map_errno(GetLastError());
7473  ret = -1;
7474  }
7475  CloseHandle(hFile);
7476  }
7477  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7478  SetFileAttributesW(path, attr);
7479  }
7480 
7481  return ret;
7482 }
7483 
7484 /* License: Ruby's */
7485 static int
7486 w32_utimensat(int dirfd, const char *path, const struct timespec *times, int flags, UINT cp)
7487 {
7488  WCHAR *wpath = mbstr_to_wstr(cp, path, -1, NULL);
7489  int ret = -1;
7490 
7491  if (wpath) {
7492  ret = wutimensat(dirfd, wpath, times, flags);
7493  free(wpath);
7494  }
7495  return ret;
7496 }
7497 
7498 /* License: Ruby's */
7499 int
7500 rb_w32_uutime(const char *path, const struct utimbuf *times)
7501 {
7502  struct timespec ts[2];
7503 
7504  ts[0].tv_sec = times->actime;
7505  ts[0].tv_nsec = 0;
7506  ts[1].tv_sec = times->modtime;
7507  ts[1].tv_nsec = 0;
7508  return w32_utimensat(AT_FDCWD, path, ts, 0, CP_UTF8);
7509 }
7510 
7511 /* License: Ruby's */
7512 int
7513 rb_w32_utime(const char *path, const struct utimbuf *times)
7514 {
7515  struct timespec ts[2];
7516 
7517  ts[0].tv_sec = times->actime;
7518  ts[0].tv_nsec = 0;
7519  ts[1].tv_sec = times->modtime;
7520  ts[1].tv_nsec = 0;
7521  return w32_utimensat(AT_FDCWD, path, ts, 0, filecp());
7522 }
7523 
7524 /* License: Ruby's */
7525 int
7526 rb_w32_uutimes(const char *path, const struct timeval *times)
7527 {
7528  struct timespec ts[2];
7529 
7530  ts[0].tv_sec = times[0].tv_sec;
7531  ts[0].tv_nsec = times[0].tv_usec * 1000;
7532  ts[1].tv_sec = times[1].tv_sec;
7533  ts[1].tv_nsec = times[1].tv_usec * 1000;
7534  return w32_utimensat(AT_FDCWD, path, ts, 0, CP_UTF8);
7535 }
7536 
7537 /* License: Ruby's */
7538 int
7539 rb_w32_utimes(const char *path, const struct timeval *times)
7540 {
7541  struct timespec ts[2];
7542 
7543  ts[0].tv_sec = times[0].tv_sec;
7544  ts[0].tv_nsec = times[0].tv_usec * 1000;
7545  ts[1].tv_sec = times[1].tv_sec;
7546  ts[1].tv_nsec = times[1].tv_usec * 1000;
7547  return w32_utimensat(AT_FDCWD, path, ts, 0, filecp());
7548 }
7549 
7550 /* License: Ruby's */
7551 int
7552 rb_w32_uutimensat(int dirfd, const char *path, const struct timespec *times, int flags)
7553 {
7554  return w32_utimensat(dirfd, path, times, flags, CP_UTF8);
7555 }
7556 
7557 /* License: Ruby's */
7558 int
7559 rb_w32_utimensat(int dirfd, const char *path, const struct timespec *times, int flags)
7560 {
7561  return w32_utimensat(dirfd, path, times, flags, filecp());
7562 }
7563 
7564 /* License: Ruby's */
7565 int
7566 rb_w32_uchdir(const char *path)
7567 {
7568  WCHAR *wpath;
7569  int ret;
7570 
7571  if (!(wpath = utf8_to_wstr(path, NULL)))
7572  return -1;
7573  ret = _wchdir(wpath);
7574  free(wpath);
7575  return ret;
7576 }
7577 
7578 /* License: Ruby's */
7579 static int
7580 wmkdir(const WCHAR *wpath, int mode)
7581 {
7582  int ret = -1;
7583 
7584  RUBY_CRITICAL do {
7585  if (CreateDirectoryW(wpath, NULL) == FALSE) {
7586  errno = map_errno(GetLastError());
7587  break;
7588  }
7589  if (_wchmod(wpath, mode) == -1) {
7590  RemoveDirectoryW(wpath);
7591  break;
7592  }
7593  ret = 0;
7594  } while (0);
7595  return ret;
7596 }
7597 
7598 /* License: Ruby's */
7599 int
7600 rb_w32_umkdir(const char *path, int mode)
7601 {
7602  WCHAR *wpath;
7603  int ret;
7604 
7605  if (!(wpath = utf8_to_wstr(path, NULL)))
7606  return -1;
7607  ret = wmkdir(wpath, mode);
7608  free(wpath);
7609  return ret;
7610 }
7611 
7612 /* License: Ruby's */
7613 int
7614 rb_w32_mkdir(const char *path, int mode)
7615 {
7616  WCHAR *wpath;
7617  int ret;
7618 
7619  if (!(wpath = filecp_to_wstr(path, NULL)))
7620  return -1;
7621  ret = wmkdir(wpath, mode);
7622  free(wpath);
7623  return ret;
7624 }
7625 
7626 /* License: Ruby's */
7627 static int
7628 wrmdir(const WCHAR *wpath)
7629 {
7630  int ret = 0;
7631  RUBY_CRITICAL {
7632  const DWORD attr = GetFileAttributesW(wpath);
7633  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7634  SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
7635  }
7636  if (RemoveDirectoryW(wpath) == FALSE) {
7637  errno = map_errno(GetLastError());
7638  ret = -1;
7639  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7640  SetFileAttributesW(wpath, attr);
7641  }
7642  }
7643  }
7644  return ret;
7645 }
7646 
7647 /* License: Ruby's */
7648 int
7649 rb_w32_rmdir(const char *path)
7650 {
7651  WCHAR *wpath;
7652  int ret;
7653 
7654  if (!(wpath = filecp_to_wstr(path, NULL)))
7655  return -1;
7656  ret = wrmdir(wpath);
7657  free(wpath);
7658  return ret;
7659 }
7660 
7661 /* License: Ruby's */
7662 int
7663 rb_w32_urmdir(const char *path)
7664 {
7665  WCHAR *wpath;
7666  int ret;
7667 
7668  if (!(wpath = utf8_to_wstr(path, NULL)))
7669  return -1;
7670  ret = wrmdir(wpath);
7671  free(wpath);
7672  return ret;
7673 }
7674 
7675 /* License: Ruby's */
7676 static int
7677 wunlink(const WCHAR *path)
7678 {
7679  int ret = 0;
7680  const DWORD SYMLINKD = FILE_ATTRIBUTE_REPARSE_POINT|FILE_ATTRIBUTE_DIRECTORY;
7681  RUBY_CRITICAL {
7682  const DWORD attr = GetFileAttributesW(path);
7683  if (attr == (DWORD)-1) {
7684  }
7685  else if ((attr & SYMLINKD) == SYMLINKD) {
7686  ret = RemoveDirectoryW(path);
7687  }
7688  else {
7689  if (attr & FILE_ATTRIBUTE_READONLY) {
7690  SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7691  }
7692  ret = DeleteFileW(path);
7693  }
7694  if (!ret) {
7695  errno = map_errno(GetLastError());
7696  ret = -1;
7697  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7698  SetFileAttributesW(path, attr);
7699  }
7700  }
7701  }
7702  return ret;
7703 }
7704 
7705 /* License: Ruby's */
7706 int
7707 rb_w32_uunlink(const char *path)
7708 {
7709  WCHAR *wpath;
7710  int ret;
7711 
7712  if (!(wpath = utf8_to_wstr(path, NULL)))
7713  return -1;
7714  ret = wunlink(wpath);
7715  free(wpath);
7716  return ret;
7717 }
7718 
7719 /* License: Ruby's */
7720 int
7721 rb_w32_unlink(const char *path)
7722 {
7723  WCHAR *wpath;
7724  int ret;
7725 
7726  if (!(wpath = filecp_to_wstr(path, NULL)))
7727  return -1;
7728  ret = wunlink(wpath);
7729  free(wpath);
7730  return ret;
7731 }
7732 
7733 /* License: Ruby's */
7734 int
7735 rb_w32_uchmod(const char *path, int mode)
7736 {
7737  WCHAR *wpath;
7738  int ret;
7739 
7740  if (!(wpath = utf8_to_wstr(path, NULL)))
7741  return -1;
7742  ret = _wchmod(wpath, mode);
7743  free(wpath);
7744  return ret;
7745 }
7746 
7747 /* License: Ruby's */
7748 int
7749 fchmod(int fd, int mode)
7750 {
7751  typedef BOOL (WINAPI *set_file_information_by_handle_func)
7752  (HANDLE, int, void*, DWORD);
7753  static set_file_information_by_handle_func set_file_info =
7754  (set_file_information_by_handle_func)-1;
7755 
7756  /* from winbase.h of the mingw-w64 runtime package. */
7757  struct {
7758  LARGE_INTEGER CreationTime;
7759  LARGE_INTEGER LastAccessTime;
7760  LARGE_INTEGER LastWriteTime;
7761  LARGE_INTEGER ChangeTime;
7762  DWORD FileAttributes;
7763  } info = {{{0}}, {{0}}, {{0}},}; /* fields with 0 are unchanged */
7764  HANDLE h = (HANDLE)_get_osfhandle(fd);
7765 
7766  if (h == INVALID_HANDLE_VALUE) {
7767  errno = EBADF;
7768  return -1;
7769  }
7770  if (set_file_info == (set_file_information_by_handle_func)-1) {
7771  /* Since Windows Vista and Windows Server 2008 */
7772  set_file_info = (set_file_information_by_handle_func)
7773  get_proc_address("kernel32", "SetFileInformationByHandle", NULL);
7774  }
7775  if (!set_file_info) {
7776  errno = ENOSYS;
7777  return -1;
7778  }
7779 
7780  info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
7781  if (!(mode & 0200)) info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
7782  if (!set_file_info(h, 0, &info, sizeof(info))) {
7783  errno = map_errno(GetLastError());
7784  return -1;
7785  }
7786  return 0;
7787 }
7788 
7789 /* License: Ruby's */
7790 int
7791 rb_w32_isatty(int fd)
7792 {
7793  DWORD mode;
7794 
7795  // validate fd by using _get_osfhandle() because we cannot access _nhandle
7796  if (_get_osfhandle(fd) == -1) {
7797  return 0;
7798  }
7799  if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) {
7800  errno = ENOTTY;
7801  return 0;
7802  }
7803  return 1;
7804 }
7805 
7806 #if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
7807 extern long _ftol(double);
7808 /* License: Ruby's */
7809 long
7810 _ftol2(double d)
7811 {
7812  return _ftol(d);
7813 }
7814 
7815 /* License: Ruby's */
7816 long
7817 _ftol2_sse(double d)
7818 {
7819  return _ftol(d);
7820 }
7821 #endif
7822 
7823 #ifndef signbit
7824 /* License: Ruby's */
7825 int
7826 signbit(double x)
7827 {
7828  int *ip = (int *)(&x + 1) - 1;
7829  return *ip < 0;
7830 }
7831 #endif
7832 
7833 /* License: Ruby's */
7834 const char * WSAAPI
7835 rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
7836 {
7837  typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t);
7838  static inet_ntop_t *pInetNtop = (inet_ntop_t *)-1;
7839  if (pInetNtop == (inet_ntop_t *)-1)
7840  pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL);
7841  if (pInetNtop) {
7842  return pInetNtop(af, (void *)addr, numaddr, numaddr_len);
7843  }
7844  else {
7845  struct in_addr in;
7846  memcpy(&in.s_addr, addr, sizeof(in.s_addr));
7847  snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
7848  }
7849  return numaddr;
7850 }
7851 
7852 /* License: Ruby's */
7853 int WSAAPI
7854 rb_w32_inet_pton(int af, const char *src, void *dst)
7855 {
7856  typedef int (WSAAPI inet_pton_t)(int, const char*, void *);
7857  static inet_pton_t *pInetPton = (inet_pton_t *)-1;
7858  if (pInetPton == (inet_pton_t *)-1)
7859  pInetPton = (inet_pton_t *)get_proc_address("ws2_32", "inet_pton", NULL);
7860  if (pInetPton) {
7861  return pInetPton(af, src, dst);
7862  }
7863  return 0;
7864 }
7865 
7866 /* License: Ruby's */
7867 char
7868 rb_w32_fd_is_text(int fd)
7869 {
7870  return _osfile(fd) & FTEXT;
7871 }
7872 
7873 #if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7874 /* License: Ruby's */
7875 static int
7876 unixtime_to_systemtime(const time_t t, SYSTEMTIME *st)
7877 {
7878  FILETIME ft;
7879  if (unixtime_to_filetime(t, &ft)) return -1;
7880  if (!FileTimeToSystemTime(&ft, st)) return -1;
7881  return 0;
7882 }
7883 
7884 /* License: Ruby's */
7885 static void
7886 systemtime_to_tm(const SYSTEMTIME *st, struct tm *t)
7887 {
7888  int y = st->wYear, m = st->wMonth, d = st->wDay;
7889  t->tm_sec = st->wSecond;
7890  t->tm_min = st->wMinute;
7891  t->tm_hour = st->wHour;
7892  t->tm_mday = st->wDay;
7893  t->tm_mon = st->wMonth - 1;
7894  t->tm_year = y - 1900;
7895  t->tm_wday = st->wDayOfWeek;
7896  switch (m) {
7897  case 1:
7898  break;
7899  case 2:
7900  d += 31;
7901  break;
7902  default:
7903  d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
7904  d += ((m - 3) * 153 + 2) / 5;
7905  break;
7906  }
7907  t->tm_yday = d - 1;
7908 }
7909 
7910 /* License: Ruby's */
7911 static int
7912 systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
7913 {
7914  TIME_ZONE_INFORMATION stdtz;
7915  SYSTEMTIME sst;
7916 
7917  if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1;
7918  if (!tz) {
7919  GetTimeZoneInformation(&stdtz);
7920  tz = &stdtz;
7921  }
7922  if (tz->StandardBias == tz->DaylightBias) return 0;
7923  if (!tz->StandardDate.wMonth) return 0;
7924  if (!tz->DaylightDate.wMonth) return 0;
7925  if (tz != &stdtz) stdtz = *tz;
7926 
7927  stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
7928  if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0;
7929  if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
7930  return 0;
7931  return 1;
7932 }
7933 #endif
7934 
7935 #ifdef HAVE__GMTIME64_S
7936 # ifndef HAVE__LOCALTIME64_S
7937 /* assume same as _gmtime64_s() */
7938 # define HAVE__LOCALTIME64_S 1
7939 # endif
7940 # ifndef MINGW_HAS_SECURE_API
7941  _CRTIMP errno_t __cdecl _gmtime64_s(struct tm* tm, const __time64_t *time);
7942  _CRTIMP errno_t __cdecl _localtime64_s(struct tm* tm, const __time64_t *time);
7943 # endif
7944 # define gmtime_s _gmtime64_s
7945 # define localtime_s _localtime64_s
7946 #endif
7947 
7948 /* License: Ruby's */
7949 struct tm *
7950 gmtime_r(const time_t *tp, struct tm *rp)
7951 {
7952  int e = EINVAL;
7953  if (!tp || !rp) {
7954  error:
7955  errno = e;
7956  return NULL;
7957  }
7958 #if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__GMTIME64_S)
7959  e = gmtime_s(rp, tp);
7960  if (e != 0) goto error;
7961 #else
7962  {
7963  SYSTEMTIME st;
7964  if (unixtime_to_systemtime(*tp, &st)) goto error;
7965  rp->tm_isdst = 0;
7966  systemtime_to_tm(&st, rp);
7967  }
7968 #endif
7969  return rp;
7970 }
7971 
7972 /* License: Ruby's */
7973 struct tm *
7974 localtime_r(const time_t *tp, struct tm *rp)
7975 {
7976  int e = EINVAL;
7977  if (!tp || !rp) {
7978  error:
7979  errno = e;
7980  return NULL;
7981  }
7982 #if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__LOCALTIME64_S)
7983  e = localtime_s(rp, tp);
7984  if (e) goto error;
7985 #else
7986  {
7987  SYSTEMTIME gst, lst;
7988  if (unixtime_to_systemtime(*tp, &gst)) goto error;
7989  rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
7990  systemtime_to_tm(&lst, rp);
7991  }
7992 #endif
7993  return rp;
7994 }
7995 
7996 /* License: Ruby's */
7997 int
7998 rb_w32_wrap_io_handle(HANDLE h, int flags)
7999 {
8000  BOOL tmp;
8001  int len = sizeof(tmp);
8002  int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (char *)&tmp, &len);
8003  if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
8004  int f = 0;
8005  if (flags & O_NONBLOCK) {
8006  flags &= ~O_NONBLOCK;
8007  f = O_NONBLOCK;
8008  }
8009  socklist_insert((SOCKET)h, f);
8010  }
8011  else if (flags & O_NONBLOCK) {
8012  errno = EINVAL;
8013  return -1;
8014  }
8015  return rb_w32_open_osfhandle((intptr_t)h, flags);
8016 }
8017 
8018 /* License: Ruby's */
8019 int
8020 rb_w32_unwrap_io_handle(int fd)
8021 {
8022  SOCKET sock = TO_SOCKET(fd);
8023  _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
8024  if (!is_socket(sock)) {
8025  UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
8026  constat_delete((HANDLE)sock);
8027  }
8028  else {
8029  socklist_delete(&sock, NULL);
8030  }
8031  return _close(fd);
8032 }
8033 
8034 #if !defined(__MINGW64__) && defined(__MINGW64_VERSION_MAJOR)
8035 /*
8036  * Set floating point precision for pow() of mingw-w64 x86.
8037  * With default precision the result is not proper on WinXP.
8038  */
8039 double
8040 rb_w32_pow(double x, double y)
8041 {
8042 #undef pow
8043  double r;
8044  unsigned int default_control = _controlfp(0, 0);
8045  _controlfp(_PC_64, _MCW_PC);
8046  r = pow(x, y);
8047  /* Restore setting */
8048  _controlfp(default_control, _MCW_PC);
8049  return r;
8050 }
8051 #endif
8052 
8053 typedef struct {
8054  BOOL file_id_p;
8055  union {
8056  BY_HANDLE_FILE_INFORMATION bhfi;
8057  FILE_ID_INFO fii;
8058  } info;
8059 } w32_io_info_t;
8060 
8061 static HANDLE
8062 w32_io_info(VALUE *file, w32_io_info_t *st)
8063 {
8064  VALUE tmp;
8065  HANDLE f, ret = 0;
8066 
8067  tmp = rb_check_convert_type_with_id(*file, T_FILE, "IO", idTo_io);
8068  if (!NIL_P(tmp)) {
8069  rb_io_t *fptr;
8070 
8071  GetOpenFile(tmp, fptr);
8072  f = (HANDLE)rb_w32_get_osfhandle(fptr->fd);
8073  if (f == (HANDLE)-1) return INVALID_HANDLE_VALUE;
8074  }
8075  else {
8076  VALUE tmp;
8077  WCHAR *ptr;
8078  int len;
8079  VALUE v;
8080 
8081  FilePathValue(*file);
8082  tmp = rb_str_encode_ospath(*file);
8083  len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, NULL, 0);
8084  ptr = ALLOCV_N(WCHAR, v, len);
8085  MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(tmp), -1, ptr, len);
8086  f = CreateFileW(ptr, 0,
8087  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
8088  FILE_FLAG_BACKUP_SEMANTICS, NULL);
8089  ALLOCV_END(v);
8090  if (f == INVALID_HANDLE_VALUE) return f;
8091  ret = f;
8092  }
8093  if (GetFileType(f) == FILE_TYPE_DISK) {
8094  DWORD err;
8095  ZeroMemory(st, sizeof(*st));
8096  err = get_ino(f, &st->info.fii);
8097  if (!err) {
8098  st->file_id_p = TRUE;
8099  return ret;
8100  }
8101  else if (err != ERROR_INVALID_PARAMETER) {
8102  CloseHandle(f);
8103  return INVALID_HANDLE_VALUE;
8104  }
8105  /* this API may not work at files on non Microsoft SMB
8106  * server, fallback to old API then. */
8107  if (GetFileInformationByHandle(f, &st->info.bhfi)) {
8108  st->file_id_p = FALSE;
8109  return ret;
8110  }
8111  }
8112  if (ret) CloseHandle(ret);
8113  return INVALID_HANDLE_VALUE;
8114 }
8115 
8116 static VALUE
8117 close_handle(VALUE h)
8118 {
8119  CloseHandle((HANDLE)h);
8120  return Qfalse;
8121 }
8122 
8124  VALUE *fname;
8125  w32_io_info_t *st;
8126 };
8127 
8128 static VALUE
8129 call_w32_io_info(VALUE arg)
8130 {
8131  struct w32_io_info_args *p = (void *)arg;
8132  return (VALUE)w32_io_info(p->fname, p->st);
8133 }
8134 
8135 VALUE
8136 rb_w32_file_identical_p(VALUE fname1, VALUE fname2)
8137 {
8138  w32_io_info_t st1, st2;
8139  HANDLE f1 = 0, f2 = 0;
8140 
8141  f1 = w32_io_info(&fname1, &st1);
8142  if (f1 == INVALID_HANDLE_VALUE) return Qfalse;
8143  if (f1) {
8144  struct w32_io_info_args arg;
8145  arg.fname = &fname2;
8146  arg.st = &st2;
8147  f2 = (HANDLE)rb_ensure(call_w32_io_info, (VALUE)&arg, close_handle, (VALUE)f1);
8148  }
8149  else {
8150  f2 = w32_io_info(&fname2, &st2);
8151  }
8152  if (f2 == INVALID_HANDLE_VALUE) return Qfalse;
8153  if (f2) CloseHandle(f2);
8154 
8155  if (st1.file_id_p != st2.file_id_p) return Qfalse;
8156  if (!st1.file_id_p) {
8157  if (st1.info.bhfi.dwVolumeSerialNumber == st2.info.bhfi.dwVolumeSerialNumber &&
8158  st1.info.bhfi.nFileIndexHigh == st2.info.bhfi.nFileIndexHigh &&
8159  st1.info.bhfi.nFileIndexLow == st2.info.bhfi.nFileIndexLow)
8160  return Qtrue;
8161  }
8162  else {
8163  if (st1.info.fii.VolumeSerialNumber == st2.info.fii.VolumeSerialNumber &&
8164  memcmp(&st1.info.fii.FileId, &st2.info.fii.FileId, sizeof(FILE_ID_128)) == 0)
8165  return Qtrue;
8166  }
8167  return Qfalse;
8168 }
8169 
8170 int
8171 rb_w32_set_thread_description(HANDLE th, const WCHAR *name)
8172 {
8173  int result = FALSE;
8174  typedef HRESULT (WINAPI *set_thread_description_func)(HANDLE, PCWSTR);
8175  static set_thread_description_func set_thread_description =
8176  (set_thread_description_func)-1;
8177  if (set_thread_description == (set_thread_description_func)-1) {
8178  /* Since Windows 10, version 1607 and Windows Server 2016 */
8179  set_thread_description = (set_thread_description_func)
8180  get_proc_address("kernel32", "SetThreadDescription", NULL);
8181  }
8182  if (set_thread_description) {
8183  result = set_thread_description(th, name);
8184  }
8185  return result;
8186 }
8187 
8188 int
8189 rb_w32_set_thread_description_str(HANDLE th, VALUE name)
8190 {
8191  int idx, result = FALSE;
8192  WCHAR *s;
8193 
8194  if (NIL_P(name)) {
8195  return rb_w32_set_thread_description(th, L"");
8196  }
8197  s = (WCHAR *)StringValueCStr(name);
8198  idx = rb_enc_get_index(name);
8199  if (idx == ENCINDEX_UTF_16LE) {
8200  result = rb_w32_set_thread_description(th, s);
8201  }
8202  else {
8203  name = rb_str_conv_enc(name, rb_enc_from_index(idx), rb_utf8_encoding());
8204  s = mbstr_to_wstr(CP_UTF8, RSTRING_PTR(name), RSTRING_LEN(name)+1, NULL);
8205  result = rb_w32_set_thread_description(th, s);
8206  free(s);
8207  }
8208  RB_GC_GUARD(name);
8209  return result;
8210 }
8211 
8212 VALUE (*const rb_f_notimplement_)(int, const VALUE *, VALUE, VALUE) = rb_f_notimplement;
8213 
8214 #if RUBY_MSVCRT_VERSION < 120
8215 #include "missing/nextafter.c"
8216 #endif
#define LONG_LONG
Definition: long_long.h:38
int ruby_glob_func(const char *path, VALUE arg, void *enc)
Type of a glob callback function.
Definition: glob.h:49
#define T_FILE
Old name of RUBY_T_FILE.
Definition: value_type.h:62
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition: memory.h:397
#define ALLOCV
Old name of RB_ALLOCV.
Definition: memory.h:398
#define ISSPACE
Old name of rb_isspace.
Definition: ctype.h:88
#define ALLOC
Old name of RB_ALLOC.
Definition: memory.h:394
#define xfree
Old name of ruby_xfree.
Definition: xmalloc.h:58
#define xrealloc
Old name of ruby_xrealloc.
Definition: xmalloc.h:56
#define ECONV_UNDEF_REPLACE
Old name of RUBY_ECONV_UNDEF_REPLACE.
Definition: transcode.h:523
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition: encoding.h:108
#define ECONV_INVALID_REPLACE
Old name of RUBY_ECONV_INVALID_REPLACE.
Definition: transcode.h:521
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition: assume.h:29
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition: memory.h:393
#define ISALPHA
Old name of rb_isalpha.
Definition: ctype.h:92
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition: memory.h:399
#define ISALNUM
Old name of rb_isalnum.
Definition: ctype.h:91
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition: memory.h:400
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
Definition: error.c:3076
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:983
Encoding relates APIs.
int rb_enc_get_index(VALUE obj)
Queries the index of the encoding of the passed object, if any.
Definition: encoding.c:979
int rb_enc_to_index(rb_encoding *enc)
Queries the index of the encoding.
Definition: encoding.c:197
rb_encoding * rb_utf8_encoding(void)
Queries the encoding that represents UTF-8.
Definition: encoding.c:1527
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
Definition: encoding.c:414
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition: encoding.h:433
rb_encoding * rb_filesystem_encoding(void)
Queries the "filesystem" encoding.
Definition: encoding.c:1592
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition: string.c:1182
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
Identical to rb_str_conv_enc(), except it additionally takes IO encoder options.
Definition: string.c:1067
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
Definition: string.c:940
int rb_econv_has_convpath_p(const char *from_encoding, const char *to_encoding)
Queries if there is more than one way to convert between the passed two encodings.
Definition: transcode.c:3226
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
Definition: file.c:251
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition: io.c:8371
VALUE rb_utf8_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "UTF-8" encoding.
Definition: string.c:932
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition: string.c:3161
#define rb_strlen_lit(str)
Length of a string literal.
Definition: string.h:1756
VALUE rb_f_notimplement(int argc, const VALUE *argv, VALUE obj, VALUE marker)
Raises rb_eNotImpError.
Definition: vm_method.c:327
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition: io.h:343
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
Definition: util.c:536
#define strdup(s)
Just another name of ruby_strdup.
Definition: util.h:176
void ruby_vm_at_exit(void(*func)(ruby_vm_t *))
ruby_vm_at_exit registers a function func to be invoked when a VM passed away.
Definition: vm.c:693
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition: sprintf.c:1201
VALUE rb_str_vcatf(VALUE dst, const char *fmt, va_list ap)
Identical to rb_str_catf(), except it takes a va_list.
Definition: sprintf.c:1214
void rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
Identical to rb_w32_fd_copy(), except it copies unlimited number of file descriptors.
Definition: win32.c:2956
void rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
Destructively overwrites an fdset with another.
Definition: win32.c:2941
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define rb_long2int
Just another name of rb_long2int_inline.
Definition: long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition: memory.h:366
#define ALLOCA_N(type, n)
Definition: memory.h:286
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition: memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition: memory.h:161
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
Definition: cxxanyargs.hpp:432
#define PRI_PIDT_PREFIX
A rb_sprintf() format prefix to be used for a pid_t parameter.
Definition: pid_t.h:38
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition: posix.h:63
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition: rstring.h:497
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition: rstring.h:483
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition: rstring.h:95
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition: ruby.h:90
C99 shim for <stdbool.h>
Definition: dir.h:21
Definition: win32.c:3670
Definition: win32.c:717
Definition: dir.h:13
Definition: win32.h:233
Definition: win32.c:2529
Definition: win32.h:222
The data structure which wraps the fd_set bitmap used by select(2).
Definition: largesize.h:74
fd_set * fdset
File descriptors buffer.
Definition: largesize.h:76
int capa
Maximum allowed number of FDs.
Definition: win32.h:50
Ruby's IO, metadata and buffers.
Definition: io.h:95
int fd
file descriptor.
Definition: io.h:104
Definition: st.h:79
Definition: win32.h:696
Definition: file.c:2929
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition: value.h:63
uintptr_t VALUE
Type that represents a Ruby object.
Definition: value.h:40
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
Definition: gc.c:13704
void ruby_xfree(void *ptr)
Deallocates a storage instance.
Definition: gc.c:11775
void * ruby_xcalloc(size_t nelems, size_t elemsiz)
Identical to ruby_xmalloc2(), except it returns a zero-filled storage instance.
Definition: gc.c:13724