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