22 #undef __STRICT_ANSI__
59 #define isdirsep(x) ((x) == '/' || (x) == '\\')
61 #if defined _MSC_VER && _MSC_VER <= 1200
62 # define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags))
65 static int w32_wopen(
const WCHAR *file,
int oflag,
int perm);
67 static char *w32_getenv(
const char *
name, UINT cp);
70 #define DLN_FIND_EXTRA_ARG_DECL ,UINT cp
71 #define DLN_FIND_EXTRA_ARG ,cp
72 #define rb_w32_stati128(path, st) w32_stati128(path, st, cp, FALSE)
73 #define getenv(name) w32_getenv(name, cp)
75 #define CharNext(p) CharNextExA(cp, (p), 0)
76 #define dln_find_exe_r rb_w32_udln_find_exe_r
77 #define dln_find_file_r rb_w32_udln_find_file_r
81 #undef rb_w32_stati128
83 #undef dln_find_file_r
84 #define dln_find_exe_r(fname, path, buf, size) rb_w32_udln_find_exe_r(fname, path, buf, size, cp)
85 #define dln_find_file_r(fname, path, buf, size) rb_w32_udln_find_file_r(fname, path, buf, size, cp)
90 # define PATH_MAX MAX_PATH
91 # elif defined HAVE_SYS_PARAM_H
92 # include <sys/param.h>
93 # define PATH_MAX MAXPATHLEN
105 #if RUBY_MSVCRT_VERSION >= 140
106 # define _filbuf _fgetc_nolock
107 # define _flsbuf _fputc_nolock
109 #define enough_to_get(n) (--(n) >= 0)
110 #define enough_to_put(n) (--(n) >= 0)
113 #define Debug(something) something
115 #define Debug(something)
118 #define TO_SOCKET(x) _get_osfhandle(x)
122 static int has_redirection(
const char *, UINT);
124 static int rb_w32_open_osfhandle(
intptr_t osfhandle,
int flags);
128 static FARPROC get_proc_address(
const char *module,
const char *func, HANDLE *mh);
130 #define RUBY_CRITICAL if (0) {} else
137 { ERROR_INVALID_FUNCTION,
EINVAL },
138 { ERROR_FILE_NOT_FOUND,
ENOENT },
139 { ERROR_PATH_NOT_FOUND,
ENOENT },
140 { ERROR_TOO_MANY_OPEN_FILES,
EMFILE },
141 { ERROR_ACCESS_DENIED,
EACCES },
142 { ERROR_INVALID_HANDLE,
EBADF },
143 { ERROR_ARENA_TRASHED,
ENOMEM },
144 { ERROR_NOT_ENOUGH_MEMORY,
ENOMEM },
145 { ERROR_INVALID_BLOCK,
ENOMEM },
146 { ERROR_BAD_ENVIRONMENT,
E2BIG },
148 { ERROR_INVALID_ACCESS,
EINVAL },
149 { ERROR_INVALID_DATA,
EINVAL },
150 { ERROR_INVALID_DRIVE,
ENOENT },
151 { ERROR_CURRENT_DIRECTORY,
EACCES },
152 { ERROR_NOT_SAME_DEVICE,
EXDEV },
153 { ERROR_NO_MORE_FILES,
ENOENT },
154 { ERROR_WRITE_PROTECT,
EROFS },
155 { ERROR_BAD_UNIT,
ENODEV },
156 { ERROR_NOT_READY,
ENXIO },
157 { ERROR_BAD_COMMAND,
EACCES },
159 { ERROR_BAD_LENGTH,
EACCES },
161 { ERROR_NOT_DOS_DISK,
EACCES },
162 { ERROR_SECTOR_NOT_FOUND,
EACCES },
163 { ERROR_OUT_OF_PAPER,
EACCES },
164 { ERROR_WRITE_FAULT,
EIO },
165 { ERROR_READ_FAULT,
EIO },
166 { ERROR_GEN_FAILURE,
EACCES },
167 { ERROR_LOCK_VIOLATION,
EACCES },
168 { ERROR_SHARING_VIOLATION,
EACCES },
169 { ERROR_WRONG_DISK,
EACCES },
170 { ERROR_SHARING_BUFFER_EXCEEDED,
EACCES },
171 { ERROR_BAD_NETPATH,
ENOENT },
172 { ERROR_NETWORK_ACCESS_DENIED,
EACCES },
173 { ERROR_BAD_NET_NAME,
ENOENT },
174 { ERROR_FILE_EXISTS,
EEXIST },
175 { ERROR_CANNOT_MAKE,
EACCES },
176 { ERROR_FAIL_I24,
EACCES },
177 { ERROR_INVALID_PARAMETER,
EINVAL },
178 { ERROR_NO_PROC_SLOTS,
EAGAIN },
179 { ERROR_DRIVE_LOCKED,
EACCES },
180 { ERROR_BROKEN_PIPE,
EPIPE },
181 { ERROR_DISK_FULL,
ENOSPC },
182 { ERROR_INVALID_TARGET_HANDLE,
EBADF },
183 { ERROR_INVALID_HANDLE,
EINVAL },
184 { ERROR_WAIT_NO_CHILDREN,
ECHILD },
185 { ERROR_CHILD_NOT_COMPLETE,
ECHILD },
186 { ERROR_DIRECT_ACCESS_HANDLE,
EBADF },
187 { ERROR_NEGATIVE_SEEK,
EINVAL },
188 { ERROR_SEEK_ON_DEVICE,
EACCES },
191 { ERROR_NOT_LOCKED,
EACCES },
192 { ERROR_BAD_PATHNAME,
ENOENT },
193 { ERROR_MAX_THRDS_REACHED,
EAGAIN },
194 { ERROR_LOCK_FAILED,
EACCES },
195 { ERROR_ALREADY_EXISTS,
EEXIST },
196 { ERROR_INVALID_STARTING_CODESEG,
ENOEXEC },
197 { ERROR_INVALID_STACKSEG,
ENOEXEC },
198 { ERROR_INVALID_MODULETYPE,
ENOEXEC },
199 { ERROR_INVALID_EXE_SIGNATURE,
ENOEXEC },
200 { ERROR_EXE_MARKED_INVALID,
ENOEXEC },
201 { ERROR_BAD_EXE_FORMAT,
ENOEXEC },
202 { ERROR_ITERATED_DATA_EXCEEDS_64k,
ENOEXEC },
203 { ERROR_INVALID_MINALLOCSIZE,
ENOEXEC },
204 { ERROR_DYNLINK_FROM_INVALID_RING,
ENOEXEC },
205 { ERROR_IOPL_NOT_ENABLED,
ENOEXEC },
206 { ERROR_INVALID_SEGDPL,
ENOEXEC },
207 { ERROR_AUTODATASEG_EXCEEDS_64k,
ENOEXEC },
208 { ERROR_RING2SEG_MUST_BE_MOVABLE,
ENOEXEC },
209 { ERROR_RELOC_CHAIN_XEEDS_SEGLIM,
ENOEXEC },
210 { ERROR_INFLOOP_IN_RELOC_CHAIN,
ENOEXEC },
211 { ERROR_FILENAME_EXCED_RANGE,
ENOENT },
212 { ERROR_NESTING_NOT_ALLOWED,
EAGAIN },
213 #ifndef ERROR_PIPE_LOCAL
214 #define ERROR_PIPE_LOCAL 229L
217 { ERROR_BAD_PIPE,
EPIPE },
218 { ERROR_PIPE_BUSY,
EAGAIN },
219 { ERROR_NO_DATA,
EPIPE },
220 { ERROR_PIPE_NOT_CONNECTED,
EPIPE },
221 { ERROR_OPERATION_ABORTED,
EINTR },
222 { ERROR_NOT_ENOUGH_QUOTA,
ENOMEM },
223 { ERROR_MOD_NOT_FOUND,
ENOENT },
224 { ERROR_PRIVILEGE_NOT_HELD,
EACCES, },
225 { ERROR_CANT_RESOLVE_FILENAME,
ELOOP, },
281 for (
i = 0;
i < (
int)(
sizeof(errmap) /
sizeof(*errmap));
i++) {
283 return errmap[
i].err;
287 if (
winerr >= WSABASEERR) {
293 #define map_errno rb_w32_map_errno
295 static const char *NTLoginName;
297 static OSVERSIONINFO osver;
303 memset(&osver, 0,
sizeof(OSVERSIONINFO));
304 osver.dwOSVersionInfoSize =
sizeof(OSVERSIONINFO);
305 GetVersionEx(&osver);
313 return osver.dwPlatformId;
321 return osver.dwMajorVersion;
327 #define LK_ERR(f,i) \
332 DWORD err = GetLastError(); \
333 if (err == ERROR_LOCK_VIOLATION || err == ERROR_IO_PENDING) \
334 errno = EWOULDBLOCK; \
335 else if (err == ERROR_NOT_LOCKED) \
338 errno = map_errno(err); \
341 #define LK_LEN ULONG_MAX
349 const HANDLE fh = (HANDLE)
self;
350 const int oper =
argc;
366 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
394 static inline WCHAR *
395 translate_wchar(WCHAR *p,
int from,
int to)
406 translate_char(
char *p,
int from,
int to, UINT cp)
409 if ((
unsigned char)*p == from)
411 p = CharNextExA(cp, p, 0);
416 #ifndef CSIDL_LOCAL_APPDATA
417 #define CSIDL_LOCAL_APPDATA 28
419 #ifndef CSIDL_COMMON_APPDATA
420 #define CSIDL_COMMON_APPDATA 35
422 #ifndef CSIDL_WINDOWS
423 #define CSIDL_WINDOWS 36
426 #define CSIDL_SYSTEM 37
428 #ifndef CSIDL_PROFILE
429 #define CSIDL_PROFILE 40
434 get_special_folder(
int n, WCHAR *
buf,
size_t len)
439 typedef BOOL (WINAPI *get_path_func)(LPITEMIDLIST, WCHAR*,
DWORD,
int);
440 static get_path_func func = (get_path_func)-1;
442 if (func == (get_path_func)-1) {
443 func = (get_path_func)
444 get_proc_address(
"shell32",
"SHGetPathFromIDListEx",
NULL);
446 if (!func &&
len < MAX_PATH)
return FALSE;
448 if (SHGetSpecialFolderLocation(
NULL,
n, &pidl) == 0) {
453 f = SHGetPathFromIDListW(pidl,
buf);
456 alloc->lpVtbl->Free(alloc, pidl);
457 alloc->lpVtbl->Release(alloc);
464 regulate_path(WCHAR *
path)
466 WCHAR *p = translate_wchar(
path,
L'\\',
L'/');
475 get_proc_address(
const char *module,
const char *func, HANDLE *mh)
481 h = LoadLibrary(module);
483 h = GetModuleHandle(module);
487 ptr = GetProcAddress(
h, func);
508 #if defined _MSC_VER && _MSC_VER <= 1200
510 #define GetSystemWindowsDirectoryW GetWindowsDirectoryW
517 static const WCHAR temp[] =
L"temp";
521 if (GetSystemWindowsDirectoryW(
path,
len))
return 0;
523 p = translate_wchar(
path,
L'\\',
L'/');
524 if (*(p - 1) !=
L'/') *p++ =
L'/';
526 memcpy(p, temp,
sizeof(temp));
542 WCHAR *buffer =
NULL;
543 size_t buffer_len = MAX_PATH,
len = 0;
545 HOME_NONE, ENV_HOME, ENV_DRIVEPATH, ENV_USERPROFILE
546 } home_type = HOME_NONE;
548 if ((
len = GetEnvironmentVariableW(
L"HOME",
NULL, 0)) != 0) {
550 home_type = ENV_HOME;
552 else if ((
len = GetEnvironmentVariableW(
L"HOMEDRIVE",
NULL, 0)) != 0) {
554 if ((
len = GetEnvironmentVariableW(
L"HOMEPATH",
NULL, 0)) != 0) {
556 home_type = ENV_DRIVEPATH;
559 else if ((
len = GetEnvironmentVariableW(
L"USERPROFILE",
NULL, 0)) != 0) {
561 home_type = ENV_USERPROFILE;
565 buffer =
ALLOC_N(WCHAR, buffer_len);
569 GetEnvironmentVariableW(
L"HOME", buffer, buffer_len);
572 len = GetEnvironmentVariableW(
L"HOMEDRIVE", buffer, buffer_len);
573 GetEnvironmentVariableW(
L"HOMEPATH", buffer +
len, buffer_len -
len);
575 case ENV_USERPROFILE:
576 GetEnvironmentVariableW(
L"USERPROFILE", buffer, buffer_len);
579 if (!get_special_folder(
CSIDL_PROFILE, buffer, buffer_len) &&
580 !get_special_folder(CSIDL_PERSONAL, buffer, buffer_len)) {
584 REALLOC_N(buffer, WCHAR, lstrlenW(buffer) + 1);
589 regulate_path(buffer);
598 static const WCHAR TMPDIR[] =
L"TMPDIR";
603 #define set_env_val(vname) do { \
604 typedef char wk_name_offset[(numberof(wk.name) - (numberof(vname) - 1)) * 2 + 1]; \
605 WCHAR *const buf = wk.name + sizeof(wk_name_offset) / 2; \
606 MEMCPY(buf, vname, WCHAR, numberof(vname) - 1); \
621 else if (GetEnvironmentVariableW(
L"USERPROFILE",
env,
numberof(
env))) {
627 else if (get_special_folder(CSIDL_PERSONAL,
env,
numberof(
env))) {
639 NTLoginName =
"<Unknown>";
661 static void init_stdhandle(
void);
663 #if RUBY_MSVCRT_VERSION >= 80
666 invalid_parameter(
const wchar_t *expr,
const wchar_t *func,
const wchar_t *file,
unsigned int line,
uintptr_t dummy)
671 int ruby_w32_rtc_error;
675 rtc_error_handler(
int e,
const char *
src,
int line,
const char *exe,
const char *
fmt, ...)
680 if (!ruby_w32_rtc_error)
return 0;
691 static CRITICAL_SECTION select_mutex;
694 #define conlist_disabled ((st_table *)-1)
695 static char *uenvarea;
717 constat_delete(HANDLE
h)
731 DeleteCriticalSection(&select_mutex);
755 install_vm_exit_handler(
void)
757 static bool installed = 0;
776 version = MAKEWORD(2, 0);
777 if (WSAStartup(version, &retdata))
778 rb_fatal(
"Unable to locate winsock library!");
779 if (LOBYTE(retdata.wVersion) != 2)
780 rb_fatal(
"could not find version 2 of winsock dll");
782 InitializeCriticalSection(&select_mutex);
787 #define MAKE_SOCKDATA(af, fl) ((int)((((int)af)<<4)|((fl)&0xFFFF)))
788 #define GET_FAMILY(v) ((int)(((v)>>4)&0xFFFF))
789 #define GET_FLAGS(v) ((int)((v)&0xFFFF))
793 socklist_insert(SOCKET sock,
int flag)
797 install_vm_exit_handler();
804 socklist_lookup(SOCKET sock,
int *flagp)
820 socklist_delete(SOCKET *sockp,
int *flagp)
833 *sockp = (SOCKET)
key;
841 static int w32_cmdvector(
const WCHAR *,
char ***, UINT,
rb_encoding *);
849 #if RUBY_MSVCRT_VERSION >= 80
850 static void set_pioinfo_extra(
void);
852 _CrtSetReportMode(_CRT_ASSERT, 0);
853 _set_invalid_parameter_handler(invalid_parameter);
854 _RTC_SetErrorFunc(rtc_error_handler);
857 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
883 return (
char *)NTLoginName;
886 #define MAXCHILDNUM 256
889 static struct ChildRecord {
895 #define FOREACH_CHILD(v) do { \
896 struct ChildRecord* v; \
897 for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
898 #define END_FOREACH_CHILD } while (0)
901 static struct ChildRecord *
906 if (child->pid == pid) {
914 static struct ChildRecord *
915 FindChildSlotByHandle(HANDLE
h)
919 if (child->hProcess ==
h) {
928 CloseChildHandle(
struct ChildRecord *child)
930 HANDLE
h = child->hProcess;
931 child->hProcess =
NULL;
937 static struct ChildRecord *
938 FindFreeChildSlot(
void)
943 child->hProcess =
NULL;
957 #define InternalCmdsMax 8
1012 internal_match(
const void *
key,
const void *elem)
1019 is_command_com(
const char *interp)
1023 if ((
i == 0 || (
i > 0 &&
isdirsep(interp[
i-1]))) &&
1030 static int internal_cmd_match(
const char *cmdname,
int nt);
1034 is_internal_cmd(
const char *cmd,
int nt)
1036 char cmdname[9], *b = cmdname, c;
1039 if (!(c = *cmd++))
return 0;
1040 }
while (isspace(c));
1043 while (isalpha(c)) {
1045 if (b == cmdname +
sizeof(cmdname))
return 0;
1048 if (c ==
'.') c = *cmd;
1050 case '<':
case '>':
case '|':
1052 case '\0':
case ' ':
case '\t':
case '\n':
1058 return internal_cmd_match(cmdname, nt);
1063 internal_cmd_match(
const char *cmdname,
int nt)
1067 nm =
bsearch(cmdname, szInternalCmds,
1068 sizeof(szInternalCmds) /
sizeof(*szInternalCmds),
1069 sizeof(*szInternalCmds),
1071 if (!nm || !(nm[0] & (nt ? 2 : 1)))
1080 return _get_osfhandle(fh);
1085 join_argv(
char *cmd,
char *
const *
argv, BOOL escape, UINT cp,
int backslash)
1089 int len,
n, bs, quote;
1091 for (t =
argv, q = cmd,
len = 0; (p = *t) != 0; t++) {
1094 if (!*p ||
strpbrk(p,
" \t\"'")) {
1099 for (bs = 0; *p; ++p) {
1118 case '<':
case '>':
case '|':
case '^':
1119 if (escape && !quote) {
1120 len += (
n = p - s) + 1;
1131 p = CharNextExA(cp, p, 0) - 1;
1135 len += (
n = p - s) + 1;
1139 if (backslash > 0) {
1142 translate_char(q,
'/',
'\\', cp);
1145 if (quote) *q++ =
'"';
1158 #define STRNDUPV(ptr, v, src, len) \
1159 (((char *)memcpy(((ptr) = ALLOCV((v), (len) + 1)), (src), (len)))[len] = 0)
1163 check_spawn_mode(
int mode)
1177 child_result(
struct ChildRecord *child,
int mode)
1185 if (mode == P_OVERLAY) {
1186 WaitForSingleObject(child->hProcess, INFINITE);
1187 GetExitCodeProcess(child->hProcess, &exitcode);
1188 CloseChildHandle(child);
1196 CreateChild(
struct ChildRecord *child,
const WCHAR *cmd,
const WCHAR *prog, HANDLE hInput, HANDLE hOutput, HANDLE hError,
DWORD dwCreationFlags)
1199 STARTUPINFOW aStartupInfo;
1200 PROCESS_INFORMATION aProcessInformation;
1201 SECURITY_ATTRIBUTES sa;
1203 if (!cmd && !prog) {
1213 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
1214 sa.lpSecurityDescriptor =
NULL;
1215 sa.bInheritHandle =
TRUE;
1217 memset(&aStartupInfo, 0,
sizeof(aStartupInfo));
1218 memset(&aProcessInformation, 0,
sizeof(aProcessInformation));
1219 aStartupInfo.cb =
sizeof(aStartupInfo);
1220 aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
1222 aStartupInfo.hStdInput = hInput;
1225 aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1228 aStartupInfo.hStdOutput = hOutput;
1231 aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1234 aStartupInfo.hStdError = hError;
1237 aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1240 dwCreationFlags |= NORMAL_PRIORITY_CLASS;
1242 if (lstrlenW(cmd) > 32767) {
1249 fRet = CreateProcessW(prog, (WCHAR *)cmd, &sa, &sa,
1250 sa.bInheritHandle, dwCreationFlags,
NULL,
NULL,
1251 &aStartupInfo, &aProcessInformation);
1260 CloseHandle(aProcessInformation.hThread);
1262 child->hProcess = aProcessInformation.hProcess;
1263 child->pid = (
rb_pid_t)aProcessInformation.dwProcessId;
1270 is_batch(
const char *cmd)
1273 if (
len <= 4)
return 0;
1275 if (*cmd++ !=
'.')
return 0;
1281 #define filecp rb_w32_filecp
1282 #define mbstr_to_wstr rb_w32_mbstr_to_wstr
1283 #define wstr_to_mbstr rb_w32_wstr_to_mbstr
1284 #define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen)
1285 #define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen)
1286 #define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen)
1287 #define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen)
1288 #define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen)
1289 #define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen)
1299 struct ChildRecord child;
1303 HANDLE outHandle =
NULL;
1322 if (!CreateChild(&child, wcmd, wprog,
NULL, outHandle, outHandle, 0)) {
1328 return child.hProcess;
1333 w32_spawn(
int mode,
const char *cmd,
const char *prog, UINT cp)
1337 const char *shell =
NULL;
1338 WCHAR *wcmd =
NULL, *wshell =
NULL;
1344 char *cmd_sep =
NULL;
1346 if (check_spawn_mode(mode))
return -1;
1354 translate_char(p,
'/',
'\\', cp);
1361 if ((shell =
getenv(
"RUBYSHELL")) && (redir = has_redirection(cmd, cp))) {
1362 size_t shell_len =
strlen(shell);
1363 char *tmp =
ALLOCV(
v, shell_len +
strlen(cmd) +
sizeof(
" -c ") + 2);
1364 memcpy(tmp, shell, shell_len + 1);
1365 translate_char(tmp,
'/',
'\\', cp);
1366 sprintf(tmp + shell_len,
" -c \"%s\"", cmd);
1369 else if ((shell =
getenv(
"COMSPEC")) &&
1370 (nt = !is_command_com(shell),
1371 (redir < 0 ? has_redirection(cmd, cp) : redir) ||
1372 is_internal_cmd(cmd, nt))) {
1374 sprintf(tmp, nt ?
"%s /c \"%s\"" :
"%s /c %s", shell, cmd);
1378 int len = 0, quote = (*cmd ==
'"') ?
'"' : (*cmd ==
'\'') ?
'\'' : 0;
1380 for (prog = cmd + !!quote;; prog = CharNextExA(cp, prog, 0)) {
1381 if (*prog ==
'/') slash = 1;
1391 if ((
unsigned char)*prog == quote) {
1392 len = prog++ - cmd - 1;
1397 if (quote)
continue;
1403 sep = *(cmd_sep = &p[
len]);
1411 if (p && slash) translate_char(p,
'/',
'\\', cp);
1413 shell = p ? p : cmd;
1417 if (
strchr(shell,
' ')) quote = -1;
1418 if (shell == fbuf) {
1421 else if (shell != p &&
strchr(shell,
'/')) {
1425 if (p) translate_char(p,
'/',
'\\', cp);
1426 if (is_batch(shell)) {
1428 cmd = p =
ALLOCV(
v,
len + alen + (quote ? 2 : 0) + 1);
1429 if (quote) *p++ =
'"';
1432 if (quote) *p++ =
'"';
1433 memcpy(p, prog, alen + 1);
1441 if (cmd_sep) *cmd_sep = sep;
1447 struct ChildRecord *child = FindFreeChildSlot();
1448 if (CreateChild(child, wcmd, wshell,
NULL,
NULL,
NULL, 0)) {
1449 ret = child_result(child, mode);
1463 return w32_spawn(mode, cmd, prog,
filecp());
1470 return w32_spawn(mode, cmd, prog, CP_UTF8);
1475 w32_aspawn_flags(
int mode,
const char *prog,
char *
const *
argv,
DWORD flags, UINT cp)
1479 BOOL ntcmd =
FALSE, tmpnt;
1487 if (check_spawn_mode(mode))
return -1;
1489 if (!prog) prog =
argv[0];
1490 if ((shell =
getenv(
"COMSPEC")) &&
1491 internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
1497 if (cmd == prog)
strlcpy(cmd = fbuf, prog,
sizeof(fbuf));
1498 translate_char(cmd,
'/',
'\\', cp);
1501 else if (
strchr(prog,
'/')) {
1503 if (
len <
sizeof(fbuf))
1504 strlcpy(cmd = fbuf, prog,
sizeof(fbuf));
1507 translate_char(cmd,
'/',
'\\', cp);
1510 if (c_switch || is_batch(prog)) {
1512 progs[0] = (
char *)prog;
1514 len = join_argv(
NULL, progs, ntcmd, cp, 1);
1515 if (c_switch)
len += 3;
1519 join_argv(cmd, progs, ntcmd, cp, 1);
1522 prog = c_switch ? shell : 0;
1535 struct ChildRecord *child = FindFreeChildSlot();
1536 if (CreateChild(child, wcmd, wprog,
NULL,
NULL,
NULL, flags)) {
1537 ret = child_result(child, mode);
1551 return w32_aspawn_flags(mode, prog,
argv, flags,
filecp());
1558 return w32_aspawn_flags(mode, prog,
argv, flags, CP_UTF8);
1587 #define NTGLOB 0x1 // element contains a wildcard
1588 #define NTMALLOC 0x2 // string in element was malloc'ed
1589 #define NTSTRING 0x4 // element contains a quoted string
1593 insert(
const char *
path,
VALUE vinfo,
void *enc)
1599 if (!tmpcurr)
return -1;
1603 if (!tmpcurr->
str)
return -1;
1606 *tail = &tmpcurr->
next;
1624 translate_char(
buf,
'\\',
'/', cp);
1629 if (status ||
last == tail)
return 0;
1643 has_redirection(
const char *cmd, UINT cp)
1659 else if (quote == *
ptr)
1677 if (*
ptr++ ==
'%')
return TRUE;
1683 ptr = CharNextExA(cp,
ptr, 0);
1691 static inline WCHAR *
1692 skipspace(WCHAR *
ptr)
1701 w32_cmdvector(
const WCHAR *cmd,
char ***vec, UINT cp,
rb_encoding *enc)
1704 int elements, strsz, done;
1705 int slashes, escape;
1706 WCHAR *
ptr, *base, *cmdline;
1707 char *cptr, *buffer;
1723 ptr = cmdline = wcsdup(cmd);
1734 while (*(
ptr = skipspace(
ptr))) {
1736 quote = slashes = globbing = escape = 0;
1737 for (done = 0; !done && *
ptr; ) {
1746 if (quote !=
L'\'') slashes++;
1786 if (!(slashes & 1)) {
1789 else if (quote == *
ptr) {
1790 if (quote ==
L'"' && quote ==
ptr[1])
1823 slashes = quote = 0;
1824 while (p < base +
len) {
1828 if (quote !=
L'\'') slashes++;
1833 if (!(slashes & 1) && quote && quote != c) {
1838 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
1839 sizeof(WCHAR) * (base +
len - p));
1840 len -= ((slashes + 1) >> 1) + (~slashes & 1);
1841 p -= (slashes + 1) >> 1;
1842 if (!(slashes & 1)) {
1844 if (quote ==
L'"' && quote == *p)
1865 if (!curr)
goto do_nothing;
1869 if (globbing && (tail = cmdglob(curr, cmdtail, cp, enc))) {
1874 cmdtail = &curr->
next;
1884 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->
next) {
1886 strsz += (curr->
len + 1);
1889 len = (elements+1)*
sizeof(
char *) + strsz;
1893 while ((curr = cmdhead) != 0) {
1894 cmdhead = curr->
next;
1899 for (vptr = *vec; *vptr; ++vptr);
1915 vptr = (
char **) buffer;
1917 cptr = buffer + (elements+1) *
sizeof(
char *);
1919 while ((curr = cmdhead) != 0) {
1921 cptr[curr->
len] =
'\0';
1923 cptr += curr->
len + 1;
1924 cmdhead = curr->
next;
1930 *vec = (
char **) buffer;
1952 get_proc_address(
"kernel32",
"GetFinalPathNameByHandleW",
NULL);
1953 if (!func) func = get_final_path_fail;
1954 get_final_path = func;
1955 return func(
f,
buf,
len, flag);
1965 const DWORD share_mode =
1966 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1967 return CreateFileW(
path,
access, share_mode,
NULL, OPEN_EXISTING,
1968 FILE_FLAG_BACKUP_SEMANTICS|
flags,
NULL);
1978 #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT))
1979 #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT))
1981 #define BitOfIsDir(n) ((n) * 2)
1982 #define BitOfIsRep(n) ((n) * 2 + 1)
1983 #define DIRENT_PER_CHAR (CHAR_BIT / 2)
1987 open_dir_handle(
const WCHAR *filename, WIN32_FIND_DATAW *fd)
1998 fh = open_special(filename, 0, 0);
1999 if (fh != INVALID_HANDLE_VALUE) {
2004 len = lstrlenW(filename);
2007 return INVALID_HANDLE_VALUE;
2011 p = &fullname[
len-1];
2012 if (!(
isdirsep(*p) || *p ==
L':')) *++p =
L'\\';
2019 fh = FindFirstFileW(fullname, fd);
2020 if (fh == INVALID_HANDLE_VALUE) {
2028 w32_wopendir(
const WCHAR *wpath)
2031 WIN32_FIND_DATAW fd;
2044 if (wstati128(wpath, &sbuf,
FALSE) < 0) {
2047 if (!(sbuf.st_mode &
S_IFDIR) &&
2048 (!
ISALPHA(wpath[0]) || wpath[1] !=
L':' || wpath[2] !=
L'\0' ||
2049 ((1 << ((wpath[0] & 0x5f) -
'A')) & GetLogicalDrives()) == 0)) {
2053 fh = open_dir_handle(wpath, &fd);
2054 if (fh == INVALID_HANDLE_VALUE) {
2065 pathlen = lstrlenW(wpath);
2075 len = lstrlenW(fd.cFileName) + 1;
2076 altlen = lstrlenW(fd.cAlternateFileName) + 1;
2093 memcpy(&p->
start[idx +
len], fd.cAlternateFileName, altlen *
sizeof(WCHAR));
2102 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2104 if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
2105 WCHAR *tmppath =
malloc((pathlen +
len + 1) *
sizeof(WCHAR));
2106 memcpy(tmppath, wpath, pathlen *
sizeof(WCHAR));
2107 tmppath[pathlen] =
L'\\';
2108 memcpy(tmppath + pathlen + 1, fd.cFileName,
len *
sizeof(WCHAR));
2115 idx +=
len + altlen;
2116 }
while (FindNextFileW(fh, &fd));
2127 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
2136 int len = WideCharToMultiByte(cp, 0, wstr, clen,
NULL, 0,
NULL,
NULL);
2141 if (clen == -1) --
len;
2153 int len = MultiByteToWideChar(cp, 0,
str, clen,
NULL, 0);
2155 MultiByteToWideChar(cp, 0,
str, clen,
ptr,
len);
2158 if (clen == -1) --
len;
2172 ret = w32_wopendir(wpath);
2185 ret = w32_wopendir(wpath);
2196 move_to_next_entry(
DIR *dirp)
2200 dirp->
curr += lstrlenW(dirp->
curr) + 1;
2201 dirp->
curr += lstrlenW(dirp->
curr) + 1;
2214 win32_direct_conv(
const WCHAR *file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2216 UINT cp = *((UINT *)enc);
2232 long len = lstrlenW(wstr);
2239 #if SIZEOF_INT < SIZEOF_LONG
2240 # error long should equal to int on Windows
2243 len = WideCharToMultiByte(CP_UTF8, 0, wstr, clen,
NULL, 0,
NULL,
NULL);
2275 ruby_direct_conv(
const WCHAR *file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2289 readdir_internal(
DIR *dirp, BOOL (*conv)(
const WCHAR *,
const WCHAR *,
struct direct *,
const void *),
const void *enc)
2291 static int dummy = 0;
2326 move_to_next_entry(dirp);
2341 const UINT cp =
filecp();
2342 return readdir_internal(dirp, win32_direct_conv, &cp);
2345 const UINT cp = CP_UTF8;
2346 return readdir_internal(dirp, win32_direct_conv, &cp);
2349 return readdir_internal(dirp, ruby_direct_conv, enc);
2373 while (dirp->
curr && dirp->
loc < loc) {
2374 move_to_next_entry(dirp);
2411 #if RUBY_MSVCRT_VERSION >= 140
2426 CRITICAL_SECTION _lock;
2428 #define FILE_COUNT(stream) ((vcruntime_file*)stream)->_cnt
2429 #define FILE_READPTR(stream) ((vcruntime_file*)stream)->_ptr
2430 #define FILE_FILENO(stream) ((vcruntime_file*)stream)->_file
2432 #define FILE_COUNT(stream) stream->_cnt
2433 #define FILE_READPTR(stream) stream->_ptr
2434 #define FILE_FILENO(stream) stream->_file
2438 #if RUBY_MSVCRT_VERSION >= 140
2439 typedef char lowio_text_mode;
2440 typedef char lowio_pipe_lookahead[3];
2443 CRITICAL_SECTION lock;
2446 unsigned char osfile;
2447 lowio_text_mode textmode;
2448 lowio_pipe_lookahead _pipe_lookahead;
2462 #if RUBY_MSVCRT_VERSION >= 80
2469 #if !defined _CRTIMP || defined __MINGW32__
2471 #define _CRTIMP __declspec(dllimport)
2474 #if RUBY_MSVCRT_VERSION >= 140
2476 #define IOINFO_L2E 6
2479 #define IOINFO_L2E 5
2481 static inline ioinfo* _pioinfo(
int);
2484 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
2485 #define _osfhnd(i) (_pioinfo(i)->osfhnd)
2486 #define _osfile(i) (_pioinfo(i)->osfile)
2487 #define rb_acrt_lowio_lock_fh(i) EnterCriticalSection(&_pioinfo(i)->lock)
2488 #define rb_acrt_lowio_unlock_fh(i) LeaveCriticalSection(&_pioinfo(i)->lock)
2490 #if RUBY_MSVCRT_VERSION >= 80
2495 set_pioinfo_extra(
void)
2497 #if RUBY_MSVCRT_VERSION >= 140
2498 # define FUNCTION_RET 0xc3
2500 # define UCRTBASE "ucrtbased.dll"
2502 # define UCRTBASE "ucrtbase.dll"
2505 char *p = (
char*)get_proc_address(UCRTBASE,
"_isatty",
NULL);
2513 # define FUNCTION_BEFORE_RET_MARK "\x48\x83\xc4"
2514 # define FUNCTION_SKIP_BYTES 1
2517 # define PIOINFO_MARK "\x48\x8d\x0d"
2520 # define PIOINFO_MARK "\x48\x8d\x15"
2525 # define FUNCTION_BEFORE_RET_MARK "\x5d"
2526 # define FUNCTION_SKIP_BYTES 0
2528 # define PIOINFO_MARK "\x8B\x04\x85"
2531 for (pend += 10; pend < p + 300; pend++) {
2533 if (
memcmp(pend, FUNCTION_BEFORE_RET_MARK,
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) == 0 &&
2534 *(pend + (
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) + FUNCTION_SKIP_BYTES) & FUNCTION_RET == FUNCTION_RET) {
2536 for (pend -= (
sizeof(PIOINFO_MARK) - 1); pend > p; pend--) {
2537 if (
memcmp(pend, PIOINFO_MARK,
sizeof(PIOINFO_MARK) - 1) == 0) {
2550 p +=
sizeof(PIOINFO_MARK) - 1;
2561 fd = _open(
"NUL", O_RDONLY);
2563 if (
_osfhnd(fd) == _get_osfhandle(fd)) {
2575 #define pioinfo_extra 0
2586 #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
2587 #define _set_osflags(fh, flags) (_osfile(fh) = (flags))
2590 #define FEOFLAG 0x02
2592 #define FNOINHERIT 0x10
2593 #define FAPPEND 0x20
2598 static int is_console(SOCKET);
2609 rb_w32_open_osfhandle(
intptr_t osfhandle,
int flags)
2618 if (flags & O_APPEND)
2624 if (flags & O_NOINHERIT)
2628 hF = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
2629 fh = _open_osfhandle((
intptr_t)hF, 0);
2651 init_stdhandle(
void)
2655 #define open_null(fd) \
2657 (nullfd = open("NUL", O_RDWR)) : 0), \
2658 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \
2673 if (nullfd >= 0 && !keep)
close(nullfd);
2683 if (socklist_lookup(sock,
NULL))
2708 static char buffer[512];
2715 #if WSAEWOULDBLOCK != EWOULDBLOCK
2720 for (s = 0; s < (
int)(
sizeof(errmap)/
sizeof(*errmap)); s++)
2721 if (errmap[s].
winerr == WSAEWOULDBLOCK)
2723 for (
i = s;
i < (
int)(
sizeof(errmap)/
sizeof(*errmap));
i++)
2724 if (errmap[
i].
err == e) {
2725 e = errmap[
i].winerr;
2730 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2731 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
2732 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
2733 buffer,
sizeof(buffer),
NULL) == 0 &&
2734 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2735 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
2736 buffer,
sizeof(buffer),
NULL) == 0)
2737 strlcpy(buffer,
"Unknown Error",
sizeof(buffer));
2832 for (
i = 0;
i < set->fd_count;
i++) {
2833 if (set->fd_array[
i] == s) {
2834 memmove(&set->fd_array[
i], &set->fd_array[
i+1],
2835 sizeof(set->fd_array[0]) * (--set->fd_count -
i));
2849 if (s == (SOCKET)INVALID_HANDLE_VALUE)
2859 max = min(
src->fd_count, (UINT)max);
2860 if ((UINT)dst->capa < (UINT)max) {
2862 dst->
fdset =
xrealloc(dst->
fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2866 max *
sizeof(
src->fd_array[0]));
2867 dst->
fdset->fd_count =
src->fd_count;
2874 if ((UINT)dst->capa <
src->fdset->fd_count) {
2876 dst->
fdset =
xrealloc(dst->
fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2880 src->fdset->fd_count *
sizeof(
src->fdset->fd_array[0]));
2881 dst->
fdset->fd_count =
src->fdset->fd_count;
2900 while (s < src->fd_count) {
2901 SOCKET fd =
src->fd_array[s];
2903 if (!func || (*func)(fd)) {
2907 for (d = 0; d < dst->
fdset->fd_count; d++) {
2908 if (dst->
fdset->fd_array[d] == fd)
2911 if (d == dst->
fdset->fd_count) {
2912 if ((
int)dst->
fdset->fd_count >= dst->capa) {
2914 dst->
fdset =
xrealloc(dst->
fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2916 dst->
fdset->fd_array[dst->
fdset->fd_count++] = fd;
2920 &
src->fd_array[s+1],
2921 sizeof(
src->fd_array[0]) * (--
src->fd_count - s));
2931 return dst ? dst->
fdset->fd_count : m;
2939 if (!
src || !dst)
return 0;
2941 for (s = 0; s <
src->fd_count; ++s) {
2942 SOCKET fd =
src->fd_array[s];
2944 for (d = 0; d < dst->fd_count; ++d) {
2945 if (dst->fd_array[d] == fd)
2949 dst->fd_array[dst->fd_count++] = fd;
2953 return dst->fd_count;
2958 is_not_socket(SOCKET sock)
2965 is_pipe(SOCKET sock)
2970 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
2978 is_readable_pipe(SOCKET sock)
2988 ret = (GetLastError() == ERROR_BROKEN_PIPE);
2997 is_console(SOCKET sock)
3004 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &
n));
3012 is_readable_console(SOCKET sock)
3019 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &
n) &&
n > 0) {
3020 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
3021 ir.Event.KeyEvent.uChar.AsciiChar) {
3025 ReadConsoleInput((HANDLE)sock, &ir, 1, &
n);
3035 is_invalid_handle(SOCKET sock)
3037 return (HANDLE)sock == INVALID_HANDLE_VALUE;
3055 EnterCriticalSection(&select_mutex);
3056 r =
select(nfds, rd, wr, ex, timeout);
3057 LeaveCriticalSection(&select_mutex);
3058 if (r == SOCKET_ERROR) {
3114 struct timeval *timeout,
void *th)
3123 struct timeval limit = {0, 0};
3125 if (nfds < 0 || (timeout && (timeout->
tv_sec < 0 || timeout->
tv_usec < 0))) {
3131 if (timeout->
tv_sec < 0 ||
3133 timeout->
tv_usec >= 1000000) {
3140 if (limit.
tv_usec >= 1000000) {
3153 nonsock += extract_fd(&else_rd, rd, is_not_socket);
3156 nonsock += extract_fd(&else_wr, wr, is_not_socket);
3159 if (extract_fd(
NULL, else_rd.
fdset, is_invalid_handle) > 0 ||
3160 extract_fd(
NULL, else_wr.
fdset, is_invalid_handle) > 0) {
3168 extract_fd(&pipe_rd, else_rd.
fdset, is_pipe);
3171 extract_fd(&cons_rd, else_rd.
fdset, is_console);
3174 extract_fd(&except, ex, is_not_socket);
3177 if (rd && (
int)rd->fd_count > r) r = (
int)rd->fd_count;
3178 if (wr && (
int)wr->fd_count > r) r = (
int)wr->fd_count;
3179 if (ex && (
int)ex->fd_count > r) r = (
int)ex->fd_count;
3180 if (nfds > r) nfds = r;
3194 extract_fd(&else_rd, pipe_rd.
fdset, is_readable_pipe);
3195 extract_fd(&else_rd, cons_rd.
fdset, is_readable_console);
3198 if (else_rd.
fdset->fd_count || else_wr.
fdset->fd_count) {
3199 r = do_select(nfds, rd, wr, ex, &zero);
3201 r += copy_fd(rd, else_rd.
fdset);
3202 r += copy_fd(wr, else_wr.
fdset);
3218 if (rd) copy_fd(&orig_rd, rd);
3219 if (wr) copy_fd(&orig_wr, wr);
3220 if (ex) copy_fd(&orig_ex, ex);
3221 r = do_select(nfds, rd, wr, ex, &zero);
3223 if (rd) copy_fd(rd, &orig_rd);
3224 if (wr) copy_fd(wr, &orig_wr);
3225 if (ex) copy_fd(ex, &orig_ex);
3232 if (compare(&rest, &
wait) < 0) dowait = &rest;
3234 Sleep(dowait->
tv_sec * 1000 + (dowait->
tv_usec + 999) / 1000);
3258 get_wsa_extension_function(SOCKET s, GUID *guid)
3263 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, guid,
sizeof(*guid),
3280 r = accept(
TO_SOCKET(s), addr, addrlen);
3281 if (r != INVALID_SOCKET) {
3282 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
3285 socklist_insert(r, 0);
3307 if (r == SOCKET_ERROR)
3321 r = connect(
TO_SOCKET(s), addr, addrlen);
3322 if (r == SOCKET_ERROR) {
3323 int err = WSAGetLastError();
3324 if (
err != WSAEWOULDBLOCK)
3342 r = getpeername(
TO_SOCKET(s), addr, addrlen);
3343 if (r == SOCKET_ERROR)
3359 r = getsockname(sock, addr, addrlen);
3360 if (r == SOCKET_ERROR) {
3361 DWORD wsaerror = WSAGetLastError();
3362 if (wsaerror == WSAEINVAL) {
3364 if (socklist_lookup(sock, &flags)) {
3367 memset(addr, 0, *addrlen);
3368 addr->sa_family = af;
3387 r = getsockopt(
TO_SOCKET(s), level, optname, optval, optlen);
3388 if (r == SOCKET_ERROR)
3402 r = ioctlsocket(
TO_SOCKET(s), cmd, argp);
3403 if (r == SOCKET_ERROR)
3418 if (r == SOCKET_ERROR)
3436 if (result != SOCKET_ERROR)
3438 else if ((
err = WSAGetLastError()) == WSA_IO_PENDING) {
3442 result = WSAGetOverlappedResult(s, wol, &
size,
TRUE, &flg);
3449 result = SOCKET_ERROR;
3452 if ((
err = WSAGetLastError()) == WSAECONNABORTED && !
input)
3454 else if (
err == WSAEMSGSIZE &&
input) {
3462 case WAIT_OBJECT_0 + 1:
3465 CancelIo((HANDLE)s);
3470 if (
err == WSAECONNABORTED && !
input)
3476 CloseHandle(wol->hEvent);
3483 overlapped_socket_io(BOOL
input,
int fd,
char *
buf,
int len,
int flags,
3484 struct sockaddr *addr,
int *addrlen)
3495 socklist_lookup(s, &mode);
3499 if (addr && addrlen)
3500 r = recvfrom(s,
buf,
len, flags, addr, addrlen);
3502 r = recv(s,
buf,
len, flags);
3503 if (r == SOCKET_ERROR)
3507 if (addr && addrlen)
3508 r = sendto(s,
buf,
len, flags, addr, *addrlen);
3510 r = send(s,
buf,
len, flags);
3511 if (r == SOCKET_ERROR) {
3513 if (
err == WSAECONNABORTED)
3526 memset(&wol, 0,
sizeof(wol));
3531 if (addr && addrlen)
3532 ret = WSARecvFrom(s, &wbuf, 1, &
size, &flg, addr, addrlen,
3535 ret = WSARecv(s, &wbuf, 1, &
size, &flg, &wol,
NULL);
3538 if (addr && addrlen)
3539 ret = WSASendTo(s, &wbuf, 1, &
size, flags, addr, *addrlen,
3542 ret = WSASend(s, &wbuf, 1, &
size, flags, &wol,
NULL);
3546 finish_overlapped_socket(
input, s, &wol, ret, &rlen,
size);
3563 struct sockaddr *from,
int *fromlen)
3565 return overlapped_socket_io(
TRUE, fd,
buf,
len, flags, from, fromlen);
3578 const struct sockaddr *to,
int tolen)
3580 return overlapped_socket_io(
FALSE, fd, (
char *)
buf,
len, flags,
3581 (
struct sockaddr *)to, &tolen);
3584 #if !defined(MSG_TRUNC) && !defined(__MINGW32__)
3595 #ifndef WSAID_WSARECVMSG
3596 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
3598 #ifndef WSAID_WSASENDMSG
3599 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
3603 #define msghdr_to_wsamsg(msg, wsamsg) \
3606 (wsamsg)->name = (msg)->msg_name; \
3607 (wsamsg)->namelen = (msg)->msg_namelen; \
3608 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
3609 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
3610 for (i = 0; i < (msg)->msg_iovlen; ++i) { \
3611 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
3612 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
3614 (wsamsg)->Control.buf = (msg)->msg_control; \
3615 (wsamsg)->Control.len = (msg)->msg_controllen; \
3616 (wsamsg)->dwFlags = (msg)->msg_flags; \
3623 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET,
WSAMSG *,
DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3624 static WSARecvMsg_t pWSARecvMsg =
NULL;
3635 pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid);
3643 socklist_lookup(s, &mode);
3646 if ((ret = pWSARecvMsg(s, &wsamsg, &
len,
NULL,
NULL)) == SOCKET_ERROR) {
3655 memset(&wol, 0,
sizeof(wol));
3658 ret = pWSARecvMsg(s, &wsamsg, &
size, &wol,
NULL);
3661 ret = finish_overlapped_socket(
TRUE, s, &wol, ret, &
len,
size);
3663 if (ret == SOCKET_ERROR)
3678 typedef int (WSAAPI *WSASendMsg_t)(SOCKET,
const WSAMSG *,
DWORD,
DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3679 static WSASendMsg_t pWSASendMsg =
NULL;
3690 pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid);
3697 socklist_lookup(s, &mode);
3700 if ((ret = pWSASendMsg(s, &wsamsg, flags, &
len,
NULL,
NULL)) == SOCKET_ERROR) {
3709 memset(&wol, 0,
sizeof(wol));
3712 ret = pWSASendMsg(s, &wsamsg, flags, &
size, &wol,
NULL);
3715 finish_overlapped_socket(
FALSE, s, &wol, ret, &
len,
size);
3729 r = setsockopt(
TO_SOCKET(s), level, optname, optval, optlen);
3730 if (r == SOCKET_ERROR)
3745 if (r == SOCKET_ERROR)
3753 open_ifs_socket(
int af,
int type,
int protocol)
3755 unsigned long proto_buffers_len = 0;
3757 SOCKET out = INVALID_SOCKET;
3759 if (WSAEnumProtocols(
NULL,
NULL, &proto_buffers_len) == SOCKET_ERROR) {
3760 error_code = WSAGetLastError();
3761 if (error_code == WSAENOBUFS) {
3762 WSAPROTOCOL_INFO *proto_buffers;
3763 int protocols_available = 0;
3765 proto_buffers = (WSAPROTOCOL_INFO *)
malloc(proto_buffers_len);
3766 if (!proto_buffers) {
3767 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
3768 return INVALID_SOCKET;
3771 protocols_available =
3772 WSAEnumProtocols(
NULL, proto_buffers, &proto_buffers_len);
3773 if (protocols_available != SOCKET_ERROR) {
3775 for (
i = 0;
i < protocols_available;
i++) {
3776 if ((af !=
AF_UNSPEC && af != proto_buffers[
i].iAddressFamily) ||
3777 (
type != proto_buffers[
i].iSocketType) ||
3778 (protocol != 0 && protocol != proto_buffers[
i].iProtocol))
3781 if ((proto_buffers[
i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
3784 out = WSASocket(af,
type, protocol, &(proto_buffers[
i]), 0,
3785 WSA_FLAG_OVERLAPPED);
3788 if (out == INVALID_SOCKET)
3789 out = WSASocket(af,
type, protocol,
NULL, 0, 0);
3790 if (out != INVALID_SOCKET)
3791 SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0);
3794 free(proto_buffers);
3811 s = open_ifs_socket(af,
type, protocol);
3812 if (s == INVALID_SOCKET) {
3817 fd = rb_w32_open_osfhandle(s, O_RDWR|
O_BINARY|O_NOINHERIT);
3827 #undef gethostbyaddr
3830 struct hostent * WSAAPI
3835 r = gethostbyaddr(addr,
len,
type);
3842 #undef gethostbyname
3845 struct hostent * WSAAPI
3850 r = gethostbyname(
name);
3866 if (r == SOCKET_ERROR)
3872 #undef getprotobyname
3875 struct protoent * WSAAPI
3880 r = getprotobyname(
name);
3887 #undef getprotobynumber
3890 struct protoent * WSAAPI
3895 r = getprotobynumber(num);
3902 #undef getservbyname
3905 struct servent * WSAAPI
3917 #undef getservbyport
3920 struct servent * WSAAPI
3925 r = getservbyport(port,
proto);
3934 socketpair_internal(
int af,
int type,
int protocol, SOCKET *sv)
3936 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
3937 struct sockaddr_in sock_in4;
3939 struct sockaddr_in6 sock_in6;
3941 struct sockaddr *addr;
3947 #if defined PF_INET && PF_INET != AF_INET
3950 sock_in4.sin_family = AF_INET;
3951 sock_in4.sin_port = 0;
3953 addr = (
struct sockaddr *)&sock_in4;
3954 len =
sizeof(sock_in4);
3958 memset(&sock_in6, 0,
sizeof(sock_in6));
3959 sock_in6.sin6_family = AF_INET6;
3960 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
3961 addr = (
struct sockaddr *)&sock_in6;
3962 len =
sizeof(sock_in6);
3969 if (
type != SOCK_STREAM) {
3974 sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
3975 sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
3978 svr = open_ifs_socket(af,
type, protocol);
3979 if (svr == INVALID_SOCKET)
3981 if (bind(svr, addr,
len) < 0)
3983 if (getsockname(svr, addr, &
len) < 0)
3985 if (
type == SOCK_STREAM)
3988 w = open_ifs_socket(af,
type, protocol);
3989 if (w == INVALID_SOCKET)
3991 if (connect(w, addr,
len) < 0)
3994 r = accept(svr, addr, &
len);
3995 if (r == INVALID_SOCKET)
3997 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
4004 if (r != INVALID_SOCKET)
4006 if (w != INVALID_SOCKET)
4013 if (svr != INVALID_SOCKET)
4026 if (socketpair_internal(af,
type, protocol, pair) < 0)
4028 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|
O_BINARY|O_NOINHERIT);
4030 closesocket(pair[0]);
4031 closesocket(pair[1]);
4034 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|
O_BINARY|O_NOINHERIT);
4037 closesocket(pair[1]);
4046 #if !defined(_MSC_VER) || _MSC_VER >= 1400
4049 str2guid(
const char *
str, GUID *guid)
4051 #define hex2byte(str) \
4052 ((isdigit(*(str)) ? *(str) - '0' : toupper(*(str)) - 'A' + 10) << 4 | (isdigit(*((str) + 1)) ? *((str) + 1) - '0' : toupper(*((str) + 1)) - 'A' + 10))
4066 for (
i = 0;
i < 6;
i++) {
4073 #ifndef HAVE_TYPE_NET_LUID
4085 static cigl_t pConvertInterfaceGuidToLuid = (
cigl_t)-1;
4093 IP_ADAPTER_ADDRESSES *root, *addr;
4097 if (ret != ERROR_BUFFER_OVERFLOW) {
4103 if (ret != ERROR_SUCCESS) {
4109 if (pConvertInterfaceGuidToLuid == (
cigl_t)-1)
4110 pConvertInterfaceGuidToLuid =
4111 (
cigl_t)get_proc_address(
"iphlpapi.dll",
4112 "ConvertInterfaceGuidToLuid",
NULL);
4113 if (pConvertInterfaceLuidToNameA == (
cilnA_t)-1)
4114 pConvertInterfaceLuidToNameA =
4115 (
cilnA_t)get_proc_address(
"iphlpapi.dll",
4116 "ConvertInterfaceLuidToNameA",
NULL);
4118 for (prev =
NULL, addr = root; addr; addr = addr->Next) {
4129 str2guid(addr->AdapterName, &guid);
4130 if (pConvertInterfaceGuidToLuid && pConvertInterfaceLuidToNameA &&
4131 pConvertInterfaceGuidToLuid(&guid, &luid) == NO_ERROR &&
4132 pConvertInterfaceLuidToNameA(&luid,
name,
sizeof(
name)) == NO_ERROR) {
4139 if (addr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
4141 if (addr->OperStatus == IfOperStatusUp) {
4144 if (addr->FirstUnicastAddress) {
4145 IP_ADAPTER_UNICAST_ADDRESS *cur;
4147 for (cur = addr->FirstUnicastAddress; cur; cur = cur->Next) {
4148 if (cur->Flags & IP_ADAPTER_ADDRESS_TRANSIENT ||
4149 cur->DadState == IpDadStateDeprecated) {
4161 cur->Address.iSockaddrLength);
4217 setfl(SOCKET sock,
int arg)
4224 socklist_lookup(sock, &flag);
4236 ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
4248 dupfd(HANDLE hDup,
int flags,
int minfd)
4258 goto close_fds_and_return;
4261 goto close_fds_and_return;
4263 fds[filled++] = ret;
4264 }
while (filled < (
int)
numberof(fds));
4266 ret = dupfd(hDup, flags, minfd);
4268 close_fds_and_return:
4270 while (filled > 0) {
4271 int fd = fds[--filled];
4299 return setfl(sock,
arg);
4305 if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
4306 GetCurrentProcess(), &hDup, 0
L,
4308 DUPLICATE_SAME_ACCESS))) {
4321 if ((ret = dupfd(hDup, flag,
arg)) == -1)
4327 if (
h == -1)
return -1;
4328 if (!GetHandleInformation((HANDLE)
h, &flag)) {
4332 return (flag & HANDLE_FLAG_INHERIT) ? 0 :
FD_CLOEXEC;
4336 if (
h == -1)
return -1;
4340 if (!SetHandleInformation((HANDLE)
h, HANDLE_FLAG_INHERIT,
4363 return setfl(sock, nonblock ?
O_NONBLOCK : 0);
4365 else if (is_pipe(sock)) {
4367 if (!GetNamedPipeHandleState((HANDLE)sock, &state,
NULL,
NULL,
NULL,
NULL, 0)) {
4372 state |= PIPE_NOWAIT;
4375 state &= ~PIPE_NOWAIT;
4377 if (!SetNamedPipeHandleState((HANDLE)sock, &state,
NULL,
NULL)) {
4401 poll_child_status(
struct ChildRecord *child,
int *stat_loc)
4406 if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
4408 err = GetLastError();
4410 case ERROR_INVALID_PARAMETER:
4413 case ERROR_INVALID_HANDLE:
4421 CloseChildHandle(child);
4424 if (exitcode != STILL_ACTIVE) {
4431 CloseChildHandle(child);
4433 *stat_loc = exitcode << 8;
4434 if (exitcode & 0xC0000000) {
4435 static const struct {
4439 {STATUS_ACCESS_VIOLATION,
SIGSEGV},
4440 {STATUS_ILLEGAL_INSTRUCTION,
SIGILL},
4441 {STATUS_PRIVILEGED_INSTRUCTION,
SIGILL},
4442 {STATUS_FLOAT_DENORMAL_OPERAND,
SIGFPE},
4443 {STATUS_FLOAT_DIVIDE_BY_ZERO,
SIGFPE},
4444 {STATUS_FLOAT_INEXACT_RESULT,
SIGFPE},
4445 {STATUS_FLOAT_INVALID_OPERATION,
SIGFPE},
4446 {STATUS_FLOAT_OVERFLOW,
SIGFPE},
4447 {STATUS_FLOAT_STACK_CHECK,
SIGFPE},
4448 {STATUS_FLOAT_UNDERFLOW,
SIGFPE},
4449 #ifdef STATUS_FLOAT_MULTIPLE_FAULTS
4450 {STATUS_FLOAT_MULTIPLE_FAULTS,
SIGFPE},
4452 #ifdef STATUS_FLOAT_MULTIPLE_TRAPS
4453 {STATUS_FLOAT_MULTIPLE_TRAPS,
SIGFPE},
4455 {STATUS_CONTROL_C_EXIT,
SIGINT},
4459 if (table[
i].status == exitcode) {
4460 *stat_loc |= table[
i].sig;
4493 struct ChildRecord* cause;
4496 if (!child->pid || child->pid < 0)
continue;
4497 if ((pid = poll_child_status(child, stat_loc)))
return pid;
4498 events[
count++] = child->hProcess;
4506 if (ret == WAIT_TIMEOUT)
return 0;
4507 if ((ret -= WAIT_OBJECT_0) ==
count) {
4515 cause = FindChildSlotByHandle(events[ret]);
4520 return poll_child_status(cause, stat_loc);
4523 struct ChildRecord* child = FindChildSlot(pid);
4530 while (!(pid = poll_child_status(child, stat_loc))) {
4533 if (ret == WAIT_OBJECT_0 + 1)
return -1;
4534 if (ret != WAIT_OBJECT_0) {
4543 if (pid == -1 && retried) pid = 0;
4549 #include <sys/timeb.h>
4551 static int have_precisetime = -1;
4554 get_systemtime(FILETIME *ft)
4556 typedef void (WINAPI *get_time_func)(FILETIME *ft);
4557 static get_time_func func = (get_time_func)-1;
4559 if (func == (get_time_func)-1) {
4561 func = (get_time_func)get_proc_address(
"kernel32",
"GetSystemTimePreciseAsFileTime",
NULL);
4563 func = GetSystemTimeAsFileTime;
4564 have_precisetime = 0;
4567 have_precisetime = 1;
4576 filetime_split(
const FILETIME* ft,
long *subsec)
4582 tmp.LowPart = ft->dwLowDateTime;
4583 tmp.HighPart = ft->dwHighDateTime;
4590 lt -= (
LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * subsec_unit;
4592 *subsec = (
long)(
lt % subsec_unit);
4603 get_systemtime(&ft);
4604 tv->
tv_sec = filetime_split(&ft, &subsec);
4620 get_systemtime(&ft);
4621 sp->
tv_sec = filetime_split(&ft, &subsec);
4628 LARGE_INTEGER
count;
4629 if (!QueryPerformanceFrequency(&freq)) {
4633 if (!QueryPerformanceCounter(&
count)) {
4638 if (freq.QuadPart < 1000000000)
4639 sp->
tv_nsec = (
count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
4641 sp->
tv_nsec = (
long)((
count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
4664 if (!QueryPerformanceFrequency(&freq)) {
4669 sp->
tv_nsec = (
long)(1000000000.0 / freq.QuadPart);
4680 w32_getcwd(
char *buffer,
int size, UINT cp,
void *alloc(
int,
void *),
void *
arg)
4685 len = GetCurrentDirectoryW(0,
NULL);
4697 if (!GetCurrentDirectoryW(
len, p)) {
4702 wlen = translate_wchar(p,
L'\\',
L'/') - p + 1;
4711 buffer = (*alloc)(
len,
arg);
4717 WideCharToMultiByte(cp, 0, p, wlen, buffer,
len,
NULL,
NULL);
4724 getcwd_alloc(
int size,
void *dummy)
4740 return w32_getcwd(buffer,
size, CP_UTF8, getcwd_alloc,
NULL);
4745 getcwd_value(
int size,
void *
arg)
4757 w32_getcwd(
NULL, 0, CP_UTF8, getcwd_value, &cwd);
4794 if (pid < 0 || (pid == 0 &&
sig !=
SIGINT)) {
4799 if ((
unsigned int)pid == GetCurrentProcessId() &&
4801 if ((ret =
raise(
sig)) != 0) {
4812 OpenProcess(PROCESS_QUERY_INFORMATION,
FALSE, (
DWORD)pid);
4813 if (hProc ==
NULL || hProc == INVALID_HANDLE_VALUE) {
4814 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4830 DWORD ctrlEvent = CTRL_C_EVENT;
4834 ctrlEvent = CTRL_BREAK_EVENT;
4836 if (!GenerateConsoleCtrlEvent(ctrlEvent, (
DWORD)pid)) {
4837 if ((
err = GetLastError()) == 0)
4849 struct ChildRecord* child = FindChildSlot(pid);
4851 hProc = child->hProcess;
4854 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
FALSE, (
DWORD)pid);
4856 if (hProc ==
NULL || hProc == INVALID_HANDLE_VALUE) {
4857 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4867 if (!GetExitCodeProcess(hProc, &status)) {
4871 else if (status == STILL_ACTIVE) {
4872 if (!TerminateProcess(hProc, 0)) {
4899 wlink(
const WCHAR *from,
const WCHAR *to)
4901 if (!CreateHardLinkW(to, from,
NULL)) {
4923 ret = wlink(wfrom, wto);
4931 link(
const char *from,
const char *to)
4943 ret = wlink(wfrom, wto);
4950 #ifndef FILE_DEVICE_FILE_SYSTEM
4951 # define FILE_DEVICE_FILE_SYSTEM 0x00000009
4953 #ifndef FSCTL_GET_REPARSE_POINT
4954 # define FSCTL_GET_REPARSE_POINT ((0x9<<16)|(42<<2))
4956 #ifndef IO_REPARSE_TAG_SYMLINK
4957 # define IO_REPARSE_TAG_SYMLINK 0xA000000CL
4968 f = open_special(
path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
4969 if (
f == INVALID_HANDLE_VALUE) {
4970 return GetLastError();
4978 rp->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
4979 e = ERROR_INVALID_PARAMETER;
4996 if (e == ERROR_MORE_DATA) {
5004 case ERROR_MORE_DATA:
5013 size_t bufsize, WCHAR **result,
DWORD *
len)
5015 int e = reparse_symlink(
path,
rp, bufsize);
5018 if (!e || e == ERROR_MORE_DATA) {
5021 name = ((
char *)
rp->SymbolicLinkReparseBuffer.PathBuffer +
5022 rp->SymbolicLinkReparseBuffer.PrintNameOffset);
5023 ret =
rp->SymbolicLinkReparseBuffer.PrintNameLength;
5024 *
len = ret /
sizeof(WCHAR);
5026 else if (
rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
5027 static const WCHAR *volume =
L"Volume{";
5029 name = ((
char *)
rp->MountPointReparseBuffer.PathBuffer +
5030 rp->MountPointReparseBuffer.SubstituteNameOffset +
5031 volume_prefix_len *
sizeof(WCHAR));
5032 ret =
rp->MountPointReparseBuffer.SubstituteNameLength;
5033 *
len = ret /
sizeof(WCHAR);
5034 ret -= volume_prefix_len *
sizeof(WCHAR);
5035 if (ret >
sizeof(volume) - 1 *
sizeof(WCHAR) &&
5036 memcmp(
name, volume,
sizeof(volume) - 1 *
sizeof(WCHAR)) == 0)
5044 if ((
char *)
name + ret +
sizeof(WCHAR) > (
char *)
rp + bufsize)
5048 ((WCHAR *)
name)[ret/
sizeof(WCHAR)] =
L'\0';
5049 translate_wchar(
name,
L'\\',
L'/');
5059 w32_readlink(UINT cp,
const char *
path,
char *
buf,
size_t bufsize)
5064 WCHAR *wname, *wpath =
ALLOCV(wtmp,
size +
sizeof(WCHAR) *
len);
5069 MultiByteToWideChar(cp, 0,
path, -1, wpath,
len);
5071 if (e && e != ERROR_MORE_DATA) {
5076 len = lstrlenW(wname) + 1;
5077 ret = WideCharToMultiByte(cp, 0, wname,
len,
buf, bufsize,
NULL,
NULL);
5094 return w32_readlink(CP_UTF8,
path,
buf, bufsize);
5104 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5105 #define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1)
5107 #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
5108 #define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
5113 w32_symlink(UINT cp,
const char *
src,
const char *
link)
5115 int atts, len1, len2;
5117 WCHAR *wsrc, *wlink;
5122 typedef BOOLEAN (WINAPI *create_symbolic_link_func)(WCHAR*, WCHAR*,
DWORD);
5123 static create_symbolic_link_func create_symbolic_link =
5124 (create_symbolic_link_func)-1;
5127 if (create_symbolic_link == (create_symbolic_link_func)-1) {
5128 create_symbolic_link = (create_symbolic_link_func)
5129 get_proc_address(
"kernel32",
"CreateSymbolicLinkW",
NULL);
5131 if (!create_symbolic_link) {
5144 len1 = MultiByteToWideChar(cp, 0,
src, -1,
NULL, 0);
5145 len2 = MultiByteToWideChar(cp, 0,
link, -1,
NULL, 0);
5147 wlink = wsrc + len1;
5148 MultiByteToWideChar(cp, 0,
src, -1, wsrc, len1);
5149 MultiByteToWideChar(cp, 0,
link, -1, wlink, len2);
5150 translate_wchar(wsrc,
L'/',
L'\\');
5152 atts = GetFileAttributesW(wsrc);
5153 if (atts != -1 && atts & FILE_ATTRIBUTE_DIRECTORY)
5155 ret = create_symbolic_link(wlink, wsrc, flag |= create_flag);
5157 (e = GetLastError()) == ERROR_INVALID_PARAMETER &&
5161 ret = create_symbolic_link(wlink, wsrc, flag);
5162 if (!ret) e = GetLastError();
5177 return w32_symlink(CP_UTF8,
src,
link);
5191 return waitpid(-1, status, 0);
5196 w32_getenv(
const char *
name, UINT cp)
5198 WCHAR *wenvarea, *wenv;
5209 wenvarea = GetEnvironmentStringsW();
5214 for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
5215 wlen += lstrlenW(wenv) + 1;
5217 FreeEnvironmentStringsW(wenvarea);
5232 return w32_getenv(
name, CP_UTF8);
5239 return w32_getenv(
name, CP_ACP);
5246 BY_HANDLE_FILE_INFORMATION
st = {0};
5248 HANDLE
h = open_special(
path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5250 if (
h == INVALID_HANDLE_VALUE) {
5251 ASSUME(e = GetLastError());
5254 if (!GetFileInformationByHandle(
h, &
st)) {
5255 ASSUME(e = GetLastError());
5258 *atts =
st.dwFileAttributes;
5259 *vsn =
st.dwVolumeSerialNumber;
5267 wrename(
const WCHAR *oldpath,
const WCHAR *newpath)
5271 DWORD oldvsn = 0, newvsn = 0, e;
5273 e = get_attr_vsn(oldpath, &oldatts, &oldvsn);
5278 if (oldatts & FILE_ATTRIBUTE_REPARSE_POINT) {
5279 HANDLE fh = open_special(oldpath, 0, 0);
5280 if (fh == INVALID_HANDLE_VALUE) {
5282 if (e == ERROR_CANT_RESOLVE_FILENAME) {
5289 get_attr_vsn(newpath, &newatts, &newvsn);
5292 if (newatts != (
DWORD)-1 && newatts & FILE_ATTRIBUTE_READONLY)
5293 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
5295 if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
5299 DWORD e = GetLastError();
5300 if ((e == ERROR_ACCESS_DENIED) && (oldatts & FILE_ATTRIBUTE_DIRECTORY) &&
5307 SetFileAttributesW(newpath, oldatts);
5326 ret = wrename(wfrom, wto);
5345 ret = wrename(wfrom, wto);
5353 isUNCRoot(
const WCHAR *
path)
5356 const WCHAR *p =
path + 2;
5357 if (p[0] ==
L'?' && p[1] ==
L'\\') {
5365 for (p++; *p; p++) {
5369 if (!p[0] || !p[1] || (p[1] ==
L'.' && !p[2]))
5376 #define COPY_STAT(src, dest, size_cast) do { \
5377 (dest).st_dev = (src).st_dev; \
5378 (dest).st_ino = (src).st_ino; \
5379 (dest).st_mode = (src).st_mode; \
5380 (dest).st_nlink = (src).st_nlink; \
5381 (dest).st_uid = (src).st_uid; \
5382 (dest).st_gid = (src).st_gid; \
5383 (dest).st_rdev = (src).st_rdev; \
5384 (dest).st_size = size_cast(src).st_size; \
5385 (dest).st_atime = (src).st_atime; \
5386 (dest).st_mtime = (src).st_mtime; \
5387 (dest).st_ctime = (src).st_ctime; \
5390 static time_t filetime_to_unixtime(
const FILETIME *ft);
5391 static long filetime_to_nsec(
const FILETIME *ft);
5392 static WCHAR *name_for_stat(WCHAR *
buf,
const WCHAR *
path);
5400 BY_HANDLE_FILE_INFORMATION info;
5403 if (ret)
return ret;
5404 if (GetEnvironmentVariableW(
L"TZ",
NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return ret;
5405 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
5406 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5407 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5408 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5418 int ret =
fstat(fd, &tmp);
5420 if (ret)
return ret;
5422 stati128_handle((HANDLE)_get_osfhandle(fd),
st);
5426 #if !defined FILE_INVALID_FILE_ID && !defined __MINGW32__
5428 BYTE Identifier[16];
5432 #if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < 0x602
5433 #define FileIdInfo 0x12
5444 typedef BOOL (WINAPI *gfibhe_t)(HANDLE,
int,
void *,
DWORD);
5445 static gfibhe_t pGetFileInformationByHandleEx = (gfibhe_t)-1;
5447 if (pGetFileInformationByHandleEx == (gfibhe_t)-1)
5448 pGetFileInformationByHandleEx = (gfibhe_t)get_proc_address(
"kernel32",
"GetFileInformationByHandleEx",
NULL);
5450 if (pGetFileInformationByHandleEx) {
5451 if (pGetFileInformationByHandleEx(
h,
FileIdInfo,
id,
sizeof(*
id)))
5454 return GetLastError();
5456 return ERROR_INVALID_PARAMETER;
5463 BY_HANDLE_FILE_INFORMATION info;
5466 if (GetFileInformationByHandle(
h, &info)) {
5468 st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
5469 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5470 st->st_atimensec = filetime_to_nsec(&info.ftLastAccessTime);
5471 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5472 st->st_mtimensec = filetime_to_nsec(&info.ftLastWriteTime);
5473 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5474 st->st_ctimensec = filetime_to_nsec(&info.ftCreationTime);
5475 st->st_nlink = info.nNumberOfLinks;
5476 attr = info.dwFileAttributes;
5477 if (!get_ino(
h, &fii)) {
5478 st->st_ino = *((
unsigned __int64 *)&fii.
FileId);
5479 st->st_inohigh = *((__int64 *)&fii.
FileId + 1);
5482 st->st_ino = ((__int64)info.nFileIndexHigh << 32) | info.nFileIndexLow;
5491 filetime_to_unixtime(
const FILETIME *ft)
5494 time_t t = filetime_split(ft, &subsec);
5496 if (t < 0)
return 0;
5502 filetime_to_nsec(
const FILETIME *ft)
5504 if (have_precisetime <= 0)
5508 tmp.LowPart = ft->dwLowDateTime;
5509 tmp.HighPart = ft->dwHighDateTime;
5510 return (
long)(tmp.QuadPart % 10000000) * 100;
5516 fileattr_to_unixmode(
DWORD attr,
const WCHAR *
path)
5520 if (attr & FILE_ATTRIBUTE_READONLY) {
5527 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5533 else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5541 const WCHAR *end =
path + lstrlenW(
path);
5542 while (
path < end) {
5543 end = CharPrevW(
path, end);
5545 if ((_wcsicmp(end,
L".bat") == 0) ||
5546 (_wcsicmp(end,
L".cmd") == 0) ||
5547 (_wcsicmp(end,
L".com") == 0) ||
5548 (_wcsicmp(end,
L".exe") == 0)) {
5553 if (!iswalnum(*end))
break;
5557 mode |= (mode & 0500) >> 3;
5558 mode |= (mode & 0500) >> 6;
5565 check_valid_dir(
const WCHAR *
path)
5567 WIN32_FIND_DATAW fd;
5575 if (!(p = wcsstr(
path,
L"...")))
5577 q = p + wcsspn(p,
L".");
5578 if ((p ==
path || wcschr(
L":/\\", *(p - 1))) &&
5579 (!*q || wcschr(
L":/\\", *q))) {
5586 if (!GetFullPathNameW(
path,
sizeof(full) /
sizeof(WCHAR), full, &dmy)) {
5590 if (full[1] ==
L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
5593 fh = open_dir_handle(
path, &fd);
5594 if (fh == INVALID_HANDLE_VALUE)
5605 WIN32_FIND_DATAW wfd;
5607 int e = GetLastError();
5609 if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
5610 || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
5616 h = FindFirstFileW(
path, &wfd);
5617 if (
h == INVALID_HANDLE_VALUE) {
5622 st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes,
path);
5623 st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
5624 st->st_atimensec = filetime_to_nsec(&wfd.ftLastAccessTime);
5625 st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
5626 st->st_mtimensec = filetime_to_nsec(&wfd.ftLastWriteTime);
5627 st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
5628 st->st_ctimensec = filetime_to_nsec(&wfd.ftCreationTime);
5629 st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
5636 path_drive(
const WCHAR *
path)
5638 return (iswalpha(
path[0]) &&
path[1] ==
L':') ?
5639 towupper(
path[0]) -
L'A' : _getdrive() - 1;
5642 static const WCHAR namespace_prefix[] = {
L'\\',
L'\\',
L'?',
L'\\'};
5648 DWORD flags =
lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0;
5653 f = open_special(
path, 0, flags);
5654 if (
f != INVALID_HANDLE_VALUE) {
5655 DWORD attr = stati128_handle(
f,
st);
5658 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5663 attr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
5665 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5666 if (check_valid_dir(
path))
return -1;
5668 st->st_mode = fileattr_to_unixmode(attr,
path);
5672 if (wcsncmp(
path, namespace_prefix,
numberof(namespace_prefix)) == 0)
5677 if (stat_by_find(
path,
st))
return -1;
5680 st->st_dev =
st->st_rdev = path_drive(
path);
5710 if (!(
path = name_for_stat(buf1,
path)))
5721 name_for_stat(WCHAR *buf1,
const WCHAR *
path)
5727 for (p =
path, s = buf1; *p; p++, s++) {
5735 if (!
len ||
L'\"' == *(--s)) {
5739 end = buf1 +
len - 1;
5741 if (isUNCRoot(buf1)) {
5744 else if (*end !=
L'\\')
5745 lstrcatW(buf1,
L"\\");
5747 else if (*end ==
L'\\' || (buf1 + 1 == end && *end ==
L':'))
5748 lstrcatW(buf1,
L".");
5776 ret = wstati128(wpath,
st,
lstat);
5785 return w32_stati128(
path,
st, CP_UTF8,
TRUE);
5804 return _lseeki64(fd, ofs, whence);
5841 long upos, lpos, usize, lsize;
5845 if ((lpos = SetFilePointer(
h, 0, (upos = 0, &upos),
SEEK_CUR)) == -1
L &&
5846 (e = GetLastError())) {
5853 (e = GetLastError())) {
5856 else if (!SetEndOfFile(
h)) {
5862 SetFilePointer(
h, lpos, &upos,
SEEK_SET);
5868 w32_truncate(
const char *
path,
off_t length, UINT cp)
5876 h = CreateFileW(wpath, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
5877 if (
h == INVALID_HANDLE_VALUE) {
5883 ret = rb_chsize(
h, length);
5892 return w32_truncate(
path, length, CP_UTF8);
5908 h = (HANDLE)_get_osfhandle(fd);
5909 if (
h == (HANDLE)-1)
return -1;
5910 return rb_chsize(
h, length);
5915 filetime_to_clock(FILETIME *ft)
5917 __int64 qw = ft->dwHighDateTime;
5919 qw |= ft->dwLowDateTime;
5928 FILETIME create,
exit, kernel, user;
5930 if (GetProcessTimes(GetCurrentProcess(),&create, &
exit, &kernel, &user)) {
5931 tmbuf->
tms_utime = filetime_to_clock(&user);
5932 tmbuf->
tms_stime = filetime_to_clock(&kernel);
5947 #define yield_once() Sleep(0)
5948 #define yield_until(condition) do yield_once(); while (!(condition))
5965 call_asynchronous(PVOID argp)
5969 arg->stackaddr = &argp;
5981 BOOL interrupted =
FALSE;
5994 thr = CreateThread(
NULL, 0, call_asynchronous, &
arg, 0, &val);
6002 if (TerminateThread(thr, intrval)) {
6007 GetExitCodeThread(thr, &val);
6012 MEMORY_BASIC_INFORMATION m;
6014 memset(&m, 0,
sizeof(m));
6015 if (!VirtualQuery(
arg.stackaddr, &m,
sizeof(m))) {
6017 arg.stackaddr, GetLastError()));
6019 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
6021 m.AllocationBase, GetLastError()));
6032 rb_fatal(
"failed to launch waiter thread:%ld", GetLastError());
6042 WCHAR *envtop, *
env;
6043 char **myenvtop, **myenv;
6056 envtop = GetEnvironmentStringsW();
6057 for (
env = envtop, num = 0; *
env;
env += lstrlenW(
env) + 1)
6058 if (*
env !=
'=') num++;
6060 myenvtop = (
char **)
malloc(
sizeof(
char *) * (num + 1));
6061 for (
env = envtop, myenv = myenvtop; *
env;
env += lstrlenW(
env) + 1) {
6070 FreeEnvironmentStringsW(envtop);
6081 while (*t)
free(*t++);
6089 return GetCurrentProcessId();
6097 typedef long (WINAPI query_func)(HANDLE,
int,
void *, ULONG, ULONG *);
6098 static query_func *pNtQueryInformationProcess = (query_func *)-1;
6101 if (pNtQueryInformationProcess == (query_func *)-1)
6102 pNtQueryInformationProcess = (query_func *)get_proc_address(
"ntdll.dll",
"NtQueryInformationProcess",
NULL);
6103 if (pNtQueryInformationProcess) {
6106 void* PebBaseAddress;
6113 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi,
sizeof(pbi), &
len);
6115 ppid = pbi.ParentProcessId;
6122 STATIC_ASSERT(std_handle, (STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)==(STD_ERROR_HANDLE-STD_OUTPUT_HANDLE));
6125 #define set_new_std_handle(newfd, handle) do { \
6126 if ((unsigned)(newfd) > 2) break; \
6127 SetStdHandle(STD_INPUT_HANDLE+(STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)*(newfd), \
6130 #define set_new_std_fd(newfd) set_new_std_handle(newfd, (HANDLE)rb_w32_get_osfhandle(newfd))
6138 if (oldfd == newfd)
return newfd;
6139 ret =
dup2(oldfd, newfd);
6140 if (ret < 0)
return ret;
6160 ret = w32_wopen(wfile, oflag, pmode);
6167 check_if_wdir(
const WCHAR *wfile)
6169 DWORD attr = GetFileAttributesW(wfile);
6170 if (attr == (
DWORD)-1
L ||
6171 !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
6172 check_valid_dir(wfile)) {
6194 ret = w32_wopen(wfile, oflag, pmode);
6205 if (oflag & O_CREAT) {
6212 return w32_wopen(file, oflag, pmode);
6216 w32_wopen(
const WCHAR *file,
int oflag,
int pmode)
6222 DWORD attr = FILE_ATTRIBUTE_NORMAL;
6223 SECURITY_ATTRIBUTES sec;
6229 if ((oflag & O_TEXT) || !(oflag &
O_BINARY)) {
6230 fd = _wopen(file, oflag, pmode);
6234 check_if_wdir(file);
6244 sec.nLength =
sizeof(sec);
6245 sec.lpSecurityDescriptor =
NULL;
6246 if (oflag & O_NOINHERIT) {
6247 sec.bInheritHandle =
FALSE;
6251 sec.bInheritHandle =
TRUE;
6253 oflag &= ~O_NOINHERIT;
6258 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
6260 access = GENERIC_READ | GENERIC_WRITE;
6272 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
6274 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
6276 create = OPEN_ALWAYS;
6280 create = OPEN_EXISTING;
6282 case O_CREAT | O_EXCL:
6283 case O_CREAT | O_EXCL | O_TRUNC:
6284 create = CREATE_NEW;
6287 case O_TRUNC | O_EXCL:
6288 create = TRUNCATE_EXISTING;
6290 case O_CREAT | O_TRUNC:
6291 create = CREATE_ALWAYS;
6297 if (oflag & O_CREAT) {
6300 attr = FILE_ATTRIBUTE_READONLY;
6302 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
6304 if (oflag & O_TEMPORARY) {
6305 attr |= FILE_FLAG_DELETE_ON_CLOSE;
6308 oflag &= ~O_TEMPORARY;
6310 if (oflag & _O_SHORT_LIVED)
6311 attr |= FILE_ATTRIBUTE_TEMPORARY;
6312 oflag &= ~_O_SHORT_LIVED;
6314 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
6318 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
6321 attr |= FILE_FLAG_RANDOM_ACCESS;
6327 oflag &= ~(O_SEQUENTIAL | O_RANDOM);
6329 if (oflag & ~O_APPEND) {
6336 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6349 h = CreateFileW(file,
access, FILE_SHARE_READ | FILE_SHARE_WRITE | share_delete, &sec, create, attr,
NULL);
6350 if (
h == INVALID_HANDLE_VALUE) {
6351 DWORD e = GetLastError();
6352 if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
6359 switch (GetFileType(
h)) {
6360 case FILE_TYPE_CHAR:
6363 case FILE_TYPE_PIPE:
6366 case FILE_TYPE_UNKNOWN:
6373 if (!(flags & (
FDEV |
FPIPE)) && (oflag & O_APPEND))
6393 int save_errno =
errno;
6395 if (
fflush(fp))
return -1;
6403 if (closesocket(sock) == SOCKET_ERROR) {
6414 static DWORD serial = 0;
6415 static const char prefix[] =
"\\\\.\\pipe\\ruby";
6417 width_of_prefix = (
int)
sizeof(prefix) - 1,
6419 width_of_serial = (
int)
sizeof(serial) * 2,
6420 width_of_ids = width_of_pid + 1 + width_of_serial + 1
6422 char name[
sizeof(prefix) + width_of_ids];
6423 SECURITY_ATTRIBUTES sec;
6424 HANDLE hRead, hWrite,
h;
6425 int fdRead, fdWrite;
6432 sec.nLength =
sizeof(sec);
6433 sec.lpSecurityDescriptor =
NULL;
6434 sec.bInheritHandle =
FALSE;
6437 hRead = CreateNamedPipe(
name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
6438 0, 2, 65536, 65536, 0, &sec);
6440 if (hRead == INVALID_HANDLE_VALUE) {
6442 if (
err == ERROR_PIPE_BUSY)
6450 hWrite = CreateFile(
name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
6451 OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
NULL);
6453 if (hWrite == INVALID_HANDLE_VALUE) {
6461 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6462 fdRead = _open_osfhandle((
intptr_t)
h, 0);
6466 CloseHandle(hWrite);
6481 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6482 fdWrite = _open_osfhandle((
intptr_t)
h, 0);
6484 if (fdWrite == -1) {
6486 CloseHandle(hWrite);
6508 console_emulator_p(
void)
6513 const void *
const func = WriteConsoleW;
6515 MEMORY_BASIC_INFORMATION m;
6517 memset(&m, 0,
sizeof(m));
6518 if (!VirtualQuery(func, &m,
sizeof(m))) {
6521 k = GetModuleHandle(
"kernel32.dll");
6522 if (!k)
return FALSE;
6523 return (HMODULE)m.AllocationBase != k;
6529 constat_handle(HANDLE
h)
6534 if (console_emulator_p()) {
6539 install_vm_exit_handler();
6548 CONSOLE_SCREEN_BUFFER_INFO csbi;
6551 p->
vt100.
attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6554 if (GetConsoleScreenBufferInfo(
h, &csbi)) {
6564 constat_reset(HANDLE
h)
6574 #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
6575 #define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
6577 #define constat_attr_color_reverse(attr) \
6578 ((attr) & ~(FOREGROUND_MASK | BACKGROUND_MASK)) | \
6579 (((attr) & FOREGROUND_MASK) << 4) | \
6580 (((attr) & BACKGROUND_MASK) >> 4)
6591 bold =
attr & FOREGROUND_INTENSITY;
6592 attr &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
6594 while (
count-- > 0) {
6597 attr = default_attr;
6602 bold = FOREGROUND_INTENSITY;
6605 #ifndef COMMON_LVB_UNDERSCORE
6606 #define COMMON_LVB_UNDERSCORE 0x8000
6615 attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
6619 attr = (
attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN)) | FOREGROUND_RED;
6623 attr = (
attr & ~(FOREGROUND_BLUE | FOREGROUND_RED)) | FOREGROUND_GREEN;
6627 attr = (
attr & ~FOREGROUND_BLUE) | FOREGROUND_GREEN | FOREGROUND_RED;
6631 attr = (
attr & ~(FOREGROUND_GREEN | FOREGROUND_RED)) | FOREGROUND_BLUE;
6635 attr = (
attr & ~FOREGROUND_GREEN) | FOREGROUND_BLUE | FOREGROUND_RED;
6639 attr = (
attr & ~FOREGROUND_RED) | FOREGROUND_BLUE | FOREGROUND_GREEN;
6643 attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6647 attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
6650 attr = (
attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN)) | BACKGROUND_RED;
6653 attr = (
attr & ~(BACKGROUND_BLUE | BACKGROUND_RED)) | BACKGROUND_GREEN;
6656 attr = (
attr & ~BACKGROUND_BLUE) | BACKGROUND_GREEN | BACKGROUND_RED;
6659 attr = (
attr & ~(BACKGROUND_GREEN | BACKGROUND_RED)) | BACKGROUND_BLUE;
6662 attr = (
attr & ~BACKGROUND_GREEN) | BACKGROUND_BLUE | BACKGROUND_RED;
6665 attr = (
attr & ~BACKGROUND_RED) | BACKGROUND_BLUE | BACKGROUND_GREEN;
6668 attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
6680 constat_clear(HANDLE handle, WORD
attr,
DWORD len, COORD pos)
6684 FillConsoleOutputAttribute(handle,
attr,
len, pos, &written);
6685 FillConsoleOutputCharacterW(handle,
L' ',
len, pos, &written);
6690 constat_apply(HANDLE handle,
struct constat *s, WCHAR w)
6692 CONSOLE_SCREEN_BUFFER_INFO csbi;
6698 if (!GetConsoleScreenBufferInfo(handle, &csbi))
return;
6700 if (arg0) arg1 =
seq[0];
6706 csbi.dwCursorPosition.X = 0;
6708 csbi.dwCursorPosition.Y -= arg1;
6709 if (csbi.dwCursorPosition.Y < csbi.srWindow.Top)
6710 csbi.dwCursorPosition.Y = csbi.srWindow.Top;
6711 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6714 csbi.dwCursorPosition.X = 0;
6717 csbi.dwCursorPosition.Y += arg1;
6718 if (csbi.dwCursorPosition.Y > csbi.srWindow.Bottom)
6719 csbi.dwCursorPosition.Y = csbi.srWindow.Bottom;
6720 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6723 csbi.dwCursorPosition.X += arg1;
6724 if (csbi.dwCursorPosition.X >= csbi.srWindow.Right)
6725 csbi.dwCursorPosition.X = csbi.srWindow.Right;
6726 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6729 csbi.dwCursorPosition.X -= arg1;
6730 if (csbi.dwCursorPosition.X < csbi.srWindow.Left)
6731 csbi.dwCursorPosition.X = csbi.srWindow.Left;
6732 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6736 arg1 += csbi.srWindow.Left;
6737 if (arg1 > csbi.srWindow.Right)
6738 arg1 = csbi.srWindow.Right;
6739 csbi.dwCursorPosition.X = arg1;
6740 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6743 arg1 += csbi.srWindow.Top;
6744 if (arg1 > csbi.srWindow.Bottom)
6745 arg1 = csbi.srWindow.Bottom;
6746 csbi.dwCursorPosition.Y = arg1;
6747 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6751 pos.Y = arg1 + csbi.srWindow.Top - 1;
6752 if (pos.Y > csbi.srWindow.Bottom) pos.Y = csbi.srWindow.Bottom;
6753 if (
count < 2 || (arg1 =
seq[1]) <= 0) arg1 = 1;
6754 pos.X = arg1 + csbi.srWindow.Left - 1;
6755 if (pos.X > csbi.srWindow.Right) pos.X = csbi.srWindow.Right;
6756 SetConsoleCursorPosition(handle, pos);
6759 switch (arg0 ? arg1 : 0) {
6761 constat_clear(handle, csbi.wAttributes,
6762 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.dwCursorPosition.Y + 1)
6763 - csbi.dwCursorPosition.X),
6764 csbi.dwCursorPosition);
6768 pos.Y = csbi.srWindow.Top;
6769 constat_clear(handle, csbi.wAttributes,
6770 (csbi.dwSize.X * (csbi.dwCursorPosition.Y - csbi.srWindow.Top)
6771 + csbi.dwCursorPosition.X + 1),
6776 pos.Y = csbi.srWindow.Top;
6777 constat_clear(handle, csbi.wAttributes,
6778 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1)),
6784 constat_clear(handle, csbi.wAttributes,
6785 (csbi.dwSize.X * csbi.dwSize.Y),
6791 switch (arg0 ? arg1 : 0) {
6793 constat_clear(handle, csbi.wAttributes,
6794 (csbi.dwSize.X - csbi.dwCursorPosition.X),
6795 csbi.dwCursorPosition);
6799 pos.Y = csbi.dwCursorPosition.Y;
6800 constat_clear(handle, csbi.wAttributes,
6801 csbi.dwCursorPosition.X + 1, pos);
6805 pos.Y = csbi.dwCursorPosition.Y;
6806 constat_clear(handle, csbi.wAttributes,
6807 csbi.dwSize.X, pos);
6815 SetConsoleCursorPosition(handle, s->
vt100.
saved);
6819 CONSOLE_CURSOR_INFO cci;
6820 GetConsoleCursorInfo(handle, &cci);
6821 cci.bVisible =
TRUE;
6822 SetConsoleCursorInfo(handle, &cci);
6827 CONSOLE_CURSOR_INFO cci;
6828 GetConsoleCursorInfo(handle, &cci);
6829 cci.bVisible =
FALSE;
6830 SetConsoleCursorInfo(handle, &cci);
6838 static const long MAXSIZE_CONSOLE_WRITING = 31366;
6842 constat_parse(HANDLE
h,
struct constat *s,
const WCHAR **ptrp,
long *lenp)
6844 const WCHAR *
ptr = *ptrp;
6845 long rest,
len = *lenp;
6849 rest = *lenp -
len - 1;
6854 if (
len > 0 && *
ptr !=
L'[')
continue;
6863 rest = *lenp -
len - 1;
6864 if (rest > 0) --rest;
6869 if (wc >=
L'0' && wc <=
L'9') {
6872 *
seq = (*
seq * 10) + (wc -
L'0');
6888 constat_apply(
h, s, wc);
6894 else if ((rest = *lenp -
len) < MAXSIZE_CONSOLE_WRITING) {
6913 int save_errno =
errno;
6917 constat_delete((HANDLE)sock);
6921 socklist_delete(&sock,
NULL);
6924 if (closesocket(sock) == SOCKET_ERROR) {
6932 setup_overlapped(OVERLAPPED *ol,
int fd,
int iswrite)
6934 memset(ol, 0,
sizeof(*ol));
6942 DWORD low = SetFilePointer((HANDLE)
_osfhnd(fd), 0, &high, method);
6943 #ifndef INVALID_SET_FILE_POINTER
6944 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
6948 if (
err != NO_ERROR) {
6954 ol->OffsetHigh = high;
6965 finish_overlapped(OVERLAPPED *ol,
int fd,
DWORD size)
6967 CloseHandle(ol->hEvent);
6970 LONG high = ol->OffsetHigh;
6972 if (low < ol->Offset)
6974 SetFilePointer((HANDLE)
_osfhnd(fd), low, &high, FILE_BEGIN);
6991 BOOL islineinput =
FALSE;
6998 if (_get_osfhandle(fd) == -1) {
7015 isconsole = is_console(
_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
7018 GetConsoleMode((HANDLE)
_osfhnd(fd),&mode);
7019 islineinput = (mode & ENABLE_LINE_INPUT) != 0;
7024 constat_reset((HANDLE)
_osfhnd(fd));
7036 if (setup_overlapped(&ol, fd,
FALSE)) {
7042 err = GetLastError();
7054 else if (
err != ERROR_IO_PENDING) {
7055 CloseHandle(ol.hEvent);
7056 if (
err == ERROR_ACCESS_DENIED)
7058 else if (
err == ERROR_BROKEN_PIPE ||
err == ERROR_HANDLE_EOF) {
7070 if (
wait != WAIT_OBJECT_0) {
7071 if (
wait == WAIT_OBJECT_0 + 1)
7075 CloseHandle(ol.hEvent);
7076 CancelIo((HANDLE)
_osfhnd(fd));
7082 (
err = GetLastError()) != ERROR_HANDLE_EOF) {
7084 if (
err != ERROR_BROKEN_PIPE) {
7088 CloseHandle(ol.hEvent);
7089 CancelIo((HANDLE)
_osfhnd(fd));
7095 err = GetLastError();
7099 finish_overlapped(&ol, fd,
read);
7104 if (
err != ERROR_OPERATION_ABORTED &&
7105 !(isconsole &&
len == 1 && (!islineinput || *((
char *)
buf - 1) ==
'\n')) &&
size > 0)
7134 if (_get_osfhandle(fd) == -1) {
7160 if (setup_overlapped(&ol, fd,
TRUE)) {
7165 if (!WriteFile((HANDLE)
_osfhnd(fd),
buf,
len, &written, &ol)) {
7166 err = GetLastError();
7167 if (
err != ERROR_IO_PENDING) {
7168 CloseHandle(ol.hEvent);
7169 if (
err == ERROR_ACCESS_DENIED)
7179 if (
wait != WAIT_OBJECT_0) {
7180 if (
wait == WAIT_OBJECT_0 + 1)
7184 CloseHandle(ol.hEvent);
7185 CancelIo((HANDLE)
_osfhnd(fd));
7190 if (!GetOverlappedResult((HANDLE)
_osfhnd(fd), &ol, &written,
TRUE)) {
7192 CloseHandle(ol.hEvent);
7193 CancelIo((HANDLE)
_osfhnd(fd));
7199 finish_overlapped(&ol, fd, written);
7202 if (written ==
len) {
7208 size_t newlen =
len / 2;
7228 DWORD dwMode, reslen;
7232 const WCHAR *
ptr, *next;
7237 if (!GetConsoleMode(handle, &dwMode))
7240 s = constat_handle(handle);
7255 if (!
ptr)
return -1
L;
7264 if (!WriteConsoleW(handle,
ptr,
len, &reslen,
NULL))
7269 long curlen = constat_parse(handle, s, (next =
ptr, &next), &
len);
7270 reslen += next -
ptr;
7273 if (!WriteConsoleW(handle,
ptr, curlen, &written,
NULL)) {
7282 if (wbuffer)
free(wbuffer);
7283 return (
long)reslen;
7286 #if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7289 unixtime_to_filetime(
time_t time, FILETIME *ft)
7294 ft->dwLowDateTime = tmp.LowPart;
7295 ft->dwHighDateTime = tmp.HighPart;
7302 timespec_to_filetime(
const struct timespec *ts, FILETIME *ft)
7307 tmp.QuadPart += ts->
tv_nsec / 100;
7308 ft->dwLowDateTime = tmp.LowPart;
7309 ft->dwHighDateTime = tmp.HighPart;
7315 wutimensat(
int dirfd,
const WCHAR *
path,
const struct timespec *times,
int flags)
7318 FILETIME atime, mtime;
7338 if (timespec_to_filetime(×[0], &atime)) {
7341 if (timespec_to_filetime(×[1], &mtime)) {
7346 get_systemtime(&atime);
7351 const DWORD attr = GetFileAttributesW(
path);
7352 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7353 SetFileAttributesW(
path, attr & ~FILE_ATTRIBUTE_READONLY);
7354 hFile = open_special(
path, GENERIC_WRITE, 0);
7355 if (hFile == INVALID_HANDLE_VALUE) {
7360 if (!SetFileTime(hFile,
NULL, &atime, &mtime)) {
7366 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7367 SetFileAttributesW(
path, attr);
7434 ret = wutimensat(dirfd, wpath, times, flags);
7448 ret = wutimensat(dirfd, wpath, times, flags);
7462 ret = _wchdir(wpath);
7469 wmkdir(
const WCHAR *wpath,
int mode)
7474 if (CreateDirectoryW(wpath,
NULL) ==
FALSE) {
7478 if (_wchmod(wpath, mode) == -1) {
7479 RemoveDirectoryW(wpath);
7496 ret = wmkdir(wpath, mode);
7510 ret = wmkdir(wpath, mode);
7517 wrmdir(
const WCHAR *wpath)
7521 const DWORD attr = GetFileAttributesW(wpath);
7522 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7523 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
7525 if (RemoveDirectoryW(wpath) ==
FALSE) {
7528 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7529 SetFileAttributesW(wpath, attr);
7545 ret = wrmdir(wpath);
7559 ret = wrmdir(wpath);
7566 wunlink(
const WCHAR *
path)
7569 const DWORD SYMLINKD = FILE_ATTRIBUTE_REPARSE_POINT|FILE_ATTRIBUTE_DIRECTORY;
7571 const DWORD attr = GetFileAttributesW(
path);
7572 if (attr == (
DWORD)-1) {
7574 else if ((attr & SYMLINKD) == SYMLINKD) {
7575 ret = RemoveDirectoryW(
path);
7578 if (attr & FILE_ATTRIBUTE_READONLY) {
7579 SetFileAttributesW(
path, attr & ~FILE_ATTRIBUTE_READONLY);
7581 ret = DeleteFileW(
path);
7586 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7587 SetFileAttributesW(
path, attr);
7603 ret = wunlink(wpath);
7617 ret = wunlink(wpath);
7631 ret = _wchmod(wpath, mode);
7640 typedef BOOL (WINAPI *set_file_information_by_handle_func)
7642 static set_file_information_by_handle_func set_file_info =
7643 (set_file_information_by_handle_func)-1;
7647 LARGE_INTEGER CreationTime;
7648 LARGE_INTEGER LastAccessTime;
7649 LARGE_INTEGER LastWriteTime;
7650 LARGE_INTEGER ChangeTime;
7651 DWORD FileAttributes;
7652 } info = {{{0}}, {{0}}, {{0}},};
7653 HANDLE
h = (HANDLE)_get_osfhandle(fd);
7655 if (
h == INVALID_HANDLE_VALUE) {
7659 if (set_file_info == (set_file_information_by_handle_func)-1) {
7660 set_file_info = (set_file_information_by_handle_func)
7661 get_proc_address(
"kernel32",
"SetFileInformationByHandle",
NULL);
7663 if (!set_file_info) {
7668 info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
7669 if (!(mode & 0200)) info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
7670 if (!set_file_info(
h, 0, &info,
sizeof(info))) {
7684 if (_get_osfhandle(fd) == -1) {
7687 if (!GetConsoleMode((HANDLE)
_osfhnd(fd), &mode)) {
7694 #if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
7695 extern long _ftol(
double);
7705 _ftol2_sse(
double d)
7716 int *ip = (
int *)(&x + 1) - 1;
7725 typedef char *(WSAAPI inet_ntop_t)(
int,
void *,
char *,
size_t);
7726 static inet_ntop_t *pInetNtop = (inet_ntop_t *)-1;
7727 if (pInetNtop == (inet_ntop_t *)-1)
7728 pInetNtop = (inet_ntop_t *)get_proc_address(
"ws2_32",
"inet_ntop",
NULL);
7730 return pInetNtop(af, (
void *)addr, numaddr, numaddr_len);
7734 memcpy(&in.s_addr, addr,
sizeof(in.s_addr));
7735 snprintf(numaddr, numaddr_len,
"%s", inet_ntoa(in));
7744 typedef int (WSAAPI inet_pton_t)(
int,
const char*,
void *);
7745 static inet_pton_t *pInetPton = (inet_pton_t *)-1;
7746 if (pInetPton == (inet_pton_t *)-1)
7747 pInetPton = (inet_pton_t *)get_proc_address(
"ws2_32",
"inet_pton",
NULL);
7749 return pInetPton(af,
src, dst);
7761 #if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7764 unixtime_to_systemtime(
const time_t t, SYSTEMTIME *
st)
7767 if (unixtime_to_filetime(t, &ft))
return -1;
7768 if (!FileTimeToSystemTime(&ft,
st))
return -1;
7774 systemtime_to_tm(
const SYSTEMTIME *
st,
struct tm *t)
7776 int y =
st->wYear, m =
st->wMonth, d =
st->wDay;
7791 d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
7792 d += ((m - 3) * 153 + 2) / 5;
7800 systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
7802 TIME_ZONE_INFORMATION stdtz;
7805 if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst))
return -1;
7807 GetTimeZoneInformation(&stdtz);
7810 if (tz->StandardBias == tz->DaylightBias)
return 0;
7811 if (!tz->StandardDate.wMonth)
return 0;
7812 if (!tz->DaylightDate.wMonth)
return 0;
7813 if (tz != &stdtz) stdtz = *tz;
7815 stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
7816 if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst))
return 0;
7817 if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
7823 #ifdef HAVE__GMTIME64_S
7824 # ifndef HAVE__LOCALTIME64_S
7826 # define HAVE__LOCALTIME64_S 1
7828 # ifndef MINGW_HAS_SECURE_API
7829 _CRTIMP errno_t __cdecl _gmtime64_s(
struct tm*
tm,
const __time64_t *
time);
7830 _CRTIMP errno_t __cdecl _localtime64_s(
struct tm*
tm,
const __time64_t *
time);
7832 # define gmtime_s _gmtime64_s
7833 # define localtime_s _localtime64_s
7846 #if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__GMTIME64_S)
7847 e = gmtime_s(
rp, tp);
7848 if (e != 0)
goto error;
7852 if (unixtime_to_systemtime(*tp, &
st))
goto error;
7854 systemtime_to_tm(&
st,
rp);
7870 #if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__LOCALTIME64_S)
7871 e = localtime_s(
rp, tp);
7875 SYSTEMTIME gst, lst;
7876 if (unixtime_to_systemtime(*tp, &gst))
goto error;
7877 rp->tm_isdst = systemtime_to_localtime(
NULL, &gst, &lst);
7878 systemtime_to_tm(&lst,
rp);
7889 int len =
sizeof(tmp);
7890 int r = getsockopt((SOCKET)
h, SOL_SOCKET, SO_DEBUG, (
char *)&tmp, &
len);
7891 if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
7897 socklist_insert((SOCKET)
h,
f);
7903 return rb_w32_open_osfhandle((
intptr_t)
h, flags);
7914 constat_delete((HANDLE)sock);
7917 socklist_delete(&sock,
NULL);
7922 #if !defined(__MINGW64__) && defined(__MINGW64_VERSION_MAJOR)
7928 rb_w32_pow(
double x,
double y)
7932 unsigned int default_control = _controlfp(0, 0);
7933 _controlfp(_PC_64, _MCW_PC);
7936 _controlfp(default_control, _MCW_PC);
7961 if (
f == (HANDLE)-1)
return INVALID_HANDLE_VALUE;
7974 f = CreateFileW(
ptr, 0,
7975 FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING,
7976 FILE_FLAG_BACKUP_SEMANTICS,
NULL);
7978 if (
f == INVALID_HANDLE_VALUE)
return f;
7981 if (GetFileType(
f) == FILE_TYPE_DISK) {
7983 ZeroMemory(
st,
sizeof(*
st));
7984 err = get_ino(
f, &
st->info.fii);
7989 else if (
err != ERROR_INVALID_PARAMETER) {
7991 return INVALID_HANDLE_VALUE;
7995 if (GetFileInformationByHandle(
f, &
st->info.bhfi)) {
8000 if (ret) CloseHandle(ret);
8001 return INVALID_HANDLE_VALUE;
8007 CloseHandle((HANDLE)
h);
8027 HANDLE f1 = 0, f2 = 0;
8029 f1 = w32_io_info(&fname1, &st1);
8030 if (f1 == INVALID_HANDLE_VALUE)
return Qfalse;
8033 arg.fname = &fname2;
8038 f2 = w32_io_info(&fname2, &st2);
8040 if (f2 == INVALID_HANDLE_VALUE)
return Qfalse;
8041 if (f2) CloseHandle(f2);
8045 if (st1.
info.
bhfi.dwVolumeSerialNumber == st2.
info.
bhfi.dwVolumeSerialNumber &&
8062 typedef HRESULT (WINAPI *set_thread_description_func)(HANDLE, PCWSTR);
8063 static set_thread_description_func set_thread_description =
8064 (set_thread_description_func)-1;
8065 if (set_thread_description == (set_thread_description_func)-1) {
8066 set_thread_description = (set_thread_description_func)
8067 get_proc_address(
"kernel32",
"SetThreadDescription",
NULL);
8069 if (set_thread_description) {
8070 result = set_thread_description(th,
name);
8078 int idx, result =
FALSE;
8101 #if RUBY_MSVCRT_VERSION < 120