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