Ruby 2.0.0p353(2013-11-22revision43784)

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