60#include "internal/static_assert.h"
63#define isdirsep(x) ((x) == '/' || (x) == '\\')
65#if defined _MSC_VER && _MSC_VER <= 1200
66# define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags))
69static int w32_wopen(
const WCHAR *
file,
int oflag,
int perm);
70static int w32_stati128(
const char *path,
struct stati128 *st, UINT cp, BOOL
lstat);
71static char *w32_getenv(
const char *
name, UINT cp);
77#define DLN_FIND_EXTRA_ARG_DECL ,UINT cp
78#define DLN_FIND_EXTRA_ARG ,cp
79#define rb_w32_stati128(path, st) w32_stati128(path, st, cp, FALSE)
80#define getenv(name) w32_getenv(name, cp)
82#define CharNext(p) CharNextExA(cp, (p), 0)
83#define dln_find_exe_r rb_w32_udln_find_exe_r
84#define dln_find_file_r rb_w32_udln_find_file_r
91#define dln_find_exe_r(fname, path, buf, size) rb_w32_udln_find_exe_r(fname, path, buf, size, cp)
92#define dln_find_file_r(fname, path, buf, size) rb_w32_udln_find_file_r(fname, path, buf, size, cp)
97# define PATH_MAX MAX_PATH
98# elif defined HAVE_SYS_PARAM_H
99# include <sys/param.h>
100# define PATH_MAX MAXPATHLEN
112#if RUBY_MSVCRT_VERSION >= 140
113# define _filbuf _fgetc_nolock
114# define _flsbuf _fputc_nolock
116#define enough_to_get(n) (--(n) >= 0)
117#define enough_to_put(n) (--(n) >= 0)
120#define Debug(something) something
122#define Debug(something)
125#define TO_SOCKET(x) _get_osfhandle(x)
129static int has_redirection(
const char *, UINT);
131static int rb_w32_open_osfhandle(
intptr_t osfhandle,
int flags);
132static int wstati128(
const WCHAR *path,
struct stati128 *st, BOOL
lstat);
135static FARPROC get_proc_address(
const char *module,
const char *func, HANDLE *mh);
137#define RUBY_CRITICAL if (0) {} else
144 { ERROR_INVALID_FUNCTION, EINVAL },
145 { ERROR_FILE_NOT_FOUND, ENOENT },
146 { ERROR_PATH_NOT_FOUND, ENOENT },
147 { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
148 { ERROR_ACCESS_DENIED, EACCES },
149 { ERROR_INVALID_HANDLE, EBADF },
150 { ERROR_ARENA_TRASHED, ENOMEM },
151 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
152 { ERROR_INVALID_BLOCK, ENOMEM },
153 { ERROR_BAD_ENVIRONMENT, E2BIG },
154 { ERROR_BAD_FORMAT, ENOEXEC },
155 { ERROR_INVALID_ACCESS, EINVAL },
156 { ERROR_INVALID_DATA, EINVAL },
157 { ERROR_INVALID_DRIVE, ENOENT },
158 { ERROR_CURRENT_DIRECTORY, EACCES },
159 { ERROR_NOT_SAME_DEVICE, EXDEV },
160 { ERROR_NO_MORE_FILES, ENOENT },
161 { ERROR_WRITE_PROTECT, EROFS },
162 { ERROR_BAD_UNIT, ENODEV },
163 { ERROR_NOT_READY, ENXIO },
164 { ERROR_BAD_COMMAND, EACCES },
165 { ERROR_CRC, EACCES },
166 { ERROR_BAD_LENGTH, EACCES },
168 { ERROR_NOT_DOS_DISK, EACCES },
169 { ERROR_SECTOR_NOT_FOUND, EACCES },
170 { ERROR_OUT_OF_PAPER, EACCES },
171 { ERROR_WRITE_FAULT, EIO },
172 { ERROR_READ_FAULT, EIO },
173 { ERROR_GEN_FAILURE, EACCES },
174 { ERROR_LOCK_VIOLATION, EACCES },
175 { ERROR_SHARING_VIOLATION, EACCES },
176 { ERROR_WRONG_DISK, EACCES },
177 { ERROR_SHARING_BUFFER_EXCEEDED, EACCES },
178 { ERROR_BAD_NETPATH, ENOENT },
179 { ERROR_NETWORK_ACCESS_DENIED, EACCES },
180 { ERROR_BAD_NET_NAME, ENOENT },
181 { ERROR_FILE_EXISTS, EEXIST },
182 { ERROR_CANNOT_MAKE, EACCES },
183 { ERROR_FAIL_I24, EACCES },
184 { ERROR_INVALID_PARAMETER, EINVAL },
185 { ERROR_NO_PROC_SLOTS, EAGAIN },
186 { ERROR_DRIVE_LOCKED, EACCES },
187 { ERROR_BROKEN_PIPE, EPIPE },
188 { ERROR_DISK_FULL, ENOSPC },
189 { ERROR_INVALID_TARGET_HANDLE, EBADF },
190 { ERROR_INVALID_HANDLE, EINVAL },
191 { ERROR_WAIT_NO_CHILDREN, ECHILD },
192 { ERROR_CHILD_NOT_COMPLETE, ECHILD },
193 { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
194 { ERROR_NEGATIVE_SEEK, EINVAL },
195 { ERROR_SEEK_ON_DEVICE, EACCES },
196 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
197 { ERROR_DIRECTORY, ENOTDIR },
198 { ERROR_NOT_LOCKED, EACCES },
199 { ERROR_BAD_PATHNAME, ENOENT },
200 { ERROR_MAX_THRDS_REACHED, EAGAIN },
201 { ERROR_LOCK_FAILED, EACCES },
202 { ERROR_ALREADY_EXISTS, EEXIST },
203 { ERROR_INVALID_STARTING_CODESEG, ENOEXEC },
204 { ERROR_INVALID_STACKSEG, ENOEXEC },
205 { ERROR_INVALID_MODULETYPE, ENOEXEC },
206 { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC },
207 { ERROR_EXE_MARKED_INVALID, ENOEXEC },
208 { ERROR_BAD_EXE_FORMAT, ENOEXEC },
209 { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC },
210 { ERROR_INVALID_MINALLOCSIZE, ENOEXEC },
211 { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC },
212 { ERROR_IOPL_NOT_ENABLED, ENOEXEC },
213 { ERROR_INVALID_SEGDPL, ENOEXEC },
214 { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC },
215 { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC },
216 { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC },
217 { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC },
218 { ERROR_FILENAME_EXCED_RANGE, ENOENT },
219 { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
220#ifndef ERROR_PIPE_LOCAL
221#define ERROR_PIPE_LOCAL 229L
224 { ERROR_BAD_PIPE, EPIPE },
225 { ERROR_PIPE_BUSY, EAGAIN },
226 { ERROR_NO_DATA, EPIPE },
227 { ERROR_PIPE_NOT_CONNECTED, EPIPE },
228 { ERROR_OPERATION_ABORTED, EINTR },
229 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM },
230 { ERROR_MOD_NOT_FOUND, ENOENT },
231 { ERROR_PRIVILEGE_NOT_HELD, EACCES, },
232 { ERROR_CANT_RESOLVE_FILENAME,
ELOOP, },
235 { WSAEACCES, EACCES },
236 { WSAEFAULT, EFAULT },
237 { WSAEINVAL, EINVAL },
238 { WSAEMFILE, EMFILE },
267 { WSAENAMETOOLONG, ENAMETOOLONG },
271 { WSAENOTEMPTY, ENOTEMPTY },
288 for (i = 0; i < (
int)(
sizeof(errmap) /
sizeof(*errmap)); i++) {
290 return errmap[i].err;
294 if (
winerr >= WSABASEERR) {
300#define map_errno rb_w32_map_errno
302static const char *NTLoginName;
304static OSVERSIONINFO osver;
310 memset(&osver, 0,
sizeof(OSVERSIONINFO));
311 osver.dwOSVersionInfoSize =
sizeof(OSVERSIONINFO);
312 GetVersionEx(&osver);
320 return osver.dwPlatformId;
328 return osver.dwMajorVersion;
339 DWORD err = GetLastError(); \
340 if (err == ERROR_LOCK_VIOLATION || err == ERROR_IO_PENDING) \
341 errno = EWOULDBLOCK; \
342 else if (err == ERROR_NOT_LOCKED) \
345 errno = map_errno(err); \
348#define LK_LEN ULONG_MAX
356 const HANDLE fh = (HANDLE)self;
357 const int oper =
argc;
359 memset(&o, 0,
sizeof(o));
373 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
402translate_wchar(WCHAR *p,
int from,
int to)
413translate_char(
char *p,
int from,
int to, UINT cp)
416 if ((
unsigned char)*p == from)
418 p = CharNextExA(cp, p, 0);
423#ifndef CSIDL_LOCAL_APPDATA
424#define CSIDL_LOCAL_APPDATA 28
426#ifndef CSIDL_COMMON_APPDATA
427#define CSIDL_COMMON_APPDATA 35
430#define CSIDL_WINDOWS 36
433#define CSIDL_SYSTEM 37
436#define CSIDL_PROFILE 40
441get_special_folder(
int n, WCHAR *
buf,
size_t len)
446 typedef BOOL (WINAPI *get_path_func)(LPITEMIDLIST, WCHAR*,
DWORD,
int);
447 static get_path_func func = (get_path_func)-1;
449 if (func == (get_path_func)-1) {
450 func = (get_path_func)
451 get_proc_address(
"shell32",
"SHGetPathFromIDListEx",
NULL);
453 if (!func &&
len < MAX_PATH)
return FALSE;
455 if (SHGetSpecialFolderLocation(
NULL, n, &pidl) == 0) {
460 f = SHGetPathFromIDListW(pidl,
buf);
463 alloc->lpVtbl->Free(alloc, pidl);
464 alloc->lpVtbl->Release(alloc);
471regulate_path(WCHAR *path)
473 WCHAR *p = translate_wchar(path,
L'\\',
L'/');
474 if (p - path == 2 && path[1] ==
L':') {
482get_proc_address(
const char *module,
const char *func, HANDLE *mh)
488 h = LoadLibrary(module);
490 h = GetModuleHandle(module);
494 ptr = GetProcAddress(h, func);
515#if defined _MSC_VER && _MSC_VER <= 1200
517#define GetSystemWindowsDirectoryW GetWindowsDirectoryW
524 static const WCHAR temp[] =
L"temp";
528 if (GetSystemWindowsDirectoryW(path,
len))
return 0;
530 p = translate_wchar(path,
L'\\',
L'/');
531 if (*(p - 1) !=
L'/') *p++ =
L'/';
532 if ((UINT)(p - path +
numberof(temp)) >=
len)
return 0;
533 memcpy(p, temp,
sizeof(temp));
534 return (UINT)(p - path +
numberof(temp) - 1);
549 WCHAR *buffer =
NULL;
550 size_t buffer_len = MAX_PATH,
len = 0;
552 HOME_NONE, ENV_HOME, ENV_DRIVEPATH, ENV_USERPROFILE
553 } home_type = HOME_NONE;
555 if ((
len = GetEnvironmentVariableW(
L"HOME",
NULL, 0)) != 0) {
557 home_type = ENV_HOME;
559 else if ((
len = GetEnvironmentVariableW(
L"HOMEDRIVE",
NULL, 0)) != 0) {
561 if ((
len = GetEnvironmentVariableW(
L"HOMEPATH",
NULL, 0)) != 0) {
563 home_type = ENV_DRIVEPATH;
566 else if ((
len = GetEnvironmentVariableW(
L"USERPROFILE",
NULL, 0)) != 0) {
568 home_type = ENV_USERPROFILE;
572 buffer =
ALLOC_N(WCHAR, buffer_len);
576 GetEnvironmentVariableW(
L"HOME", buffer, buffer_len);
579 len = GetEnvironmentVariableW(
L"HOMEDRIVE", buffer, buffer_len);
580 GetEnvironmentVariableW(
L"HOMEPATH", buffer +
len, buffer_len -
len);
582 case ENV_USERPROFILE:
583 GetEnvironmentVariableW(
L"USERPROFILE", buffer, buffer_len);
586 if (!get_special_folder(
CSIDL_PROFILE, buffer, buffer_len) &&
587 !get_special_folder(CSIDL_PERSONAL, buffer, buffer_len)) {
591 REALLOC_N(buffer, WCHAR, lstrlenW(buffer) + 1);
596 regulate_path(buffer);
605 static const WCHAR TMPDIR[] =
L"TMPDIR";
610#define set_env_val(vname) do { \
611 typedef char wk_name_offset[(numberof(wk.name) - (numberof(vname) - 1)) * 2 + 1]; \
612 WCHAR *const buf = wk.name + sizeof(wk_name_offset) / 2; \
613 MEMCPY(buf, vname, WCHAR, numberof(vname) - 1); \
628 else if (GetEnvironmentVariableW(
L"USERPROFILE",
env,
numberof(
env))) {
634 else if (get_special_folder(CSIDL_PERSONAL,
env,
numberof(
env))) {
646 NTLoginName =
"<Unknown>";
668static void init_stdhandle(
void);
670#if RUBY_MSVCRT_VERSION >= 80
673invalid_parameter(
const wchar_t *expr,
const wchar_t *func,
const wchar_t *
file,
unsigned int line,
uintptr_t dummy)
678int ruby_w32_rtc_error;
682rtc_error_handler(
int e,
const char *src,
int line,
const char *exe,
const char *fmt, ...)
687 if (!ruby_w32_rtc_error)
return 0;
698static CRITICAL_SECTION select_mutex;
700static CRITICAL_SECTION socklist_mutex;
703static CRITICAL_SECTION conlist_mutex;
705#define conlist_disabled ((st_table *)-1)
707static char *uenvarea;
729constat_delete(HANDLE h)
731 EnterCriticalSection(&conlist_mutex);
737 LeaveCriticalSection(&conlist_mutex);
745 DeleteCriticalSection(&select_mutex);
746 DeleteCriticalSection(&socklist_mutex);
747 DeleteCriticalSection(&conlist_mutex);
758 EnterCriticalSection(&socklist_mutex);
763 LeaveCriticalSection(&socklist_mutex);
765 EnterCriticalSection(&conlist_mutex);
771 LeaveCriticalSection(&conlist_mutex);
776install_vm_exit_handler(
void)
778 static bool installed = 0;
797 version = MAKEWORD(2, 0);
798 if (WSAStartup(version, &retdata))
799 rb_fatal(
"Unable to locate winsock library!");
800 if (LOBYTE(retdata.wVersion) != 2)
801 rb_fatal(
"could not find version 2 of winsock dll");
803 InitializeCriticalSection(&select_mutex);
804 InitializeCriticalSection(&socklist_mutex);
805 InitializeCriticalSection(&conlist_mutex);
807 atexit(exit_handler);
810#define MAKE_SOCKDATA(af, fl) ((int)((((int)af)<<4)|((fl)&0xFFFF)))
811#define GET_FAMILY(v) ((int)(((v)>>4)&0xFFFF))
812#define GET_FLAGS(v) ((int)((v)&0xFFFF))
816socklist_insert(SOCKET sock,
int flag)
820 EnterCriticalSection(&socklist_mutex);
823 install_vm_exit_handler();
826 LeaveCriticalSection(&socklist_mutex);
833socklist_lookup(SOCKET sock,
int *flagp)
838 EnterCriticalSection(&socklist_mutex);
846 LeaveCriticalSection(&socklist_mutex);
853socklist_delete(SOCKET *sockp,
int *flagp)
859 EnterCriticalSection(&socklist_mutex);
866 *sockp = (SOCKET)
key;
873 LeaveCriticalSection(&socklist_mutex);
878static int w32_cmdvector(
const WCHAR *,
char ***, UINT,
rb_encoding *);
886#if RUBY_MSVCRT_VERSION >= 80
887 static void set_pioinfo_extra(
void);
889 _CrtSetReportMode(_CRT_ASSERT, 0);
890 _set_invalid_parameter_handler(invalid_parameter);
891 _RTC_SetErrorFunc(rtc_error_handler);
894 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
920 return (
char *)NTLoginName;
923#define MAXCHILDNUM 256
926static struct ChildRecord {
932#define FOREACH_CHILD(v) do { \
933 struct ChildRecord* v; \
934 for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
935#define END_FOREACH_CHILD } while (0)
938static struct ChildRecord *
939FindChildSlot(rb_pid_t pid)
943 if (child->pid == pid) {
951static struct ChildRecord *
952FindChildSlotByHandle(HANDLE h)
956 if (child->hProcess == h) {
965CloseChildHandle(
struct ChildRecord *child)
967 HANDLE h = child->hProcess;
968 child->hProcess =
NULL;
974static struct ChildRecord *
975FindFreeChildSlot(
void)
980 child->hProcess =
NULL;
994#define InternalCmdsMax 8
1049internal_match(
const void *
key,
const void *elem)
1056is_command_com(
const char *interp)
1058 int i =
strlen(interp) - 11;
1060 if ((i == 0 || (i > 0 &&
isdirsep(interp[i-1]))) &&
1067static int internal_cmd_match(
const char *cmdname,
int nt);
1071is_internal_cmd(
const char *cmd,
int nt)
1073 char cmdname[9], *b = cmdname, c;
1076 if (!(c = *cmd++))
return 0;
1077 }
while (isspace(c));
1080 while (isalpha(c)) {
1082 if (b == cmdname +
sizeof(cmdname))
return 0;
1085 if (c ==
'.') c = *cmd;
1087 case '<':
case '>':
case '|':
1089 case '\0':
case ' ':
case '\t':
case '\n':
1095 return internal_cmd_match(cmdname, nt);
1100internal_cmd_match(
const char *cmdname,
int nt)
1104 nm = bsearch(cmdname, szInternalCmds,
1105 sizeof(szInternalCmds) /
sizeof(*szInternalCmds),
1106 sizeof(*szInternalCmds),
1108 if (!nm || !(nm[0] & (nt ? 2 : 1)))
1117 return _get_osfhandle(fh);
1122join_argv(
char *cmd,
char *
const *
argv, BOOL escape, UINT cp,
int backslash)
1126 int len, n, bs, quote;
1128 for (
t =
argv, q = cmd,
len = 0; (p = *
t) != 0;
t++) {
1131 if (!*p || strpbrk(p,
" \t\"'")) {
1136 for (bs = 0; *p; ++p) {
1150 memset(q,
'\\', bs);
1155 case '<':
case '>':
case '|':
case '^':
1156 if (escape && !quote) {
1157 len += (n = p - s) + 1;
1168 p = CharNextExA(cp, p, 0) - 1;
1172 len += (n = p - s) + 1;
1176 if (backslash > 0) {
1179 translate_char(q,
'/',
'\\', cp);
1182 if (quote) *q++ =
'"';
1195#define STRNDUPV(ptr, v, src, len) \
1196 (((char *)memcpy(((ptr) = ALLOCV((v), (len) + 1)), (src), (len)))[len] = 0)
1200check_spawn_mode(
int mode)
1214child_result(
struct ChildRecord *child,
int mode)
1222 if (
mode == P_OVERLAY) {
1223 WaitForSingleObject(child->hProcess, INFINITE);
1224 GetExitCodeProcess(child->hProcess, &exitcode);
1225 CloseChildHandle(child);
1233CreateChild(
struct ChildRecord *child,
const WCHAR *cmd,
const WCHAR *
prog, HANDLE hInput, HANDLE hOutput, HANDLE hError,
DWORD dwCreationFlags)
1236 STARTUPINFOW aStartupInfo;
1237 PROCESS_INFORMATION aProcessInformation;
1238 SECURITY_ATTRIBUTES sa;
1240 if (!cmd && !
prog) {
1250 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
1251 sa.lpSecurityDescriptor =
NULL;
1252 sa.bInheritHandle =
TRUE;
1254 memset(&aStartupInfo, 0,
sizeof(aStartupInfo));
1255 memset(&aProcessInformation, 0,
sizeof(aProcessInformation));
1256 aStartupInfo.cb =
sizeof(aStartupInfo);
1257 aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
1259 aStartupInfo.hStdInput = hInput;
1262 aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1265 aStartupInfo.hStdOutput = hOutput;
1268 aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1271 aStartupInfo.hStdError = hError;
1274 aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1277 dwCreationFlags |= NORMAL_PRIORITY_CLASS;
1279 if (lstrlenW(cmd) > 32767) {
1286 fRet = CreateProcessW(
prog, (WCHAR *)cmd, &sa, &sa,
1287 sa.bInheritHandle, dwCreationFlags,
NULL,
NULL,
1288 &aStartupInfo, &aProcessInformation);
1297 CloseHandle(aProcessInformation.hThread);
1299 child->hProcess = aProcessInformation.hProcess;
1300 child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
1307is_batch(
const char *cmd)
1310 if (
len <= 4)
return 0;
1312 if (*cmd++ !=
'.')
return 0;
1318#define filecp rb_w32_filecp
1319#define mbstr_to_wstr rb_w32_mbstr_to_wstr
1320#define wstr_to_mbstr rb_w32_wstr_to_mbstr
1321#define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen)
1322#define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen)
1323#define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen)
1324#define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen)
1325#define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen)
1326#define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen)
1336 struct ChildRecord child;
1340 HANDLE outHandle =
NULL;
1359 if (!CreateChild(&child, wcmd, wprog,
NULL, outHandle, outHandle, 0)) {
1365 return child.hProcess;
1370w32_spawn(
int mode,
const char *cmd,
const char *
prog, UINT cp)
1374 const char *shell =
NULL;
1375 WCHAR *wcmd =
NULL, *wshell =
NULL;
1381 char *cmd_sep =
NULL;
1383 if (check_spawn_mode(
mode))
return -1;
1391 translate_char(p,
'/',
'\\', cp);
1398 if ((shell = w32_getenv(
"RUBYSHELL", cp)) && (redir = has_redirection(cmd, cp))) {
1399 size_t shell_len =
strlen(shell);
1400 char *tmp =
ALLOCV(v, shell_len +
strlen(cmd) +
sizeof(
" -c ") + 2);
1401 memcpy(tmp, shell, shell_len + 1);
1402 translate_char(tmp,
'/',
'\\', cp);
1403 sprintf(tmp + shell_len,
" -c \"%s\"", cmd);
1406 else if ((shell = w32_getenv(
"COMSPEC", cp)) &&
1407 (nt = !is_command_com(shell),
1408 (redir < 0 ? has_redirection(cmd, cp) : redir) ||
1409 is_internal_cmd(cmd, nt))) {
1411 sprintf(tmp, nt ?
"%s /c \"%s\"" :
"%s /c %s", shell, cmd);
1415 int len = 0, quote = (*cmd ==
'"') ?
'"' : (*cmd ==
'\'') ?
'\'' : 0;
1417 for (
prog = cmd + !!quote;;
prog = CharNextExA(cp,
prog, 0)) {
1418 if (*
prog ==
'/') slash = 1;
1428 if ((
unsigned char)*
prog == quote) {
1434 if (quote)
continue;
1440 sep = *(cmd_sep = &p[
len]);
1448 if (p && slash) translate_char(p,
'/',
'\\', cp);
1450 shell = p ? p : cmd;
1454 if (
strchr(shell,
' ')) quote = -1;
1455 if (shell == fbuf) {
1458 else if (shell != p &&
strchr(shell,
'/')) {
1462 if (p) translate_char(p,
'/',
'\\', cp);
1463 if (is_batch(shell)) {
1465 cmd = p =
ALLOCV(v,
len + alen + (quote ? 2 : 0) + 1);
1466 if (quote) *p++ =
'"';
1469 if (quote) *p++ =
'"';
1478 if (cmd_sep) *cmd_sep = sep;
1484 struct ChildRecord *child = FindFreeChildSlot();
1485 if (CreateChild(child, wcmd, wshell,
NULL,
NULL,
NULL, 0)) {
1486 ret = child_result(child,
mode);
1507 return w32_spawn(
mode, cmd,
prog, CP_UTF8);
1512w32_aspawn_flags(
int mode,
const char *
prog,
char *
const *
argv,
DWORD flags, UINT cp)
1516 BOOL ntcmd =
FALSE, tmpnt;
1524 if (check_spawn_mode(
mode))
return -1;
1527 if ((shell = w32_getenv(
"COMSPEC", cp)) &&
1528 internal_cmd_match(
prog, tmpnt = !is_command_com(shell))) {
1535 translate_char(cmd,
'/',
'\\', cp);
1540 if (
len <
sizeof(fbuf))
1544 translate_char(cmd,
'/',
'\\', cp);
1547 if (c_switch || is_batch(
prog)) {
1549 progs[0] = (
char *)
prog;
1551 len = join_argv(
NULL, progs, ntcmd, cp, 1);
1552 if (c_switch)
len += 3;
1556 join_argv(cmd, progs, ntcmd, cp, 1);
1559 prog = c_switch ? shell : 0;
1572 struct ChildRecord *child = FindFreeChildSlot();
1573 if (CreateChild(child, wcmd, wprog,
NULL,
NULL,
NULL, flags)) {
1574 ret = child_result(child,
mode);
1595 return w32_aspawn_flags(
mode,
prog,
argv, flags, CP_UTF8);
1630insert(
const char *path,
VALUE vinfo,
void *enc)
1636 if (!tmpcurr)
return -1;
1640 if (!tmpcurr->
str)
return -1;
1643 *tail = &tmpcurr->
next;
1661 translate_char(
buf,
'\\',
'/', cp);
1666 if (status ||
last == tail)
return 0;
1680has_redirection(
const char *cmd, UINT cp)
1696 else if (quote == *
ptr)
1714 if (*
ptr++ ==
'%')
return TRUE;
1720 ptr = CharNextExA(cp,
ptr, 0);
1728static inline WCHAR *
1729skipspace(WCHAR *
ptr)
1738w32_cmdvector(
const WCHAR *cmd,
char ***vec, UINT cp,
rb_encoding *enc)
1741 int elements, strsz,
done;
1742 int slashes, escape;
1743 WCHAR *
ptr, *base, *cmdline;
1744 char *cptr, *buffer;
1760 ptr = cmdline = wcsdup(cmd);
1771 while (*(
ptr = skipspace(
ptr))) {
1773 quote = slashes = globbing = escape = 0;
1783 if (quote !=
L'\'') slashes++;
1823 if (!(slashes & 1)) {
1826 else if (quote == *
ptr) {
1827 if (quote ==
L'"' && quote ==
ptr[1])
1860 slashes = quote = 0;
1861 while (p < base +
len) {
1865 if (quote !=
L'\'') slashes++;
1870 if (!(slashes & 1) && quote && quote != c) {
1875 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
1876 sizeof(WCHAR) * (base +
len - p));
1877 len -= ((slashes + 1) >> 1) + (~slashes & 1);
1878 p -= (slashes + 1) >> 1;
1879 if (!(slashes & 1)) {
1881 if (quote ==
L'"' && quote == *p)
1902 if (!curr)
goto do_nothing;
1906 if (globbing && (tail = cmdglob(curr, cmdtail, cp, enc))) {
1911 cmdtail = &curr->
next;
1921 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->
next) {
1923 strsz += (curr->
len + 1);
1926 len = (elements+1)*
sizeof(
char *) + strsz;
1930 while ((curr = cmdhead) != 0) {
1931 cmdhead = curr->
next;
1936 for (vptr = *vec; *vptr; ++vptr);
1952 vptr = (
char **) buffer;
1954 cptr = buffer + (elements+1) *
sizeof(
char *);
1956 while ((curr = cmdhead) != 0) {
1958 cptr[curr->
len] =
'\0';
1960 cptr += curr->
len + 1;
1961 cmdhead = curr->
next;
1967 *vec = (
char **) buffer;
1989 get_proc_address(
"kernel32",
"GetFinalPathNameByHandleW",
NULL);
1990 if (!func) func = get_final_path_fail;
1991 get_final_path = func;
1992 return func(
f,
buf,
len, flag);
2002 const DWORD share_mode =
2003 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2004 return CreateFileW(path,
access, share_mode,
NULL, OPEN_EXISTING,
2005 FILE_FLAG_BACKUP_SEMANTICS|
flags,
NULL);
2015#define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT))
2016#define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT))
2018#define BitOfIsDir(n) ((n) * 2)
2019#define BitOfIsRep(n) ((n) * 2 + 1)
2020#define DIRENT_PER_CHAR (CHAR_BIT / 2)
2024open_dir_handle(
const WCHAR *
filename, WIN32_FIND_DATAW *fd)
2043 errno = ENAMETOOLONG;
2048 p = &fullname[
len-1];
2049 if (!(
isdirsep(*p) || *p ==
L':')) *++p =
L'\\';
2056 fh = FindFirstFileW(fullname, fd);
2065w32_wopendir(
const WCHAR *wpath)
2068 WIN32_FIND_DATAW fd;
2081 if (wstati128(wpath, &sbuf,
FALSE) < 0) {
2084 if (!(sbuf.st_mode & S_IFDIR) &&
2085 (!
ISALPHA(wpath[0]) || wpath[1] !=
L':' || wpath[2] !=
L'\0' ||
2086 ((1 << ((wpath[0] & 0x5f) -
'A')) & GetLogicalDrives()) == 0)) {
2090 fh = open_dir_handle(wpath, &fd);
2102 pathlen = lstrlenW(wpath);
2112 len = lstrlenW(fd.cFileName) + 1;
2113 altlen = lstrlenW(fd.cAlternateFileName) + 1;
2130 memcpy(&p->
start[idx +
len], fd.cAlternateFileName, altlen *
sizeof(WCHAR));
2139 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2141 if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
2142 WCHAR *tmppath =
malloc((pathlen +
len + 1) *
sizeof(WCHAR));
2143 memcpy(tmppath, wpath, pathlen *
sizeof(WCHAR));
2144 tmppath[pathlen] =
L'\\';
2145 memcpy(tmppath + pathlen + 1, fd.cFileName,
len *
sizeof(WCHAR));
2152 idx +=
len + altlen;
2153 }
while (FindNextFileW(fh, &fd));
2164 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
2173 int len = WideCharToMultiByte(cp, 0, wstr, clen,
NULL, 0,
NULL,
NULL);
2178 if (clen == -1) --
len;
2190 int len = MultiByteToWideChar(cp, 0,
str, clen,
NULL, 0);
2192 MultiByteToWideChar(cp, 0,
str, clen,
ptr,
len);
2195 if (clen == -1) --
len;
2209 ret = w32_wopendir(wpath);
2222 ret = w32_wopendir(wpath);
2233move_to_next_entry(
DIR *dirp)
2237 dirp->
curr += lstrlenW(dirp->
curr) + 1;
2238 dirp->
curr += lstrlenW(dirp->
curr) + 1;
2251win32_direct_conv(
const WCHAR *
file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2253 UINT cp = *((UINT *)enc);
2269 long len = lstrlenW(wstr);
2276#if SIZEOF_INT < SIZEOF_LONG
2277# error long should equal to int on Windows
2280 len = WideCharToMultiByte(CP_UTF8, 0, wstr, clen,
NULL, 0,
NULL,
NULL);
2312ruby_direct_conv(
const WCHAR *
file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2326readdir_internal(
DIR *dirp, BOOL (*conv)(
const WCHAR *,
const WCHAR *,
struct direct *,
const void *),
const void *enc)
2328 static int dummy = 0;
2363 move_to_next_entry(dirp);
2378 const UINT cp =
filecp();
2379 return readdir_internal(dirp, win32_direct_conv, &cp);
2382 const UINT cp = CP_UTF8;
2383 return readdir_internal(dirp, win32_direct_conv, &cp);
2386 return readdir_internal(dirp, ruby_direct_conv, enc);
2393 const UINT cp = CP_UTF8;
2394 return readdir_internal(dirp, win32_direct_conv, &cp);
2418 while (dirp->
curr && dirp->
loc < loc) {
2419 move_to_next_entry(dirp);
2456#if RUBY_MSVCRT_VERSION >= 140
2471 CRITICAL_SECTION _lock;
2473#define FILE_COUNT(stream) ((vcruntime_file*)stream)->_cnt
2474#define FILE_READPTR(stream) ((vcruntime_file*)stream)->_ptr
2475#define FILE_FILENO(stream) ((vcruntime_file*)stream)->_file
2477#define FILE_COUNT(stream) stream->_cnt
2478#define FILE_READPTR(stream) stream->_ptr
2479#define FILE_FILENO(stream) stream->_file
2483#if RUBY_MSVCRT_VERSION >= 140
2484typedef char lowio_text_mode;
2485typedef char lowio_pipe_lookahead[3];
2488 CRITICAL_SECTION lock;
2491 unsigned char osfile;
2492 lowio_text_mode textmode;
2493 lowio_pipe_lookahead _pipe_lookahead;
2507#if RUBY_MSVCRT_VERSION >= 80
2514#if !defined _CRTIMP || defined __MINGW32__
2516#define _CRTIMP __declspec(dllimport)
2519#if RUBY_MSVCRT_VERSION >= 140
2526static inline ioinfo* _pioinfo(
int);
2529#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
2530#define _osfhnd(i) (_pioinfo(i)->osfhnd)
2531#define _osfile(i) (_pioinfo(i)->osfile)
2532#define rb_acrt_lowio_lock_fh(i) EnterCriticalSection(&_pioinfo(i)->lock)
2533#define rb_acrt_lowio_unlock_fh(i) LeaveCriticalSection(&_pioinfo(i)->lock)
2535#if RUBY_MSVCRT_VERSION >= 80
2540set_pioinfo_extra(
void)
2542#if RUBY_MSVCRT_VERSION >= 140
2543# define FUNCTION_RET 0xc3
2545# define UCRTBASE "ucrtbased.dll"
2547# define UCRTBASE "ucrtbase.dll"
2550 char *p = (
char*)get_proc_address(UCRTBASE,
"_isatty",
NULL);
2558# define FUNCTION_BEFORE_RET_MARK "\x48\x83\xc4"
2559# define FUNCTION_SKIP_BYTES 1
2562# define PIOINFO_MARK "\x48\x8d\x0d"
2565# define PIOINFO_MARK "\x48\x8d\x15"
2570# define FUNCTION_BEFORE_RET_MARK "\x5d"
2571# define FUNCTION_SKIP_BYTES 0
2573# define PIOINFO_MARK "\x8B\x04\x85"
2576 for (pend += 10; pend < p + 300; pend++) {
2578 if (
memcmp(pend, FUNCTION_BEFORE_RET_MARK,
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) == 0 &&
2579 *(pend + (
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) + FUNCTION_SKIP_BYTES) & FUNCTION_RET == FUNCTION_RET) {
2581 for (pend -= (
sizeof(PIOINFO_MARK) - 1); pend > p; pend--) {
2582 if (
memcmp(pend, PIOINFO_MARK,
sizeof(PIOINFO_MARK) - 1) == 0) {
2591 fprintf(stderr,
"unexpected " UCRTBASE
"\n");
2595 p +=
sizeof(PIOINFO_MARK) - 1;
2597 rel = *(int32_t*)(p);
2598 rip = p +
sizeof(int32_t);
2606 fd = _open(
"NUL", O_RDONLY);
2608 if (
_osfhnd(fd) == _get_osfhandle(fd)) {
2620#define pioinfo_extra 0
2631#define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
2632#define _set_osflags(fh, flags) (_osfile(fh) = (flags))
2637#define FNOINHERIT 0x10
2643static int is_console(SOCKET);
2654rb_w32_open_osfhandle(
intptr_t osfhandle,
int flags)
2663 if (flags & O_APPEND)
2669 if (flags & O_NOINHERIT)
2673 hF = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
2674 fh = _open_osfhandle((
intptr_t)hF, 0);
2700#define open_null(fd) \
2702 (nullfd = open("NUL", O_RDWR)) : 0), \
2703 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \
2712 if (
fileno(stdout) < 0) {
2715 if (
fileno(stderr) < 0) {
2718 if (nullfd >= 0 && !keep) close(nullfd);
2719 setvbuf(stderr,
NULL, _IONBF, 0);
2722 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
2724 if (GetConsoleMode(h, &m)) {
2725#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
2726#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
2739 if (socklist_lookup(sock,
NULL))
2764 static char buffer[512];
2771#if WSAEWOULDBLOCK != EWOULDBLOCK
2776 for (s = 0; s < (
int)(
sizeof(errmap)/
sizeof(*errmap)); s++)
2777 if (errmap[s].
winerr == WSAEWOULDBLOCK)
2779 for (i = s; i < (
int)(
sizeof(errmap)/
sizeof(*errmap)); i++)
2780 if (errmap[i].
err == e) {
2781 e = errmap[i].winerr;
2786 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2787 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
2788 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
2789 buffer,
sizeof(buffer),
NULL) == 0 &&
2790 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2791 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
2792 buffer,
sizeof(buffer),
NULL) == 0)
2793 strlcpy(buffer,
"Unknown Error",
sizeof(buffer));
2799 while ((p = strpbrk(p,
"\r\n")) !=
NULL) {
2888 for (i = 0; i < set->fd_count; i++) {
2889 if (set->fd_array[i] == s) {
2890 memmove(&set->fd_array[i], &set->fd_array[i+1],
2891 sizeof(set->fd_array[0]) * (--set->fd_count - i));
2915 max = min(src->fd_count, (UINT)
max);
2916 if ((UINT)dst->
capa < (UINT)
max) {
2917 dst->
capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2922 max *
sizeof(src->fd_array[0]));
2923 dst->
fdset->fd_count = src->fd_count;
2930 if ((UINT)dst->
capa < src->
fdset->fd_count) {
2931 dst->
capa = (src->
fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2936 src->
fdset->fd_count *
sizeof(src->
fdset->fd_array[0]));
2950extract_fd(
rb_fdset_t *dst, fd_set *src,
int (*func)(SOCKET))
2956 while (s < src->fd_count) {
2957 SOCKET fd = src->fd_array[s];
2959 if (!func || (*func)(fd)) {
2963 for (d = 0; d < dst->
fdset->fd_count; d++) {
2964 if (dst->
fdset->fd_array[d] == fd)
2967 if (d == dst->
fdset->fd_count) {
2968 if ((
int)dst->
fdset->fd_count >= dst->
capa) {
2969 dst->
capa = (dst->
fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2972 dst->
fdset->fd_array[dst->
fdset->fd_count++] = fd;
2976 &src->fd_array[s+1],
2977 sizeof(src->fd_array[0]) * (--src->fd_count - s));
2987 return dst ? dst->
fdset->fd_count : m;
2992copy_fd(fd_set *dst, fd_set *src)
2995 if (!src || !dst)
return 0;
2997 for (s = 0; s < src->fd_count; ++s) {
2998 SOCKET fd = src->fd_array[s];
3000 for (d = 0; d < dst->fd_count; ++d) {
3001 if (dst->fd_array[d] == fd)
3004 if (d == dst->fd_count && d < FD_SETSIZE) {
3005 dst->fd_array[dst->fd_count++] = fd;
3009 return dst->fd_count;
3014is_not_socket(SOCKET sock)
3026 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
3034is_readable_pipe(SOCKET sock)
3040 if (PeekNamedPipe((HANDLE)sock,
NULL, 0,
NULL, &n,
NULL)) {
3044 ret = (GetLastError() == ERROR_BROKEN_PIPE);
3053is_console(SOCKET sock)
3060 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n));
3068is_readable_console(SOCKET sock)
3075 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
3076 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
3077 ir.Event.KeyEvent.uChar.AsciiChar) {
3081 ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
3091is_invalid_handle(SOCKET sock)
3098do_select(
int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
3111 EnterCriticalSection(&select_mutex);
3112 r = select(nfds, rd, wr, ex, timeout);
3113 LeaveCriticalSection(&select_mutex);
3114 if (r == SOCKET_ERROR) {
3170 struct timeval *timeout,
void *th)
3179 struct timeval limit = {0, 0};
3181 if (nfds < 0 || (timeout && (timeout->
tv_sec < 0 || timeout->
tv_usec < 0))) {
3187 if (timeout->
tv_sec < 0 ||
3189 timeout->
tv_usec >= 1000000) {
3196 if (limit.
tv_usec >= 1000000) {
3209 nonsock += extract_fd(&else_rd, rd, is_not_socket);
3212 nonsock += extract_fd(&else_wr, wr, is_not_socket);
3215 if (extract_fd(
NULL, else_rd.
fdset, is_invalid_handle) > 0 ||
3216 extract_fd(
NULL, else_wr.
fdset, is_invalid_handle) > 0) {
3224 extract_fd(&pipe_rd, else_rd.
fdset, is_pipe);
3227 extract_fd(&cons_rd, else_rd.
fdset, is_console);
3230 extract_fd(&except, ex, is_not_socket);
3233 if (rd && (
int)rd->fd_count > r) r = (
int)rd->fd_count;
3234 if (wr && (
int)wr->fd_count > r) r = (
int)wr->fd_count;
3235 if (ex && (
int)ex->fd_count > r) r = (
int)ex->fd_count;
3236 if (nfds > r) nfds = r;
3250 extract_fd(&else_rd, pipe_rd.
fdset, is_readable_pipe);
3251 extract_fd(&else_rd, cons_rd.
fdset, is_readable_console);
3254 if (else_rd.
fdset->fd_count || else_wr.
fdset->fd_count) {
3255 r = do_select(nfds, rd, wr, ex, &zero);
3257 r += copy_fd(rd, else_rd.
fdset);
3258 r += copy_fd(wr, else_wr.
fdset);
3274 if (rd) copy_fd(&orig_rd, rd);
3275 if (wr) copy_fd(&orig_wr, wr);
3276 if (ex) copy_fd(&orig_ex, ex);
3277 r = do_select(nfds, rd, wr, ex, &zero);
3279 if (rd) copy_fd(rd, &orig_rd);
3280 if (wr) copy_fd(wr, &orig_wr);
3281 if (ex) copy_fd(ex, &orig_ex);
3288 if (compare(&rest, &
wait) < 0) dowait = &rest;
3290 Sleep(dowait->
tv_sec * 1000 + (dowait->
tv_usec + 999) / 1000);
3314get_wsa_extension_function(SOCKET s, GUID *guid)
3319 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, guid,
sizeof(*guid),
3336 r = accept(
TO_SOCKET(s), addr, addrlen);
3337 if (r != INVALID_SOCKET) {
3338 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
3341 socklist_insert(r, 0);
3363 if (r == SOCKET_ERROR)
3377 r = connect(
TO_SOCKET(s), addr, addrlen);
3378 if (r == SOCKET_ERROR) {
3379 int err = WSAGetLastError();
3380 if (
err != WSAEWOULDBLOCK)
3398 r = getpeername(
TO_SOCKET(s), addr, addrlen);
3399 if (r == SOCKET_ERROR)
3415 r = getsockname(sock, addr, addrlen);
3416 if (r == SOCKET_ERROR) {
3417 DWORD wsaerror = WSAGetLastError();
3418 if (wsaerror == WSAEINVAL) {
3420 if (socklist_lookup(sock, &flags)) {
3423 memset(addr, 0, *addrlen);
3424 addr->sa_family = af;
3443 r = getsockopt(
TO_SOCKET(s), level, optname, optval, optlen);
3444 if (r == SOCKET_ERROR)
3458 r = ioctlsocket(
TO_SOCKET(s), cmd, argp);
3459 if (r == SOCKET_ERROR)
3474 if (r == SOCKET_ERROR)
3492 if (result != SOCKET_ERROR)
3494 else if ((
err = WSAGetLastError()) == WSA_IO_PENDING) {
3498 result = WSAGetOverlappedResult(s, wol, &
size,
TRUE, &flg);
3505 result = SOCKET_ERROR;
3508 if ((
err = WSAGetLastError()) == WSAECONNABORTED && !
input)
3510 else if (
err == WSAEMSGSIZE &&
input) {
3518 case WAIT_OBJECT_0 + 1:
3521 CancelIo((HANDLE)s);
3526 if (
err == WSAECONNABORTED && !
input)
3532 CloseHandle(wol->hEvent);
3539overlapped_socket_io(BOOL
input,
int fd,
char *
buf,
int len,
int flags,
3540 struct sockaddr *addr,
int *addrlen)
3551 socklist_lookup(s, &
mode);
3555 if (addr && addrlen)
3556 r = recvfrom(s,
buf,
len, flags, addr, addrlen);
3558 r = recv(s,
buf,
len, flags);
3559 if (r == SOCKET_ERROR)
3563 if (addr && addrlen)
3564 r = sendto(s,
buf,
len, flags, addr, *addrlen);
3566 r = send(s,
buf,
len, flags);
3567 if (r == SOCKET_ERROR) {
3569 if (
err == WSAECONNABORTED)
3582 memset(&wol, 0,
sizeof(wol));
3587 if (addr && addrlen)
3588 ret = WSARecvFrom(s, &wbuf, 1, &
size, &flg, addr, addrlen,
3591 ret = WSARecv(s, &wbuf, 1, &
size, &flg, &wol,
NULL);
3594 if (addr && addrlen)
3595 ret = WSASendTo(s, &wbuf, 1, &
size, flags, addr, *addrlen,
3598 ret = WSASend(s, &wbuf, 1, &
size, flags, &wol,
NULL);
3602 finish_overlapped_socket(
input, s, &wol, ret, &rlen,
size);
3619 struct sockaddr *from,
int *fromlen)
3621 return overlapped_socket_io(
TRUE, fd,
buf,
len, flags, from, fromlen);
3634 const struct sockaddr *to,
int tolen)
3636 return overlapped_socket_io(
FALSE, fd, (
char *)
buf,
len, flags,
3637 (
struct sockaddr *)to, &tolen);
3640#if !defined(MSG_TRUNC) && !defined(__MINGW32__)
3651#ifndef WSAID_WSARECVMSG
3652#define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
3654#ifndef WSAID_WSASENDMSG
3655#define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
3659#define msghdr_to_wsamsg(msg, wsamsg) \
3662 (wsamsg)->name = (msg)->msg_name; \
3663 (wsamsg)->namelen = (msg)->msg_namelen; \
3664 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
3665 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
3666 for (i = 0; i < (msg)->msg_iovlen; ++i) { \
3667 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
3668 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
3670 (wsamsg)->Control.buf = (msg)->msg_control; \
3671 (wsamsg)->Control.len = (msg)->msg_controllen; \
3672 (wsamsg)->dwFlags = (msg)->msg_flags; \
3679 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET,
WSAMSG *,
DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3680 static WSARecvMsg_t pWSARecvMsg =
NULL;
3691 pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid);
3699 socklist_lookup(s, &
mode);
3702 if ((ret = pWSARecvMsg(s, &wsamsg, &
len,
NULL,
NULL)) == SOCKET_ERROR) {
3711 memset(&wol, 0,
sizeof(wol));
3714 ret = pWSARecvMsg(s, &wsamsg, &
size, &wol,
NULL);
3717 ret = finish_overlapped_socket(
TRUE, s, &wol, ret, &
len,
size);
3719 if (ret == SOCKET_ERROR)
3734 typedef int (WSAAPI *WSASendMsg_t)(SOCKET,
const WSAMSG *,
DWORD,
DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3735 static WSASendMsg_t pWSASendMsg =
NULL;
3746 pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid);
3753 socklist_lookup(s, &
mode);
3756 if ((ret = pWSASendMsg(s, &wsamsg, flags, &
len,
NULL,
NULL)) == SOCKET_ERROR) {
3765 memset(&wol, 0,
sizeof(wol));
3768 ret = pWSASendMsg(s, &wsamsg, flags, &
size, &wol,
NULL);
3771 finish_overlapped_socket(
FALSE, s, &wol, ret, &
len,
size);
3785 r = setsockopt(
TO_SOCKET(s), level, optname, optval, optlen);
3786 if (r == SOCKET_ERROR)
3801 if (r == SOCKET_ERROR)
3809open_ifs_socket(
int af,
int type,
int protocol)
3811 unsigned long proto_buffers_len = 0;
3813 SOCKET
out = INVALID_SOCKET;
3815 if (WSAEnumProtocols(
NULL,
NULL, &proto_buffers_len) == SOCKET_ERROR) {
3816 error_code = WSAGetLastError();
3817 if (error_code == WSAENOBUFS) {
3818 WSAPROTOCOL_INFO *proto_buffers;
3819 int protocols_available = 0;
3821 proto_buffers = (WSAPROTOCOL_INFO *)
malloc(proto_buffers_len);
3822 if (!proto_buffers) {
3823 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
3824 return INVALID_SOCKET;
3827 protocols_available =
3828 WSAEnumProtocols(
NULL, proto_buffers, &proto_buffers_len);
3829 if (protocols_available != SOCKET_ERROR) {
3831 for (i = 0; i < protocols_available; i++) {
3832 if ((af !=
AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
3833 (
type != proto_buffers[i].iSocketType) ||
3834 (protocol != 0 && protocol != proto_buffers[i].iProtocol))
3837 if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
3840 out = WSASocket(af,
type, protocol, &(proto_buffers[i]), 0,
3841 WSA_FLAG_OVERLAPPED);
3844 if (
out == INVALID_SOCKET)
3846 if (
out != INVALID_SOCKET)
3847 SetHandleInformation((HANDLE)
out, HANDLE_FLAG_INHERIT, 0);
3850 free(proto_buffers);
3867 s = open_ifs_socket(af,
type, protocol);
3868 if (s == INVALID_SOCKET) {
3873 fd = rb_w32_open_osfhandle(s, O_RDWR|
O_BINARY|O_NOINHERIT);
3886struct hostent * WSAAPI
3891 r = gethostbyaddr(addr,
len,
type);
3901struct hostent * WSAAPI
3906 r = gethostbyname(
name);
3922 if (r == SOCKET_ERROR)
3928#undef getprotobyname
3931struct protoent * WSAAPI
3936 r = getprotobyname(
name);
3943#undef getprotobynumber
3946struct protoent * WSAAPI
3951 r = getprotobynumber(
num);
3961struct servent * WSAAPI
3966 r = getservbyname(
name, proto);
3976struct servent * WSAAPI
3981 r = getservbyport(port, proto);
3990socketpair_internal(
int af,
int type,
int protocol, SOCKET *sv)
3992 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
3993 struct sockaddr_in sock_in4;
3995 struct sockaddr_in6 sock_in6;
3997 struct sockaddr *addr;
4003#if defined PF_INET && PF_INET != AF_INET
4006 sock_in4.sin_family = AF_INET;
4007 sock_in4.sin_port = 0;
4009 addr = (
struct sockaddr *)&sock_in4;
4010 len =
sizeof(sock_in4);
4014 memset(&sock_in6, 0,
sizeof(sock_in6));
4015 sock_in6.sin6_family = AF_INET6;
4016 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
4017 addr = (
struct sockaddr *)&sock_in6;
4018 len =
sizeof(sock_in6);
4025 if (
type != SOCK_STREAM) {
4034 svr = open_ifs_socket(af,
type, protocol);
4035 if (svr == INVALID_SOCKET)
4037 if (bind(svr, addr,
len) < 0)
4039 if (getsockname(svr, addr, &
len) < 0)
4041 if (
type == SOCK_STREAM)
4044 w = open_ifs_socket(af,
type, protocol);
4045 if (w == INVALID_SOCKET)
4047 if (connect(w, addr,
len) < 0)
4050 r = accept(svr, addr, &
len);
4051 if (r == INVALID_SOCKET)
4053 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
4060 if (r != INVALID_SOCKET)
4062 if (w != INVALID_SOCKET)
4069 if (svr != INVALID_SOCKET)
4082 if (socketpair_internal(af,
type, protocol, pair) < 0)
4084 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|
O_BINARY|O_NOINHERIT);
4086 closesocket(pair[0]);
4087 closesocket(pair[1]);
4090 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|
O_BINARY|O_NOINHERIT);
4093 closesocket(pair[1]);
4102#if !defined(_MSC_VER) || _MSC_VER >= 1400
4105str2guid(
const char *
str, GUID *guid)
4107#define hex2byte(str) \
4108 ((isdigit(*(str)) ? *(str) - '0' : toupper(*(str)) - 'A' + 10) << 4 | (isdigit(*((str) + 1)) ? *((str) + 1) - '0' : toupper(*((str) + 1)) - 'A' + 10))
4112 guid->Data1 = (
long)strtoul(
str, &end, 16);
4114 guid->Data2 = (
unsigned short)strtoul(
str, &end, 16);
4116 guid->Data3 = (
unsigned short)strtoul(
str, &end, 16);
4122 for (i = 0; i < 6; i++) {
4129#ifndef HAVE_TYPE_NET_LUID
4149 IP_ADAPTER_ADDRESSES *
root, *addr;
4153 if (ret != ERROR_BUFFER_OVERFLOW) {
4159 if (ret != ERROR_SUCCESS) {
4165 if (pConvertInterfaceGuidToLuid == (
cigl_t)-1)
4166 pConvertInterfaceGuidToLuid =
4167 (
cigl_t)get_proc_address(
"iphlpapi.dll",
4168 "ConvertInterfaceGuidToLuid",
NULL);
4169 if (pConvertInterfaceLuidToNameA == (
cilnA_t)-1)
4170 pConvertInterfaceLuidToNameA =
4171 (
cilnA_t)get_proc_address(
"iphlpapi.dll",
4172 "ConvertInterfaceLuidToNameA",
NULL);
4174 for (prev =
NULL, addr =
root; addr; addr = addr->Next) {
4185 str2guid(addr->AdapterName, &guid);
4186 if (pConvertInterfaceGuidToLuid && pConvertInterfaceLuidToNameA &&
4187 pConvertInterfaceGuidToLuid(&guid, &luid) == NO_ERROR &&
4188 pConvertInterfaceLuidToNameA(&luid,
name,
sizeof(
name)) == NO_ERROR) {
4195 if (addr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
4197 if (addr->OperStatus == IfOperStatusUp) {
4200 if (addr->FirstUnicastAddress) {
4201 IP_ADAPTER_UNICAST_ADDRESS *cur;
4203 for (cur = addr->FirstUnicastAddress; cur; cur = cur->Next) {
4204 if (cur->Flags & IP_ADAPTER_ADDRESS_TRANSIENT ||
4205 cur->DadState == IpDadStateDeprecated) {
4217 cur->Address.iSockaddrLength);
4273setfl(SOCKET sock,
int arg)
4280 socklist_lookup(sock, &flag);
4288 flag &= ~O_NONBLOCK;
4292 ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
4304dupfd(HANDLE hDup,
int flags,
int minfd)
4314 goto close_fds_and_return;
4317 goto close_fds_and_return;
4319 fds[filled++] = ret;
4320 }
while (filled < (
int)
numberof(fds));
4322 ret = dupfd(hDup, flags, minfd);
4324 close_fds_and_return:
4326 while (filled > 0) {
4327 int fd = fds[--filled];
4353 arg = va_arg(va,
int);
4355 return setfl(sock, arg);
4361 if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
4362 GetCurrentProcess(), &hDup, 0
L,
4364 DUPLICATE_SAME_ACCESS))) {
4370 arg = va_arg(va,
int);
4376 flag &= ~FNOINHERIT;
4377 if ((ret = dupfd(hDup, flag, arg)) == -1)
4383 if (h == -1)
return -1;
4384 if (!GetHandleInformation((HANDLE)h, &flag)) {
4388 return (flag & HANDLE_FLAG_INHERIT) ? 0 :
FD_CLOEXEC;
4392 if (h == -1)
return -1;
4394 arg = va_arg(va,
int);
4396 if (!SetHandleInformation((HANDLE)h, HANDLE_FLAG_INHERIT,
4397 (arg &
FD_CLOEXEC) ? 0 : HANDLE_FLAG_INHERIT)) {
4419 return setfl(sock, nonblock ?
O_NONBLOCK : 0);
4421 else if (is_pipe(sock)) {
4428 state |= PIPE_NOWAIT;
4431 state &= ~PIPE_NOWAIT;
4433 if (!SetNamedPipeHandleState((HANDLE)sock, &
state,
NULL,
NULL)) {
4457poll_child_status(
struct ChildRecord *child,
int *stat_loc)
4462 if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
4464 err = GetLastError();
4466 case ERROR_INVALID_PARAMETER:
4469 case ERROR_INVALID_HANDLE:
4477 CloseChildHandle(child);
4480 if (exitcode != STILL_ACTIVE) {
4487 CloseChildHandle(child);
4489 *stat_loc = exitcode << 8;
4490 if (exitcode & 0xC0000000) {
4491 static const struct {
4495 {STATUS_ACCESS_VIOLATION, SIGSEGV},
4496 {STATUS_ILLEGAL_INSTRUCTION, SIGILL},
4497 {STATUS_PRIVILEGED_INSTRUCTION, SIGILL},
4498 {STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE},
4499 {STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE},
4500 {STATUS_FLOAT_INEXACT_RESULT, SIGFPE},
4501 {STATUS_FLOAT_INVALID_OPERATION, SIGFPE},
4502 {STATUS_FLOAT_OVERFLOW, SIGFPE},
4503 {STATUS_FLOAT_STACK_CHECK, SIGFPE},
4504 {STATUS_FLOAT_UNDERFLOW, SIGFPE},
4505#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
4506 {STATUS_FLOAT_MULTIPLE_FAULTS, SIGFPE},
4508#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
4509 {STATUS_FLOAT_MULTIPLE_TRAPS, SIGFPE},
4511 {STATUS_CONTROL_C_EXIT,
SIGINT},
4515 if (table[i].status == exitcode) {
4516 *stat_loc |= table[i].sig;
4522 *stat_loc |= SIGSEGV;
4549 struct ChildRecord* cause;
4552 if (!child->pid || child->pid < 0)
continue;
4553 if ((pid = poll_child_status(child, stat_loc)))
return pid;
4554 events[
count++] = child->hProcess;
4562 if (ret == WAIT_TIMEOUT)
return 0;
4563 if ((ret -= WAIT_OBJECT_0) ==
count) {
4571 cause = FindChildSlotByHandle(events[ret]);
4576 return poll_child_status(cause, stat_loc);
4579 struct ChildRecord* child = FindChildSlot(pid);
4586 while (!(pid = poll_child_status(child, stat_loc))) {
4589 if (ret == WAIT_OBJECT_0 + 1)
return -1;
4590 if (ret != WAIT_OBJECT_0) {
4599 if (pid == -1 && retried) pid = 0;
4605#include <sys/timeb.h>
4607static int have_precisetime = -1;
4610get_systemtime(FILETIME *ft)
4612 typedef void (WINAPI *get_time_func)(FILETIME *ft);
4613 static get_time_func func = (get_time_func)-1;
4615 if (func == (get_time_func)-1) {
4617 func = (get_time_func)get_proc_address(
"kernel32",
"GetSystemTimePreciseAsFileTime",
NULL);
4619 func = GetSystemTimeAsFileTime;
4620 have_precisetime = 0;
4623 have_precisetime = 1;
4632filetime_split(
const FILETIME* ft,
long *subsec)
4635 unsigned LONG_LONG
lt;
4636 const unsigned LONG_LONG subsec_unit = (
unsigned LONG_LONG)10 * 1000 * 1000;
4638 tmp.LowPart = ft->dwLowDateTime;
4639 tmp.HighPart = ft->dwHighDateTime;
4646 lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * subsec_unit;
4648 *subsec = (
long)(
lt % subsec_unit);
4649 return (time_t)(
lt / subsec_unit);
4659 get_systemtime(&ft);
4660 tv->
tv_sec = filetime_split(&ft, &subsec);
4676 get_systemtime(&ft);
4677 sp->
tv_sec = filetime_split(&ft, &subsec);
4684 LARGE_INTEGER
count;
4685 if (!QueryPerformanceFrequency(&freq)) {
4689 if (!QueryPerformanceCounter(&
count)) {
4694 if (freq.QuadPart < 1000000000)
4695 sp->
tv_nsec = (
count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
4697 sp->
tv_nsec = (
long)((
count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
4720 if (!QueryPerformanceFrequency(&freq)) {
4725 sp->
tv_nsec = (
long)(1000000000.0 / freq.QuadPart);
4736w32_getcwd(
char *buffer,
int size, UINT cp,
void *alloc(
int,
void *),
void *arg)
4741 len = GetCurrentDirectoryW(0,
NULL);
4753 if (!GetCurrentDirectoryW(
len, p)) {
4758 wlen = translate_wchar(p,
L'\\',
L'/') - p + 1;
4767 buffer = (*alloc)(
len, arg);
4773 WideCharToMultiByte(cp, 0, p, wlen, buffer,
len,
NULL,
NULL);
4780getcwd_alloc(
int size,
void *dummy)
4796 return w32_getcwd(buffer,
size, CP_UTF8, getcwd_alloc,
NULL);
4801getcwd_value(
int size,
void *arg)
4813 w32_getcwd(
NULL, 0, CP_UTF8, getcwd_value, &cwd);
4819chown(
const char *path,
int owner,
int group)
4832lchown(
const char *path,
int owner,
int group)
4850 if (pid < 0 || (pid == 0 && sig !=
SIGINT)) {
4855 if ((
unsigned int)pid == GetCurrentProcessId() &&
4856 (sig != 0 && sig !=
SIGKILL)) {
4857 if ((ret = raise(sig)) != 0) {
4868 OpenProcess(PROCESS_QUERY_INFORMATION,
FALSE, (
DWORD)pid);
4870 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4886 DWORD ctrlEvent = CTRL_C_EVENT;
4890 ctrlEvent = CTRL_BREAK_EVENT;
4892 if (!GenerateConsoleCtrlEvent(ctrlEvent, (
DWORD)pid)) {
4893 if ((
err = GetLastError()) == 0)
4905 struct ChildRecord* child = FindChildSlot(pid);
4907 hProc = child->hProcess;
4910 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
FALSE, (
DWORD)pid);
4913 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4923 if (!GetExitCodeProcess(hProc, &status)) {
4927 else if (status == STILL_ACTIVE) {
4928 if (!TerminateProcess(hProc, 0)) {
4955wlink(
const WCHAR *from,
const WCHAR *to)
4957 if (!CreateHardLinkW(to, from,
NULL)) {
4979 ret = wlink(wfrom, wto);
4987link(
const char *from,
const char *to)
4999 ret = wlink(wfrom, wto);
5006#ifndef FILE_DEVICE_FILE_SYSTEM
5007# define FILE_DEVICE_FILE_SYSTEM 0x00000009
5009#ifndef FSCTL_GET_REPARSE_POINT
5010# define FSCTL_GET_REPARSE_POINT ((0x9<<16)|(42<<2))
5012#ifndef IO_REPARSE_TAG_SYMLINK
5013# define IO_REPARSE_TAG_SYMLINK 0xA000000CL
5024 f = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5026 return GetLastError();
5034 rp->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
5035 e = ERROR_INVALID_PARAMETER;
5052 if (e == ERROR_MORE_DATA) {
5060 case ERROR_MORE_DATA:
5069 size_t bufsize, WCHAR **result,
DWORD *
len)
5071 int e = reparse_symlink(path,
rp, bufsize);
5074 if (!e || e == ERROR_MORE_DATA) {
5077 name = ((
char *)
rp->SymbolicLinkReparseBuffer.PathBuffer +
5078 rp->SymbolicLinkReparseBuffer.PrintNameOffset);
5079 ret =
rp->SymbolicLinkReparseBuffer.PrintNameLength;
5080 *
len = ret /
sizeof(WCHAR);
5082 else if (
rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
5083 static const WCHAR *volume =
L"Volume{";
5085 name = ((
char *)
rp->MountPointReparseBuffer.PathBuffer +
5086 rp->MountPointReparseBuffer.SubstituteNameOffset +
5087 volume_prefix_len *
sizeof(WCHAR));
5088 ret =
rp->MountPointReparseBuffer.SubstituteNameLength;
5089 *
len = ret /
sizeof(WCHAR);
5090 ret -= volume_prefix_len *
sizeof(WCHAR);
5091 if (ret >
sizeof(volume) - 1 *
sizeof(WCHAR) &&
5092 memcmp(
name, volume,
sizeof(volume) - 1 *
sizeof(WCHAR)) == 0)
5100 if ((
char *)
name + ret +
sizeof(WCHAR) > (
char *)
rp + bufsize)
5104 ((WCHAR *)
name)[ret/
sizeof(WCHAR)] =
L'\0';
5105 translate_wchar(
name,
L'\\',
L'/');
5115w32_readlink(UINT cp,
const char *path,
char *
buf,
size_t bufsize)
5118 DWORD len = MultiByteToWideChar(cp, 0, path, -1,
NULL, 0);
5120 WCHAR *wname, *wpath =
ALLOCV(wtmp,
size +
sizeof(WCHAR) *
len);
5125 MultiByteToWideChar(cp, 0, path, -1, wpath,
len);
5127 if (e && e != ERROR_MORE_DATA) {
5132 len = lstrlenW(wname) + 1;
5133 ret = WideCharToMultiByte(cp, 0, wname,
len,
buf, bufsize,
NULL,
NULL);
5150 return w32_readlink(CP_UTF8, path,
buf, bufsize);
5157 return w32_readlink(
filecp(), path,
buf, bufsize);
5160#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5161#define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1)
5163#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
5164#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
5169w32_symlink(UINT cp,
const char *src,
const char *
link)
5171 int atts, len1, len2;
5173 WCHAR *wsrc, *wlink;
5178 typedef BOOLEAN (WINAPI *create_symbolic_link_func)(WCHAR*, WCHAR*,
DWORD);
5179 static create_symbolic_link_func create_symbolic_link =
5180 (create_symbolic_link_func)-1;
5183 if (create_symbolic_link == (create_symbolic_link_func)-1) {
5184 create_symbolic_link = (create_symbolic_link_func)
5185 get_proc_address(
"kernel32",
"CreateSymbolicLinkW",
NULL);
5187 if (!create_symbolic_link) {
5200 len1 = MultiByteToWideChar(cp, 0, src, -1,
NULL, 0);
5201 len2 = MultiByteToWideChar(cp, 0,
link, -1,
NULL, 0);
5203 wlink = wsrc + len1;
5204 MultiByteToWideChar(cp, 0, src, -1, wsrc, len1);
5205 MultiByteToWideChar(cp, 0,
link, -1, wlink, len2);
5206 translate_wchar(wsrc,
L'/',
L'\\');
5208 atts = GetFileAttributesW(wsrc);
5209 if (atts != -1 && atts & FILE_ATTRIBUTE_DIRECTORY)
5211 ret = create_symbolic_link(wlink, wsrc, flag |= create_flag);
5213 (e = GetLastError()) == ERROR_INVALID_PARAMETER &&
5216 flag &= ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
5217 ret = create_symbolic_link(wlink, wsrc, flag);
5218 if (!ret) e = GetLastError();
5233 return w32_symlink(CP_UTF8, src,
link);
5247 return waitpid(-1, status, 0);
5252w32_getenv(
const char *
name, UINT cp)
5254 WCHAR *wenvarea, *wenv;
5265 wenvarea = GetEnvironmentStringsW();
5270 for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
5271 wlen += lstrlenW(wenv) + 1;
5273 FreeEnvironmentStringsW(wenvarea);
5288 return w32_getenv(
name, CP_UTF8);
5295 return w32_getenv(
name, CP_ACP);
5300get_attr_vsn(
const WCHAR *path,
DWORD *atts,
DWORD *vsn)
5302 BY_HANDLE_FILE_INFORMATION st = {0};
5304 HANDLE h = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5307 ASSUME(e = GetLastError());
5310 if (!GetFileInformationByHandle(h, &st)) {
5311 ASSUME(e = GetLastError());
5314 *atts = st.dwFileAttributes;
5315 *vsn = st.dwVolumeSerialNumber;
5323wrename(
const WCHAR *oldpath,
const WCHAR *newpath)
5327 DWORD oldvsn = 0, newvsn = 0, e;
5329 e = get_attr_vsn(oldpath, &oldatts, &oldvsn);
5334 if (oldatts & FILE_ATTRIBUTE_REPARSE_POINT) {
5335 HANDLE fh = open_special(oldpath, 0, 0);
5338 if (e == ERROR_CANT_RESOLVE_FILENAME) {
5345 get_attr_vsn(newpath, &newatts, &newvsn);
5348 if (newatts != (
DWORD)-1 && newatts & FILE_ATTRIBUTE_READONLY)
5349 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
5351 if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
5355 DWORD e = GetLastError();
5356 if ((e == ERROR_ACCESS_DENIED) && (oldatts & FILE_ATTRIBUTE_DIRECTORY) &&
5363 SetFileAttributesW(newpath, oldatts);
5382 ret = wrename(wfrom, wto);
5401 ret = wrename(wfrom, wto);
5409isUNCRoot(
const WCHAR *path)
5411 if (path[0] ==
L'\\' && path[1] ==
L'\\') {
5412 const WCHAR *p = path + 2;
5413 if (p[0] ==
L'?' && p[1] ==
L'\\') {
5421 for (p++; *p; p++) {
5425 if (!p[0] || !p[1] || (p[1] ==
L'.' && !p[2]))
5432#define COPY_STAT(src, dest, size_cast) do { \
5433 (dest).st_dev = (src).st_dev; \
5434 (dest).st_ino = (src).st_ino; \
5435 (dest).st_mode = (src).st_mode; \
5436 (dest).st_nlink = (src).st_nlink; \
5437 (dest).st_uid = (src).st_uid; \
5438 (dest).st_gid = (src).st_gid; \
5439 (dest).st_rdev = (src).st_rdev; \
5440 (dest).st_size = size_cast(src).st_size; \
5441 (dest).st_atime = (src).st_atime; \
5442 (dest).st_mtime = (src).st_mtime; \
5443 (dest).st_ctime = (src).st_ctime; \
5446static time_t filetime_to_unixtime(
const FILETIME *ft);
5447static long filetime_to_nsec(
const FILETIME *ft);
5448static WCHAR *name_for_stat(WCHAR *
buf,
const WCHAR *path);
5456 BY_HANDLE_FILE_INFORMATION info;
5457 int ret =
fstat(fd, st);
5459 if (ret)
return ret;
5460 if (GetEnvironmentVariableW(
L"TZ",
NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return ret;
5461 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
5462 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5463 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5464 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5474 int ret =
fstat(fd, &tmp);
5476 if (ret)
return ret;
5478 stati128_handle((HANDLE)_get_osfhandle(fd), st);
5482#if !defined FILE_INVALID_FILE_ID && !defined __MINGW32__
5484 BYTE Identifier[16];
5488#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < 0x602
5489#define FileIdInfo 0x12
5500 typedef BOOL (WINAPI *gfibhe_t)(HANDLE,
int,
void *,
DWORD);
5501 static gfibhe_t pGetFileInformationByHandleEx = (gfibhe_t)-1;
5503 if (pGetFileInformationByHandleEx == (gfibhe_t)-1)
5504 pGetFileInformationByHandleEx = (gfibhe_t)get_proc_address(
"kernel32",
"GetFileInformationByHandleEx",
NULL);
5506 if (pGetFileInformationByHandleEx) {
5507 if (pGetFileInformationByHandleEx(h,
FileIdInfo,
id,
sizeof(*
id)))
5510 return GetLastError();
5512 return ERROR_INVALID_PARAMETER;
5517stati128_handle(HANDLE h,
struct stati128 *st)
5519 BY_HANDLE_FILE_INFORMATION info;
5522 if (GetFileInformationByHandle(h, &info)) {
5524 st->
st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
5525 st->
st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5526 st->
st_atimensec = filetime_to_nsec(&info.ftLastAccessTime);
5527 st->
st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5528 st->
st_mtimensec = filetime_to_nsec(&info.ftLastWriteTime);
5529 st->
st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5530 st->
st_ctimensec = filetime_to_nsec(&info.ftCreationTime);
5531 st->
st_nlink = info.nNumberOfLinks;
5532 attr = info.dwFileAttributes;
5533 if (!get_ino(h, &fii)) {
5538 st->
st_ino = ((__int64)info.nFileIndexHigh << 32) | info.nFileIndexLow;
5547filetime_to_unixtime(
const FILETIME *ft)
5550 time_t
t = filetime_split(ft, &subsec);
5552 if (
t < 0)
return 0;
5558filetime_to_nsec(
const FILETIME *ft)
5560 if (have_precisetime <= 0)
5564 tmp.LowPart = ft->dwLowDateTime;
5565 tmp.HighPart = ft->dwHighDateTime;
5566 return (
long)(tmp.QuadPart % 10000000) * 100;
5572fileattr_to_unixmode(
DWORD attr,
const WCHAR *path,
unsigned mode)
5574 if (attr & FILE_ATTRIBUTE_READONLY) {
5581 if (
mode & S_IFMT) {
5584 else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5588 mode |= S_IFDIR | S_IEXEC;
5590 else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5591 mode |= S_IFDIR | S_IEXEC;
5597 if (path && (
mode & S_IFREG)) {
5598 const WCHAR *end = path + lstrlenW(path);
5599 while (path < end) {
5600 end = CharPrevW(path, end);
5602 if ((_wcsicmp(end,
L".bat") == 0) ||
5603 (_wcsicmp(end,
L".cmd") == 0) ||
5604 (_wcsicmp(end,
L".com") == 0) ||
5605 (_wcsicmp(end,
L".exe") == 0)) {
5610 if (!iswalnum(*end))
break;
5622check_valid_dir(
const WCHAR *path)
5624 WIN32_FIND_DATAW fd;
5632 if (!(p = wcsstr(path,
L"...")))
5634 q = p + wcsspn(p,
L".");
5635 if ((p == path || wcschr(
L":/\\", *(p - 1))) &&
5636 (!*q || wcschr(
L":/\\", *q))) {
5643 if (!GetFullPathNameW(path,
sizeof(full) /
sizeof(WCHAR), full, &dmy)) {
5647 if (full[1] ==
L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
5650 fh = open_dir_handle(path, &fd);
5659stat_by_find(
const WCHAR *path,
struct stati128 *st)
5662 WIN32_FIND_DATAW wfd;
5664 int e = GetLastError();
5666 if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
5667 || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
5673 h = FindFirstFileW(path, &wfd);
5679 st->
st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path, 0);
5680 st->
st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
5681 st->
st_atimensec = filetime_to_nsec(&wfd.ftLastAccessTime);
5682 st->
st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
5683 st->
st_mtimensec = filetime_to_nsec(&wfd.ftLastWriteTime);
5684 st->
st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
5685 st->
st_ctimensec = filetime_to_nsec(&wfd.ftCreationTime);
5686 st->
st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
5693path_drive(
const WCHAR *path)
5695 return (iswalpha(path[0]) && path[1] ==
L':') ?
5696 towupper(path[0]) -
L'A' : _getdrive() - 1;
5699static const WCHAR namespace_prefix[] = {
L'\\',
L'\\',
L'?',
L'\\'};
5703winnt_stat(
const WCHAR *path,
struct stati128 *st, BOOL
lstat)
5705 DWORD flags =
lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0;
5709 memset(st, 0,
sizeof(*st));
5710 f = open_special(path, 0, flags);
5712 DWORD attr = stati128_handle(
f, st);
5715 switch (GetFileType(
f)) {
5716 case FILE_TYPE_CHAR:
5719 case FILE_TYPE_PIPE:
5724 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5729 attr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
5731 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5732 if (check_valid_dir(path))
return -1;
5734 st->
st_mode = fileattr_to_unixmode(attr, path,
mode);
5738 if (wcsncmp(path, namespace_prefix,
numberof(namespace_prefix)) == 0)
5739 path +=
numberof(namespace_prefix);
5743 if (stat_by_find(path, st))
return -1;
5757 if (w32_stati128(path, &tmp,
filecp(),
FALSE))
return -1;
5764wstati128(
const WCHAR *path,
struct stati128 *st, BOOL
lstat)
5774 size = lstrlenW(path) + 2;
5776 if (!(path = name_for_stat(buf1, path)))
5778 ret = winnt_stat(path, st,
lstat);
5787name_for_stat(WCHAR *buf1,
const WCHAR *path)
5793 for (p = path, s = buf1; *p; p++, s++) {
5801 if (!
len ||
L'\"' == *(--s)) {
5805 end = buf1 +
len - 1;
5807 if (isUNCRoot(buf1)) {
5810 else if (*end !=
L'\\')
5811 lstrcatW(buf1,
L"\\");
5813 else if (*end ==
L'\\' || (buf1 + 1 == end && *end ==
L':'))
5814 lstrcatW(buf1,
L".");
5823 return w32_stati128(path, st, CP_UTF8,
FALSE);
5835w32_stati128(
const char *path,
struct stati128 *st, UINT cp, BOOL
lstat)
5842 ret = wstati128(wpath, st,
lstat);
5851 return w32_stati128(path, st, CP_UTF8,
TRUE);
5858 return w32_stati128(path, st,
filecp(),
TRUE);
5870 return _lseeki64(fd, ofs, whence);
5875w32_access(
const char *path,
int mode, UINT cp)
5878 if (w32_stati128(path, &
stat, cp,
FALSE) != 0)
5899 return w32_access(path,
mode, CP_UTF8);
5906 long upos, lpos, usize, lsize;
5910 if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos),
SEEK_CUR)) == -1L &&
5911 (e = GetLastError())) {
5917 if (SetFilePointer(h, lsize, &usize,
SEEK_SET) == (
DWORD)-1L &&
5918 (e = GetLastError())) {
5921 else if (!SetEndOfFile(h)) {
5927 SetFilePointer(h, lpos, &upos,
SEEK_SET);
5933w32_truncate(
const char *path,
off_t length, UINT cp)
5941 h = CreateFileW(wpath, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
5948 ret = rb_chsize(h, length);
5957 return w32_truncate(path, length, CP_UTF8);
5964 return w32_truncate(path, length,
filecp());
5973 h = (HANDLE)_get_osfhandle(fd);
5974 if (h == (HANDLE)-1)
return -1;
5975 return rb_chsize(h, length);
5980filetime_to_clock(FILETIME *ft)
5982 __int64 qw = ft->dwHighDateTime;
5984 qw |= ft->dwLowDateTime;
5993 FILETIME create, exit, kernel, user;
5995 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
5996 tmbuf->
tms_utime = filetime_to_clock(&user);
5997 tmbuf->
tms_stime = filetime_to_clock(&kernel);
6012#define yield_once() Sleep(0)
6013#define yield_until(condition) do yield_once(); while (!(condition))
6030call_asynchronous(PVOID argp)
6046 BOOL interrupted =
FALSE;
6059 thr = CreateThread(
NULL, 0, call_asynchronous, &arg, 0, &val);
6067 if (TerminateThread(thr, intrval)) {
6072 GetExitCodeThread(thr, &val);
6077 MEMORY_BASIC_INFORMATION m;
6079 memset(&m, 0,
sizeof(m));
6080 if (!VirtualQuery(arg.
stackaddr, &m,
sizeof(m))) {
6081 Debug(fprintf(stderr,
"couldn't get stack base:%p:%d\n",
6084 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
6085 Debug(fprintf(stderr,
"couldn't release stack:%p:%d\n",
6086 m.AllocationBase, GetLastError()));
6097 rb_fatal(
"failed to launch waiter thread:%ld", GetLastError());
6107 WCHAR *envtop, *
env;
6108 char **myenvtop, **myenv;
6121 envtop = GetEnvironmentStringsW();
6125 myenvtop = (
char **)
malloc(
sizeof(
char *) * (
num + 1));
6126 for (
env = envtop, myenv = myenvtop; *
env;
env += lstrlenW(
env) + 1) {
6135 FreeEnvironmentStringsW(envtop);
6154 return GetCurrentProcessId();
6162 typedef long (WINAPI query_func)(HANDLE,
int,
void *, ULONG, ULONG *);
6163 static query_func *pNtQueryInformationProcess = (query_func *)-1;
6166 if (pNtQueryInformationProcess == (query_func *)-1)
6167 pNtQueryInformationProcess = (query_func *)get_proc_address(
"ntdll.dll",
"NtQueryInformationProcess",
NULL);
6168 if (pNtQueryInformationProcess) {
6171 void* PebBaseAddress;
6178 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi,
sizeof(pbi), &
len);
6180 ppid = pbi.ParentProcessId;
6187STATIC_ASSERT(std_handle, (STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)==(STD_ERROR_HANDLE-STD_OUTPUT_HANDLE));
6190#define set_new_std_handle(newfd, handle) do { \
6191 if ((unsigned)(newfd) > 2) break; \
6192 SetStdHandle(STD_INPUT_HANDLE+(STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)*(newfd), \
6195#define set_new_std_fd(newfd) set_new_std_handle(newfd, (HANDLE)rb_w32_get_osfhandle(newfd))
6203 if (oldfd == newfd)
return newfd;
6204 ret =
dup2(oldfd, newfd);
6205 if (ret < 0)
return ret;
6219 va_start(arg, oflag);
6220 pmode = va_arg(arg,
int);
6225 ret = w32_wopen(wfile, oflag, pmode);
6232check_if_wdir(
const WCHAR *wfile)
6234 DWORD attr = GetFileAttributesW(wfile);
6235 if (attr == (
DWORD)-1L ||
6236 !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
6237 check_valid_dir(wfile)) {
6253 va_start(arg, oflag);
6254 pmode = va_arg(arg,
int);
6259 ret = w32_wopen(wfile, oflag, pmode);
6270 if (oflag & O_CREAT) {
6272 va_start(arg, oflag);
6273 pmode = va_arg(arg,
int);
6277 return w32_wopen(
file, oflag, pmode);
6281w32_wopen(
const WCHAR *
file,
int oflag,
int pmode)
6287 DWORD attr = FILE_ATTRIBUTE_NORMAL;
6288 SECURITY_ATTRIBUTES sec;
6293 oflag &= ~O_SHARE_DELETE;
6294 if ((oflag & O_TEXT) || !(oflag &
O_BINARY)) {
6295 fd = _wopen(
file, oflag, pmode);
6299 check_if_wdir(
file);
6309 sec.nLength =
sizeof(sec);
6310 sec.lpSecurityDescriptor =
NULL;
6311 if (oflag & O_NOINHERIT) {
6312 sec.bInheritHandle =
FALSE;
6316 sec.bInheritHandle =
TRUE;
6318 oflag &= ~O_NOINHERIT;
6323 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
6325 access = GENERIC_READ | GENERIC_WRITE;
6337 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
6339 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
6341 create = OPEN_ALWAYS;
6345 create = OPEN_EXISTING;
6347 case O_CREAT | O_EXCL:
6348 case O_CREAT | O_EXCL | O_TRUNC:
6349 create = CREATE_NEW;
6352 case O_TRUNC | O_EXCL:
6353 create = TRUNCATE_EXISTING;
6355 case O_CREAT | O_TRUNC:
6356 create = CREATE_ALWAYS;
6362 if (oflag & O_CREAT) {
6364 if (!(pmode & S_IWRITE))
6365 attr = FILE_ATTRIBUTE_READONLY;
6367 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
6369 if (oflag & O_TEMPORARY) {
6370 attr |= FILE_FLAG_DELETE_ON_CLOSE;
6373 oflag &= ~O_TEMPORARY;
6375 if (oflag & _O_SHORT_LIVED)
6376 attr |= FILE_ATTRIBUTE_TEMPORARY;
6377 oflag &= ~_O_SHORT_LIVED;
6379 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
6383 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
6386 attr |= FILE_FLAG_RANDOM_ACCESS;
6392 oflag &= ~(O_SEQUENTIAL | O_RANDOM);
6394 if (oflag & ~O_APPEND) {
6401 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6402 fd = _open_osfhandle((
intptr_t)h, 0);
6414 h = CreateFileW(
file,
access, FILE_SHARE_READ | FILE_SHARE_WRITE | share_delete, &sec, create, attr,
NULL);
6416 DWORD e = GetLastError();
6417 if (e != ERROR_ACCESS_DENIED || !check_if_wdir(
file))
6424 switch (GetFileType(h)) {
6425 case FILE_TYPE_CHAR:
6428 case FILE_TYPE_PIPE:
6431 case FILE_TYPE_UNKNOWN:
6438 if (!(flags & (
FDEV |
FPIPE)) && (oflag & O_APPEND))
6458 int save_errno = errno;
6460 if (fflush(fp))
return -1;
6468 if (closesocket(sock) == SOCKET_ERROR) {
6479 static DWORD serial = 0;
6480 static const char prefix[] =
"\\\\.\\pipe\\ruby";
6482 width_of_prefix = (
int)
sizeof(
prefix) - 1,
6483 width_of_pid = (
int)
sizeof(rb_pid_t) * 2,
6484 width_of_serial = (
int)
sizeof(serial) * 2,
6485 width_of_ids = width_of_pid + 1 + width_of_serial + 1
6488 SECURITY_ATTRIBUTES sec;
6489 HANDLE hRead, hWrite, h;
6490 int fdRead, fdWrite;
6494 snprintf(
name + width_of_prefix, width_of_ids,
"%.*"PRI_PIDT_PREFIX
"x-%.*lx",
6497 sec.nLength =
sizeof(sec);
6498 sec.lpSecurityDescriptor =
NULL;
6499 sec.bInheritHandle =
FALSE;
6502 hRead = CreateNamedPipe(
name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
6503 0, 2, 65536, 65536, 0, &sec);
6507 if (
err == ERROR_PIPE_BUSY)
6515 hWrite = CreateFile(
name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
6516 OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
NULL);
6526 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6527 fdRead = _open_osfhandle((
intptr_t)h, 0);
6531 CloseHandle(hWrite);
6546 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6547 fdWrite = _open_osfhandle((
intptr_t)h, 0);
6549 if (fdWrite == -1) {
6551 CloseHandle(hWrite);
6573console_emulator_p(
void)
6578 const void *
const func = WriteConsoleW;
6580 MEMORY_BASIC_INFORMATION m;
6582 memset(&m, 0,
sizeof(m));
6583 if (!VirtualQuery(func, &m,
sizeof(m))) {
6586 k = GetModuleHandle(
"kernel32.dll");
6587 if (!k)
return FALSE;
6588 return (HMODULE)m.AllocationBase != k;
6594constat_handle(HANDLE h)
6599 EnterCriticalSection(&conlist_mutex);
6601 if (console_emulator_p()) {
6605 install_vm_exit_handler();
6612 CONSOLE_SCREEN_BUFFER_INFO csbi;
6615 p->
vt100.
attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6618 if (GetConsoleScreenBufferInfo(h, &csbi)) {
6626 LeaveCriticalSection(&conlist_mutex);
6633constat_reset(HANDLE h)
6638 EnterCriticalSection(&conlist_mutex);
6646 LeaveCriticalSection(&conlist_mutex);
6649#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
6650#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
6652#define constat_attr_color_reverse(attr) \
6653 ((attr) & ~(FOREGROUND_MASK | BACKGROUND_MASK)) | \
6654 (((attr) & FOREGROUND_MASK) << 4) | \
6655 (((attr) & BACKGROUND_MASK) >> 4)
6666 bold =
attr & FOREGROUND_INTENSITY;
6667 attr &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
6669 while (
count-- > 0) {
6672 attr = default_attr;
6677 bold = FOREGROUND_INTENSITY;
6680#ifndef COMMON_LVB_UNDERSCORE
6681#define COMMON_LVB_UNDERSCORE 0x8000
6690 attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
6694 attr = (
attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN)) | FOREGROUND_RED;
6698 attr = (
attr & ~(FOREGROUND_BLUE | FOREGROUND_RED)) | FOREGROUND_GREEN;
6702 attr = (
attr & ~FOREGROUND_BLUE) | FOREGROUND_GREEN | FOREGROUND_RED;
6706 attr = (
attr & ~(FOREGROUND_GREEN | FOREGROUND_RED)) | FOREGROUND_BLUE;
6710 attr = (
attr & ~FOREGROUND_GREEN) | FOREGROUND_BLUE | FOREGROUND_RED;
6714 attr = (
attr & ~FOREGROUND_RED) | FOREGROUND_BLUE | FOREGROUND_GREEN;
6718 attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6722 attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
6725 attr = (
attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN)) | BACKGROUND_RED;
6728 attr = (
attr & ~(BACKGROUND_BLUE | BACKGROUND_RED)) | BACKGROUND_GREEN;
6731 attr = (
attr & ~BACKGROUND_BLUE) | BACKGROUND_GREEN | BACKGROUND_RED;
6734 attr = (
attr & ~(BACKGROUND_GREEN | BACKGROUND_RED)) | BACKGROUND_BLUE;
6737 attr = (
attr & ~BACKGROUND_GREEN) | BACKGROUND_BLUE | BACKGROUND_RED;
6740 attr = (
attr & ~BACKGROUND_RED) | BACKGROUND_BLUE | BACKGROUND_GREEN;
6743 attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
6755constat_clear(HANDLE handle, WORD
attr,
DWORD len, COORD pos)
6759 FillConsoleOutputAttribute(handle,
attr,
len, pos, &written);
6760 FillConsoleOutputCharacterW(handle,
L' ',
len, pos, &written);
6765constat_apply(HANDLE handle,
struct constat *s, WCHAR w)
6767 CONSOLE_SCREEN_BUFFER_INFO csbi;
6773 if (!GetConsoleScreenBufferInfo(handle, &csbi))
return;
6775 if (arg0) arg1 =
seq[0];
6781 csbi.dwCursorPosition.X = 0;
6783 csbi.dwCursorPosition.Y -= arg1;
6784 if (csbi.dwCursorPosition.Y < csbi.srWindow.Top)
6785 csbi.dwCursorPosition.Y = csbi.srWindow.Top;
6786 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6789 csbi.dwCursorPosition.X = 0;
6792 csbi.dwCursorPosition.Y += arg1;
6793 if (csbi.dwCursorPosition.Y > csbi.srWindow.Bottom)
6794 csbi.dwCursorPosition.Y = csbi.srWindow.Bottom;
6795 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6798 csbi.dwCursorPosition.X += arg1;
6799 if (csbi.dwCursorPosition.X >= csbi.srWindow.Right)
6800 csbi.dwCursorPosition.X = csbi.srWindow.Right;
6801 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6804 csbi.dwCursorPosition.X -= arg1;
6805 if (csbi.dwCursorPosition.X < csbi.srWindow.Left)
6806 csbi.dwCursorPosition.X = csbi.srWindow.Left;
6807 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6811 arg1 += csbi.srWindow.Left;
6812 if (arg1 > csbi.srWindow.Right)
6813 arg1 = csbi.srWindow.Right;
6814 csbi.dwCursorPosition.X = arg1;
6815 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6818 arg1 += csbi.srWindow.Top;
6819 if (arg1 > csbi.srWindow.Bottom)
6820 arg1 = csbi.srWindow.Bottom;
6821 csbi.dwCursorPosition.Y = arg1;
6822 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6826 pos.Y = arg1 + csbi.srWindow.Top - 1;
6827 if (pos.Y > csbi.srWindow.Bottom) pos.Y = csbi.srWindow.Bottom;
6828 if (
count < 2 || (arg1 =
seq[1]) <= 0) arg1 = 1;
6829 pos.X = arg1 + csbi.srWindow.Left - 1;
6830 if (pos.X > csbi.srWindow.Right) pos.X = csbi.srWindow.Right;
6831 SetConsoleCursorPosition(handle, pos);
6834 switch (arg0 ? arg1 : 0) {
6836 constat_clear(handle, csbi.wAttributes,
6837 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.dwCursorPosition.Y + 1)
6838 - csbi.dwCursorPosition.X),
6839 csbi.dwCursorPosition);
6843 pos.Y = csbi.srWindow.Top;
6844 constat_clear(handle, csbi.wAttributes,
6845 (csbi.dwSize.X * (csbi.dwCursorPosition.Y - csbi.srWindow.Top)
6846 + csbi.dwCursorPosition.X + 1),
6851 pos.Y = csbi.srWindow.Top;
6852 constat_clear(handle, csbi.wAttributes,
6853 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1)),
6859 constat_clear(handle, csbi.wAttributes,
6860 (csbi.dwSize.X * csbi.dwSize.Y),
6866 switch (arg0 ? arg1 : 0) {
6868 constat_clear(handle, csbi.wAttributes,
6869 (csbi.dwSize.X - csbi.dwCursorPosition.X),
6870 csbi.dwCursorPosition);
6874 pos.Y = csbi.dwCursorPosition.Y;
6875 constat_clear(handle, csbi.wAttributes,
6876 csbi.dwCursorPosition.X + 1, pos);
6880 pos.Y = csbi.dwCursorPosition.Y;
6881 constat_clear(handle, csbi.wAttributes,
6882 csbi.dwSize.X, pos);
6890 SetConsoleCursorPosition(handle, s->
vt100.
saved);
6894 CONSOLE_CURSOR_INFO cci;
6895 GetConsoleCursorInfo(handle, &cci);
6896 cci.bVisible =
TRUE;
6897 SetConsoleCursorInfo(handle, &cci);
6902 CONSOLE_CURSOR_INFO cci;
6903 GetConsoleCursorInfo(handle, &cci);
6904 cci.bVisible =
FALSE;
6905 SetConsoleCursorInfo(handle, &cci);
6913static const long MAXSIZE_CONSOLE_WRITING = 31366;
6917constat_parse(HANDLE h,
struct constat *s,
const WCHAR **ptrp,
long *lenp)
6919 const WCHAR *
ptr = *ptrp;
6920 long rest,
len = *lenp;
6924 rest = *lenp -
len - 1;
6929 if (
len > 0 && *
ptr !=
L'[')
continue;
6938 rest = *lenp -
len - 1;
6939 if (rest > 0) --rest;
6944 if (wc >=
L'0' && wc <=
L'9') {
6947 *
seq = (*
seq * 10) + (wc -
L'0');
6963 constat_apply(h, s, wc);
6969 else if ((rest = *lenp -
len) < MAXSIZE_CONSOLE_WRITING) {
6988 int save_errno = errno;
6992 constat_delete((HANDLE)sock);
6996 socklist_delete(&sock,
NULL);
6999 if (closesocket(sock) == SOCKET_ERROR) {
7007setup_overlapped(OVERLAPPED *ol,
int fd,
int iswrite)
7009 memset(ol, 0,
sizeof(*ol));
7017 DWORD low = SetFilePointer((HANDLE)
_osfhnd(fd), 0, &high, method);
7018#ifndef INVALID_SET_FILE_POINTER
7019#define INVALID_SET_FILE_POINTER ((DWORD)-1)
7023 if (
err != NO_ERROR) {
7029 ol->OffsetHigh = high;
7040finish_overlapped(OVERLAPPED *ol,
int fd,
DWORD size)
7042 CloseHandle(ol->hEvent);
7045 LONG high = ol->OffsetHigh;
7047 if (low < ol->Offset)
7049 SetFilePointer((HANDLE)
_osfhnd(fd), low, &high, FILE_BEGIN);
7066 BOOL islineinput =
FALSE;
7073 if (_get_osfhandle(fd) == -1) {
7090 isconsole = is_console(
_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
7094 islineinput = (
mode & ENABLE_LINE_INPUT) != 0;
7099 constat_reset((HANDLE)
_osfhnd(fd));
7111 if (setup_overlapped(&ol, fd,
FALSE)) {
7117 err = GetLastError();
7129 else if (
err != ERROR_IO_PENDING) {
7130 CloseHandle(ol.hEvent);
7131 if (
err == ERROR_ACCESS_DENIED)
7133 else if (
err == ERROR_BROKEN_PIPE ||
err == ERROR_HANDLE_EOF) {
7145 if (
wait != WAIT_OBJECT_0) {
7146 if (
wait == WAIT_OBJECT_0 + 1)
7150 CloseHandle(ol.hEvent);
7151 CancelIo((HANDLE)
_osfhnd(fd));
7157 (
err = GetLastError()) != ERROR_HANDLE_EOF) {
7159 if (
err != ERROR_BROKEN_PIPE) {
7163 CloseHandle(ol.hEvent);
7164 CancelIo((HANDLE)
_osfhnd(fd));
7170 err = GetLastError();
7174 finish_overlapped(&ol, fd,
read);
7179 if (
err != ERROR_OPERATION_ABORTED &&
7180 !(isconsole &&
len == 1 && (!islineinput || *((
char *)
buf - 1) ==
'\n')) &&
size > 0)
7209 if (_get_osfhandle(fd) == -1) {
7215 ssize_t w = _write(fd,
buf,
size);
7216 if (w == (ssize_t)-1 && errno == EINVAL) {
7235 if (setup_overlapped(&ol, fd,
TRUE)) {
7240 if (!WriteFile((HANDLE)
_osfhnd(fd),
buf,
len, &written, &ol)) {
7241 err = GetLastError();
7242 if (
err != ERROR_IO_PENDING) {
7243 CloseHandle(ol.hEvent);
7244 if (
err == ERROR_ACCESS_DENIED)
7254 if (
wait != WAIT_OBJECT_0) {
7255 if (
wait == WAIT_OBJECT_0 + 1)
7259 CloseHandle(ol.hEvent);
7260 CancelIo((HANDLE)
_osfhnd(fd));
7265 if (!GetOverlappedResult((HANDLE)
_osfhnd(fd), &ol, &written,
TRUE)) {
7267 CloseHandle(ol.hEvent);
7268 CancelIo((HANDLE)
_osfhnd(fd));
7274 finish_overlapped(&ol, fd, written);
7277 if (written ==
len) {
7283 size_t newlen =
len / 2;
7303 DWORD dwMode, reslen;
7307 const WCHAR *
ptr, *next;
7312 if (!GetConsoleMode(handle, &dwMode))
7315 s = constat_handle(handle);
7330 if (!
ptr)
return -1L;
7339 if (!WriteConsoleW(handle,
ptr,
len, &reslen,
NULL))
7340 reslen = (
DWORD)-1L;
7344 long curlen = constat_parse(handle, s, (next =
ptr, &next), &
len);
7345 reslen += next -
ptr;
7348 if (!WriteConsoleW(handle,
ptr, curlen, &written,
NULL)) {
7349 reslen = (
DWORD)-1L;
7357 if (wbuffer)
free(wbuffer);
7358 return (
long)reslen;
7361#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7364unixtime_to_filetime(time_t time, FILETIME *ft)
7368 tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
7369 ft->dwLowDateTime = tmp.LowPart;
7370 ft->dwHighDateTime = tmp.HighPart;
7377timespec_to_filetime(
const struct timespec *ts, FILETIME *ft)
7381 tmp.QuadPart = ((LONG_LONG)ts->
tv_sec + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
7382 tmp.QuadPart += ts->
tv_nsec / 100;
7383 ft->dwLowDateTime = tmp.LowPart;
7384 ft->dwHighDateTime = tmp.HighPart;
7390wutimensat(
int dirfd,
const WCHAR *path,
const struct timespec *times,
int flags)
7393 FILETIME atime, mtime;
7413 if (timespec_to_filetime(×[0], &atime)) {
7416 if (timespec_to_filetime(×[1], &mtime)) {
7421 get_systemtime(&atime);
7426 const DWORD attr = GetFileAttributesW(path);
7427 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7428 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7429 hFile = open_special(path, GENERIC_WRITE, 0);
7435 if (!SetFileTime(hFile,
NULL, &atime, &mtime)) {
7441 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7442 SetFileAttributesW(path, attr);
7450w32_utimensat(
int dirfd,
const char *path,
const struct timespec *times,
int flags, UINT cp)
7456 ret = wutimensat(dirfd, wpath, times, flags);
7472 return w32_utimensat(
AT_FDCWD, path, ts, 0, CP_UTF8);
7498 return w32_utimensat(
AT_FDCWD, path, ts, 0, CP_UTF8);
7518 return w32_utimensat(dirfd, path, times, flags, CP_UTF8);
7525 return w32_utimensat(dirfd, path, times, flags,
filecp());
7537 ret = _wchdir(wpath);
7544wmkdir(
const WCHAR *wpath,
int mode)
7549 if (CreateDirectoryW(wpath,
NULL) ==
FALSE) {
7553 if (_wchmod(wpath,
mode) == -1) {
7554 RemoveDirectoryW(wpath);
7571 ret = wmkdir(wpath,
mode);
7585 ret = wmkdir(wpath,
mode);
7592wrmdir(
const WCHAR *wpath)
7596 const DWORD attr = GetFileAttributesW(wpath);
7597 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7598 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
7600 if (RemoveDirectoryW(wpath) ==
FALSE) {
7603 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7604 SetFileAttributesW(wpath, attr);
7620 ret = wrmdir(wpath);
7634 ret = wrmdir(wpath);
7641wunlink(
const WCHAR *path)
7644 const DWORD SYMLINKD = FILE_ATTRIBUTE_REPARSE_POINT|FILE_ATTRIBUTE_DIRECTORY;
7646 const DWORD attr = GetFileAttributesW(path);
7647 if (attr == (
DWORD)-1) {
7649 else if ((attr & SYMLINKD) == SYMLINKD) {
7650 ret = RemoveDirectoryW(path);
7653 if (attr & FILE_ATTRIBUTE_READONLY) {
7654 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7656 ret = DeleteFileW(path);
7661 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7662 SetFileAttributesW(path, attr);
7678 ret = wunlink(wpath);
7692 ret = wunlink(wpath);
7706 ret = _wchmod(wpath,
mode);
7715 typedef BOOL (WINAPI *set_file_information_by_handle_func)
7717 static set_file_information_by_handle_func set_file_info =
7718 (set_file_information_by_handle_func)-1;
7722 LARGE_INTEGER CreationTime;
7723 LARGE_INTEGER LastAccessTime;
7724 LARGE_INTEGER LastWriteTime;
7725 LARGE_INTEGER ChangeTime;
7726 DWORD FileAttributes;
7727 } info = {{{0}}, {{0}}, {{0}},};
7728 HANDLE h = (HANDLE)_get_osfhandle(fd);
7734 if (set_file_info == (set_file_information_by_handle_func)-1) {
7735 set_file_info = (set_file_information_by_handle_func)
7736 get_proc_address(
"kernel32",
"SetFileInformationByHandle",
NULL);
7738 if (!set_file_info) {
7743 info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
7744 if (!(
mode & 0200)) info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
7745 if (!set_file_info(h, 0, &info,
sizeof(info))) {
7759 if (_get_osfhandle(fd) == -1) {
7762 if (!GetConsoleMode((HANDLE)
_osfhnd(fd), &
mode)) {
7769#if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
7791 int *ip = (
int *)(&x + 1) - 1;
7800 typedef char *(WSAAPI inet_ntop_t)(
int,
void *,
char *,
size_t);
7801 static inet_ntop_t *pInetNtop = (inet_ntop_t *)-1;
7802 if (pInetNtop == (inet_ntop_t *)-1)
7803 pInetNtop = (inet_ntop_t *)get_proc_address(
"ws2_32",
"inet_ntop",
NULL);
7805 return pInetNtop(af, (
void *)addr, numaddr, numaddr_len);
7810 snprintf(numaddr, numaddr_len,
"%s", inet_ntoa(
in));
7819 typedef int (WSAAPI inet_pton_t)(
int,
const char*,
void *);
7820 static inet_pton_t *pInetPton = (inet_pton_t *)-1;
7821 if (pInetPton == (inet_pton_t *)-1)
7822 pInetPton = (inet_pton_t *)get_proc_address(
"ws2_32",
"inet_pton",
NULL);
7824 return pInetPton(af, src, dst);
7836#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7839unixtime_to_systemtime(
const time_t
t, SYSTEMTIME *st)
7842 if (unixtime_to_filetime(
t, &ft))
return -1;
7843 if (!FileTimeToSystemTime(&ft, st))
return -1;
7849systemtime_to_tm(
const SYSTEMTIME *st,
struct tm *
t)
7851 int y = st->wYear, m = st->wMonth, d = st->wDay;
7852 t->tm_sec = st->wSecond;
7853 t->tm_min = st->wMinute;
7854 t->tm_hour = st->wHour;
7855 t->tm_mday = st->wDay;
7856 t->tm_mon = st->wMonth - 1;
7857 t->tm_year = y - 1900;
7858 t->tm_wday = st->wDayOfWeek;
7866 d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
7867 d += ((m - 3) * 153 + 2) / 5;
7875systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
7877 TIME_ZONE_INFORMATION stdtz;
7880 if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst))
return -1;
7882 GetTimeZoneInformation(&stdtz);
7885 if (tz->StandardBias == tz->DaylightBias)
return 0;
7886 if (!tz->StandardDate.wMonth)
return 0;
7887 if (!tz->DaylightDate.wMonth)
return 0;
7888 if (tz != &stdtz) stdtz = *tz;
7890 stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
7891 if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst))
return 0;
7892 if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
7898#ifdef HAVE__GMTIME64_S
7899# ifndef HAVE__LOCALTIME64_S
7901# define HAVE__LOCALTIME64_S 1
7903# ifndef MINGW_HAS_SECURE_API
7904 _CRTIMP errno_t __cdecl _gmtime64_s(
struct tm* tm,
const __time64_t *time);
7905 _CRTIMP errno_t __cdecl _localtime64_s(
struct tm* tm,
const __time64_t *time);
7907# define gmtime_s _gmtime64_s
7908# define localtime_s _localtime64_s
7921#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__GMTIME64_S)
7922 e = gmtime_s(
rp, tp);
7923 if (e != 0)
goto error;
7927 if (unixtime_to_systemtime(*tp, &st))
goto error;
7929 systemtime_to_tm(&st,
rp);
7945#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__LOCALTIME64_S)
7946 e = localtime_s(
rp, tp);
7950 SYSTEMTIME gst, lst;
7951 if (unixtime_to_systemtime(*tp, &gst))
goto error;
7952 rp->tm_isdst = systemtime_to_localtime(
NULL, &gst, &lst);
7953 systemtime_to_tm(&lst,
rp);
7964 int len =
sizeof(tmp);
7965 int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (
char *)&tmp, &
len);
7966 if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
7969 flags &= ~O_NONBLOCK;
7972 socklist_insert((SOCKET)h,
f);
7978 return rb_w32_open_osfhandle((
intptr_t)h, flags);
7989 constat_delete((HANDLE)sock);
7992 socklist_delete(&sock,
NULL);
7997#if !defined(__MINGW64__) && defined(__MINGW64_VERSION_MAJOR)
8003rb_w32_pow(
double x,
double y)
8007 unsigned int default_control = _controlfp(0, 0);
8008 _controlfp(_PC_64, _MCW_PC);
8011 _controlfp(default_control, _MCW_PC);
8049 f = CreateFileW(
ptr, 0,
8050 FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
8051 FILE_FLAG_BACKUP_SEMANTICS,
NULL);
8056 if (GetFileType(
f) == FILE_TYPE_DISK) {
8058 ZeroMemory(st,
sizeof(*st));
8064 else if (
err != ERROR_INVALID_PARAMETER) {
8070 if (GetFileInformationByHandle(
f, &st->
info.
bhfi)) {
8075 if (ret) CloseHandle(ret);
8080close_handle(
VALUE h)
8082 CloseHandle((HANDLE)h);
8092call_w32_io_info(
VALUE arg)
8102 HANDLE f1 = 0, f2 = 0;
8104 f1 = w32_io_info(&fname1, &st1);
8108 arg.
fname = &fname2;
8113 f2 = w32_io_info(&fname2, &st2);
8116 if (f2) CloseHandle(f2);
8120 if (st1.
info.
bhfi.dwVolumeSerialNumber == st2.
info.
bhfi.dwVolumeSerialNumber &&
8137 typedef HRESULT (WINAPI *set_thread_description_func)(HANDLE, PCWSTR);
8138 static set_thread_description_func set_thread_description =
8139 (set_thread_description_func)-1;
8140 if (set_thread_description == (set_thread_description_func)-1) {
8141 set_thread_description = (set_thread_description_func)
8142 get_proc_address(
"kernel32",
"SetThreadDescription",
NULL);
8144 if (set_thread_description) {
8145 result = set_thread_description(th,
name);
8153 int idx, result =
FALSE;
8176#if RUBY_MSVCRT_VERSION < 120
Our own, locale independent, character handling routines.
char * strchr(char *, char)
#define MJIT_FUNC_EXPORTED
Internal header for Encoding.
#define ENCINDEX_UTF_16LE
#define ENCINDEX_US_ASCII
int rb_enc_get_index(VALUE obj)
rb_encoding * rb_utf8_encoding(void)
rb_encoding * rb_enc_from_index(int index)
rb_encoding * rb_filesystem_encoding(void)
int rb_enc_to_index(rb_encoding *enc)
char str[HTML_ESCAPE_MAX_LEN+1]
#define RSTRING_LEN(string)
#define RSTRING_PTR(string)
VALUE rb_str_encode_ospath(VALUE path)
void ruby_xfree(void *x)
Deallocates a storage instance.
void * ruby_xcalloc(size_t n, size_t size)
Identical to ruby_xmalloc2(), except it zero-fills the region before it returns.
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
int ruby_glob_func(const char *, VALUE, void *)
void rb_fatal(const char *fmt,...)
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
VALUE rb_check_convert_type_with_id(VALUE, int, const char *, ID)
unsigned in(void *in_desc, z_const unsigned char **buf)
unsigned short prefix[65536]
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
int rb_econv_has_convpath_p(const char *from_encoding, const char *to_encoding)
#define ECONV_UNDEF_REPLACE
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
#define ENCODING_GET(obj)
#define ECONV_INVALID_REPLACE
void rb_write_error2(const char *, long)
VALUE rb_str_cat(VALUE, const char *, long)
#define rb_strlen_lit(str)
#define rb_utf8_str_new(str, len)
VALUE rb_f_notimplement(int argc, const VALUE *argv, VALUE obj, VALUE marker)
size_t strlcat(char *, const char *, size_t)
size_t strlcpy(char *, const char *, size_t)
void * memmove(void *, const void *, size_t)
char * ruby_strdup(const char *)
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.
Internal header for Object.
#define is_socket(fd, path)
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define INVALID_HANDLE_VALUE
int memcmp(const void *s1, const void *s2, size_t len)
#define MEMCPY(p1, p2, type, n)
#define ALLOCA_N(type, n)
#define MEMZERO(p, type, n)
VALUE type(ANYARGS)
ANYARGS-ed function type.
ONIG_EXTERN const OnigEncodingType OnigEncodingUTF_8
#define StringValueCStr(v)
unsigned long long uint64_t
VALUE rb_str_vcatf(VALUE, const char *, va_list)
VALUE rb_sprintf(const char *,...)
size_t strlen(const char *)
struct _NtCmdLineElement * next
unsigned LONG_LONG VolumeSerialNumber
uintptr_t(* func)(uintptr_t self, int argc, uintptr_t *argv)
struct constat::@212 vt100
struct sockaddr * ifa_addr
struct ifaddrs * ifa_next
BY_HANDLE_FILE_INFORMATION bhfi
union w32_io_info_t::@214 info
void error(const char *msg)
#define rb_w32_reparse_buffer_size(n)
#define COPY_STAT(src, dest, size_cast)
VALUE rb_w32_special_folder(int type)
int rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout, void *th)
int WSAAPI rb_w32_getsockname(int fd, struct sockaddr *addr, int *addrlen)
int rb_w32_check_interrupt(void *)
int WSAAPI rb_w32_socket(int af, int type, int protocol)
int WSAAPI rb_w32_listen(int s, int backlog)
void setnetent(int stayopen)
int rb_w32_uutimensat(int dirfd, const char *path, const struct timespec *times, int flags)
int WSAAPI rb_w32_shutdown(int s, int how)
int WSAAPI rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout)
struct servent *WSAAPI rb_w32_getservbyname(const char *name, const char *proto)
#define FSCTL_GET_REPARSE_POINT
int rb_w32_ftruncate(int fd, off_t length)
int rb_w32_times(struct tms *tmbuf)
struct servent *WSAAPI rb_w32_getservbyport(int port, const char *proto)
#define constat_attr_color_reverse(attr)
int kill(int pid, int sig)
struct netent * getnetent(void)
VALUE rb_dir_getwd_ospath(void)
EXTERN_C _CRTIMP ioinfo * __pioinfo[]
ssize_t rb_w32_read(int fd, void *buf, size_t size)
void rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
SOCKET rb_w32_get_osfhandle(int fh)
int rb_w32_mkdir(const char *path, int mode)
ssize_t rb_w32_write(int fd, const void *buf, size_t size)
int rb_w32_utimes(const char *path, const struct timeval *times)
const char *WSAAPI rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
int rb_w32_set_thread_description(HANDLE th, const WCHAR *name)
#define SYMBOLIC_LINK_FLAG_DIRECTORY
int ioctl(int i, int u,...)
#define COMMON_LVB_UNDERSCORE
#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
int rb_w32_isatty(int fd)
rb_pid_t rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
int sendmsg(int fd, const struct msghdr *msg, int flags)
#define INVALID_SET_FILE_POINTER
WCHAR * rb_w32_home_dir(void)
struct netent * getnetbyname(const char *name)
int symlink(const char *src, const char *link)
char * rb_w32_ugetcwd(char *buffer, int size)
int rb_w32_truncate(const char *path, off_t length)
#define rb_acrt_lowio_lock_fh(i)
struct direct * rb_w32_ureaddir(DIR *dirp)
int rb_w32_uchown(const char *path, int owner, int group)
#define _set_osflags(fh, flags)
int fchmod(int fd, int mode)
#define utf8_to_wstr(str, plen)
int rb_w32_umkdir(const char *path, int mode)
int rb_w32_wopen(const WCHAR *file, int oflag,...)
#define rb_w32_stati128(path, st)
DWORD(WINAPI * cilnA_t)(const NET_LUID *, char *, size_t)
DWORD(WINAPI * cigl_t)(const GUID *, NET_LUID *)
rb_pid_t rb_w32_uspawn(int mode, const char *cmd, const char *prog)
int rb_w32_ulink(const char *from, const char *to)
DIR * rb_w32_uopendir(const char *filename)
#define FILE_FILENO(stream)
long rb_w32_telldir(DIR *dirp)
int WSAAPI rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
int rb_w32_stat(const char *path, struct stat *st)
int clock_gettime(clockid_t clock_id, struct timespec *sp)
int rb_w32_uchdir(const char *path)
DWORD(WINAPI * get_final_path_func)(HANDLE, WCHAR *, DWORD, DWORD)
int rb_w32_uchmod(const char *path, int mode)
struct protoent *WSAAPI rb_w32_getprotobyname(const char *name)
int rb_w32_pipe(int fds[2])
char * rb_w32_getenv(const char *name)
int rb_w32_uutime(const char *path, const struct utimbuf *times)
char * rb_w32_ugetenv(const char *name)
void rb_w32_rewinddir(DIR *dirp)
#define set_new_std_fd(newfd)
int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
int rb_w32_uaccess(const char *path, int mode)
int rb_w32_utime(const char *path, const struct utimbuf *times)
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
int WSAAPI rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
void setprotoent(int stayopen)
#define rb_acrt_lowio_unlock_fh(i)
struct tm * localtime_r(const time_t *tp, struct tm *rp)
void rb_w32_free_environ(char **env)
char ** rb_w32_get_environ(void)
int rb_w32_fstati128(int fd, struct stati128 *st)
#define yield_until(condition)
int rb_w32_set_nonblock(int fd)
int lchown(const char *path, int owner, int group)
void rb_w32_closedir(DIR *dirp)
ssize_t readlink(const char *path, char *buf, size_t bufsize)
rb_pid_t rb_w32_aspawn(int mode, const char *prog, char *const *argv)
int WSAAPI rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
VALUE(*const rb_f_notimplement_)(int, const VALUE *, VALUE, VALUE)
int WSAAPI rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
char * rb_w32_wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen)
void rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
struct tm * gmtime_r(const time_t *tp, struct tm *rp)
int rb_w32_lstati128(const char *path, struct stati128 *st)
int rb_w32_unlink(const char *path)
struct protoent * getprotoent(void)
int link(const char *from, const char *to)
rb_pid_t rb_w32_uaspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len)
#define CSIDL_LOCAL_APPDATA
#define wstr_to_utf8(str, plen)
void rb_w32_seekdir(DIR *dirp, long loc)
rb_pid_t rb_w32_getppid(void)
int getifaddrs(struct ifaddrs **ifap)
int WSAAPI rb_w32_send(int fd, const char *buf, int len, int flags)
int rb_w32_rmdir(const char *path)
int rb_w32_usymlink(const char *src, const char *link)
int rb_w32_utimensat(int dirfd, const char *path, const struct timespec *times, int flags)
void rb_w32_fdset(int fd, fd_set *set)
int rb_w32_ustati128(const char *path, struct stati128 *st)
int WSAAPI rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
char rb_w32_fd_is_text(int fd)
int WSAAPI rb_w32_gethostname(char *name, int len)
int flock(int fd, int oper)
int WSAAPI rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
VALUE rb_w32_file_identical_p(VALUE fname1, VALUE fname2)
rb_pid_t rb_w32_getpid(void)
int recvmsg(int fd, struct msghdr *msg, int flags)
HANDLE rb_w32_start_process(const char *abspath, char *const *argv, int out_fd)
int rb_w32_set_thread_description_str(HANDLE th, VALUE name)
int rb_w32_urmdir(const char *path)
int __cdecl gettimeofday(struct timeval *tv, struct timezone *tz)
int rb_w32_ulchown(const char *path, int owner, int group)
struct servent * getservent(void)
#define END_FOREACH_CHILD
int rb_w32_uutimes(const char *path, const struct timeval *times)
int WSAAPI rb_w32_recv(int fd, char *buf, int len, int flags)
int rb_w32_fstat(int fd, struct stat *st)
DIR * rb_w32_opendir(const char *filename)
#define IOINFO_ARRAY_ELTS
ssize_t rb_w32_ureadlink(const char *path, char *buf, size_t bufsize)
int rb_w32_is_socket(int fd)
void setservent(int stayopen)
rb_pid_t rb_w32_spawn(int mode, const char *cmd, const char *prog)
int rb_w32_utruncate(const char *path, off_t length)
#define IO_REPARSE_TAG_SYMLINK
void rb_w32_sysinit(int *argc, char ***argv)
int WSAAPI rb_w32_sendto(int fd, const char *buf, int len, int flags, const struct sockaddr *to, int tolen)
int rb_w32_fclose(FILE *fp)
int rb_w32_access(const char *path, int mode)
char * rb_w32_strerror(int e)
rb_pid_t waitpid(rb_pid_t pid, int *stat_loc, int options)
void freeifaddrs(struct ifaddrs *ifp)
WCHAR * rb_w32_mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen)
int socketpair(int af, int type, int protocol, int *sv)
int rb_w32_uopen(const char *file, int oflag,...)
int rb_w32_reparse_symlink_p(const WCHAR *path)
#define _set_osfhnd(fh, osfh)
off_t rb_w32_lseek(int fd, off_t ofs, int whence)
int rb_w32_ulstati128(const char *path, struct stati128 *st)
#define MAKE_SOCKDATA(af, fl)
int chown(const char *path, int owner, int group)
int rb_w32_wrap_io_handle(HANDLE h, int flags)
int rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait)
struct _NtCmdLineElement NtCmdLineElement
#define set_env_val(vname)
struct hostent *WSAAPI rb_w32_gethostbyaddr(const char *addr, int len, int type)
int rb_w32_map_errno(DWORD winerr)
#define filecp_to_wstr(str, plen)
int fcntl(int fd, int cmd,...)
void sethostent(int stayopen)
int WSAAPI rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
rb_pid_t rb_w32_uaspawn(int mode, const char *prog, char *const *argv)
int rb_w32_uunlink(const char *path)
#define msghdr_to_wsamsg(msg, wsamsg)
int clock_getres(clockid_t clock_id, struct timespec *sp)
int rb_w32_urename(const char *from, const char *to)
int rb_w32_io_cancelable_p(int fd)
struct hostent *WSAAPI rb_w32_gethostbyname(const char *name)
int WSAAPI rb_w32_recvfrom(int fd, char *buf, int len, int flags, struct sockaddr *from, int *fromlen)
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING
struct protoent *WSAAPI rb_w32_getprotobynumber(int num)
int rb_w32_open(const char *file, int oflag,...)
long _ftol2_sse(double d)
int rb_w32_read_reparse_point(const WCHAR *path, rb_w32_reparse_buffer_t *rp, size_t bufsize, WCHAR **result, DWORD *len)
struct netent * getnetbyaddr(long net, int type)
int rb_w32_fdisset(int fd, fd_set *set)
int rb_w32_rename(const char *from, const char *to)
uintptr_t rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self, int argc, uintptr_t *argv, uintptr_t intrval)
struct direct * rb_w32_readdir(DIR *dirp, rb_encoding *enc)
#define STRNDUPV(ptr, v, src, len)
long rb_w32_write_console(uintptr_t strarg, int fd)
int WSAAPI rb_w32_inet_pton(int af, const char *src, void *dst)
char * rb_w32_getcwd(char *buffer, int size)
int rb_w32_dup2(int oldfd, int newfd)
void rb_w32_fdclr(int fd, fd_set *set)
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout)
char * rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc)
int rb_w32_unwrap_io_handle(int fd)
int rb_w32_set_nonblock2(int fd, int nonblock)
int rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout)
int rb_w32_sleep(unsigned long msec)
#define access(path, mode)
uintptr_t(* asynchronous_func_t)(uintptr_t self, int argc, uintptr_t *argv)
typedef HRESULT(STDAPICALLTYPE FNCOCREATEINSTANCEEX)(REFCLSID
if((ID)(DISPID) nameid !=nameid)
int read(izstream &zs, T *x, Items items)