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