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