Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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