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