Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

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