Ruby  2.0.0p594(2014-10-27revision48167)
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  SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
2921  MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
2922  _set_osfhnd(fd, r);
2923  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
2924  CloseHandle(h);
2925  socklist_insert(r, 0);
2926  }
2927  else {
2928  errno = map_errno(WSAGetLastError());
2929  close(fd);
2930  fd = -1;
2931  }
2932  }
2933  else
2934  CloseHandle(h);
2935  });
2936  return fd;
2937 }
2938 
2939 #undef bind
2940 
2941 /* License: Artistic or GPL */
2942 int WSAAPI
2943 rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
2944 {
2945  int r;
2946 
2947  if (!NtSocketsInitialized) {
2948  StartSockets();
2949  }
2950  RUBY_CRITICAL({
2951  r = bind(TO_SOCKET(s), addr, addrlen);
2952  if (r == SOCKET_ERROR)
2953  errno = map_errno(WSAGetLastError());
2954  });
2955  return r;
2956 }
2957 
2958 #undef connect
2959 
2960 /* License: Artistic or GPL */
2961 int WSAAPI
2962 rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
2963 {
2964  int r;
2965  if (!NtSocketsInitialized) {
2966  StartSockets();
2967  }
2968  RUBY_CRITICAL({
2969  r = connect(TO_SOCKET(s), addr, addrlen);
2970  if (r == SOCKET_ERROR) {
2971  int err = WSAGetLastError();
2972  if (err != WSAEWOULDBLOCK)
2973  errno = map_errno(err);
2974  else
2975  errno = EINPROGRESS;
2976  }
2977  });
2978  return r;
2979 }
2980 
2981 
2982 #undef getpeername
2983 
2984 /* License: Artistic or GPL */
2985 int WSAAPI
2986 rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
2987 {
2988  int r;
2989  if (!NtSocketsInitialized) {
2990  StartSockets();
2991  }
2992  RUBY_CRITICAL({
2993  r = getpeername(TO_SOCKET(s), addr, addrlen);
2994  if (r == SOCKET_ERROR)
2995  errno = map_errno(WSAGetLastError());
2996  });
2997  return r;
2998 }
2999 
3000 #undef getsockname
3001 
3002 /* License: Artistic or GPL */
3003 int WSAAPI
3004 rb_w32_getsockname(int fd, struct sockaddr *addr, int *addrlen)
3005 {
3006  int sock;
3007  int r;
3008  if (!NtSocketsInitialized) {
3009  StartSockets();
3010  }
3011  RUBY_CRITICAL({
3012  sock = TO_SOCKET(fd);
3013  r = getsockname(sock, addr, addrlen);
3014  if (r == SOCKET_ERROR) {
3015  DWORD wsaerror = WSAGetLastError();
3016  if (wsaerror == WSAEINVAL) {
3017  int flags;
3018  if (socklist_lookup(sock, &flags)) {
3019  int af = GET_FAMILY(flags);
3020  if (af) {
3021  memset(addr, 0, *addrlen);
3022  addr->sa_family = af;
3023  return 0;
3024  }
3025  }
3026  }
3027  errno = map_errno(wsaerror);
3028  }
3029  });
3030  return r;
3031 }
3032 
3033 #undef getsockopt
3034 
3035 /* License: Artistic or GPL */
3036 int WSAAPI
3037 rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
3038 {
3039  int r;
3040  if (!NtSocketsInitialized) {
3041  StartSockets();
3042  }
3043  RUBY_CRITICAL({
3044  r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
3045  if (r == SOCKET_ERROR)
3046  errno = map_errno(WSAGetLastError());
3047  });
3048  return r;
3049 }
3050 
3051 #undef ioctlsocket
3052 
3053 /* License: Artistic or GPL */
3054 int WSAAPI
3055 rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
3056 {
3057  int r;
3058  if (!NtSocketsInitialized) {
3059  StartSockets();
3060  }
3061  RUBY_CRITICAL({
3062  r = ioctlsocket(TO_SOCKET(s), cmd, argp);
3063  if (r == SOCKET_ERROR)
3064  errno = map_errno(WSAGetLastError());
3065  });
3066  return r;
3067 }
3068 
3069 #undef listen
3070 
3071 /* License: Artistic or GPL */
3072 int WSAAPI
3073 rb_w32_listen(int s, int backlog)
3074 {
3075  int r;
3076  if (!NtSocketsInitialized) {
3077  StartSockets();
3078  }
3079  RUBY_CRITICAL({
3080  r = listen(TO_SOCKET(s), backlog);
3081  if (r == SOCKET_ERROR)
3082  errno = map_errno(WSAGetLastError());
3083  });
3084  return r;
3085 }
3086 
3087 #undef recv
3088 #undef recvfrom
3089 #undef send
3090 #undef sendto
3091 
3092 /* License: Ruby's */
3093 static int
3094 finish_overlapped_socket(BOOL input, SOCKET s, WSAOVERLAPPED *wol, int result, DWORD *len, DWORD size)
3095 {
3096  DWORD flg;
3097  int err;
3098 
3099  if (result != SOCKET_ERROR)
3100  *len = size;
3101  else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
3102  switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) {
3103  case WAIT_OBJECT_0:
3104  RUBY_CRITICAL(
3105  result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg)
3106  );
3107  if (result) {
3108  *len = size;
3109  break;
3110  }
3111  /* thru */
3112  default:
3113  if ((err = WSAGetLastError()) == WSAECONNABORTED && !input)
3114  errno = EPIPE;
3115  else
3116  errno = map_errno(WSAGetLastError());
3117  /* thru */
3118  case WAIT_OBJECT_0 + 1:
3119  /* interrupted */
3120  *len = -1;
3121  cancel_io((HANDLE)s);
3122  break;
3123  }
3124  }
3125  else {
3126  if (err == WSAECONNABORTED && !input)
3127  errno = EPIPE;
3128  else
3129  errno = map_errno(err);
3130  *len = -1;
3131  }
3132  CloseHandle(wol->hEvent);
3133 
3134  return result;
3135 }
3136 
3137 /* License: Artistic or GPL */
3138 static int
3139 overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
3140  struct sockaddr *addr, int *addrlen)
3141 {
3142  int r;
3143  int ret;
3144  int mode = 0;
3145  DWORD flg;
3146  WSAOVERLAPPED wol;
3147  WSABUF wbuf;
3148  SOCKET s;
3149 
3150  if (!NtSocketsInitialized)
3151  StartSockets();
3152 
3153  s = TO_SOCKET(fd);
3154  socklist_lookup(s, &mode);
3155  if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
3156  RUBY_CRITICAL({
3157  if (input) {
3158  if (addr && addrlen)
3159  r = recvfrom(s, buf, len, flags, addr, addrlen);
3160  else
3161  r = recv(s, buf, len, flags);
3162  if (r == SOCKET_ERROR)
3163  errno = map_errno(WSAGetLastError());
3164  }
3165  else {
3166  if (addr && addrlen)
3167  r = sendto(s, buf, len, flags, addr, *addrlen);
3168  else
3169  r = send(s, buf, len, flags);
3170  if (r == SOCKET_ERROR) {
3171  DWORD err = WSAGetLastError();
3172  if (err == WSAECONNABORTED)
3173  errno = EPIPE;
3174  else
3175  errno = map_errno(err);
3176  }
3177  }
3178  });
3179  }
3180  else {
3181  DWORD size;
3182  DWORD rlen;
3183  wbuf.len = len;
3184  wbuf.buf = buf;
3185  memset(&wol, 0, sizeof(wol));
3186  RUBY_CRITICAL({
3187  wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3188  if (input) {
3189  flg = flags;
3190  if (addr && addrlen)
3191  ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
3192  &wol, NULL);
3193  else
3194  ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL);
3195  }
3196  else {
3197  if (addr && addrlen)
3198  ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
3199  &wol, NULL);
3200  else
3201  ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL);
3202  }
3203  });
3204 
3205  finish_overlapped_socket(input, s, &wol, ret, &rlen, size);
3206  r = (int)rlen;
3207  }
3208 
3209  return r;
3210 }
3211 
3212 /* License: Ruby's */
3213 int WSAAPI
3214 rb_w32_recv(int fd, char *buf, int len, int flags)
3215 {
3216  return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
3217 }
3218 
3219 /* License: Ruby's */
3220 int WSAAPI
3221 rb_w32_recvfrom(int fd, char *buf, int len, int flags,
3222  struct sockaddr *from, int *fromlen)
3223 {
3224  return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
3225 }
3226 
3227 /* License: Ruby's */
3228 int WSAAPI
3229 rb_w32_send(int fd, const char *buf, int len, int flags)
3230 {
3231  return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL);
3232 }
3233 
3234 /* License: Ruby's */
3235 int WSAAPI
3236 rb_w32_sendto(int fd, const char *buf, int len, int flags,
3237  const struct sockaddr *to, int tolen)
3238 {
3239  return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
3240  (struct sockaddr *)to, &tolen);
3241 }
3242 
3243 #if !defined(MSG_TRUNC) && !defined(__MINGW32__)
3244 /* License: Ruby's */
3245 typedef struct {
3246  SOCKADDR *name;
3247  int namelen;
3248  WSABUF *lpBuffers;
3250  WSABUF Control;
3252 } WSAMSG;
3253 #endif
3254 #ifndef WSAID_WSARECVMSG
3255 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
3256 #endif
3257 #ifndef WSAID_WSASENDMSG
3258 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
3259 #endif
3260 
3261 /* License: Ruby's */
3262 #define msghdr_to_wsamsg(msg, wsamsg) \
3263  do { \
3264  int i; \
3265  (wsamsg)->name = (msg)->msg_name; \
3266  (wsamsg)->namelen = (msg)->msg_namelen; \
3267  (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
3268  (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
3269  for (i = 0; i < (msg)->msg_iovlen; ++i) { \
3270  (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
3271  (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
3272  } \
3273  (wsamsg)->Control.buf = (msg)->msg_control; \
3274  (wsamsg)->Control.len = (msg)->msg_controllen; \
3275  (wsamsg)->dwFlags = (msg)->msg_flags; \
3276  } while (0)
3277 
3278 /* License: Ruby's */
3279 int
3280 recvmsg(int fd, struct msghdr *msg, int flags)
3281 {
3282  typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3283  static WSARecvMsg_t pWSARecvMsg = NULL;
3284  WSAMSG wsamsg;
3285  SOCKET s;
3286  int mode = 0;
3287  DWORD len;
3288  int ret;
3289 
3290  if (!NtSocketsInitialized)
3291  StartSockets();
3292 
3293  s = TO_SOCKET(fd);
3294 
3295  if (!pWSARecvMsg) {
3296  static GUID guid = WSAID_WSARECVMSG;
3297  pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid);
3298  if (!pWSARecvMsg)
3299  return -1;
3300  }
3301 
3302  msghdr_to_wsamsg(msg, &wsamsg);
3303  wsamsg.dwFlags |= flags;
3304 
3305  socklist_lookup(s, &mode);
3306  if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
3307  RUBY_CRITICAL({
3308  if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
3309  errno = map_errno(WSAGetLastError());
3310  len = -1;
3311  }
3312  });
3313  }
3314  else {
3315  DWORD size;
3316  WSAOVERLAPPED wol;
3317  memset(&wol, 0, sizeof(wol));
3318  RUBY_CRITICAL({
3319  wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3320  ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL);
3321  });
3322 
3323  ret = finish_overlapped_socket(TRUE, s, &wol, ret, &len, size);
3324  }
3325  if (ret == SOCKET_ERROR)
3326  return -1;
3327 
3328  /* WSAMSG to msghdr */
3329  msg->msg_name = wsamsg.name;
3330  msg->msg_namelen = wsamsg.namelen;
3331  msg->msg_flags = wsamsg.dwFlags;
3332 
3333  return len;
3334 }
3335 
3336 /* License: Ruby's */
3337 int
3338 sendmsg(int fd, const struct msghdr *msg, int flags)
3339 {
3340  typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3341  static WSASendMsg_t pWSASendMsg = NULL;
3342  WSAMSG wsamsg;
3343  SOCKET s;
3344  int mode = 0;
3345  DWORD len;
3346  int ret;
3347 
3348  if (!NtSocketsInitialized)
3349  StartSockets();
3350 
3351  s = TO_SOCKET(fd);
3352 
3353  if (!pWSASendMsg) {
3354  static GUID guid = WSAID_WSASENDMSG;
3355  pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid);
3356  if (!pWSASendMsg)
3357  return -1;
3358  }
3359 
3360  msghdr_to_wsamsg(msg, &wsamsg);
3361 
3362  socklist_lookup(s, &mode);
3363  if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
3364  RUBY_CRITICAL({
3365  if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
3366  errno = map_errno(WSAGetLastError());
3367  len = -1;
3368  }
3369  });
3370  }
3371  else {
3372  DWORD size;
3373  WSAOVERLAPPED wol;
3374  memset(&wol, 0, sizeof(wol));
3375  RUBY_CRITICAL({
3376  wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3377  ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL);
3378  });
3379 
3380  finish_overlapped_socket(FALSE, s, &wol, ret, &len, size);
3381  }
3382 
3383  return len;
3384 }
3385 
3386 #undef setsockopt
3387 
3388 /* License: Artistic or GPL */
3389 int WSAAPI
3390 rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
3391 {
3392  int r;
3393  if (!NtSocketsInitialized) {
3394  StartSockets();
3395  }
3396  RUBY_CRITICAL({
3397  r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
3398  if (r == SOCKET_ERROR)
3399  errno = map_errno(WSAGetLastError());
3400  });
3401  return r;
3402 }
3403 
3404 #undef shutdown
3405 
3406 /* License: Artistic or GPL */
3407 int WSAAPI
3408 rb_w32_shutdown(int s, int how)
3409 {
3410  int r;
3411  if (!NtSocketsInitialized) {
3412  StartSockets();
3413  }
3414  RUBY_CRITICAL({
3415  r = shutdown(TO_SOCKET(s), how);
3416  if (r == SOCKET_ERROR)
3417  errno = map_errno(WSAGetLastError());
3418  });
3419  return r;
3420 }
3421 
3422 /* License: Ruby's */
3423 static SOCKET
3424 open_ifs_socket(int af, int type, int protocol)
3425 {
3426  unsigned long proto_buffers_len = 0;
3427  int error_code;
3428  SOCKET out = INVALID_SOCKET;
3429 
3430  if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) {
3431  error_code = WSAGetLastError();
3432  if (error_code == WSAENOBUFS) {
3433  WSAPROTOCOL_INFO *proto_buffers;
3434  int protocols_available = 0;
3435 
3436  proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len);
3437  if (!proto_buffers) {
3438  WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
3439  return INVALID_SOCKET;
3440  }
3441 
3442  protocols_available =
3443  WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len);
3444  if (protocols_available != SOCKET_ERROR) {
3445  int i;
3446  for (i = 0; i < protocols_available; i++) {
3447  if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
3448  (type != proto_buffers[i].iSocketType) ||
3449  (protocol != 0 && protocol != proto_buffers[i].iProtocol))
3450  continue;
3451 
3452  if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
3453  continue;
3454 
3455  out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
3456  WSA_FLAG_OVERLAPPED);
3457  break;
3458  }
3459  if (out == INVALID_SOCKET)
3460  out = WSASocket(af, type, protocol, NULL, 0, 0);
3461  if (out != INVALID_SOCKET)
3462  SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0);
3463  }
3464 
3465  free(proto_buffers);
3466  }
3467  }
3468 
3469  return out;
3470 }
3471 
3472 #undef socket
3473 
3474 /* License: Artistic or GPL */
3475 int WSAAPI
3476 rb_w32_socket(int af, int type, int protocol)
3477 {
3478  SOCKET s;
3479  int fd;
3480 
3481  if (!NtSocketsInitialized) {
3482  StartSockets();
3483  }
3484  RUBY_CRITICAL({
3485  s = open_ifs_socket(af, type, protocol);
3486  if (s == INVALID_SOCKET) {
3487  errno = map_errno(WSAGetLastError());
3488  fd = -1;
3489  }
3490  else {
3491  fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
3492  if (fd != -1)
3493  socklist_insert(s, MAKE_SOCKDATA(af, 0));
3494  else
3495  closesocket(s);
3496  }
3497  });
3498  return fd;
3499 }
3500 
3501 #undef gethostbyaddr
3502 
3503 /* License: Artistic or GPL */
3504 struct hostent * WSAAPI
3505 rb_w32_gethostbyaddr(const char *addr, int len, int type)
3506 {
3507  struct hostent *r;
3508  if (!NtSocketsInitialized) {
3509  StartSockets();
3510  }
3511  RUBY_CRITICAL({
3512  r = gethostbyaddr(addr, len, type);
3513  if (r == NULL)
3514  errno = map_errno(WSAGetLastError());
3515  });
3516  return r;
3517 }
3518 
3519 #undef gethostbyname
3520 
3521 /* License: Artistic or GPL */
3522 struct hostent * WSAAPI
3524 {
3525  struct hostent *r;
3526  if (!NtSocketsInitialized) {
3527  StartSockets();
3528  }
3529  RUBY_CRITICAL({
3530  r = gethostbyname(name);
3531  if (r == NULL)
3532  errno = map_errno(WSAGetLastError());
3533  });
3534  return r;
3535 }
3536 
3537 #undef gethostname
3538 
3539 /* License: Artistic or GPL */
3540 int WSAAPI
3542 {
3543  int r;
3544  if (!NtSocketsInitialized) {
3545  StartSockets();
3546  }
3547  RUBY_CRITICAL({
3548  r = gethostname(name, len);
3549  if (r == SOCKET_ERROR)
3550  errno = map_errno(WSAGetLastError());
3551  });
3552  return r;
3553 }
3554 
3555 #undef getprotobyname
3556 
3557 /* License: Artistic or GPL */
3558 struct protoent * WSAAPI
3560 {
3561  struct protoent *r;
3562  if (!NtSocketsInitialized) {
3563  StartSockets();
3564  }
3565  RUBY_CRITICAL({
3566  r = getprotobyname(name);
3567  if (r == NULL)
3568  errno = map_errno(WSAGetLastError());
3569  });
3570  return r;
3571 }
3572 
3573 #undef getprotobynumber
3574 
3575 /* License: Artistic or GPL */
3576 struct protoent * WSAAPI
3578 {
3579  struct protoent *r;
3580  if (!NtSocketsInitialized) {
3581  StartSockets();
3582  }
3583  RUBY_CRITICAL({
3584  r = getprotobynumber(num);
3585  if (r == NULL)
3586  errno = map_errno(WSAGetLastError());
3587  });
3588  return r;
3589 }
3590 
3591 #undef getservbyname
3592 
3593 /* License: Artistic or GPL */
3594 struct servent * WSAAPI
3595 rb_w32_getservbyname(const char *name, const char *proto)
3596 {
3597  struct servent *r;
3598  if (!NtSocketsInitialized) {
3599  StartSockets();
3600  }
3601  RUBY_CRITICAL({
3602  r = getservbyname(name, proto);
3603  if (r == NULL)
3604  errno = map_errno(WSAGetLastError());
3605  });
3606  return r;
3607 }
3608 
3609 #undef getservbyport
3610 
3611 /* License: Artistic or GPL */
3612 struct servent * WSAAPI
3613 rb_w32_getservbyport(int port, const char *proto)
3614 {
3615  struct servent *r;
3616  if (!NtSocketsInitialized) {
3617  StartSockets();
3618  }
3619  RUBY_CRITICAL({
3620  r = getservbyport(port, proto);
3621  if (r == NULL)
3622  errno = map_errno(WSAGetLastError());
3623  });
3624  return r;
3625 }
3626 
3627 /* License: Ruby's */
3628 static int
3629 socketpair_internal(int af, int type, int protocol, SOCKET *sv)
3630 {
3631  SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
3632  struct sockaddr_in sock_in4;
3633 #ifdef INET6
3634  struct sockaddr_in6 sock_in6;
3635 #endif
3636  struct sockaddr *addr;
3637  int ret = -1;
3638  int len;
3639 
3640  if (!NtSocketsInitialized) {
3641  StartSockets();
3642  }
3643 
3644  switch (af) {
3645  case AF_INET:
3646 #if defined PF_INET && PF_INET != AF_INET
3647  case PF_INET:
3648 #endif
3649  sock_in4.sin_family = AF_INET;
3650  sock_in4.sin_port = 0;
3651  sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3652  addr = (struct sockaddr *)&sock_in4;
3653  len = sizeof(sock_in4);
3654  break;
3655 #ifdef INET6
3656  case AF_INET6:
3657  memset(&sock_in6, 0, sizeof(sock_in6));
3658  sock_in6.sin6_family = AF_INET6;
3659  sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
3660  addr = (struct sockaddr *)&sock_in6;
3661  len = sizeof(sock_in6);
3662  break;
3663 #endif
3664  default:
3665  errno = EAFNOSUPPORT;
3666  return -1;
3667  }
3668  if (type != SOCK_STREAM) {
3669  errno = EPROTOTYPE;
3670  return -1;
3671  }
3672 
3673  sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
3674  sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
3675  RUBY_CRITICAL({
3676  do {
3677  svr = open_ifs_socket(af, type, protocol);
3678  if (svr == INVALID_SOCKET)
3679  break;
3680  if (bind(svr, addr, len) < 0)
3681  break;
3682  if (getsockname(svr, addr, &len) < 0)
3683  break;
3684  if (type == SOCK_STREAM)
3685  listen(svr, 5);
3686 
3687  w = open_ifs_socket(af, type, protocol);
3688  if (w == INVALID_SOCKET)
3689  break;
3690  if (connect(w, addr, len) < 0)
3691  break;
3692 
3693  r = accept(svr, addr, &len);
3694  if (r == INVALID_SOCKET)
3695  break;
3696  SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
3697 
3698  ret = 0;
3699  } while (0);
3700 
3701  if (ret < 0) {
3702  errno = map_errno(WSAGetLastError());
3703  if (r != INVALID_SOCKET)
3704  closesocket(r);
3705  if (w != INVALID_SOCKET)
3706  closesocket(w);
3707  }
3708  else {
3709  sv[0] = r;
3710  sv[1] = w;
3711  }
3712  if (svr != INVALID_SOCKET)
3713  closesocket(svr);
3714  });
3715 
3716  return ret;
3717 }
3718 
3719 /* License: Ruby's */
3720 int
3721 rb_w32_socketpair(int af, int type, int protocol, int *sv)
3722 {
3723  SOCKET pair[2];
3724 
3725  if (socketpair_internal(af, type, protocol, pair) < 0)
3726  return -1;
3727  sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
3728  if (sv[0] == -1) {
3729  closesocket(pair[0]);
3730  closesocket(pair[1]);
3731  return -1;
3732  }
3733  sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
3734  if (sv[1] == -1) {
3735  rb_w32_close(sv[0]);
3736  closesocket(pair[1]);
3737  return -1;
3738  }
3739  socklist_insert(pair[0], MAKE_SOCKDATA(af, 0));
3740  socklist_insert(pair[1], MAKE_SOCKDATA(af, 0));
3741 
3742  return 0;
3743 }
3744 
3745 //
3746 // Networking stubs
3747 //
3748 
3749 void endhostent(void) {}
3750 void endnetent(void) {}
3751 void endprotoent(void) {}
3752 void endservent(void) {}
3753 
3754 struct netent *getnetent (void) {return (struct netent *) NULL;}
3755 
3756 struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;}
3757 
3758 struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;}
3759 
3760 struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
3761 
3762 struct servent *getservent (void) {return (struct servent *) NULL;}
3763 
3764 void sethostent (int stayopen) {}
3765 
3766 void setnetent (int stayopen) {}
3767 
3768 void setprotoent (int stayopen) {}
3769 
3770 void setservent (int stayopen) {}
3771 
3772 /* License: Ruby's */
3773 static int
3774 setfl(SOCKET sock, int arg)
3775 {
3776  int ret;
3777  int af = 0;
3778  int flag = 0;
3779  u_long ioctlArg;
3780 
3781  socklist_lookup(sock, &flag);
3782  af = GET_FAMILY(flag);
3783  flag = GET_FLAGS(flag);
3784  if (arg & O_NONBLOCK) {
3785  flag |= O_NONBLOCK;
3786  ioctlArg = 1;
3787  }
3788  else {
3789  flag &= ~O_NONBLOCK;
3790  ioctlArg = 0;
3791  }
3792  RUBY_CRITICAL({
3793  ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
3794  if (ret == 0)
3795  socklist_insert(sock, MAKE_SOCKDATA(af, flag));
3796  else
3797  errno = map_errno(WSAGetLastError());
3798  });
3799 
3800  return ret;
3801 }
3802 
3803 /* License: Ruby's */
3804 static int
3805 dupfd(HANDLE hDup, char flags, int minfd)
3806 {
3807  int save_errno;
3808  int ret;
3809  int fds[32];
3810  int filled = 0;
3811 
3812  do {
3813  ret = _open_osfhandle((intptr_t)hDup, flags | FOPEN);
3814  if (ret == -1) {
3815  goto close_fds_and_return;
3816  }
3817  if (ret >= minfd) {
3818  goto close_fds_and_return;
3819  }
3820  fds[filled++] = ret;
3821  } while (filled < (int)numberof(fds));
3822 
3823  ret = dupfd(hDup, flags, minfd);
3824 
3825  close_fds_and_return:
3826  save_errno = errno;
3827  while (filled > 0) {
3828  int fd = fds[--filled];
3829  _osfhnd(fd) = (intptr_t)INVALID_HANDLE_VALUE;
3830  close(fd);
3831  }
3832  errno = save_errno;
3833 
3834  return ret;
3835 }
3836 
3837 /* License: Ruby's */
3838 int
3839 fcntl(int fd, int cmd, ...)
3840 {
3841  va_list va;
3842  int arg;
3843 
3844  if (cmd == F_SETFL) {
3845  SOCKET sock = TO_SOCKET(fd);
3846  if (!is_socket(sock)) {
3847  errno = EBADF;
3848  return -1;
3849  }
3850 
3851  va_start(va, cmd);
3852  arg = va_arg(va, int);
3853  va_end(va);
3854  return setfl(sock, arg);
3855  }
3856  else if (cmd == F_DUPFD) {
3857  int ret;
3858  HANDLE hDup;
3859  if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
3860  GetCurrentProcess(), &hDup, 0L,
3861  !(_osfile(fd) & FNOINHERIT),
3862  DUPLICATE_SAME_ACCESS))) {
3863  errno = map_errno(GetLastError());
3864  return -1;
3865  }
3866 
3867  va_start(va, cmd);
3868  arg = va_arg(va, int);
3869  va_end(va);
3870 
3871  if ((ret = dupfd(hDup, _osfile(fd), arg)) == -1)
3872  CloseHandle(hDup);
3873  return ret;
3874  }
3875  else {
3876  errno = EINVAL;
3877  return -1;
3878  }
3879 }
3880 
3881 #ifndef WNOHANG
3882 #define WNOHANG -1
3883 #endif
3884 
3885 /* License: Ruby's */
3886 static rb_pid_t
3887 poll_child_status(struct ChildRecord *child, int *stat_loc)
3888 {
3889  DWORD exitcode;
3890  DWORD err;
3891 
3892  if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
3893  /* If an error occured, return immediatly. */
3894  error_exit:
3895  err = GetLastError();
3896  if (err == ERROR_INVALID_PARAMETER)
3897  errno = ECHILD;
3898  else {
3899  if (GetLastError() == ERROR_INVALID_HANDLE)
3900  errno = EINVAL;
3901  else
3902  errno = map_errno(GetLastError());
3903  }
3904  CloseChildHandle(child);
3905  return -1;
3906  }
3907  if (exitcode != STILL_ACTIVE) {
3908  rb_pid_t pid;
3909  /* If already died, wait process's real termination. */
3910  if (rb_w32_wait_events_blocking(&child->hProcess, 1, INFINITE) != WAIT_OBJECT_0) {
3911  goto error_exit;
3912  }
3913  pid = child->pid;
3914  CloseChildHandle(child);
3915  if (stat_loc) *stat_loc = exitcode << 8;
3916  return pid;
3917  }
3918  return 0;
3919 }
3920 
3921 /* License: Artistic or GPL */
3922 rb_pid_t
3923 waitpid(rb_pid_t pid, int *stat_loc, int options)
3924 {
3925  DWORD timeout;
3926 
3927  /* Artistic or GPL part start */
3928  if (options == WNOHANG) {
3929  timeout = 0;
3930  }
3931  else {
3932  timeout = INFINITE;
3933  }
3934  /* Artistic or GPL part end */
3935 
3936  if (pid == -1) {
3937  int count = 0;
3938  int ret;
3939  HANDLE events[MAXCHILDNUM];
3940  struct ChildRecord* cause;
3941 
3942  FOREACH_CHILD(child) {
3943  if (!child->pid || child->pid < 0) continue;
3944  if ((pid = poll_child_status(child, stat_loc))) return pid;
3945  events[count++] = child->hProcess;
3947  if (!count) {
3948  errno = ECHILD;
3949  return -1;
3950  }
3951 
3952  ret = rb_w32_wait_events_blocking(events, count, timeout);
3953  if (ret == WAIT_TIMEOUT) return 0;
3954  if ((ret -= WAIT_OBJECT_0) == count) {
3955  return -1;
3956  }
3957  if (ret > count) {
3958  errno = map_errno(GetLastError());
3959  return -1;
3960  }
3961 
3962  cause = FindChildSlotByHandle(events[ret]);
3963  if (!cause) {
3964  errno = ECHILD;
3965  return -1;
3966  }
3967  return poll_child_status(cause, stat_loc);
3968  }
3969  else {
3970  struct ChildRecord* child = FindChildSlot(pid);
3971  if (!child) {
3972  errno = ECHILD;
3973  return -1;
3974  }
3975 
3976  while (!(pid = poll_child_status(child, stat_loc))) {
3977  /* wait... */
3978  if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) {
3979  /* still active */
3980  pid = 0;
3981  break;
3982  }
3983  }
3984  }
3985 
3986  return pid;
3987 }
3988 
3989 #include <sys/timeb.h>
3990 
3991 /* License: Ruby's */
3992 static int
3993 filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
3994 {
3995  ULARGE_INTEGER tmp;
3996  unsigned LONG_LONG lt;
3997 
3998  tmp.LowPart = ft->dwLowDateTime;
3999  tmp.HighPart = ft->dwHighDateTime;
4000  lt = tmp.QuadPart;
4001 
4002  /* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC,
4003  convert it into UNIX time (since 1970/01/01 00:00:00 UTC).
4004  the first leap second is at 1972/06/30, so we doesn't need to think
4005  about it. */
4006  lt /= 10; /* to usec */
4007  lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000;
4008 
4009  tv->tv_sec = (long)(lt / (1000 * 1000));
4010  tv->tv_usec = (long)(lt % (1000 * 1000));
4011 
4012  return tv->tv_sec > 0 ? 0 : -1;
4013 }
4014 
4015 /* License: Ruby's */
4016 int _cdecl
4017 gettimeofday(struct timeval *tv, struct timezone *tz)
4018 {
4019  FILETIME ft;
4020 
4021  GetSystemTimeAsFileTime(&ft);
4022  filetime_to_timeval(&ft, tv);
4023 
4024  return 0;
4025 }
4026 
4027 /* License: Ruby's */
4028 char *
4029 rb_w32_getcwd(char *buffer, int size)
4030 {
4031  char *p = buffer;
4032  int len;
4033 
4034  len = GetCurrentDirectory(0, NULL);
4035  if (!len) {
4036  errno = map_errno(GetLastError());
4037  return NULL;
4038  }
4039 
4040  if (p) {
4041  if (size < len) {
4042  errno = ERANGE;
4043  return NULL;
4044  }
4045  }
4046  else {
4047  p = malloc(len);
4048  size = len;
4049  if (!p) {
4050  errno = ENOMEM;
4051  return NULL;
4052  }
4053  }
4054 
4055  if (!GetCurrentDirectory(size, p)) {
4056  errno = map_errno(GetLastError());
4057  if (!buffer)
4058  free(p);
4059  return NULL;
4060  }
4061 
4062  translate_char(p, '\\', '/');
4063 
4064  return p;
4065 }
4066 
4067 /* License: Artistic or GPL */
4068 int
4069 chown(const char *path, int owner, int group)
4070 {
4071  return 0;
4072 }
4073 
4074 /* License: Artistic or GPL */
4075 int
4076 rb_w32_uchown(const char *path, int owner, int group)
4077 {
4078  return 0;
4079 }
4080 
4081 /* License: Ruby's */
4082 int
4083 kill(int pid, int sig)
4084 {
4085  int ret = 0;
4086  DWORD err;
4087 
4088  if (pid < 0 || pid == 0 && sig != SIGINT) {
4089  errno = EINVAL;
4090  return -1;
4091  }
4092 
4093  if ((unsigned int)pid == GetCurrentProcessId() &&
4094  (sig != 0 && sig != SIGKILL)) {
4095  if ((ret = raise(sig)) != 0) {
4096  /* MSVCRT doesn't set errno... */
4097  errno = EINVAL;
4098  }
4099  return ret;
4100  }
4101 
4102  switch (sig) {
4103  case 0:
4104  RUBY_CRITICAL({
4105  HANDLE hProc =
4106  OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
4107  if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
4108  if (GetLastError() == ERROR_INVALID_PARAMETER) {
4109  errno = ESRCH;
4110  }
4111  else {
4112  errno = EPERM;
4113  }
4114  ret = -1;
4115  }
4116  else {
4117  CloseHandle(hProc);
4118  }
4119  });
4120  break;
4121 
4122  case SIGINT:
4123  RUBY_CRITICAL({
4124  DWORD ctrlEvent = CTRL_C_EVENT;
4125  if (pid != 0) {
4126  /* CTRL+C signal cannot be generated for process groups.
4127  * Instead, we use CTRL+BREAK signal. */
4128  ctrlEvent = CTRL_BREAK_EVENT;
4129  }
4130  if (!GenerateConsoleCtrlEvent(ctrlEvent, (DWORD)pid)) {
4131  if ((err = GetLastError()) == 0)
4132  errno = EPERM;
4133  else
4134  errno = map_errno(GetLastError());
4135  ret = -1;
4136  }
4137  });
4138  break;
4139 
4140  case SIGKILL:
4141  RUBY_CRITICAL({
4142  HANDLE hProc;
4143  struct ChildRecord* child = FindChildSlot(pid);
4144  if (child) {
4145  hProc = child->hProcess;
4146  }
4147  else {
4148  hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
4149  }
4150  if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
4151  if (GetLastError() == ERROR_INVALID_PARAMETER) {
4152  errno = ESRCH;
4153  }
4154  else {
4155  errno = EPERM;
4156  }
4157  ret = -1;
4158  }
4159  else {
4160  DWORD status;
4161  if (!GetExitCodeProcess(hProc, &status)) {
4162  errno = map_errno(GetLastError());
4163  ret = -1;
4164  }
4165  else if (status == STILL_ACTIVE) {
4166  if (!TerminateProcess(hProc, 0)) {
4167  errno = EPERM;
4168  ret = -1;
4169  }
4170  }
4171  else {
4172  errno = ESRCH;
4173  ret = -1;
4174  }
4175  if (!child) {
4176  CloseHandle(hProc);
4177  }
4178  }
4179  });
4180  break;
4181 
4182  default:
4183  errno = EINVAL;
4184  ret = -1;
4185  break;
4186  }
4187 
4188  return ret;
4189 }
4190 
4191 /* License: Ruby's */
4192 static int
4193 wlink(const WCHAR *from, const WCHAR *to)
4194 {
4195  typedef BOOL (WINAPI link_func)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
4196  static link_func *pCreateHardLinkW = NULL;
4197  static int myerrno = 0;
4198 
4199  if (!pCreateHardLinkW && !myerrno) {
4200  pCreateHardLinkW = (link_func *)get_proc_address("kernel32", "CreateHardLinkW", NULL);
4201  if (!pCreateHardLinkW)
4202  myerrno = ENOSYS;
4203  }
4204  if (!pCreateHardLinkW) {
4205  errno = myerrno;
4206  return -1;
4207  }
4208 
4209  if (!pCreateHardLinkW(to, from, NULL)) {
4210  errno = map_errno(GetLastError());
4211  return -1;
4212  }
4213 
4214  return 0;
4215 }
4216 
4217 /* License: Ruby's */
4218 int
4219 rb_w32_ulink(const char *from, const char *to)
4220 {
4221  WCHAR *wfrom;
4222  WCHAR *wto;
4223  int ret;
4224 
4225  if (!(wfrom = utf8_to_wstr(from, NULL)))
4226  return -1;
4227  if (!(wto = utf8_to_wstr(to, NULL))) {
4228  free(wfrom);
4229  return -1;
4230  }
4231  ret = wlink(wfrom, wto);
4232  free(wto);
4233  free(wfrom);
4234  return ret;
4235 }
4236 
4237 /* License: Ruby's */
4238 int
4239 link(const char *from, const char *to)
4240 {
4241  WCHAR *wfrom;
4242  WCHAR *wto;
4243  int ret;
4244 
4245  if (!(wfrom = filecp_to_wstr(from, NULL)))
4246  return -1;
4247  if (!(wto = filecp_to_wstr(to, NULL))) {
4248  free(wfrom);
4249  return -1;
4250  }
4251  ret = wlink(wfrom, wto);
4252  free(wto);
4253  free(wfrom);
4254  return ret;
4255 }
4256 
4257 /* License: Ruby's */
4258 int
4260 {
4261  return waitpid(-1, status, 0);
4262 }
4263 
4264 /* License: Ruby's */
4265 char *
4266 rb_w32_ugetenv(const char *name)
4267 {
4268  WCHAR *wenvarea, *wenv;
4269  int len = strlen(name);
4270  char *env;
4271  int wlen;
4272 
4273  if (len == 0) return NULL;
4274 
4275  if (uenvarea) {
4276  free(uenvarea);
4277  uenvarea = NULL;
4278  }
4279  if (envarea) {
4280  FreeEnvironmentStrings(envarea);
4281  envarea = NULL;
4282  }
4283  wenvarea = GetEnvironmentStringsW();
4284  if (!wenvarea) {
4285  map_errno(GetLastError());
4286  return NULL;
4287  }
4288  for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
4289  wlen += lstrlenW(wenv) + 1;
4290  uenvarea = wstr_to_mbstr(CP_UTF8, wenvarea, wlen, NULL);
4291  FreeEnvironmentStringsW(wenvarea);
4292  if (!uenvarea)
4293  return NULL;
4294 
4295  for (env = uenvarea; *env; env += strlen(env) + 1)
4296  if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
4297  return env + len + 1;
4298 
4299  return NULL;
4300 }
4301 
4302 /* License: Ruby's */
4303 char *
4304 rb_w32_getenv(const char *name)
4305 {
4306  int len = strlen(name);
4307  char *env;
4308 
4309  if (len == 0) return NULL;
4310  if (uenvarea) {
4311  free(uenvarea);
4312  uenvarea = NULL;
4313  }
4314  if (envarea) {
4315  FreeEnvironmentStrings(envarea);
4316  envarea = NULL;
4317  }
4318  envarea = GetEnvironmentStrings();
4319  if (!envarea) {
4320  map_errno(GetLastError());
4321  return NULL;
4322  }
4323 
4324  for (env = envarea; *env; env += strlen(env) + 1)
4325  if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
4326  return env + len + 1;
4327 
4328  return NULL;
4329 }
4330 
4331 /* License: Artistic or GPL */
4332 static int
4333 wrename(const WCHAR *oldpath, const WCHAR *newpath)
4334 {
4335  int res = 0;
4336  int oldatts;
4337  int newatts;
4338 
4339  oldatts = GetFileAttributesW(oldpath);
4340  newatts = GetFileAttributesW(newpath);
4341 
4342  if (oldatts == -1) {
4343  errno = map_errno(GetLastError());
4344  return -1;
4345  }
4346 
4347  RUBY_CRITICAL({
4348  if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
4349  SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
4350 
4351  if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
4352  res = -1;
4353 
4354  if (res)
4355  errno = map_errno(GetLastError());
4356  else
4357  SetFileAttributesW(newpath, oldatts);
4358  });
4359 
4360  return res;
4361 }
4362 
4363 /* License: Ruby's */
4364 int rb_w32_urename(const char *from, const char *to)
4365 {
4366  WCHAR *wfrom;
4367  WCHAR *wto;
4368  int ret = -1;
4369 
4370  if (!(wfrom = utf8_to_wstr(from, NULL)))
4371  return -1;
4372  if (!(wto = utf8_to_wstr(to, NULL))) {
4373  free(wfrom);
4374  return -1;
4375  }
4376  ret = wrename(wfrom, wto);
4377  free(wto);
4378  free(wfrom);
4379  return ret;
4380 }
4381 
4382 /* License: Ruby's */
4383 int rb_w32_rename(const char *from, const char *to)
4384 {
4385  WCHAR *wfrom;
4386  WCHAR *wto;
4387  int ret = -1;
4388 
4389  if (!(wfrom = filecp_to_wstr(from, NULL)))
4390  return -1;
4391  if (!(wto = filecp_to_wstr(to, NULL))) {
4392  free(wfrom);
4393  return -1;
4394  }
4395  ret = wrename(wfrom, wto);
4396  free(wto);
4397  free(wfrom);
4398  return ret;
4399 }
4400 
4401 /* License: Ruby's */
4402 static int
4403 isUNCRoot(const WCHAR *path)
4404 {
4405  if (path[0] == L'\\' && path[1] == L'\\') {
4406  const WCHAR *p = path + 2;
4407  if (p[0] == L'?' && p[1] == L'\\') {
4408  p += 2;
4409  }
4410  for (; *p; p++) {
4411  if (*p == L'\\')
4412  break;
4413  }
4414  if (p[0] && p[1]) {
4415  for (p++; *p; p++) {
4416  if (*p == L'\\')
4417  break;
4418  }
4419  if (!p[0] || !p[1] || (p[1] == L'.' && !p[2]))
4420  return 1;
4421  }
4422  }
4423  return 0;
4424 }
4425 
4426 #define COPY_STAT(src, dest, size_cast) do { \
4427  (dest).st_dev = (src).st_dev; \
4428  (dest).st_ino = (src).st_ino; \
4429  (dest).st_mode = (src).st_mode; \
4430  (dest).st_nlink = (src).st_nlink; \
4431  (dest).st_uid = (src).st_uid; \
4432  (dest).st_gid = (src).st_gid; \
4433  (dest).st_rdev = (src).st_rdev; \
4434  (dest).st_size = size_cast(src).st_size; \
4435  (dest).st_atime = (src).st_atime; \
4436  (dest).st_mtime = (src).st_mtime; \
4437  (dest).st_ctime = (src).st_ctime; \
4438  } while (0)
4439 
4440 static time_t filetime_to_unixtime(const FILETIME *ft);
4441 
4442 #undef fstat
4443 /* License: Ruby's */
4444 int
4445 rb_w32_fstat(int fd, struct stat *st)
4446 {
4447  BY_HANDLE_FILE_INFORMATION info;
4448  int ret = fstat(fd, st);
4449 
4450  if (ret) return ret;
4451 #ifdef __BORLANDC__
4452  st->st_mode &= ~(S_IWGRP | S_IWOTH);
4453 #endif
4454  if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
4455 #ifdef __BORLANDC__
4456  if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
4457  st->st_mode |= S_IWUSR;
4458  }
4459 #endif
4460  st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
4461  st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
4462  st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
4463  }
4464  return ret;
4465 }
4466 
4467 /* License: Ruby's */
4468 int
4469 rb_w32_fstati64(int fd, struct stati64 *st)
4470 {
4471  BY_HANDLE_FILE_INFORMATION info;
4472  struct stat tmp;
4473  int ret = fstat(fd, &tmp);
4474 
4475  if (ret) return ret;
4476 #ifdef __BORLANDC__
4477  tmp.st_mode &= ~(S_IWGRP | S_IWOTH);
4478 #endif
4479  COPY_STAT(tmp, *st, +);
4480  if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
4481 #ifdef __BORLANDC__
4482  if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
4483  st->st_mode |= S_IWUSR;
4484  }
4485 #endif
4486  st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
4487  st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
4488  st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
4489  st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
4490  }
4491  return ret;
4492 }
4493 
4494 /* License: Ruby's */
4495 static time_t
4496 filetime_to_unixtime(const FILETIME *ft)
4497 {
4498  struct timeval tv;
4499 
4500  if (filetime_to_timeval(ft, &tv) == (time_t)-1)
4501  return 0;
4502  else
4503  return tv.tv_sec;
4504 }
4505 
4506 /* License: Ruby's */
4507 static unsigned
4508 fileattr_to_unixmode(DWORD attr, const WCHAR *path)
4509 {
4510  unsigned mode = 0;
4511 
4512  if (attr & FILE_ATTRIBUTE_READONLY) {
4513  mode |= S_IREAD;
4514  }
4515  else {
4516  mode |= S_IREAD | S_IWRITE | S_IWUSR;
4517  }
4518 
4519  if (attr & FILE_ATTRIBUTE_DIRECTORY) {
4520  mode |= S_IFDIR | S_IEXEC;
4521  }
4522  else {
4523  mode |= S_IFREG;
4524  }
4525 
4526  if (path && (mode & S_IFREG)) {
4527  const WCHAR *end = path + lstrlenW(path);
4528  while (path < end) {
4529  end = CharPrevW(path, end);
4530  if (*end == L'.') {
4531  if ((_wcsicmp(end, L".bat") == 0) ||
4532  (_wcsicmp(end, L".cmd") == 0) ||
4533  (_wcsicmp(end, L".com") == 0) ||
4534  (_wcsicmp(end, L".exe") == 0)) {
4535  mode |= S_IEXEC;
4536  }
4537  break;
4538  }
4539  }
4540  }
4541 
4542  mode |= (mode & 0700) >> 3;
4543  mode |= (mode & 0700) >> 6;
4544 
4545  return mode;
4546 }
4547 
4548 /* License: Ruby's */
4549 static int
4550 check_valid_dir(const WCHAR *path)
4551 {
4552  WIN32_FIND_DATAW fd;
4553  HANDLE fh;
4554  WCHAR full[MAX_PATH];
4555  WCHAR *dmy;
4556  WCHAR *p, *q;
4557 
4558  /* GetFileAttributes() determines "..." as directory. */
4559  /* We recheck it by FindFirstFile(). */
4560  if (!(p = wcsstr(path, L"...")))
4561  return 0;
4562  q = p + wcsspn(p, L".");
4563  if ((p == path || wcschr(L":/\\", *(p - 1))) &&
4564  (!*q || wcschr(L":/\\", *q))) {
4565  errno = ENOENT;
4566  return -1;
4567  }
4568 
4569  /* if the specified path is the root of a drive and the drive is empty, */
4570  /* FindFirstFile() returns INVALID_HANDLE_VALUE. */
4571  if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) {
4572  errno = map_errno(GetLastError());
4573  return -1;
4574  }
4575  if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
4576  return 0;
4577 
4578  fh = open_dir_handle(path, &fd);
4579  if (fh == INVALID_HANDLE_VALUE)
4580  return -1;
4581  FindClose(fh);
4582  return 0;
4583 }
4584 
4585 /* License: Ruby's */
4586 static int
4587 winnt_stat(const WCHAR *path, struct stati64 *st)
4588 {
4589  HANDLE h;
4590  WIN32_FIND_DATAW wfd;
4591  WIN32_FILE_ATTRIBUTE_DATA wfa;
4592  const WCHAR *p = path;
4593 
4594  memset(st, 0, sizeof(*st));
4595  st->st_nlink = 1;
4596 
4597  if (wcsncmp(p, L"\\\\?\\", 4) == 0) p += 4;
4598  if (wcspbrk(p, L"?*")) {
4599  errno = ENOENT;
4600  return -1;
4601  }
4602  if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) {
4603  if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
4604  if (check_valid_dir(path)) return -1;
4605  st->st_size = 0;
4606  }
4607  else {
4608  st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow;
4609  }
4610  st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path);
4611  st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
4612  st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
4613  st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
4614  }
4615  else {
4616  /* GetFileAttributesEx failed; check why. */
4617  int e = GetLastError();
4618 
4619  if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
4620  || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
4621  errno = map_errno(e);
4622  return -1;
4623  }
4624 
4625  /* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
4626  h = FindFirstFileW(path, &wfd);
4627  if (h != INVALID_HANDLE_VALUE) {
4628  FindClose(h);
4629  st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
4630  st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
4631  st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
4632  st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
4633  st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
4634  }
4635  else {
4636  errno = map_errno(GetLastError());
4637  return -1;
4638  }
4639  }
4640 
4641  st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?
4642  towupper(path[0]) - L'A' : _getdrive() - 1;
4643 
4644  return 0;
4645 }
4646 
4647 /* License: Ruby's */
4648 int
4649 rb_w32_stat(const char *path, struct stat *st)
4650 {
4651  struct stati64 tmp;
4652 
4653  if (rb_w32_stati64(path, &tmp)) return -1;
4654  COPY_STAT(tmp, *st, (_off_t));
4655  return 0;
4656 }
4657 
4658 /* License: Ruby's */
4659 static int
4660 wstati64(const WCHAR *path, struct stati64 *st)
4661 {
4662  const WCHAR *p;
4663  WCHAR *buf1, *s, *end;
4664  int len, size;
4665  int ret;
4666  VALUE v;
4667 
4668  if (!path || !st) {
4669  errno = EFAULT;
4670  return -1;
4671  }
4672  size = lstrlenW(path) + 2;
4673  buf1 = ALLOCV_N(WCHAR, v, size);
4674  for (p = path, s = buf1; *p; p++, s++) {
4675  if (*p == L'/')
4676  *s = L'\\';
4677  else
4678  *s = *p;
4679  }
4680  *s = '\0';
4681  len = s - buf1;
4682  if (!len || L'\"' == *(--s)) {
4683  errno = ENOENT;
4684  return -1;
4685  }
4686  end = buf1 + len - 1;
4687 
4688  if (isUNCRoot(buf1)) {
4689  if (*end == L'.')
4690  *end = L'\0';
4691  else if (*end != L'\\')
4692  lstrcatW(buf1, L"\\");
4693  }
4694  else if (*end == L'\\' || (buf1 + 1 == end && *end == L':'))
4695  lstrcatW(buf1, L".");
4696 
4697  ret = winnt_stat(buf1, st);
4698  if (ret == 0) {
4699  st->st_mode &= ~(S_IWGRP | S_IWOTH);
4700  }
4701  if (v)
4702  ALLOCV_END(v);
4703 
4704  return ret;
4705 }
4706 
4707 /* License: Ruby's */
4708 int
4709 rb_w32_ustati64(const char *path, struct stati64 *st)
4710 {
4711  WCHAR *wpath;
4712  int ret;
4713 
4714  if (!(wpath = utf8_to_wstr(path, NULL)))
4715  return -1;
4716  ret = wstati64(wpath, st);
4717  free(wpath);
4718  return ret;
4719 }
4720 
4721 /* License: Ruby's */
4722 int
4723 rb_w32_stati64(const char *path, struct stati64 *st)
4724 {
4725  WCHAR *wpath;
4726  int ret;
4727 
4728  if (!(wpath = filecp_to_wstr(path, NULL)))
4729  return -1;
4730  ret = wstati64(wpath, st);
4731  free(wpath);
4732  return ret;
4733 }
4734 
4735 /* License: Ruby's */
4736 int
4737 rb_w32_access(const char *path, int mode)
4738 {
4739  struct stati64 stat;
4740  if (rb_w32_stati64(path, &stat) != 0)
4741  return -1;
4742  mode <<= 6;
4743  if ((stat.st_mode & mode) != mode) {
4744  errno = EACCES;
4745  return -1;
4746  }
4747  return 0;
4748 }
4749 
4750 /* License: Ruby's */
4751 int
4752 rb_w32_uaccess(const char *path, int mode)
4753 {
4754  struct stati64 stat;
4755  if (rb_w32_ustati64(path, &stat) != 0)
4756  return -1;
4757  mode <<= 6;
4758  if ((stat.st_mode & mode) != mode) {
4759  errno = EACCES;
4760  return -1;
4761  }
4762  return 0;
4763 }
4764 
4765 /* License: Ruby's */
4766 static int
4768 {
4769  long upos, lpos, usize, lsize;
4770  int ret = -1;
4771  DWORD e;
4772 
4773  if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
4774  (e = GetLastError())) {
4775  errno = map_errno(e);
4776  return -1;
4777  }
4778  usize = (long)(size >> 32);
4779  lsize = (long)size;
4780  if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L &&
4781  (e = GetLastError())) {
4782  errno = map_errno(e);
4783  }
4784  else if (!SetEndOfFile(h)) {
4785  errno = map_errno(GetLastError());
4786  }
4787  else {
4788  ret = 0;
4789  }
4790  SetFilePointer(h, lpos, &upos, SEEK_SET);
4791  return ret;
4792 }
4793 
4794 /* License: Ruby's */
4795 int
4797 {
4798  HANDLE h;
4799  int ret;
4800  h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
4801  if (h == INVALID_HANDLE_VALUE) {
4802  errno = map_errno(GetLastError());
4803  return -1;
4804  }
4805  ret = rb_chsize(h, length);
4806  CloseHandle(h);
4807  return ret;
4808 }
4809 
4810 /* License: Ruby's */
4811 int
4813 {
4814  HANDLE h;
4815 
4816  h = (HANDLE)_get_osfhandle(fd);
4817  if (h == (HANDLE)-1) return -1;
4818  return rb_chsize(h, length);
4819 }
4820 
4821 #ifdef __BORLANDC__
4822 /* License: Ruby's */
4823 off_t
4824 _filelengthi64(int fd)
4825 {
4826  DWORD u, l;
4827  int e;
4828 
4829  l = GetFileSize((HANDLE)_get_osfhandle(fd), &u);
4830  if (l == (DWORD)-1L && (e = GetLastError())) {
4831  errno = map_errno(e);
4832  return (off_t)-1;
4833  }
4834  return ((off_t)u << 32) | l;
4835 }
4836 
4837 /* License: Ruby's */
4838 off_t
4839 _lseeki64(int fd, off_t offset, int whence)
4840 {
4841  long u, l;
4842  int e;
4843  HANDLE h = (HANDLE)_get_osfhandle(fd);
4844 
4845  if (!h) {
4846  errno = EBADF;
4847  return -1;
4848  }
4849  u = (long)(offset >> 32);
4850  if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L &&
4851  (e = GetLastError())) {
4852  errno = map_errno(e);
4853  return -1;
4854  }
4855  return ((off_t)u << 32) | l;
4856 }
4857 #endif
4858 
4859 /* License: Ruby's */
4860 int
4861 fseeko(FILE *stream, off_t offset, int whence)
4862 {
4863  off_t pos;
4864  switch (whence) {
4865  case SEEK_CUR:
4866  if (fgetpos(stream, (fpos_t *)&pos))
4867  return -1;
4868  pos += offset;
4869  break;
4870  case SEEK_END:
4871  if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1)
4872  return -1;
4873  pos += offset;
4874  break;
4875  default:
4876  pos = offset;
4877  break;
4878  }
4879  return fsetpos(stream, (fpos_t *)&pos);
4880 }
4881 
4882 /* License: Ruby's */
4883 off_t
4885 {
4886  off_t pos;
4887  if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1;
4888  return pos;
4889 }
4890 
4891 /* License: Ruby's */
4892 static long
4893 filetime_to_clock(FILETIME *ft)
4894 {
4895  __int64 qw = ft->dwHighDateTime;
4896  qw <<= 32;
4897  qw |= ft->dwLowDateTime;
4898  qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
4899  return (long) qw;
4900 }
4901 
4902 /* License: Ruby's */
4903 int
4904 rb_w32_times(struct tms *tmbuf)
4905 {
4906  FILETIME create, exit, kernel, user;
4907 
4908  if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
4909  tmbuf->tms_utime = filetime_to_clock(&user);
4910  tmbuf->tms_stime = filetime_to_clock(&kernel);
4911  tmbuf->tms_cutime = 0;
4912  tmbuf->tms_cstime = 0;
4913  }
4914  else {
4915  tmbuf->tms_utime = clock();
4916  tmbuf->tms_stime = 0;
4917  tmbuf->tms_cutime = 0;
4918  tmbuf->tms_cstime = 0;
4919  }
4920  return 0;
4921 }
4922 
4923 #define yield_once() Sleep(0)
4924 #define yield_until(condition) do yield_once(); while (!(condition))
4925 
4926 /* License: Ruby's */
4927 static void
4929 {
4930  yield_once();
4932 }
4933 
4934 #if defined __BORLANDC__
4935 #undef read
4936 /* License: Ruby's */
4937 int
4938 read(int fd, void *buf, size_t size)
4939 {
4940  int ret = _read(fd, buf, size);
4941  if ((ret < 0) && (errno == EPIPE)) {
4942  errno = 0;
4943  ret = 0;
4944  }
4945  catch_interrupt();
4946  return ret;
4947 }
4948 #endif
4949 
4950 
4951 #define FILE_COUNT _cnt
4952 #define FILE_READPTR _ptr
4953 
4954 #undef fgetc
4955 /* License: Ruby's */
4956 int
4958 {
4959  int c;
4960  if (enough_to_get(stream->FILE_COUNT)) {
4961  c = (unsigned char)*stream->FILE_READPTR++;
4962  }
4963  else {
4964  c = _filbuf(stream);
4965 #if defined __BORLANDC__
4966  if ((c == EOF) && (errno == EPIPE)) {
4967  clearerr(stream);
4968  }
4969 #endif
4970  catch_interrupt();
4971  }
4972  return c;
4973 }
4974 
4975 #undef fputc
4976 /* License: Ruby's */
4977 int
4978 rb_w32_putc(int c, FILE* stream)
4979 {
4980  if (enough_to_put(stream->FILE_COUNT)) {
4981  c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
4982  }
4983  else {
4984  c = _flsbuf(c, stream);
4985  catch_interrupt();
4986  }
4987  return c;
4988 }
4989 
4990 /* License: Ruby's */
4992  /* output field */
4993  void* stackaddr;
4994  int errnum;
4995 
4996  /* input field */
4999  int argc;
5001 };
5002 
5003 /* License: Ruby's */
5004 static DWORD WINAPI
5006 {
5007  DWORD ret;
5008  struct asynchronous_arg_t *arg = argp;
5009  arg->stackaddr = &argp;
5010  ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
5011  arg->errnum = errno;
5012  return ret;
5013 }
5014 
5015 /* License: Ruby's */
5016 uintptr_t
5018  int argc, uintptr_t* argv, uintptr_t intrval)
5019 {
5020  DWORD val;
5021  BOOL interrupted = FALSE;
5022  HANDLE thr;
5023 
5024  RUBY_CRITICAL({
5025  struct asynchronous_arg_t arg;
5026 
5027  arg.stackaddr = NULL;
5028  arg.errnum = 0;
5029  arg.func = func;
5030  arg.self = self;
5031  arg.argc = argc;
5032  arg.argv = argv;
5033 
5034  thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
5035 
5036  if (thr) {
5037  yield_until(arg.stackaddr);
5038 
5039  if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
5040  interrupted = TRUE;
5041 
5042  if (TerminateThread(thr, intrval)) {
5043  yield_once();
5044  }
5045  }
5046 
5047  GetExitCodeThread(thr, &val);
5048  CloseHandle(thr);
5049 
5050  if (interrupted) {
5051  /* must release stack of killed thread, why doesn't Windows? */
5052  MEMORY_BASIC_INFORMATION m;
5053 
5054  memset(&m, 0, sizeof(m));
5055  if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
5056  Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
5057  arg.stackaddr, GetLastError()));
5058  }
5059  else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
5060  Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
5061  m.AllocationBase, GetLastError()));
5062  }
5063  errno = EINTR;
5064  }
5065  else {
5066  errno = arg.errnum;
5067  }
5068  }
5069  });
5070 
5071  if (!thr) {
5072  rb_fatal("failed to launch waiter thread:%ld", GetLastError());
5073  }
5074 
5075  return val;
5076 }
5077 
5078 /* License: Ruby's */
5079 char **
5081 {
5082  WCHAR *envtop, *env;
5083  char **myenvtop, **myenv;
5084  int num;
5085 
5086  /*
5087  * We avoid values started with `='. If you want to deal those values,
5088  * change this function, and some functions in hash.c which recognize
5089  * `=' as delimiter or rb_w32_getenv() and ruby_setenv().
5090  * CygWin deals these values by changing first `=' to '!'. But we don't
5091  * use such trick and follow cmd.exe's way that just doesn't show these
5092  * values.
5093  *
5094  * This function returns UTF-8 strings.
5095  */
5096  envtop = GetEnvironmentStringsW();
5097  for (env = envtop, num = 0; *env; env += lstrlenW(env) + 1)
5098  if (*env != '=') num++;
5099 
5100  myenvtop = (char **)malloc(sizeof(char *) * (num + 1));
5101  for (env = envtop, myenv = myenvtop; *env; env += lstrlenW(env) + 1) {
5102  if (*env != '=') {
5103  if (!(*myenv = wstr_to_utf8(env, NULL))) {
5104  break;
5105  }
5106  myenv++;
5107  }
5108  }
5109  *myenv = NULL;
5110  FreeEnvironmentStringsW(envtop);
5111 
5112  return myenvtop;
5113 }
5114 
5115 /* License: Ruby's */
5116 void
5118 {
5119  char **t = env;
5120 
5121  while (*t) free(*t++);
5122  free(env);
5123 }
5124 
5125 /* License: Ruby's */
5126 rb_pid_t
5128 {
5129  return GetCurrentProcessId();
5130 }
5131 
5132 
5133 /* License: Ruby's */
5134 rb_pid_t
5136 {
5137  typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *);
5138  static query_func *pNtQueryInformationProcess = NULL;
5139  rb_pid_t ppid = 0;
5140 
5141  if (rb_w32_osver() >= 5) {
5142  if (!pNtQueryInformationProcess)
5143  pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL);
5144  if (pNtQueryInformationProcess) {
5145  struct {
5146  long ExitStatus;
5147  void* PebBaseAddress;
5148  uintptr_t AffinityMask;
5149  uintptr_t BasePriority;
5150  uintptr_t UniqueProcessId;
5151  uintptr_t ParentProcessId;
5152  } pbi;
5153  ULONG len;
5154  long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
5155  if (!ret) {
5156  ppid = pbi.ParentProcessId;
5157  }
5158  }
5159  }
5160 
5161  return ppid;
5162 }
5163 
5164 /* License: Ruby's */
5165 int
5166 rb_w32_uopen(const char *file, int oflag, ...)
5167 {
5168  WCHAR *wfile;
5169  int ret;
5170  int pmode;
5171 
5172  va_list arg;
5173  va_start(arg, oflag);
5174  pmode = va_arg(arg, int);
5175  va_end(arg);
5176 
5177  if (!(wfile = utf8_to_wstr(file, NULL)))
5178  return -1;
5179  ret = rb_w32_wopen(wfile, oflag, pmode);
5180  free(wfile);
5181  return ret;
5182 }
5183 
5184 /* License: Ruby's */
5185 static int
5186 check_if_wdir(const WCHAR *wfile)
5187 {
5188  DWORD attr = GetFileAttributesW(wfile);
5189  if (attr == (DWORD)-1L ||
5190  !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
5191  check_valid_dir(wfile)) {
5192  return FALSE;
5193  }
5194  errno = EISDIR;
5195  return TRUE;
5196 }
5197 
5198 /* License: Ruby's */
5199 static int
5200 check_if_dir(const char *file)
5201 {
5202  WCHAR *wfile;
5203  int ret;
5204 
5205  if (!(wfile = filecp_to_wstr(file, NULL)))
5206  return FALSE;
5207  ret = check_if_wdir(wfile);
5208  free(wfile);
5209  return ret;
5210 }
5211 
5212 /* License: Ruby's */
5213 int
5214 rb_w32_open(const char *file, int oflag, ...)
5215 {
5216  WCHAR *wfile;
5217  int ret;
5218  int pmode;
5219 
5220  va_list arg;
5221  va_start(arg, oflag);
5222  pmode = va_arg(arg, int);
5223  va_end(arg);
5224 
5225  if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
5226  ret = _open(file, oflag, pmode);
5227  if (ret == -1 && errno == EACCES) check_if_dir(file);
5228  return ret;
5229  }
5230 
5231  if (!(wfile = filecp_to_wstr(file, NULL)))
5232  return -1;
5233  ret = rb_w32_wopen(wfile, oflag, pmode);
5234  free(wfile);
5235  return ret;
5236 }
5237 
5238 int
5239 rb_w32_wopen(const WCHAR *file, int oflag, ...)
5240 {
5241  char flags = 0;
5242  int fd;
5243  DWORD access;
5244  DWORD create;
5245  DWORD attr = FILE_ATTRIBUTE_NORMAL;
5246  SECURITY_ATTRIBUTES sec;
5247  HANDLE h;
5248 
5249  if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
5250  va_list arg;
5251  int pmode;
5252  va_start(arg, oflag);
5253  pmode = va_arg(arg, int);
5254  va_end(arg);
5255  fd = _wopen(file, oflag, pmode);
5256  if (fd == -1 && errno == EACCES) check_if_wdir(file);
5257  return fd;
5258  }
5259 
5260  sec.nLength = sizeof(sec);
5261  sec.lpSecurityDescriptor = NULL;
5262  if (oflag & O_NOINHERIT) {
5263  sec.bInheritHandle = FALSE;
5264  flags |= FNOINHERIT;
5265  }
5266  else {
5267  sec.bInheritHandle = TRUE;
5268  }
5269  oflag &= ~O_NOINHERIT;
5270 
5271  /* always open with binary mode */
5272  oflag &= ~(O_BINARY | O_TEXT);
5273 
5274  switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
5275  case O_RDWR:
5276  access = GENERIC_READ | GENERIC_WRITE;
5277  break;
5278  case O_RDONLY:
5279  access = GENERIC_READ;
5280  break;
5281  case O_WRONLY:
5282  access = GENERIC_WRITE;
5283  break;
5284  default:
5285  errno = EINVAL;
5286  return -1;
5287  }
5288  oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
5289 
5290  switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
5291  case O_CREAT:
5292  create = OPEN_ALWAYS;
5293  break;
5294  case 0:
5295  case O_EXCL:
5296  create = OPEN_EXISTING;
5297  break;
5298  case O_CREAT | O_EXCL:
5299  case O_CREAT | O_EXCL | O_TRUNC:
5300  create = CREATE_NEW;
5301  break;
5302  case O_TRUNC:
5303  case O_TRUNC | O_EXCL:
5304  create = TRUNCATE_EXISTING;
5305  break;
5306  case O_CREAT | O_TRUNC:
5307  create = CREATE_ALWAYS;
5308  break;
5309  default:
5310  errno = EINVAL;
5311  return -1;
5312  }
5313  if (oflag & O_CREAT) {
5314  va_list arg;
5315  int pmode;
5316  va_start(arg, oflag);
5317  pmode = va_arg(arg, int);
5318  va_end(arg);
5319  /* TODO: we need to check umask here, but it's not exported... */
5320  if (!(pmode & S_IWRITE))
5321  attr = FILE_ATTRIBUTE_READONLY;
5322  }
5323  oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
5324 
5325  if (oflag & O_TEMPORARY) {
5326  attr |= FILE_FLAG_DELETE_ON_CLOSE;
5327  access |= DELETE;
5328  }
5329  oflag &= ~O_TEMPORARY;
5330 
5331  if (oflag & _O_SHORT_LIVED)
5332  attr |= FILE_ATTRIBUTE_TEMPORARY;
5333  oflag &= ~_O_SHORT_LIVED;
5334 
5335  switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
5336  case 0:
5337  break;
5338  case O_SEQUENTIAL:
5339  attr |= FILE_FLAG_SEQUENTIAL_SCAN;
5340  break;
5341  case O_RANDOM:
5342  attr |= FILE_FLAG_RANDOM_ACCESS;
5343  break;
5344  default:
5345  errno = EINVAL;
5346  return -1;
5347  }
5348  oflag &= ~(O_SEQUENTIAL | O_RANDOM);
5349 
5350  if (oflag & ~O_APPEND) {
5351  errno = EINVAL;
5352  return -1;
5353  }
5354 
5355  /* allocate a C Runtime file handle */
5356  RUBY_CRITICAL({
5357  h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
5358  fd = _open_osfhandle((intptr_t)h, 0);
5359  CloseHandle(h);
5360  });
5361  if (fd == -1) {
5362  errno = EMFILE;
5363  return -1;
5364  }
5365  RUBY_CRITICAL({
5366  MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
5367  _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
5368  _set_osflags(fd, 0);
5369 
5370  h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec,
5371  create, attr, NULL);
5372  if (h == INVALID_HANDLE_VALUE) {
5373  DWORD e = GetLastError();
5374  if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
5375  errno = map_errno(e);
5376  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
5377  fd = -1;
5378  goto quit;
5379  }
5380 
5381  switch (GetFileType(h)) {
5382  case FILE_TYPE_CHAR:
5383  flags |= FDEV;
5384  break;
5385  case FILE_TYPE_PIPE:
5386  flags |= FPIPE;
5387  break;
5388  case FILE_TYPE_UNKNOWN:
5389  errno = map_errno(GetLastError());
5390  CloseHandle(h);
5391  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
5392  fd = -1;
5393  goto quit;
5394  }
5395  if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
5396  flags |= FAPPEND;
5397 
5398  _set_osfhnd(fd, (intptr_t)h);
5399  _osfile(fd) = flags | FOPEN;
5400 
5401  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
5402  quit:
5403  ;
5404  });
5405 
5406  return fd;
5407 }
5408 
5409 /* License: Ruby's */
5410 int
5412 {
5413  int fd = fileno(fp);
5414  SOCKET sock = TO_SOCKET(fd);
5415  int save_errno = errno;
5416 
5417  if (fflush(fp)) return -1;
5418  if (!is_socket(sock)) {
5419  UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
5420  return fclose(fp);
5421  }
5422  _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
5423  fclose(fp);
5424  errno = save_errno;
5425  if (closesocket(sock) == SOCKET_ERROR) {
5426  errno = map_errno(WSAGetLastError());
5427  return -1;
5428  }
5429  return 0;
5430 }
5431 
5432 /* License: Ruby's */
5433 int
5434 rb_w32_pipe(int fds[2])
5435 {
5436  static DWORD serial = 0;
5437  char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
5438  char *p;
5439  SECURITY_ATTRIBUTES sec;
5440  HANDLE hRead, hWrite, h;
5441  int fdRead, fdWrite;
5442  int ret;
5443 
5444  /* if doesn't have CancelIo, use default pipe function */
5445  if (!cancel_io)
5446  return _pipe(fds, 65536L, _O_NOINHERIT);
5447 
5448  p = strchr(name, '0');
5449  snprintf(p, strlen(p) + 1, "%"PRI_PIDT_PREFIX"x-%lx", rb_w32_getpid(), serial++);
5450 
5451  sec.nLength = sizeof(sec);
5452  sec.lpSecurityDescriptor = NULL;
5453  sec.bInheritHandle = FALSE;
5454 
5455  RUBY_CRITICAL({
5456  hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
5457  0, 2, 65536, 65536, 0, &sec);
5458  });
5459  if (hRead == INVALID_HANDLE_VALUE) {
5460  DWORD err = GetLastError();
5461  if (err == ERROR_PIPE_BUSY)
5462  errno = EMFILE;
5463  else
5464  errno = map_errno(GetLastError());
5465  return -1;
5466  }
5467 
5468  RUBY_CRITICAL({
5469  hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
5470  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
5471  });
5472  if (hWrite == INVALID_HANDLE_VALUE) {
5473  errno = map_errno(GetLastError());
5474  CloseHandle(hRead);
5475  return -1;
5476  }
5477 
5478  RUBY_CRITICAL(do {
5479  ret = 0;
5480  h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
5481  fdRead = _open_osfhandle((intptr_t)h, 0);
5482  CloseHandle(h);
5483  if (fdRead == -1) {
5484  errno = EMFILE;
5485  CloseHandle(hWrite);
5486  CloseHandle(hRead);
5487  ret = -1;
5488  break;
5489  }
5490 
5491  MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock)));
5492  _set_osfhnd(fdRead, (intptr_t)hRead);
5493  _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
5494  MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock)));
5495  } while (0));
5496  if (ret)
5497  return ret;
5498 
5499  RUBY_CRITICAL(do {
5500  h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
5501  fdWrite = _open_osfhandle((intptr_t)h, 0);
5502  CloseHandle(h);
5503  if (fdWrite == -1) {
5504  errno = EMFILE;
5505  CloseHandle(hWrite);
5506  ret = -1;
5507  break;
5508  }
5509  MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock)));
5510  _set_osfhnd(fdWrite, (intptr_t)hWrite);
5511  _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
5512  MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock)));
5513  } while (0));
5514  if (ret) {
5515  rb_w32_close(fdRead);
5516  return ret;
5517  }
5518 
5519  fds[0] = fdRead;
5520  fds[1] = fdWrite;
5521 
5522  return 0;
5523 }
5524 
5525 /* License: Ruby's */
5526 static struct constat *
5528 {
5529  st_data_t data;
5530  struct constat *p;
5531  if (!conlist) {
5532  conlist = st_init_numtable();
5533  }
5534  if (st_lookup(conlist, (st_data_t)h, &data)) {
5535  p = (struct constat *)data;
5536  }
5537  else {
5538  CONSOLE_SCREEN_BUFFER_INFO csbi;
5539  p = ALLOC(struct constat);
5540  p->vt100.state = constat_init;
5541  p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
5542  p->vt100.saved.X = p->vt100.saved.Y = 0;
5543  if (GetConsoleScreenBufferInfo(h, &csbi)) {
5544  p->vt100.attr = csbi.wAttributes;
5545  }
5546  st_insert(conlist, (st_data_t)h, (st_data_t)p);
5547  }
5548  return p;
5549 }
5550 
5551 /* License: Ruby's */
5552 static void
5553 constat_reset(HANDLE h)
5554 {
5555  st_data_t data;
5556  struct constat *p;
5557  if (!conlist) return;
5558  if (!st_lookup(conlist, (st_data_t)h, &data)) return;
5559  p = (struct constat *)data;
5560  p->vt100.state = constat_init;
5561 }
5562 
5563 /* License: Ruby's */
5564 static DWORD
5565 constat_attr(int count, const int *seq, DWORD attr, DWORD default_attr)
5566 {
5567 #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
5568 #define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
5569  DWORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
5570  int rev = 0;
5571 
5572  if (!count) return attr;
5573  while (count-- > 0) {
5574  switch (*seq++) {
5575  case 0:
5576  attr = default_attr;
5577  rev = 0;
5578  bold = 0;
5579  break;
5580  case 1:
5581  bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
5582  break;
5583  case 4:
5584 #ifndef COMMON_LVB_UNDERSCORE
5585 #define COMMON_LVB_UNDERSCORE 0x8000
5586 #endif
5587  attr |= COMMON_LVB_UNDERSCORE;
5588  break;
5589  case 7:
5590  rev = 1;
5591  break;
5592 
5593  case 30:
5594  attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
5595  break;
5596  case 17:
5597  case 31:
5598  attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED;
5599  break;
5600  case 18:
5601  case 32:
5602  attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN;
5603  break;
5604  case 19:
5605  case 33:
5606  attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
5607  break;
5608  case 20:
5609  case 34:
5610  attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE;
5611  break;
5612  case 21:
5613  case 35:
5614  attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
5615  break;
5616  case 22:
5617  case 36:
5618  attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
5619  break;
5620  case 23:
5621  case 37:
5622  attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
5623  break;
5624 
5625  case 40:
5626  attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
5627  break;
5628  case 41:
5629  attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED;
5630  break;
5631  case 42:
5632  attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN;
5633  break;
5634  case 43:
5635  attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
5636  break;
5637  case 44:
5638  attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE;
5639  break;
5640  case 45:
5641  attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
5642  break;
5643  case 46:
5644  attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN;
5645  break;
5646  case 47:
5647  attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
5648  break;
5649  }
5650  }
5651  if (rev) {
5652  attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) |
5653  ((attr & FOREGROUND_MASK) << 4) |
5654  ((attr & BACKGROUND_MASK) >> 4);
5655  }
5656  return attr | bold;
5657 }
5658 
5659 /* License: Ruby's */
5660 static void
5661 constat_apply(HANDLE handle, struct constat *s, WCHAR w)
5662 {
5663  CONSOLE_SCREEN_BUFFER_INFO csbi;
5664  const int *seq = s->vt100.seq;
5665  int count = s->vt100.state;
5666  int arg1 = 1;
5667  COORD pos;
5668  DWORD written;
5669 
5670  if (!GetConsoleScreenBufferInfo(handle, &csbi)) return;
5671  if (count > 0 && seq[0] > 0) arg1 = seq[0];
5672  switch (w) {
5673  case L'm':
5674  SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr));
5675  break;
5676  case L'F':
5677  csbi.dwCursorPosition.X = 0;
5678  case L'A':
5679  csbi.dwCursorPosition.Y -= arg1;
5680  if (csbi.dwCursorPosition.Y < 0)
5681  csbi.dwCursorPosition.Y = 0;
5682  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5683  break;
5684  case L'E':
5685  csbi.dwCursorPosition.X = 0;
5686  case L'B':
5687  case L'e':
5688  csbi.dwCursorPosition.Y += arg1;
5689  if (csbi.dwCursorPosition.Y >= csbi.dwSize.Y)
5690  csbi.dwCursorPosition.Y = csbi.dwSize.Y;
5691  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5692  break;
5693  case L'C':
5694  csbi.dwCursorPosition.X += arg1;
5695  if (csbi.dwCursorPosition.X >= csbi.dwSize.X)
5696  csbi.dwCursorPosition.X = csbi.dwSize.X;
5697  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5698  break;
5699  case L'D':
5700  csbi.dwCursorPosition.X -= arg1;
5701  if (csbi.dwCursorPosition.X < 0)
5702  csbi.dwCursorPosition.X = 0;
5703  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5704  break;
5705  case L'G':
5706  case L'`':
5707  csbi.dwCursorPosition.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
5708  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5709  break;
5710  case L'd':
5711  csbi.dwCursorPosition.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
5712  SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
5713  break;
5714  case L'H':
5715  case L'f':
5716  pos.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
5717  if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1;
5718  pos.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
5719  SetConsoleCursorPosition(handle, pos);
5720  break;
5721  case L'J':
5722  switch (arg1) {
5723  case 0: /* erase after cursor */
5724  FillConsoleOutputCharacterW(handle, L' ',
5725  csbi.dwSize.X * (csbi.dwSize.Y - csbi.dwCursorPosition.Y) - csbi.dwCursorPosition.X,
5726  csbi.dwCursorPosition, &written);
5727  break;
5728  case 1: /* erase before cursor */
5729  pos.X = 0;
5730  pos.Y = csbi.dwCursorPosition.Y;
5731  FillConsoleOutputCharacterW(handle, L' ',
5732  csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X,
5733  pos, &written);
5734  break;
5735  case 2: /* erase entire line */
5736  pos.X = 0;
5737  pos.Y = 0;
5738  FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X * csbi.dwSize.Y, pos, &written);
5739  break;
5740  }
5741  break;
5742  case L'K':
5743  switch (arg1) {
5744  case 0: /* erase after cursor */
5745  FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written);
5746  break;
5747  case 1: /* erase before cursor */
5748  pos.X = 0;
5749  pos.Y = csbi.dwCursorPosition.Y;
5750  FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written);
5751  break;
5752  case 2: /* erase entire line */
5753  pos.X = 0;
5754  pos.Y = csbi.dwCursorPosition.Y;
5755  FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written);
5756  break;
5757  }
5758  break;
5759  case L's':
5760  s->vt100.saved = csbi.dwCursorPosition;
5761  break;
5762  case L'u':
5763  SetConsoleCursorPosition(handle, s->vt100.saved);
5764  break;
5765  case L'h':
5766  if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
5767  CONSOLE_CURSOR_INFO cci;
5768  GetConsoleCursorInfo(handle, &cci);
5769  cci.bVisible = TRUE;
5770  SetConsoleCursorInfo(handle, &cci);
5771  }
5772  break;
5773  case L'l':
5774  if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
5775  CONSOLE_CURSOR_INFO cci;
5776  GetConsoleCursorInfo(handle, &cci);
5777  cci.bVisible = FALSE;
5778  SetConsoleCursorInfo(handle, &cci);
5779  }
5780  break;
5781  }
5782 }
5783 
5784 /* License: Ruby's */
5785 static long
5786 constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
5787 {
5788  const WCHAR *ptr = *ptrp;
5789  long rest, len = *lenp;
5790  while (len-- > 0) {
5791  WCHAR wc = *ptr++;
5792  if (wc == 0x1b) {
5793  rest = *lenp - len - 1;
5794  s->vt100.state = constat_esc;
5795  }
5796  else if (s->vt100.state == constat_esc && wc == L'[') {
5797  rest = *lenp - len - 1;
5798  if (rest > 0) --rest;
5799  s->vt100.state = constat_seq;
5800  s->vt100.seq[0] = 0;
5801  }
5802  else if (s->vt100.state >= constat_seq) {
5803  if (wc >= L'0' && wc <= L'9') {
5804  if (s->vt100.state < (int)numberof(s->vt100.seq)) {
5805  int *seq = &s->vt100.seq[s->vt100.state];
5806  *seq = (*seq * 10) + (wc - L'0');
5807  }
5808  }
5809  else if (s->vt100.state == constat_seq && s->vt100.seq[0] == 0 && wc == L'?') {
5810  s->vt100.seq[s->vt100.state++] = -1;
5811  }
5812  else {
5813  do {
5814  if (++s->vt100.state < (int)numberof(s->vt100.seq)) {
5815  s->vt100.seq[s->vt100.state] = 0;
5816  }
5817  else {
5818  s->vt100.state = (int)numberof(s->vt100.seq);
5819  }
5820  } while (0);
5821  if (wc != L';') {
5822  constat_apply(h, s, wc);
5823  s->vt100.state = constat_init;
5824  }
5825  }
5826  rest = 0;
5827  }
5828  else {
5829  continue;
5830  }
5831  *ptrp = ptr;
5832  *lenp = len;
5833  return rest;
5834  }
5835  len = *lenp;
5836  *ptrp = ptr;
5837  *lenp = 0;
5838  return len;
5839 }
5840 
5841 
5842 /* License: Ruby's */
5843 int
5845 {
5846  SOCKET sock = TO_SOCKET(fd);
5847  int save_errno = errno;
5848 
5849  if (!is_socket(sock)) {
5850  UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
5851  constat_delete((HANDLE)sock);
5852  return _close(fd);
5853  }
5854  _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
5855  socklist_delete(&sock, NULL);
5856  _close(fd);
5857  errno = save_errno;
5858  if (closesocket(sock) == SOCKET_ERROR) {
5859  errno = map_errno(WSAGetLastError());
5860  return -1;
5861  }
5862  return 0;
5863 }
5864 
5865 static int
5866 setup_overlapped(OVERLAPPED *ol, int fd)
5867 {
5868  memset(ol, 0, sizeof(*ol));
5869  if (!(_osfile(fd) & (FDEV | FPIPE))) {
5870  LONG high = 0;
5871  DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
5872  DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
5873 #ifndef INVALID_SET_FILE_POINTER
5874 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
5875 #endif
5876  if (low == INVALID_SET_FILE_POINTER) {
5877  DWORD err = GetLastError();
5878  if (err != NO_ERROR) {
5879  errno = map_errno(err);
5880  return -1;
5881  }
5882  }
5883  ol->Offset = low;
5884  ol->OffsetHigh = high;
5885  }
5886  ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
5887  if (!ol->hEvent) {
5888  errno = map_errno(GetLastError());
5889  return -1;
5890  }
5891  return 0;
5892 }
5893 
5894 static void
5895 finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
5896 {
5897  CloseHandle(ol->hEvent);
5898 
5899  if (!(_osfile(fd) & (FDEV | FPIPE))) {
5900  LONG high = ol->OffsetHigh;
5901  DWORD low = ol->Offset + size;
5902  if (low < ol->Offset)
5903  ++high;
5904  SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
5905  }
5906 }
5907 
5908 #undef read
5909 /* License: Ruby's */
5910 ssize_t
5911 rb_w32_read(int fd, void *buf, size_t size)
5912 {
5913  SOCKET sock = TO_SOCKET(fd);
5914  DWORD read;
5915  DWORD wait;
5916  DWORD err;
5917  size_t len;
5918  size_t ret;
5919  OVERLAPPED ol, *pol = NULL;
5920  BOOL isconsole;
5921  BOOL islineinput = FALSE;
5922  int start = 0;
5923 
5924  if (is_socket(sock))
5925  return rb_w32_recv(fd, buf, size, 0);
5926 
5927  // validate fd by using _get_osfhandle() because we cannot access _nhandle
5928  if (_get_osfhandle(fd) == -1) {
5929  return -1;
5930  }
5931 
5932  if (_osfile(fd) & FTEXT) {
5933  return _read(fd, buf, size);
5934  }
5935 
5936  MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
5937 
5938  if (!size || _osfile(fd) & FEOFLAG) {
5939  _set_osflags(fd, _osfile(fd) & ~FEOFLAG);
5940  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
5941  return 0;
5942  }
5943 
5944  ret = 0;
5945  isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
5946  if (isconsole) {
5947  DWORD mode;
5948  GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
5949  islineinput = (mode & ENABLE_LINE_INPUT) != 0;
5950  }
5951  retry:
5952  /* get rid of console reading bug */
5953  if (isconsole) {
5954  constat_reset((HANDLE)_osfhnd(fd));
5955  if (start)
5956  len = 1;
5957  else {
5958  len = 0;
5959  start = 1;
5960  }
5961  }
5962  else
5963  len = size;
5964  size -= len;
5965 
5966  /* if have cancel_io, use Overlapped I/O */
5967  if (cancel_io) {
5968  if (setup_overlapped(&ol, fd)) {
5969  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
5970  return -1;
5971  }
5972 
5973  pol = &ol;
5974  }
5975 
5976  if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
5977  err = GetLastError();
5978  if (err != ERROR_IO_PENDING) {
5979  if (pol) CloseHandle(ol.hEvent);
5980  if (err == ERROR_ACCESS_DENIED)
5981  errno = EBADF;
5982  else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
5983  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
5984  return 0;
5985  }
5986  else
5987  errno = map_errno(err);
5988 
5989  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
5990  return -1;
5991  }
5992 
5993  if (pol) {
5994  wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
5995  if (wait != WAIT_OBJECT_0) {
5996  if (wait == WAIT_OBJECT_0 + 1)
5997  errno = EINTR;
5998  else
5999  errno = map_errno(GetLastError());
6000  CloseHandle(ol.hEvent);
6001  cancel_io((HANDLE)_osfhnd(fd));
6002  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6003  return -1;
6004  }
6005 
6006  if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
6007  (err = GetLastError()) != ERROR_HANDLE_EOF) {
6008  int ret = 0;
6009  if (err != ERROR_BROKEN_PIPE) {
6010  errno = map_errno(err);
6011  ret = -1;
6012  }
6013  CloseHandle(ol.hEvent);
6014  cancel_io((HANDLE)_osfhnd(fd));
6015  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6016  return ret;
6017  }
6018  }
6019  }
6020  else {
6021  err = GetLastError();
6022  errno = map_errno(err);
6023  }
6024 
6025  if (pol) {
6026  finish_overlapped(&ol, fd, read);
6027  }
6028 
6029  ret += read;
6030  if (read >= len) {
6031  buf = (char *)buf + read;
6032  if (err != ERROR_OPERATION_ABORTED &&
6033  !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0)
6034  goto retry;
6035  }
6036  if (read == 0)
6037  _set_osflags(fd, _osfile(fd) | FEOFLAG);
6038 
6039 
6040  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6041 
6042  return ret;
6043 }
6044 
6045 #undef write
6046 /* License: Ruby's */
6047 ssize_t
6048 rb_w32_write(int fd, const void *buf, size_t size)
6049 {
6050  SOCKET sock = TO_SOCKET(fd);
6051  DWORD written;
6052  DWORD wait;
6053  DWORD err;
6054  size_t len;
6055  size_t ret;
6056  OVERLAPPED ol, *pol = NULL;
6057 
6058  if (is_socket(sock))
6059  return rb_w32_send(fd, buf, size, 0);
6060 
6061  // validate fd by using _get_osfhandle() because we cannot access _nhandle
6062  if (_get_osfhandle(fd) == -1) {
6063  return -1;
6064  }
6065 
6066  if ((_osfile(fd) & FTEXT) &&
6067  (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) {
6068  return _write(fd, buf, size);
6069  }
6070 
6071  MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
6072 
6073  if (!size || _osfile(fd) & FEOFLAG) {
6074  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6075  return 0;
6076  }
6077 
6078  ret = 0;
6079  retry:
6080  /* get rid of console writing bug */
6081  len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size;
6082  size -= len;
6083 
6084  /* if have cancel_io, use Overlapped I/O */
6085  if (cancel_io) {
6086  if (setup_overlapped(&ol, fd)) {
6087  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6088  return -1;
6089  }
6090 
6091  pol = &ol;
6092  }
6093 
6094  if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) {
6095  err = GetLastError();
6096  if (err != ERROR_IO_PENDING) {
6097  if (pol) CloseHandle(ol.hEvent);
6098  if (err == ERROR_ACCESS_DENIED)
6099  errno = EBADF;
6100  else
6101  errno = map_errno(err);
6102 
6103  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6104  return -1;
6105  }
6106 
6107  if (pol) {
6108  wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
6109  if (wait != WAIT_OBJECT_0) {
6110  if (wait == WAIT_OBJECT_0 + 1)
6111  errno = EINTR;
6112  else
6113  errno = map_errno(GetLastError());
6114  CloseHandle(ol.hEvent);
6115  cancel_io((HANDLE)_osfhnd(fd));
6116  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6117  return -1;
6118  }
6119 
6120  if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written,
6121  TRUE)) {
6122  errno = map_errno(err);
6123  CloseHandle(ol.hEvent);
6124  cancel_io((HANDLE)_osfhnd(fd));
6125  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6126  return -1;
6127  }
6128  }
6129  }
6130 
6131  if (pol) {
6132  finish_overlapped(&ol, fd, written);
6133  }
6134 
6135  ret += written;
6136  if (written == len) {
6137  buf = (const char *)buf + len;
6138  if (size > 0)
6139  goto retry;
6140  }
6141 
6142  MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
6143 
6144  return ret;
6145 }
6146 
6147 /* License: Ruby's */
6148 long
6150 {
6151  static int disable;
6152  HANDLE handle;
6153  DWORD dwMode, reslen;
6154  VALUE str = strarg;
6155  rb_encoding *utf16 = rb_enc_find("UTF-16LE");
6156  const WCHAR *ptr, *next;
6157  struct constat *s;
6158  long len;
6159 
6160  if (disable) return -1L;
6161  handle = (HANDLE)_osfhnd(fd);
6162  if (!GetConsoleMode(handle, &dwMode) ||
6163  !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE"))
6164  return -1L;
6165 
6166  str = rb_str_encode(str, rb_enc_from_encoding(utf16),
6168  ptr = (const WCHAR *)RSTRING_PTR(str);
6169  len = RSTRING_LEN(str) / sizeof(WCHAR);
6170  s = constat_handle(handle);
6171  while (len > 0) {
6172  long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
6173  if (curlen > 0) {
6174  if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) {
6175  if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
6176  disable = TRUE;
6177  return -1L;
6178  }
6179  }
6180  ptr = next;
6181  }
6182  RB_GC_GUARD(str);
6183  return (long)reslen;
6184 }
6185 
6186 /* License: Ruby's */
6187 static int
6188 unixtime_to_filetime(time_t time, FILETIME *ft)
6189 {
6190  ULARGE_INTEGER tmp;
6191 
6192  tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
6193  ft->dwLowDateTime = tmp.LowPart;
6194  ft->dwHighDateTime = tmp.HighPart;
6195  return 0;
6196 }
6197 
6198 /* License: Ruby's */
6199 static int
6200 wutime(const WCHAR *path, const struct utimbuf *times)
6201 {
6202  HANDLE hFile;
6203  FILETIME atime, mtime;
6204  struct stati64 stat;
6205  int ret = 0;
6206 
6207  if (wstati64(path, &stat)) {
6208  return -1;
6209  }
6210 
6211  if (times) {
6212  if (unixtime_to_filetime(times->actime, &atime)) {
6213  return -1;
6214  }
6215  if (unixtime_to_filetime(times->modtime, &mtime)) {
6216  return -1;
6217  }
6218  }
6219  else {
6220  GetSystemTimeAsFileTime(&atime);
6221  mtime = atime;
6222  }
6223 
6224  RUBY_CRITICAL({
6225  const DWORD attr = GetFileAttributesW(path);
6226  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
6227  SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
6228  hFile = CreateFileW(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
6229  FILE_FLAG_BACKUP_SEMANTICS, 0);
6230  if (hFile == INVALID_HANDLE_VALUE) {
6231  errno = map_errno(GetLastError());
6232  ret = -1;
6233  }
6234  else {
6235  if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
6236  errno = map_errno(GetLastError());
6237  ret = -1;
6238  }
6239  CloseHandle(hFile);
6240  }
6241  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
6242  SetFileAttributesW(path, attr);
6243  });
6244 
6245  return ret;
6246 }
6247 
6248 /* License: Ruby's */
6249 int
6250 rb_w32_uutime(const char *path, const struct utimbuf *times)
6251 {
6252  WCHAR *wpath;
6253  int ret;
6254 
6255  if (!(wpath = utf8_to_wstr(path, NULL)))
6256  return -1;
6257  ret = wutime(wpath, times);
6258  free(wpath);
6259  return ret;
6260 }
6261 
6262 /* License: Ruby's */
6263 int
6264 rb_w32_utime(const char *path, const struct utimbuf *times)
6265 {
6266  WCHAR *wpath;
6267  int ret;
6268 
6269  if (!(wpath = filecp_to_wstr(path, NULL)))
6270  return -1;
6271  ret = wutime(wpath, times);
6272  free(wpath);
6273  return ret;
6274 }
6275 
6276 /* License: Ruby's */
6277 int
6278 rb_w32_uchdir(const char *path)
6279 {
6280  WCHAR *wpath;
6281  int ret;
6282 
6283  if (!(wpath = utf8_to_wstr(path, NULL)))
6284  return -1;
6285  ret = _wchdir(wpath);
6286  free(wpath);
6287  return ret;
6288 }
6289 
6290 /* License: Ruby's */
6291 static int
6292 wmkdir(const WCHAR *wpath, int mode)
6293 {
6294  int ret = -1;
6295 
6296  RUBY_CRITICAL(do {
6297  if (CreateDirectoryW(wpath, NULL) == FALSE) {
6298  errno = map_errno(GetLastError());
6299  break;
6300  }
6301  if (_wchmod(wpath, mode) == -1) {
6302  RemoveDirectoryW(wpath);
6303  break;
6304  }
6305  ret = 0;
6306  } while (0));
6307  return ret;
6308 }
6309 
6310 /* License: Ruby's */
6311 int
6312 rb_w32_umkdir(const char *path, int mode)
6313 {
6314  WCHAR *wpath;
6315  int ret;
6316 
6317  if (!(wpath = utf8_to_wstr(path, NULL)))
6318  return -1;
6319  ret = wmkdir(wpath, mode);
6320  free(wpath);
6321  return ret;
6322 }
6323 
6324 /* License: Ruby's */
6325 int
6326 rb_w32_mkdir(const char *path, int mode)
6327 {
6328  WCHAR *wpath;
6329  int ret;
6330 
6331  if (!(wpath = filecp_to_wstr(path, NULL)))
6332  return -1;
6333  ret = wmkdir(wpath, mode);
6334  free(wpath);
6335  return ret;
6336 }
6337 
6338 /* License: Ruby's */
6339 static int
6340 wrmdir(const WCHAR *wpath)
6341 {
6342  int ret = 0;
6343  RUBY_CRITICAL({
6344  const DWORD attr = GetFileAttributesW(wpath);
6345  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
6346  SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
6347  }
6348  if (RemoveDirectoryW(wpath) == FALSE) {
6349  errno = map_errno(GetLastError());
6350  ret = -1;
6351  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
6352  SetFileAttributesW(wpath, attr);
6353  }
6354  }
6355  });
6356  return ret;
6357 }
6358 
6359 /* License: Ruby's */
6360 int
6361 rb_w32_rmdir(const char *path)
6362 {
6363  WCHAR *wpath;
6364  int ret;
6365 
6366  if (!(wpath = filecp_to_wstr(path, NULL)))
6367  return -1;
6368  ret = wrmdir(wpath);
6369  free(wpath);
6370  return ret;
6371 }
6372 
6373 /* License: Ruby's */
6374 int
6375 rb_w32_urmdir(const char *path)
6376 {
6377  WCHAR *wpath;
6378  int ret;
6379 
6380  if (!(wpath = utf8_to_wstr(path, NULL)))
6381  return -1;
6382  ret = wrmdir(wpath);
6383  free(wpath);
6384  return ret;
6385 }
6386 
6387 /* License: Ruby's */
6388 static int
6389 wunlink(const WCHAR *path)
6390 {
6391  int ret = 0;
6392  RUBY_CRITICAL({
6393  const DWORD attr = GetFileAttributesW(path);
6394  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
6395  SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
6396  }
6397  if (!DeleteFileW(path)) {
6398  errno = map_errno(GetLastError());
6399  ret = -1;
6400  if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
6401  SetFileAttributesW(path, attr);
6402  }
6403  }
6404  });
6405  return ret;
6406 }
6407 
6408 /* License: Ruby's */
6409 int
6410 rb_w32_uunlink(const char *path)
6411 {
6412  WCHAR *wpath;
6413  int ret;
6414 
6415  if (!(wpath = utf8_to_wstr(path, NULL)))
6416  return -1;
6417  ret = wunlink(wpath);
6418  free(wpath);
6419  return ret;
6420 }
6421 
6422 /* License: Ruby's */
6423 int
6424 rb_w32_unlink(const char *path)
6425 {
6426  WCHAR *wpath;
6427  int ret;
6428 
6429  if (!(wpath = filecp_to_wstr(path, NULL)))
6430  return -1;
6431  ret = wunlink(wpath);
6432  free(wpath);
6433  return ret;
6434 }
6435 
6436 /* License: Ruby's */
6437 int
6438 rb_w32_uchmod(const char *path, int mode)
6439 {
6440  WCHAR *wpath;
6441  int ret;
6442 
6443  if (!(wpath = utf8_to_wstr(path, NULL)))
6444  return -1;
6445  ret = _wchmod(wpath, mode);
6446  free(wpath);
6447  return ret;
6448 }
6449 
6450 #if !defined(__BORLANDC__)
6451 /* License: Ruby's */
6452 int
6454 {
6455  DWORD mode;
6456 
6457  // validate fd by using _get_osfhandle() because we cannot access _nhandle
6458  if (_get_osfhandle(fd) == -1) {
6459  return 0;
6460  }
6461  if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) {
6462  errno = ENOTTY;
6463  return 0;
6464  }
6465  return 1;
6466 }
6467 #endif
6468 
6469 //
6470 // Fix bcc32's stdio bug
6471 //
6472 
6473 #ifdef __BORLANDC__
6474 /* License: Ruby's */
6475 static int
6476 too_many_files(void)
6477 {
6478  FILE *f;
6479  for (f = _streams; f < _streams + _nfile; f++) {
6480  if (f->fd < 0) return 0;
6481  }
6482  return 1;
6483 }
6484 
6485 #undef fopen
6486 /* License: Ruby's */
6487 FILE *
6488 rb_w32_fopen(const char *path, const char *mode)
6489 {
6490  FILE *f = (errno = 0, fopen(path, mode));
6491  if (f == NULL && errno == 0) {
6492  if (too_many_files())
6493  errno = EMFILE;
6494  }
6495  return f;
6496 }
6497 
6498 /* License: Ruby's */
6499 FILE *
6500 rb_w32_fdopen(int handle, const char *type)
6501 {
6502  FILE *f = (errno = 0, _fdopen(handle, (char *)type));
6503  if (f == NULL && errno == 0) {
6504  if (handle < 0)
6505  errno = EBADF;
6506  else if (too_many_files())
6507  errno = EMFILE;
6508  }
6509  return f;
6510 }
6511 
6512 /* License: Ruby's */
6513 FILE *
6514 rb_w32_fsopen(const char *path, const char *mode, int shflags)
6515 {
6516  FILE *f = (errno = 0, _fsopen(path, mode, shflags));
6517  if (f == NULL && errno == 0) {
6518  if (too_many_files())
6519  errno = EMFILE;
6520  }
6521  return f;
6522 }
6523 #endif
6524 
6525 #if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
6526 extern long _ftol(double);
6527 /* License: Ruby's */
6528 long
6529 _ftol2(double d)
6530 {
6531  return _ftol(d);
6532 }
6533 
6534 /* License: Ruby's */
6535 long
6536 _ftol2_sse(double d)
6537 {
6538  return _ftol(d);
6539 }
6540 #endif
6541 
6542 #ifndef signbit
6543 /* License: Ruby's */
6544 int
6545 signbit(double x)
6546 {
6547  int *ip = (int *)(&x + 1) - 1;
6548  return *ip < 0;
6549 }
6550 #endif
6551 
6552 /* License: Ruby's */
6553 const char * WSAAPI
6554 rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
6555 {
6556  typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t);
6557  inet_ntop_t *pInetNtop;
6558  pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL);
6559  if (pInetNtop) {
6560  return pInetNtop(af, (void *)addr, numaddr, numaddr_len);
6561  }
6562  else {
6563  struct in_addr in;
6564  memcpy(&in.s_addr, addr, sizeof(in.s_addr));
6565  snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
6566  }
6567  return numaddr;
6568 }
6569 
6570 /* License: Ruby's */
6571 char
6573 {
6574  return _osfile(fd) & FTEXT;
6575 }
6576 
6577 #if RUBY_MSVCRT_VERSION < 80 && !defined(__MINGW64__)
6578 /* License: Ruby's */
6579 static int
6580 unixtime_to_systemtime(const time_t t, SYSTEMTIME *st)
6581 {
6582  FILETIME ft;
6583  if (unixtime_to_filetime(t, &ft)) return -1;
6584  if (!FileTimeToSystemTime(&ft, st)) return -1;
6585  return 0;
6586 }
6587 
6588 /* License: Ruby's */
6589 static void
6590 systemtime_to_tm(const SYSTEMTIME *st, struct tm *t)
6591 {
6592  int y = st->wYear, m = st->wMonth, d = st->wDay;
6593  t->tm_sec = st->wSecond;
6594  t->tm_min = st->wMinute;
6595  t->tm_hour = st->wHour;
6596  t->tm_mday = st->wDay;
6597  t->tm_mon = st->wMonth - 1;
6598  t->tm_year = y - 1900;
6599  t->tm_wday = st->wDayOfWeek;
6600  switch (m) {
6601  case 1:
6602  break;
6603  case 2:
6604  d += 31;
6605  break;
6606  default:
6607  d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
6608  d += ((m - 3) * 153 + 2) / 5;
6609  break;
6610  }
6611  t->tm_yday = d - 1;
6612 }
6613 
6614 /* License: Ruby's */
6615 static int
6616 systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
6617 {
6618  TIME_ZONE_INFORMATION stdtz;
6619  SYSTEMTIME sst;
6620 
6621  if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1;
6622  if (!tz) {
6623  GetTimeZoneInformation(&stdtz);
6624  tz = &stdtz;
6625  }
6626  if (tz->StandardBias == tz->DaylightBias) return 0;
6627  if (!tz->StandardDate.wMonth) return 0;
6628  if (!tz->DaylightDate.wMonth) return 0;
6629  if (tz != &stdtz) stdtz = *tz;
6630 
6631  stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
6632  if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0;
6633  if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
6634  return 0;
6635  return 1;
6636 }
6637 #endif
6638 
6639 #ifdef __MINGW64__
6640 # ifndef MINGW_HAS_SECURE_API
6641  _CRTIMP errno_t __cdecl _gmtime64_s(struct tm* tm, const __time64_t *time);
6642  _CRTIMP errno_t __cdecl _localtime64_s(struct tm* tm, const __time64_t *time);
6643 # endif
6644 # define gmtime_s _gmtime64_s
6645 # define localtime_s _localtime64_s
6646 #endif
6647 
6648 /* License: Ruby's */
6649 struct tm *
6650 gmtime_r(const time_t *tp, struct tm *rp)
6651 {
6652  int e = EINVAL;
6653  if (!tp || !rp) {
6654  error:
6655  errno = e;
6656  return NULL;
6657  }
6658 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
6659  e = gmtime_s(rp, tp);
6660  if (e != 0) goto error;
6661 #else
6662  {
6663  SYSTEMTIME st;
6664  if (unixtime_to_systemtime(*tp, &st)) goto error;
6665  rp->tm_isdst = 0;
6666  systemtime_to_tm(&st, rp);
6667  }
6668 #endif
6669  return rp;
6670 }
6671 
6672 /* License: Ruby's */
6673 struct tm *
6674 localtime_r(const time_t *tp, struct tm *rp)
6675 {
6676  int e = EINVAL;
6677  if (!tp || !rp) {
6678  error:
6679  errno = e;
6680  return NULL;
6681  }
6682 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
6683  e = localtime_s(rp, tp);
6684  if (e) goto error;
6685 #else
6686  {
6687  SYSTEMTIME gst, lst;
6688  if (unixtime_to_systemtime(*tp, &gst)) goto error;
6689  rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
6690  systemtime_to_tm(&lst, rp);
6691  }
6692 #endif
6693  return rp;
6694 }
6695 
6696 /* License: Ruby's */
6697 int
6698 rb_w32_wrap_io_handle(HANDLE h, int flags)
6699 {
6700  BOOL tmp;
6701  int len = sizeof(tmp);
6702  int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (char *)&tmp, &len);
6703  if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
6704  int f = 0;
6705  if (flags & O_NONBLOCK) {
6706  flags &= ~O_NONBLOCK;
6707  f = O_NONBLOCK;
6708  }
6709  socklist_insert((SOCKET)h, f);
6710  }
6711  else if (flags & O_NONBLOCK) {
6712  errno = EINVAL;
6713  return -1;
6714  }
6715  return rb_w32_open_osfhandle((intptr_t)h, flags);
6716 }
6717 
6718 /* License: Ruby's */
6719 int
6721 {
6722  SOCKET sock = TO_SOCKET(fd);
6723  _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
6724  if (!is_socket(sock)) {
6725  UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
6726  constat_delete((HANDLE)sock);
6727  }
6728  else {
6729  socklist_delete(&sock, NULL);
6730  }
6731  return _close(fd);
6732 }
VALUE data
Definition: tcltklib.c:3367
static const char * NTLoginName
Definition: win32.c:245
void setnetent(int stayopen)
Definition: win32.c:3766
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:10208
int state
Definition: win32.c:590
long d_namlen
Definition: dir.h:13
ssize_t n
Definition: bigdecimal.c:5676
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:5071
static time_t filetime_to_unixtime(const FILETIME *ft)
Definition: win32.c:4496
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:4266
int gettimeofday(struct timeval *, struct timezone *)
Definition: win32.c:4017
void * malloc()
#define FALSE
Definition: nkf.h:174
DWORD dwFlags
Definition: win32.c:3251
#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:4957
static VALUE VALUE th
Definition: tcltklib.c:2947
#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:226
#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:5135
static int max(int a, int b)
Definition: strftime.c:141
#define ESHUTDOWN
Definition: win32.h:543
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:6048
static FARPROC get_wsa_extension_function(SOCKET s, GUID *guid)
Definition: win32.c:2890
int rb_w32_fstat(int, struct stat *)
Definition: win32.c:4445
#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:3338
C_block * out
Definition: crypt.c:308
int WSAAPI rb_w32_connect(int, const struct sockaddr *, int)
Definition: win32.c:2962
static ioinfo * _pioinfo(int)
Definition: win32.c:2172
static void catch_interrupt(void)
Definition: win32.c:4928
int WSAAPI rb_w32_bind(int, const struct sockaddr *, int)
Definition: win32.c:2943
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:3236
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:711
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:559
#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:3887
static int NtSocketsInitialized
Definition: win32.c:581
#define LK_ERR(f, i)
Definition: win32.c:277
#define ENOTSOCK
Definition: win32.h:483
ssize_t i
Definition: bigdecimal.c:5676
#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:1462
#define rb_enc_name(enc)
ino_t d_ino
Definition: dir.h:14
Definition: win32.h:215
#define F_DUPFD
Definition: win32.h:581
intptr_t osfhnd
Definition: win32.c:2117
#define P_NOWAIT
Definition: process.c:1408
#define strcasecmp
Definition: win32.h:200
int ret
Definition: tcltklib.c:280
int rb_w32_ustati64(const char *, struct stati64 *)
Definition: win32.c:4709
int rb_w32_wrap_io_handle(HANDLE, int)
Definition: win32.c:6698
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:103
#define ENETDOWN
Definition: win32.h:519
static unsigned fileattr_to_unixmode(DWORD attr, const WCHAR *path)
Definition: win32.c:4508
int namelen
Definition: win32.c:3247
int status
Definition: tcltklib.c:2196
static void constat_apply(HANDLE handle, struct constat *s, WCHAR w)
Definition: win32.c:5661
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:6312
#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:10310
#define INVALID_SET_FILE_POINTER
#define FAPPEND
Definition: win32.c:2186
#define ESTALE
Definition: win32.h:575
int fcntl(int, int,...)
Definition: win32.c:3839
gz path
Definition: zlib.c:2277
ssize_t rb_w32_read(int, void *, size_t)
Definition: win32.c:5911
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:4083
NIL_P(eventloop_thread)
Definition: tcltklib.c:4067
int sys_nerr
#define ENETRESET
Definition: win32.h:525
static struct tm * localtime_r(const time_t *t, struct tm *tm)
Definition: date_core.c:3616
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:439
#define WSAID_WSARECVMSG
Definition: win32.c:3255
int WSAAPI rb_w32_getsockopt(int, int, int, char *, int *)
Definition: win32.c:3037
#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:4998
static int is_socket(SOCKET)
Definition: win32.c:2299
static int wmkdir(const WCHAR *wpath, int mode)
Definition: win32.c:6292
static long filetime_to_clock(FILETIME *ft)
Definition: win32.c:4893
#define COPY_STAT(src, dest, size_cast)
Definition: win32.c:4426
#define ENOBUFS
Definition: win32.h:534
int rb_w32_urename(const char *, const char *)
Definition: win32.c:4364
#define ENETUNREACH
Definition: win32.h:522
static int check_if_dir(const char *file)
Definition: win32.c:5200
Definition: dir.h:19
static int is_invalid_handle(SOCKET sock)
Definition: win32.c:2662
#define SIGKILL
Definition: win32.h:463
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:3595
#define IOINFO_L2E
Definition: win32.c:2139
struct _NtCmdLineElement * next
Definition: win32.c:1364
int rb_w32_pipe(int[2])
Definition: win32.c:5434
int rb_w32_open(const char *, int,...)
Definition: win32.c:5214
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:5117
r
Definition: bigdecimal.c:1210
void * stackaddr
Definition: win32.c:4993
#define LOCK_NB
Definition: file.c:4187
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:3577
rb_pid_t rb_w32_getpid(void)
Definition: win32.c:5127
#define msghdr_to_wsamsg(msg, wsamsg)
Definition: win32.c:3262
unsigned int last
Definition: nkf.c:4310
#define EINPROGRESS
Definition: win32.h:477
int rb_w32_uaccess(const char *, int)
Definition: win32.c:4752
#define ELOOP
Definition: win32.h:555
int rb_w32_map_errno(DWORD)
Definition: win32.c:223
struct protoent * getprotoent(void)
Definition: win32.c:3760
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:3280
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:3607
#define ECONNRESET
Definition: win32.h:531
#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:2047
#define rb_fd_term(f)
d
Definition: strlcat.c:58
static SOCKET open_ifs_socket(int af, int type, int protocol)
Definition: win32.c:3424
int rb_w32_times(struct tms *)
Definition: win32.c:4904
static struct @155 errmap[]
int WSAAPI rb_w32_socket(int, int, int)
Definition: win32.c:3476
const char * fmt
Definition: tcltklib.c:841
int rb_w32_is_socket(int)
Definition: win32.c:2309
#define ENOPROTOOPT
Definition: win32.h:495
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:3004
#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:3250
const char *WSAAPI rb_w32_inet_ntop(int, const void *, char *, size_t)
Definition: win32.c:6554
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:3505
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:2928
static int internal_cmd_match(const char *cmdname, int nt)
Definition: win32.c:943
void endhostent(void)
Definition: win32.c:3749
#define ETOOMANYREFS
Definition: win32.h:546
Definition: file.c:2361
#define wstr_to_utf8(str, plen)
Definition: win32.c:1176
#define LOCK_EX
Definition: file.c:4184
struct hostent *WSAAPI rb_w32_gethostbyname(const char *)
Definition: win32.c:3523
#define LOCK_UN
Definition: file.c:4190
memset(y->frac+ix+1, 0,(y->Prec-(ix+1))*sizeof(BDIGIT))
DWORD dwBufferCount
Definition: win32.c:3249
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:5239
BDIGIT m
Definition: bigdecimal.c:5106
#define EREMOTE
Definition: win32.h:578
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:587
#define Qnil
Definition: tcltklib.c:1895
volatile VALUE elem
Definition: tcltklib.c:9712
static int is_pipe(SOCKET sock)
Definition: win32.c:2592
#define val
Definition: tcltklib.c:1948
#define ESOCKTNOSUPPORT
Definition: win32.h:501
#define EPROTONOSUPPORT
Definition: win32.h:498
long tv_usec
Definition: ossl_asn1.c:18
uintptr_t(* asynchronous_func_t)(uintptr_t self, int argc, uintptr_t *argv)
Definition: win32.h:749
#define END_FOREACH_CHILD
Definition: win32.c:779
IUnknown DWORD
Definition: win32ole.c:149
int WSAAPI rb_w32_send(int, const char *, int, int)
Definition: win32.c:3229
#define ECONNABORTED
Definition: win32.h:528
long nfiles
Definition: dir.h:23
#define DIRENT_PER_CHAR
Definition: win32.c:1742
static VALUE char * str
Definition: tcltklib.c:3546
#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:4884
#define GET_FAMILY(v)
Definition: win32.c:667
#define yield_once()
Definition: win32.c:4923
int flags
Definition: tcltklib.c:3022
#define EALREADY
Definition: win32.h:480
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:4587
int WSAAPI rb_w32_recvfrom(int, char *, int, int, struct sockaddr *, int *)
Definition: win32.c:3221
VALUE wait
Definition: tcltklib.c:1758
#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:100
#define RSTRING_LEN(str)
int chown(const char *, int, int)
Definition: win32.c:4069
int idx
Definition: tcltklib.c:9715
#define ENOTCONN
Definition: win32.h:540
#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:3758
int WSAAPI rb_w32_listen(int, int)
Definition: win32.c:3073
static int wutime(const WCHAR *path, const struct utimbuf *times)
Definition: win32.c:6200
#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:3598
#define S_IWGRP
Definition: win32.h:375
#define EHOSTUNREACH
Definition: win32.h:562
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len)
Definition: win32.c:460
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:4181
int rb_w32_mkdir(const char *, int)
Definition: win32.c:6326
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:5866
int rb_w32_uutime(const char *, const struct utimbuf *)
Definition: win32.c:6250
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:6361
uintptr_t(* func)(uintptr_t self, int argc, uintptr_t *argv)
Definition: win32.c:4997
int link(const char *, const char *)
Definition: win32.c:4239
#define FD_SET(fd, set)
Definition: win32.h:594
void sethostent(int stayopen)
Definition: win32.c:3764
struct servent * getservent(void)
Definition: win32.c:3762
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:6720
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:516
VALUE * argv
Definition: tcltklib.c:1970
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:3993
int st_foreach(st_table *, int(*)(ANYARGS), st_data_t)
Definition: st.c:1006
static int is_not_socket(SOCKET sock)
Definition: win32.c:2585
int rb_w32_putc(int, FILE *)
Definition: win32.c:4978
int rb_w32_fstati64(int, struct stati64 *)
Definition: win32.c:4469
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:5565
int errno
#define TRUE
Definition: nkf.h:175
q result
Definition: tcltklib.c:7069
int rb_w32_unlink(const char *)
Definition: win32.c:6424
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:1275
int rb_w32_truncate(const char *path, off_t length)
Definition: win32.c:4796
void setservent(int stayopen)
Definition: win32.c:3770
static long constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
Definition: win32.c:5786
void rb_w32_sysinit(int *argc, char ***argv)
Definition: win32.c:723
void rb_fatal(const char *fmt,...)
Definition: error.c:1842
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:3094
VALUE mode
Definition: tcltklib.c:1663
static CRITICAL_SECTION select_mutex
Definition: win32.c:580
int rb_w32_urmdir(const char *)
Definition: win32.c:6375
#define strdup(s)
Definition: util.h:69
struct netent * getnetent(void)
Definition: win32.c:3754
void setprotoent(int stayopen)
Definition: win32.c:3768
int fseeko(FILE *stream, off_t offset, int whence)
Definition: win32.c:4861
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:6580
char ** rb_w32_get_environ(void)
Definition: win32.c:5080
size_t length
Definition: tcltklib.c:4558
static int rb_chsize(HANDLE h, off_t size)
Definition: win32.c:4767
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:3752
unsigned int uintptr_t
Definition: win32.h:94
#define RB_GC_GUARD(v)
int rb_w32_uopen(const char *, int,...)
Definition: win32.c:5166
WORD attr
Definition: win32.c:591
int type
Definition: tcltklib.c:111
int rb_w32_stati64(const char *, struct stati64 *)
Definition: win32.c:4723
#define ECONNREFUSED
Definition: win32.h:552
static int unixtime_to_filetime(time_t time, FILETIME *ft)
Definition: win32.c:6188
int argc
Definition: tcltklib.c:1969
rb_uid_t geteuid(void)
Definition: win32.c:2399
int rb_w32_uchmod(const char *, int)
Definition: win32.c:6438
char * rb_w32_getenv(const char *)
Definition: win32.c:4304
void rb_w32_closedir(DIR *)
Definition: win32.c:2088
ssize_t ex
Definition: bigdecimal.c:5108
char * strchr(char *, char)
int intptr_t
Definition: win32.h:86
struct protoent *WSAAPI rb_w32_getprotobyname(const char *)
Definition: win32.c:3559
#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:492
static int isUNCRoot(const WCHAR *path)
Definition: win32.c:4403
long tms_utime
Definition: win32.h:710
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:3390
Real * b
Definition: bigdecimal.c:1196
struct timeval t0 t1
Definition: tcltklib.c:2797
static int internal_match(const void *key, const void *elem)
Definition: win32.c:892
#define EPFNOSUPPORT
Definition: win32.h:507
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:1219
static UINT get_system_directory(WCHAR *path, UINT len)
Definition: win32.c:435
void endprotoent(void)
Definition: win32.c:3751
VALUE msg
Definition: tcltklib.c:846
#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:4737
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:713
#define shutdown(a, b)
Definition: io.c:562
void rb_write_error2(const char *, long)
Definition: io.c:7085
#define SEEK_END
Definition: io.c:757
Definition: win32.h:709
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:6453
arg
Definition: ripper.y:1317
#define EDQUOT
Definition: win32.h:572
VALUE src
Definition: tcltklib.c:7952
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:1967
#define ECONV_INVALID_REPLACE
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:772
char * getlogin()
Definition: win32.c:762
int rb_w32_uchdir(const char *)
Definition: win32.c:6278
int rb_w32_ulink(const char *, const char *)
Definition: win32.c:4219
static int wstati64(const WCHAR *path, struct stati64 *st)
Definition: win32.c:4660
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:537
static DIR * opendir_internal(WCHAR *wpath, const char *filename)
Definition: win32.c:1780
if(RB_TYPE_P(r, T_FLOAT))
Definition: bigdecimal.c:1200
Definition: win32.c:588
static int wlink(const WCHAR *from, const WCHAR *to)
Definition: win32.c:4193
int t
Definition: ripper.c:14654
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:5005
static int wrmdir(const WCHAR *wpath)
Definition: win32.c:6340
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:5527
#define EADDRINUSE
Definition: win32.h:513
long rb_w32_write_console(uintptr_t, int)
Definition: win32.c:6149
#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:6616
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:591
static char * wstr_to_mbstr(UINT, const WCHAR *, int, long *)
Definition: win32.c:1873
struct direct dirstr
Definition: dir.h:25
#define GetBit(bits, i)
Definition: win32.c:1737
#define AF_UNSPEC
Definition: sockport.h:69
#define EOPNOTSUPP
Definition: win32.h:504
#define EMSGSIZE
Definition: win32.h:489
#define S_IWOTH
#define FPIPE
Definition: win32.c:2184
DWORD rb_w32_osid(void)
int WSAAPI rb_w32_ioctlsocket(int, long, u_long *)
Definition: win32.c:3055
VALUE rb_str_vcatf(VALUE, const char *, va_list)
Definition: sprintf.c:1288
void endnetent(void)
Definition: win32.c:3750
#define ETIMEDOUT
Definition: win32.h:549
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:3246
struct _NtCmdLineElement NtCmdLineElement
struct servent *WSAAPI rb_w32_getservbyport(int, const char *)
Definition: win32.c:3613
int WSAAPI rb_w32_gethostname(char *, int)
Definition: win32.c:3541
#define Debug(something)
Definition: win32.c:70
int ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
Definition: dir.c:1680
int st_insert(st_table *, st_data_t, st_data_t)
#define set_env_val(vname)
WSABUF * lpBuffers
Definition: win32.c:3248
static int check_if_wdir(const WCHAR *wfile)
Definition: win32.c:5186
int rb_w32_ftruncate(int fd, off_t length)
Definition: win32.c:4812
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:3774
int WSAAPI rb_w32_shutdown(int, int)
Definition: win32.c:3408
#define WSAID_WSASENDMSG
Definition: win32.c:3258
int seq[16]
Definition: win32.c:590
Real * res
Definition: bigdecimal.c:1247
int rb_w32_close(int)
Definition: win32.c:5844
static int wrename(const WCHAR *oldpath, const WCHAR *newpath)
Definition: win32.c:4333
static int dupfd(HANDLE hDup, char flags, int minfd)
Definition: win32.c:3805
#define COMMON_LVB_UNDERSCORE
#define _osfhnd(i)
Definition: win32.c:2141
int WSAAPI rb_w32_getpeername(int, struct sockaddr *, int *)
Definition: win32.c:2986
char * rb_w32_getcwd(char *, int)
Definition: win32.c:4029
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:6590
BDIGIT e
Definition: bigdecimal.c:5106
#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:4480
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:372
#define EDESTADDRREQ
Definition: win32.h:486
#define yield_until(condition)
Definition: win32.c:4924
int rb_w32_fclose(FILE *)
Definition: win32.c:5411
static int overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen)
Definition: win32.c:3139
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:3756
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:1293
#define MTHREAD_ONLY(x)
Definition: win32.c:2111
#define EPROCLIM
Definition: win32.h:566
char rb_w32_fd_is_text(int)
Definition: win32.c:6572
long tms_cutime
Definition: win32.h:712
#define snprintf
static int socketpair_internal(int af, int type, int protocol, SOCKET *sv)
Definition: win32.c:3629
static void finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
Definition: win32.c:5895
BDIGIT v
Definition: bigdecimal.c:5677
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:1865
q
Definition: tcltklib.c:2967
const char * name
Definition: nkf.c:208
#define ECONV_UNDEF_REPLACE
int rb_w32_socketpair(int, int, int, int *)
Definition: win32.c:3721
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:510
int WSAAPI rb_w32_recv(int, char *, int, int)
Definition: win32.c:3214
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:10150
#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:569
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:5017
int rb_w32_check_interrupt(void *)
#define ALLOCV_N(type, v, n)
char * dst
Definition: tcltklib.c:9867
#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:755
int rb_w32_uunlink(const char *)
Definition: win32.c:6410
rb_encoding * rb_enc_find(const char *name)
Definition: encoding.c:659
#define O_BINARY
Definition: _sdbm.c:89
int rb_w32_stat(const char *, struct stat *)
Definition: win32.c:4649
Definition: win32.c:3245
void st_free_table(st_table *)
Definition: st.c:334
int rb_w32_utime(const char *, const struct utimbuf *)
Definition: win32.c:6264
rb_pid_t waitpid(rb_pid_t, int *, int)
Definition: win32.c:3923
Tcl_Interp *int * st
Definition: stubs.c:508
long actime
Definition: file.c:2362
int dummy
Definition: tcltklib.c:4482
#define SEEK_CUR
Definition: io.c:756
static int check_valid_dir(const WCHAR *path)
Definition: win32.c:4550
int rb_w32_uchown(const char *, int, int)
Definition: win32.c:4076
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:4383
#define BACKGROUND_MASK
STATIC void unsigned char * cp
Definition: crypt.c:307
#define NTMALLOC
Definition: win32.c:1375
uintptr_t * argv
Definition: win32.c:5000
#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:5553
#define SIGINT
Definition: win32.h:460
size_t len
Definition: tcltklib.c:3567
static int wunlink(const WCHAR *path)
Definition: win32.c:6389