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