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