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