22 #undef __STRICT_ANSI__ 56 #define isdirsep(x) ((x) == '/' || (x) == '\\') 58 #if defined _MSC_VER && _MSC_VER <= 1200 59 # define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags)) 62 static int w32_wopen(
const WCHAR *file,
int oflag,
int perm);
63 static int w32_stati64(
const char *path,
struct stati64 *st, UINT cp);
64 static int w32_lstati64(
const char *path,
struct stati64 *st, UINT cp);
65 static char *w32_getenv(
const char *
name, UINT cp);
68 #define DLN_FIND_EXTRA_ARG_DECL ,UINT cp 69 #define DLN_FIND_EXTRA_ARG ,cp 70 #define rb_w32_stati64(path, st) w32_stati64(path, st, cp) 71 #define getenv(name) w32_getenv(name, cp) 73 #define CharNext(p) CharNextExA(cp, (p), 0) 74 #define dln_find_exe_r rb_w32_udln_find_exe_r 75 #define dln_find_file_r rb_w32_udln_find_file_r 81 #undef dln_find_file_r 82 #define dln_find_exe_r(fname, path, buf, size) rb_w32_udln_find_exe_r(fname, path, buf, size, cp) 83 #define dln_find_file_r(fname, path, buf, size) rb_w32_udln_find_file_r(fname, path, buf, size, cp) 88 # define PATH_MAX MAX_PATH 89 # elif defined HAVE_SYS_PARAM_H 90 # include <sys/param.h> 91 # define PATH_MAX MAXPATHLEN 103 #if RUBY_MSVCRT_VERSION >= 140 104 # define _filbuf _fgetc_nolock 105 # define _flsbuf _fputc_nolock 107 #define enough_to_get(n) (--(n) >= 0) 108 #define enough_to_put(n) (--(n) >= 0) 111 #define Debug(something) something 113 #define Debug(something) 116 #define TO_SOCKET(x) _get_osfhandle(x) 120 static struct ChildRecord *CreateChild(
const WCHAR *,
const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE,
DWORD);
121 static int has_redirection(
const char *, UINT);
123 static int rb_w32_open_osfhandle(
intptr_t osfhandle,
int flags);
124 static int wstati64(
const WCHAR *path,
struct stati64 *st);
125 static int wlstati64(
const WCHAR *path,
struct stati64 *st);
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 },
147 { ERROR_BAD_FORMAT, ENOEXEC },
148 { ERROR_INVALID_ACCESS, EINVAL },
149 { ERROR_INVALID_DATA, EINVAL },
150 { ERROR_INVALID_DRIVE, ENOENT },
151 { ERROR_CURRENT_DIRECTORY, EACCES },
152 { ERROR_NOT_SAME_DEVICE, EXDEV },
153 { ERROR_NO_MORE_FILES, ENOENT },
154 { ERROR_WRITE_PROTECT, EROFS },
155 { ERROR_BAD_UNIT, ENODEV },
156 { ERROR_NOT_READY, ENXIO },
157 { ERROR_BAD_COMMAND, EACCES },
158 { ERROR_CRC, EACCES },
159 { ERROR_BAD_LENGTH, EACCES },
161 { ERROR_NOT_DOS_DISK, EACCES },
162 { ERROR_SECTOR_NOT_FOUND, EACCES },
163 { ERROR_OUT_OF_PAPER, EACCES },
164 { ERROR_WRITE_FAULT, EIO },
165 { ERROR_READ_FAULT, EIO },
166 { ERROR_GEN_FAILURE, EACCES },
167 { ERROR_LOCK_VIOLATION, EACCES },
168 { ERROR_SHARING_VIOLATION, EACCES },
169 { ERROR_WRONG_DISK, EACCES },
170 { ERROR_SHARING_BUFFER_EXCEEDED, EACCES },
171 { ERROR_BAD_NETPATH, ENOENT },
172 { ERROR_NETWORK_ACCESS_DENIED, EACCES },
173 { ERROR_BAD_NET_NAME, ENOENT },
174 { ERROR_FILE_EXISTS, EEXIST },
175 { ERROR_CANNOT_MAKE, EACCES },
176 { ERROR_FAIL_I24, EACCES },
177 { ERROR_INVALID_PARAMETER, EINVAL },
178 { ERROR_NO_PROC_SLOTS, EAGAIN },
179 { ERROR_DRIVE_LOCKED, EACCES },
180 { ERROR_BROKEN_PIPE, EPIPE },
181 { ERROR_DISK_FULL, ENOSPC },
182 { ERROR_INVALID_TARGET_HANDLE, EBADF },
183 { ERROR_INVALID_HANDLE, EINVAL },
184 { ERROR_WAIT_NO_CHILDREN, ECHILD },
185 { ERROR_CHILD_NOT_COMPLETE, ECHILD },
186 { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
187 { ERROR_NEGATIVE_SEEK, EINVAL },
188 { ERROR_SEEK_ON_DEVICE, EACCES },
189 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
190 { ERROR_DIRECTORY, ENOTDIR },
191 { ERROR_NOT_LOCKED, EACCES },
192 { ERROR_BAD_PATHNAME, ENOENT },
193 { ERROR_MAX_THRDS_REACHED, EAGAIN },
194 { ERROR_LOCK_FAILED, EACCES },
195 { ERROR_ALREADY_EXISTS, EEXIST },
196 { ERROR_INVALID_STARTING_CODESEG, ENOEXEC },
197 { ERROR_INVALID_STACKSEG, ENOEXEC },
198 { ERROR_INVALID_MODULETYPE, ENOEXEC },
199 { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC },
200 { ERROR_EXE_MARKED_INVALID, ENOEXEC },
201 { ERROR_BAD_EXE_FORMAT, ENOEXEC },
202 { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC },
203 { ERROR_INVALID_MINALLOCSIZE, ENOEXEC },
204 { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC },
205 { ERROR_IOPL_NOT_ENABLED, ENOEXEC },
206 { ERROR_INVALID_SEGDPL, ENOEXEC },
207 { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC },
208 { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC },
209 { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC },
210 { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC },
211 { ERROR_FILENAME_EXCED_RANGE, ENOENT },
212 { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
213 #ifndef ERROR_PIPE_LOCAL 214 #define ERROR_PIPE_LOCAL 229L 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, },
228 { WSAEACCES, EACCES },
229 { WSAEFAULT, EFAULT },
230 { WSAEINVAL, EINVAL },
231 { WSAEMFILE, EMFILE },
260 { WSAENAMETOOLONG, ENAMETOOLONG },
264 { WSAENOTEMPTY, ENOTEMPTY },
281 for (i = 0; i < (int)(
sizeof(errmap) /
sizeof(*errmap)); i++) {
282 if (errmap[i].winerr == winerr) {
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;
352 memset(&o, 0,
sizeof(o));
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) {
450 f = func(pidl, buf, len, 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
'/');
467 if (p - path == 2 && path[1] == 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);
503 if (!get_special_folder(type, path,
numberof(path)))
return Qnil;
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
'/';
525 if ((UINT)(p - path +
numberof(temp)) >= len)
return 0;
526 memcpy(p, temp,
sizeof(temp));
527 return (UINT)(p - path +
numberof(temp) - 1);
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); \ 618 if (GetEnvironmentVariableW(L
"HOMEPATH",
env + len,
numberof(
env) - len) || len) {
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;
692 static int NtSocketsInitialized = 0;
695 #define conlist_disabled ((st_table *)-1) 696 static char *uenvarea;
718 constat_delete(HANDLE h)
731 if (NtSocketsInitialized) {
737 DeleteCriticalSection(&select_mutex);
738 NtSocketsInitialized = 0;
762 version = MAKEWORD(2, 0);
763 if (WSAStartup(version, &retdata))
764 rb_fatal(
"Unable to locate winsock library!");
765 if (LOBYTE(retdata.wVersion) != 2)
766 rb_fatal(
"could not find version 2 of winsock dll");
768 InitializeCriticalSection(&select_mutex);
770 NtSocketsInitialized = 1;
773 #define MAKE_SOCKDATA(af, fl) ((int)((((int)af)<<4)|((fl)&0xFFFF))) 774 #define GET_FAMILY(v) ((int)(((v)>>4)&0xFFFF)) 775 #define GET_FLAGS(v) ((int)((v)&0xFFFF)) 779 socklist_insert(SOCKET sock,
int flag)
788 socklist_lookup(SOCKET sock,
int *flagp)
804 socklist_delete(SOCKET *sockp,
int *flagp)
817 *sockp = (SOCKET)key;
825 static int w32_cmdvector(
const WCHAR *,
char ***, UINT,
rb_encoding *);
833 #if RUBY_MSVCRT_VERSION >= 80 834 static void set_pioinfo_extra(
void);
836 _CrtSetReportMode(_CRT_ASSERT, 0);
837 _set_invalid_parameter_handler(invalid_parameter);
838 _RTC_SetErrorFunc(rtc_error_handler);
841 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
860 atexit(exit_handler);
869 return (
char *)NTLoginName;
872 #define MAXCHILDNUM 256 875 static struct ChildRecord {
881 #define FOREACH_CHILD(v) do { \ 882 struct ChildRecord* v; \ 883 for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v) 884 #define END_FOREACH_CHILD } while (0) 887 static struct ChildRecord *
888 FindChildSlot(rb_pid_t pid)
892 if (child->pid == pid) {
900 static struct ChildRecord *
901 FindChildSlotByHandle(HANDLE h)
905 if (child->hProcess == h) {
914 CloseChildHandle(
struct ChildRecord *child)
916 HANDLE h = child->hProcess;
917 child->hProcess =
NULL;
923 static struct ChildRecord *
924 FindFreeChildSlot(
void)
929 child->hProcess =
NULL;
943 #define InternalCmdsMax 8 998 internal_match(
const void *
key,
const void *elem)
1005 is_command_com(
const char *interp)
1007 int i =
strlen(interp) - 11;
1009 if ((i == 0 || (i > 0 &&
isdirsep(interp[i-1]))) &&
1016 static int internal_cmd_match(
const char *cmdname,
int nt);
1020 is_internal_cmd(
const char *cmd,
int nt)
1022 char cmdname[9], *b = cmdname, c;
1025 if (!(c = *cmd++))
return 0;
1026 }
while (isspace(c));
1029 while (isalpha(c)) {
1031 if (b == cmdname +
sizeof(cmdname))
return 0;
1034 if (c ==
'.') c = *cmd;
1036 case '<':
case '>':
case '|':
1038 case '\0':
case ' ':
case '\t':
case '\n':
1044 return internal_cmd_match(cmdname, nt);
1049 internal_cmd_match(
const char *cmdname,
int nt)
1053 nm = bsearch(cmdname, szInternalCmds,
1054 sizeof(szInternalCmds) /
sizeof(*szInternalCmds),
1055 sizeof(*szInternalCmds),
1057 if (!nm || !(nm[0] & (nt ? 2 : 1)))
1066 return _get_osfhandle(fh);
1071 join_argv(
char *cmd,
char *
const *
argv, BOOL escape, UINT cp,
int backslash)
1075 int len, n, bs, quote;
1077 for (t =
argv, q = cmd, len = 0; (p = *t) != 0; t++) {
1080 if (!*p || strpbrk(p,
" \t\"'")) {
1085 for (bs = 0; *p; ++p) {
1099 memset(q,
'\\', bs);
1104 case '<':
case '>':
case '|':
case '^':
1105 if (escape && !quote) {
1106 len += (n = p - s) + 1;
1117 p = CharNextExA(cp, p, 0) - 1;
1121 len += (n = p - s) + 1;
1125 if (backslash > 0) {
1128 translate_char(q,
'/',
'\\', cp);
1131 if (quote) *q++ =
'"';
1144 #define STRNDUPV(ptr, v, src, len) \ 1145 (((char *)memcpy(((ptr) = ALLOCV((v), (len) + 1)), (src), (len)))[len] = 0) 1149 check_spawn_mode(
int mode)
1163 child_result(
struct ChildRecord *child,
int mode)
1171 if (mode == P_OVERLAY) {
1172 WaitForSingleObject(child->hProcess, INFINITE);
1173 GetExitCodeProcess(child->hProcess, &exitcode);
1174 CloseChildHandle(child);
1181 static struct ChildRecord *
1182 CreateChild(
const WCHAR *cmd,
const WCHAR *prog, SECURITY_ATTRIBUTES *psa,
1183 HANDLE hInput, HANDLE hOutput, HANDLE hError,
DWORD dwCreationFlags)
1186 STARTUPINFOW aStartupInfo;
1187 PROCESS_INFORMATION aProcessInformation;
1188 SECURITY_ATTRIBUTES sa;
1189 struct ChildRecord *child;
1191 if (!cmd && !prog) {
1196 child = FindFreeChildSlot();
1203 sa.nLength =
sizeof (SECURITY_ATTRIBUTES);
1204 sa.lpSecurityDescriptor =
NULL;
1205 sa.bInheritHandle =
TRUE;
1209 memset(&aStartupInfo, 0,
sizeof(aStartupInfo));
1210 memset(&aProcessInformation, 0,
sizeof(aProcessInformation));
1211 aStartupInfo.cb =
sizeof(aStartupInfo);
1212 aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
1214 aStartupInfo.hStdInput = hInput;
1217 aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1220 aStartupInfo.hStdOutput = hOutput;
1223 aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1226 aStartupInfo.hStdError = hError;
1229 aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1232 dwCreationFlags |= NORMAL_PRIORITY_CLASS;
1234 if (lstrlenW(cmd) > 32767) {
1241 fRet = CreateProcessW(prog, (WCHAR *)cmd, psa, psa,
1242 psa->bInheritHandle, dwCreationFlags,
NULL,
NULL,
1243 &aStartupInfo, &aProcessInformation);
1252 CloseHandle(aProcessInformation.hThread);
1254 child->hProcess = aProcessInformation.hProcess;
1255 child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
1262 is_batch(
const char *cmd)
1265 if (len <= 4)
return 0;
1267 if (*cmd++ !=
'.')
return 0;
1273 #define filecp rb_w32_filecp 1274 #define mbstr_to_wstr rb_w32_mbstr_to_wstr 1275 #define wstr_to_mbstr rb_w32_wstr_to_mbstr 1276 #define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen) 1277 #define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen) 1278 #define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen) 1279 #define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen) 1280 #define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen) 1281 #define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen) 1285 w32_spawn(
int mode,
const char *cmd,
const char *prog, UINT cp)
1289 const char *shell =
NULL;
1290 WCHAR *wcmd =
NULL, *wshell =
NULL;
1296 char *cmd_sep =
NULL;
1298 if (check_spawn_mode(mode))
return -1;
1306 translate_char(p,
'/',
'\\', cp);
1313 if ((shell =
getenv(
"RUBYSHELL")) && (redir = has_redirection(cmd, cp))) {
1314 size_t shell_len =
strlen(shell);
1315 char *tmp =
ALLOCV(v, shell_len +
strlen(cmd) +
sizeof(
" -c ") + 2);
1316 memcpy(tmp, shell, shell_len + 1);
1317 translate_char(tmp,
'/',
'\\', cp);
1318 sprintf(tmp + shell_len,
" -c \"%s\"", cmd);
1321 else if ((shell =
getenv(
"COMSPEC")) &&
1322 (nt = !is_command_com(shell),
1323 (redir < 0 ? has_redirection(cmd, cp) : redir) ||
1324 is_internal_cmd(cmd, nt))) {
1326 sprintf(tmp, nt ?
"%s /c \"%s\"" :
"%s /c %s", shell, cmd);
1330 int len = 0, quote = (*cmd ==
'"') ?
'"' : (*cmd ==
'\'') ?
'\'' : 0;
1332 for (prog = cmd + !!quote;; prog = CharNextExA(cp, prog, 0)) {
1333 if (*prog ==
'/') slash = 1;
1343 if ((
unsigned char)*prog == quote) {
1344 len = prog++ - cmd - 1;
1349 if (quote)
continue;
1355 sep = *(cmd_sep = &p[
len]);
1363 if (p && slash) translate_char(p,
'/',
'\\', cp);
1365 shell = p ? p : cmd;
1369 if (
strchr(shell,
' ')) quote = -1;
1370 if (shell == fbuf) {
1373 else if (shell != p &&
strchr(shell,
'/')) {
1377 if (p) translate_char(p,
'/',
'\\', cp);
1378 if (is_batch(shell)) {
1380 cmd = p =
ALLOCV(v, len + alen + (quote ? 2 : 0) + 1);
1381 if (quote) *p++ =
'"';
1382 memcpy(p, shell, len);
1384 if (quote) *p++ =
'"';
1385 memcpy(p, prog, alen + 1);
1393 if (cmd_sep) *cmd_sep = sep;
1399 ret = child_result(CreateChild(wcmd, wshell,
NULL,
NULL,
NULL,
NULL, 0), mode);
1412 return w32_spawn(mode, cmd, prog,
filecp());
1419 return w32_spawn(mode, cmd, prog, CP_UTF8);
1424 w32_aspawn_flags(
int mode,
const char *prog,
char *
const *
argv,
DWORD flags, UINT cp)
1428 BOOL ntcmd =
FALSE, tmpnt;
1436 if (check_spawn_mode(mode))
return -1;
1438 if (!prog) prog =
argv[0];
1439 if ((shell =
getenv(
"COMSPEC")) &&
1440 internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
1446 if (cmd == prog)
strlcpy(cmd = fbuf, prog,
sizeof(fbuf));
1447 translate_char(cmd,
'/',
'\\', cp);
1450 else if (
strchr(prog,
'/')) {
1452 if (len <
sizeof(fbuf))
1453 strlcpy(cmd = fbuf, prog,
sizeof(fbuf));
1456 translate_char(cmd,
'/',
'\\', cp);
1459 if (c_switch || is_batch(prog)) {
1461 progs[0] = (
char *)prog;
1463 len = join_argv(
NULL, progs, ntcmd, cp, 1);
1464 if (c_switch) len += 3;
1466 if (
argv[0]) len += join_argv(
NULL,
argv, ntcmd, cp, 0);
1468 join_argv(cmd, progs, ntcmd, cp, 1);
1469 if (c_switch)
strlcat(cmd,
" /c", len);
1470 if (
argv[0]) join_argv(cmd +
strlcat(cmd,
" ", len),
argv, ntcmd, cp, 0);
1471 prog = c_switch ? shell : 0;
1484 ret = child_result(CreateChild(wcmd, wprog,
NULL,
NULL,
NULL,
NULL, flags), mode);
1497 return w32_aspawn_flags(mode, prog, argv, flags,
filecp());
1504 return w32_aspawn_flags(mode, prog, argv, flags, CP_UTF8);
1533 #define NTGLOB 0x1 // element contains a wildcard 1534 #define NTMALLOC 0x2 // string in element was malloc'ed 1535 #define NTSTRING 0x4 // element contains a quoted string 1539 insert(
const char *path,
VALUE vinfo,
void *enc)
1545 if (!tmpcurr)
return -1;
1549 if (!tmpcurr->
str)
return -1;
1552 *tail = &tmpcurr->
next;
1566 if (!(buf =
malloc(patt->
len + 1)))
return 0;
1568 memcpy(buf, patt->
str, patt->
len);
1569 buf[patt->
len] =
'\0';
1570 translate_char(buf,
'\\',
'/', cp);
1575 if (status || last == tail)
return 0;
1589 has_redirection(
const char *cmd, UINT cp)
1599 for (ptr = cmd; *ptr;) {
1605 else if (quote == *ptr)
1621 if (*++ptr !=
'_' && !
ISALPHA(*ptr))
break;
1622 while (*++ptr ==
'_' ||
ISALNUM(*ptr));
1623 if (*ptr++ ==
'%')
return TRUE;
1629 ptr = CharNextExA(cp, ptr, 0);
1637 static inline WCHAR *
1638 skipspace(WCHAR *ptr)
1647 w32_cmdvector(
const WCHAR *cmd,
char ***vec, UINT cp,
rb_encoding *enc)
1650 int elements, strsz, done;
1651 int slashes, escape;
1652 WCHAR *ptr, *base, *cmdline;
1653 char *cptr, *buffer;
1669 ptr = cmdline = wcsdup(cmd);
1680 while (*(ptr = skipspace(ptr))) {
1682 quote = slashes = globbing = escape = 0;
1683 for (done = 0; !done && *ptr; ) {
1692 if (quote != L
'\'') slashes++;
1732 if (!(slashes & 1)) {
1735 else if (quote == *ptr) {
1736 if (quote == L
'"' && quote == ptr[1])
1746 ptr = CharNextW(ptr);
1769 slashes = quote = 0;
1770 while (p < base + len) {
1774 if (quote != L
'\'') slashes++;
1779 if (!(slashes & 1) && quote && quote != c) {
1784 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
1785 sizeof(WCHAR) * (base + len - p));
1786 len -= ((slashes + 1) >> 1) + (~slashes & 1);
1787 p -= (slashes + 1) >> 1;
1788 if (!(slashes & 1)) {
1790 if (quote == L
'"' && quote == *p)
1811 if (!curr)
goto do_nothing;
1815 if (globbing && (tail = cmdglob(curr, cmdtail, cp, enc))) {
1820 cmdtail = &curr->
next;
1830 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->
next) {
1832 strsz += (curr->
len + 1);
1835 len = (elements+1)*
sizeof(
char *) + strsz;
1836 buffer = (
char *)
malloc(len);
1839 while ((curr = cmdhead) != 0) {
1840 cmdhead = curr->
next;
1845 for (vptr = *vec; *vptr; ++vptr);
1861 vptr = (
char **) buffer;
1863 cptr = buffer + (elements+1) *
sizeof(
char *);
1865 while ((curr = cmdhead) != 0) {
1866 memcpy(cptr, curr->
str, curr->
len);
1867 cptr[curr->
len] =
'\0';
1869 cptr += curr->
len + 1;
1870 cmdhead = curr->
next;
1876 *vec = (
char **) buffer;
1898 get_proc_address(
"kernel32",
"GetFinalPathNameByHandleW",
NULL);
1899 if (!func) func = get_final_path_fail;
1900 get_final_path = func;
1901 return func(
f,
buf,
len, flag);
1911 const DWORD share_mode =
1912 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1913 return CreateFileW(path,
access, share_mode,
NULL, OPEN_EXISTING,
1914 FILE_FLAG_BACKUP_SEMANTICS|flags,
NULL);
1924 #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT)) 1925 #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT)) 1927 #define BitOfIsDir(n) ((n) * 2) 1928 #define BitOfIsRep(n) ((n) * 2 + 1) 1929 #define DIRENT_PER_CHAR (CHAR_BIT / 2) 1933 open_dir_handle(
const WCHAR *filename, WIN32_FIND_DATAW *fd)
1944 fh = open_special(filename, 0, 0);
1945 if (fh != INVALID_HANDLE_VALUE) {
1946 len = get_final_path(fh, fullname,
PATH_MAX, 0);
1950 len = lstrlenW(filename);
1952 errno = ENAMETOOLONG;
1953 return INVALID_HANDLE_VALUE;
1955 MEMCPY(fullname, filename, WCHAR, len);
1957 p = &fullname[len-1];
1958 if (!(
isdirsep(*p) || *p == L
':')) *++p = L
'\\';
1965 fh = FindFirstFileW(fullname, fd);
1966 if (fh == INVALID_HANDLE_VALUE) {
1974 w32_wopendir(
const WCHAR *wpath)
1976 struct stati64 sbuf;
1977 WIN32_FIND_DATAW fd;
1990 if (wstati64(wpath, &sbuf) < 0) {
1993 if (!(sbuf.st_mode & S_IFDIR) &&
1994 (!
ISALPHA(wpath[0]) || wpath[1] != L
':' || wpath[2] != L
'\0' ||
1995 ((1 << ((wpath[0] & 0x5f) -
'A')) & GetLogicalDrives()) == 0)) {
1999 fh = open_dir_handle(wpath, &fd);
2000 if (fh == INVALID_HANDLE_VALUE) {
2011 pathlen = lstrlenW(wpath);
2021 len = lstrlenW(fd.cFileName) + 1;
2022 altlen = lstrlenW(fd.cAlternateFileName) + 1;
2028 tmpW =
realloc(p->
start, (idx + len + altlen) *
sizeof(WCHAR));
2038 memcpy(&p->
start[idx], fd.cFileName, len *
sizeof(WCHAR));
2039 memcpy(&p->
start[idx + len], fd.cAlternateFileName, altlen *
sizeof(WCHAR));
2048 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2050 if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
2051 WCHAR *tmppath =
malloc((pathlen + len + 1) *
sizeof(WCHAR));
2052 memcpy(tmppath, wpath, pathlen *
sizeof(WCHAR));
2053 tmppath[pathlen] = L
'\\';
2054 memcpy(tmppath + pathlen + 1, fd.cFileName, len *
sizeof(WCHAR));
2061 idx += len + altlen;
2062 }
while (FindNextFileW(fh, &fd));
2073 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
2082 int len = WideCharToMultiByte(cp, 0, wstr, clen,
NULL, 0,
NULL,
NULL);
2083 if (!(ptr =
malloc(len)))
return 0;
2084 WideCharToMultiByte(cp, 0, wstr, clen, ptr, len,
NULL,
NULL);
2087 if (clen == -1) --
len;
2098 int len = MultiByteToWideChar(cp, 0, str, clen,
NULL, 0);
2099 if (!(ptr =
malloc(
sizeof(WCHAR) * len)))
return 0;
2100 MultiByteToWideChar(cp, 0, str, clen, ptr, len);
2103 if (clen == -1) --
len;
2117 ret = w32_wopendir(wpath);
2130 ret = w32_wopendir(wpath);
2141 move_to_next_entry(
DIR *dirp)
2145 dirp->
curr += lstrlenW(dirp->
curr) + 1;
2146 dirp->
curr += lstrlenW(dirp->
curr) + 1;
2159 win32_direct_conv(
const WCHAR *file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2161 UINT cp = *((UINT *)enc);
2177 long len = lstrlenW(wstr);
2184 #if SIZEOF_INT < SIZEOF_LONG 2185 # error long should equal to int on Windows 2188 len = WideCharToMultiByte(CP_UTF8, 0, wstr, clen,
NULL, 0,
NULL,
NULL);
2220 ruby_direct_conv(
const WCHAR *file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2234 readdir_internal(
DIR *dirp, BOOL (*conv)(
const WCHAR *,
const WCHAR *,
struct direct *,
const void *),
const void *enc)
2236 static int dummy = 0;
2271 move_to_next_entry(dirp);
2286 const UINT cp =
filecp();
2287 return readdir_internal(dirp, win32_direct_conv, &cp);
2290 const UINT cp = CP_UTF8;
2291 return readdir_internal(dirp, win32_direct_conv, &cp);
2294 return readdir_internal(dirp, ruby_direct_conv, enc);
2318 while (dirp->
curr && dirp->
loc < loc) {
2319 move_to_next_entry(dirp);
2356 #if RUBY_MSVCRT_VERSION >= 140 2371 CRITICAL_SECTION _lock;
2373 #define FILE_COUNT(stream) ((vcruntime_file*)stream)->_cnt 2374 #define FILE_READPTR(stream) ((vcruntime_file*)stream)->_ptr 2375 #define FILE_FILENO(stream) ((vcruntime_file*)stream)->_file 2377 #define FILE_COUNT(stream) stream->_cnt 2378 #define FILE_READPTR(stream) stream->_ptr 2379 #define FILE_FILENO(stream) stream->_file 2383 #if RUBY_MSVCRT_VERSION >= 140 2384 typedef char lowio_text_mode;
2385 typedef char lowio_pipe_lookahead[3];
2388 CRITICAL_SECTION lock;
2391 unsigned char osfile;
2392 lowio_text_mode textmode;
2393 lowio_pipe_lookahead _pipe_lookahead;
2407 #if RUBY_MSVCRT_VERSION >= 80 2414 #if !defined _CRTIMP || defined __MINGW32__ 2416 #define _CRTIMP __declspec(dllimport) 2419 #if RUBY_MSVCRT_VERSION >= 140 2421 #define IOINFO_L2E 6 2424 #define IOINFO_L2E 5 2426 static inline ioinfo* _pioinfo(
int);
2428 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) 2429 #define _osfhnd(i) (_pioinfo(i)->osfhnd) 2430 #define _osfile(i) (_pioinfo(i)->osfile) 2431 #define rb_acrt_lowio_lock_fh(i) EnterCriticalSection(&_pioinfo(i)->lock) 2432 #define rb_acrt_lowio_unlock_fh(i) LeaveCriticalSection(&_pioinfo(i)->lock) 2434 #if RUBY_MSVCRT_VERSION >= 80 2439 set_pioinfo_extra(
void)
2441 #if RUBY_MSVCRT_VERSION >= 140 2442 # define FUNCTION_RET 0xc3 2444 # define UCRTBASE "ucrtbased.dll" 2446 # define UCRTBASE "ucrtbase.dll" 2449 char *p = (
char*)get_proc_address(UCRTBASE,
"_isatty",
NULL);
2457 # define FUNCTION_BEFORE_RET_MARK "\x48\x83\xc4" 2458 # define FUNCTION_SKIP_BYTES 1 2461 # define PIOINFO_MARK "\x48\x8d\x0d" 2464 # define PIOINFO_MARK "\x48\x8d\x15" 2469 # define FUNCTION_BEFORE_RET_MARK "\x5d" 2470 # define FUNCTION_SKIP_BYTES 0 2472 # define PIOINFO_MARK "\x8B\x04\x85" 2475 for (pend += 10; pend < p + 300; pend++) {
2477 if (
memcmp(pend, FUNCTION_BEFORE_RET_MARK,
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) == 0 &&
2478 *(pend + (
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) + FUNCTION_SKIP_BYTES) & FUNCTION_RET == FUNCTION_RET) {
2480 for (pend -= (
sizeof(PIOINFO_MARK) - 1); pend > p; pend--) {
2481 if (
memcmp(pend, PIOINFO_MARK,
sizeof(PIOINFO_MARK) - 1) == 0) {
2490 fprintf(stderr,
"unexpected " UCRTBASE
"\n");
2494 p +=
sizeof(PIOINFO_MARK) - 1;
2496 rel = *(int32_t*)(p);
2497 rip = p +
sizeof(int32_t);
2498 __pioinfo = (
ioinfo**)(rip + rel);
2500 __pioinfo = *(
ioinfo***)(p);
2505 fd = _open(
"NUL", O_RDONLY);
2507 if (
_osfhnd(fd) == _get_osfhandle(fd)) {
2520 #define pioinfo_extra 0 2531 #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh) 2532 #define _set_osflags(fh, flags) (_osfile(fh) = (flags)) 2535 #define FEOFLAG 0x02 2537 #define FNOINHERIT 0x10 2538 #define FAPPEND 0x20 2543 static int is_console(SOCKET);
2554 rb_w32_open_osfhandle(
intptr_t osfhandle,
int flags)
2563 if (flags & O_APPEND)
2569 if (flags & O_NOINHERIT)
2573 hF = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
2574 fh = _open_osfhandle((
intptr_t)hF, 0);
2596 init_stdhandle(
void)
2600 #define open_null(fd) \ 2602 (nullfd = open("NUL", O_RDWR)) : 0), \ 2603 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \ 2612 if (
fileno(stdout) < 0) {
2615 if (
fileno(stderr) < 0) {
2618 if (nullfd >= 0 && !keep) close(nullfd);
2619 setvbuf(stderr,
NULL, _IONBF, 0);
2628 if (socklist_lookup(sock,
NULL))
2653 static char buffer[512];
2660 #if WSAEWOULDBLOCK != EWOULDBLOCK 2665 for (s = 0; s < (int)(
sizeof(errmap)/
sizeof(*errmap)); s++)
2666 if (errmap[s].
winerr == WSAEWOULDBLOCK)
2668 for (i = s; i < (int)(
sizeof(errmap)/
sizeof(*errmap)); i++)
2669 if (errmap[i].
err == e) {
2670 e = errmap[i].winerr;
2675 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2676 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
2677 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
2678 buffer,
sizeof(buffer),
NULL) == 0 &&
2679 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2680 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
2681 buffer,
sizeof(buffer),
NULL) == 0)
2682 strlcpy(buffer,
"Unknown Error",
sizeof(buffer));
2688 while ((p = strpbrk(p,
"\r\n")) !=
NULL) {
2777 for (i = 0; i <
set->fd_count; i++) {
2778 if (set->fd_array[i] == s) {
2779 memmove(&set->fd_array[i], &set->fd_array[i+1],
2780 sizeof(set->fd_array[0]) * (--set->fd_count - i));
2794 if (s == (SOCKET)INVALID_HANDLE_VALUE)
2804 max = min(src->fd_count, (UINT)max);
2805 if ((UINT)dst->capa < (UINT)max) {
2806 dst->capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2807 dst->fdset =
xrealloc(dst->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2810 memcpy(dst->fdset->fd_array, src->fd_array,
2811 max *
sizeof(src->fd_array[0]));
2812 dst->fdset->fd_count = src->fd_count;
2819 if ((UINT)dst->capa < src->fdset->fd_count) {
2820 dst->capa = (src->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2821 dst->fdset =
xrealloc(dst->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2824 memcpy(dst->fdset->fd_array, src->fdset->fd_array,
2825 src->fdset->fd_count *
sizeof(src->fdset->fd_array[0]));
2826 dst->fdset->fd_count = src->fdset->fd_count;
2839 extract_fd(
rb_fdset_t *dst, fd_set *src,
int (*func)(SOCKET))
2845 while (s < src->fd_count) {
2846 SOCKET fd = src->fd_array[s];
2848 if (!func || (*func)(fd)) {
2852 for (d = 0; d < dst->fdset->fd_count; d++) {
2853 if (dst->fdset->fd_array[d] == fd)
2856 if (d == dst->fdset->fd_count) {
2857 if ((
int)dst->fdset->fd_count >= dst->capa) {
2858 dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2859 dst->fdset =
xrealloc(dst->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2861 dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
2865 &src->fd_array[s+1],
2866 sizeof(src->fd_array[0]) * (--src->fd_count - s));
2876 return dst ? dst->fdset->fd_count : m;
2881 copy_fd(fd_set *dst, fd_set *src)
2884 if (!src || !dst)
return 0;
2886 for (s = 0; s < src->fd_count; ++s) {
2887 SOCKET fd = src->fd_array[s];
2889 for (d = 0; d < dst->fd_count; ++d) {
2890 if (dst->fd_array[d] == fd)
2893 if (d == dst->fd_count && d < FD_SETSIZE) {
2894 dst->fd_array[dst->fd_count++] = fd;
2898 return dst->fd_count;
2903 is_not_socket(SOCKET sock)
2910 is_pipe(SOCKET sock)
2915 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
2923 is_readable_pipe(SOCKET sock)
2929 if (PeekNamedPipe((HANDLE)sock,
NULL, 0,
NULL, &n,
NULL)) {
2933 ret = (GetLastError() == ERROR_BROKEN_PIPE);
2942 is_console(SOCKET sock)
2949 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n));
2957 is_readable_console(SOCKET sock)
2964 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
2965 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
2966 ir.Event.KeyEvent.uChar.AsciiChar) {
2970 ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
2980 is_invalid_handle(SOCKET sock)
2982 return (HANDLE)sock == INVALID_HANDLE_VALUE;
2987 do_select(
int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
2999 if (!NtSocketsInitialized)
3003 EnterCriticalSection(&select_mutex);
3004 r =
select(nfds, rd, wr, ex, timeout);
3005 LeaveCriticalSection(&select_mutex);
3006 if (r == SOCKET_ERROR) {
3062 struct timeval *timeout,
void *th)
3071 struct timeval limit = {0, 0};
3073 if (nfds < 0 || (timeout && (timeout->
tv_sec < 0 || timeout->
tv_usec < 0))) {
3079 if (timeout->
tv_sec < 0 ||
3081 timeout->
tv_usec >= 1000000) {
3088 if (limit.
tv_usec >= 1000000) {
3101 nonsock += extract_fd(&else_rd, rd, is_not_socket);
3104 nonsock += extract_fd(&else_wr, wr, is_not_socket);
3107 if (extract_fd(
NULL, else_rd.fdset, is_invalid_handle) > 0 ||
3108 extract_fd(
NULL, else_wr.fdset, is_invalid_handle) > 0) {
3116 extract_fd(&pipe_rd, else_rd.fdset, is_pipe);
3119 extract_fd(&cons_rd, else_rd.fdset, is_console);
3122 extract_fd(&except, ex, is_not_socket);
3125 if (rd && (
int)rd->fd_count > r) r = (int)rd->fd_count;
3126 if (wr && (
int)wr->fd_count > r) r = (
int)wr->fd_count;
3127 if (ex && (
int)ex->fd_count > r) r = (
int)ex->fd_count;
3128 if (nfds > r) nfds = r;
3132 const struct timeval wait = {0, 10 * 1000};
3142 extract_fd(&else_rd, pipe_rd.fdset, is_readable_pipe);
3143 extract_fd(&else_rd, cons_rd.fdset, is_readable_console);
3146 if (else_rd.fdset->fd_count || else_wr.fdset->fd_count) {
3147 r = do_select(nfds, rd, wr, ex, &zero);
3149 r += copy_fd(rd, else_rd.fdset);
3150 r += copy_fd(wr, else_wr.fdset);
3166 if (rd) copy_fd(&orig_rd, rd);
3167 if (wr) copy_fd(&orig_wr, wr);
3168 if (ex) copy_fd(&orig_ex, ex);
3169 r = do_select(nfds, rd, wr, ex, &zero);
3171 if (rd) copy_fd(rd, &orig_rd);
3172 if (wr) copy_fd(wr, &orig_wr);
3173 if (ex) copy_fd(ex, &orig_ex);
3180 if (compare(&rest, &wait) < 0) dowait = &rest;
3182 Sleep(dowait->
tv_sec * 1000 + (dowait->
tv_usec + 999) / 1000);
3206 get_wsa_extension_function(SOCKET s, GUID *guid)
3211 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, guid,
sizeof(*guid),
3212 &ptr,
sizeof(ptr), &dmy,
NULL,
NULL);
3227 if (!NtSocketsInitialized) {
3231 r = accept(
TO_SOCKET(s), addr, addrlen);
3232 if (r != INVALID_SOCKET) {
3233 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
3236 socklist_insert(r, 0);
3256 if (!NtSocketsInitialized) {
3261 if (r == SOCKET_ERROR)
3274 if (!NtSocketsInitialized) {
3278 r = connect(
TO_SOCKET(s), addr, addrlen);
3279 if (r == SOCKET_ERROR) {
3280 int err = WSAGetLastError();
3281 if (err != WSAEWOULDBLOCK)
3298 if (!NtSocketsInitialized) {
3302 r = getpeername(
TO_SOCKET(s), addr, addrlen);
3303 if (r == SOCKET_ERROR)
3317 if (!NtSocketsInitialized) {
3322 r = getsockname(sock, addr, addrlen);
3323 if (r == SOCKET_ERROR) {
3324 DWORD wsaerror = WSAGetLastError();
3325 if (wsaerror == WSAEINVAL) {
3327 if (socklist_lookup(sock, &flags)) {
3330 memset(addr, 0, *addrlen);
3331 addr->sa_family = af;
3349 if (!NtSocketsInitialized) {
3353 r = getsockopt(
TO_SOCKET(s), level, optname, optval, optlen);
3354 if (r == SOCKET_ERROR)
3367 if (!NtSocketsInitialized) {
3371 r = ioctlsocket(
TO_SOCKET(s), cmd, argp);
3372 if (r == SOCKET_ERROR)
3385 if (!NtSocketsInitialized) {
3390 if (r == SOCKET_ERROR)
3408 if (result != SOCKET_ERROR)
3410 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
3414 result = WSAGetOverlappedResult(s, wol, &size,
TRUE, &flg);
3421 result = SOCKET_ERROR;
3424 if ((err = WSAGetLastError()) == WSAECONNABORTED && !
input)
3426 else if (err == WSAEMSGSIZE &&
input) {
3434 case WAIT_OBJECT_0 + 1:
3437 CancelIo((HANDLE)s);
3442 if (err == WSAECONNABORTED && !
input)
3448 CloseHandle(wol->hEvent);
3455 overlapped_socket_io(BOOL
input,
int fd,
char *
buf,
int len,
int flags,
3456 struct sockaddr *addr,
int *addrlen)
3466 if (!NtSocketsInitialized)
3470 socklist_lookup(s, &mode);
3474 if (addr && addrlen)
3475 r = recvfrom(s,
buf,
len, flags, addr, addrlen);
3477 r = recv(s,
buf,
len, flags);
3478 if (r == SOCKET_ERROR)
3482 if (addr && addrlen)
3483 r = sendto(s,
buf,
len, flags, addr, *addrlen);
3485 r = send(s,
buf,
len, flags);
3486 if (r == SOCKET_ERROR) {
3488 if (err == WSAECONNABORTED)
3501 memset(&wol, 0,
sizeof(wol));
3506 if (addr && addrlen)
3507 ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
3510 ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol,
NULL);
3513 if (addr && addrlen)
3514 ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
3517 ret = WSASend(s, &wbuf, 1, &size, flags, &wol,
NULL);
3521 finish_overlapped_socket(
input, s, &wol, ret, &rlen, size);
3532 return overlapped_socket_io(
TRUE, fd, buf, len, flags,
NULL,
NULL);
3538 struct sockaddr *from,
int *fromlen)
3540 return overlapped_socket_io(
TRUE, fd, buf, len, flags, from, fromlen);
3547 return overlapped_socket_io(
FALSE, fd, (
char *)buf, len, flags,
NULL,
NULL);
3553 const struct sockaddr *to,
int tolen)
3555 return overlapped_socket_io(
FALSE, fd, (
char *)buf, len, flags,
3556 (
struct sockaddr *)to, &tolen);
3559 #if !defined(MSG_TRUNC) && !defined(__MINGW32__) 3570 #ifndef WSAID_WSARECVMSG 3571 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} 3573 #ifndef WSAID_WSASENDMSG 3574 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} 3578 #define msghdr_to_wsamsg(msg, wsamsg) \ 3581 (wsamsg)->name = (msg)->msg_name; \ 3582 (wsamsg)->namelen = (msg)->msg_namelen; \ 3583 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \ 3584 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \ 3585 for (i = 0; i < (msg)->msg_iovlen; ++i) { \ 3586 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \ 3587 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \ 3589 (wsamsg)->Control.buf = (msg)->msg_control; \ 3590 (wsamsg)->Control.len = (msg)->msg_controllen; \ 3591 (wsamsg)->dwFlags = (msg)->msg_flags; \ 3598 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET,
WSAMSG *,
DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3599 static WSARecvMsg_t pWSARecvMsg =
NULL;
3606 if (!NtSocketsInitialized)
3613 pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid);
3621 socklist_lookup(s, &mode);
3624 if ((ret = pWSARecvMsg(s, &wsamsg, &len,
NULL,
NULL)) == SOCKET_ERROR) {
3633 memset(&wol, 0,
sizeof(wol));
3636 ret = pWSARecvMsg(s, &wsamsg, &size, &wol,
NULL);
3639 ret = finish_overlapped_socket(
TRUE, s, &wol, ret, &len, size);
3641 if (ret == SOCKET_ERROR)
3656 typedef int (WSAAPI *WSASendMsg_t)(SOCKET,
const WSAMSG *,
DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3657 static WSASendMsg_t pWSASendMsg =
NULL;
3664 if (!NtSocketsInitialized)
3671 pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid);
3678 socklist_lookup(s, &mode);
3681 if ((ret = pWSASendMsg(s, &wsamsg, flags, &len,
NULL,
NULL)) == SOCKET_ERROR) {
3690 memset(&wol, 0,
sizeof(wol));
3693 ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol,
NULL);
3696 finish_overlapped_socket(
FALSE, s, &wol, ret, &len, size);
3709 if (!NtSocketsInitialized) {
3713 r = setsockopt(
TO_SOCKET(s), level, optname, optval, optlen);
3714 if (r == SOCKET_ERROR)
3727 if (!NtSocketsInitialized) {
3732 if (r == SOCKET_ERROR)
3740 open_ifs_socket(
int af,
int type,
int protocol)
3742 unsigned long proto_buffers_len = 0;
3744 SOCKET out = INVALID_SOCKET;
3746 if (WSAEnumProtocols(
NULL,
NULL, &proto_buffers_len) == SOCKET_ERROR) {
3747 error_code = WSAGetLastError();
3748 if (error_code == WSAENOBUFS) {
3749 WSAPROTOCOL_INFO *proto_buffers;
3750 int protocols_available = 0;
3752 proto_buffers = (WSAPROTOCOL_INFO *)
malloc(proto_buffers_len);
3753 if (!proto_buffers) {
3754 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
3755 return INVALID_SOCKET;
3758 protocols_available =
3759 WSAEnumProtocols(
NULL, proto_buffers, &proto_buffers_len);
3760 if (protocols_available != SOCKET_ERROR) {
3762 for (i = 0; i < protocols_available; i++) {
3763 if ((af !=
AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
3764 (type != proto_buffers[i].iSocketType) ||
3765 (protocol != 0 && protocol != proto_buffers[i].iProtocol))
3768 if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
3771 out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
3772 WSA_FLAG_OVERLAPPED);
3775 if (out == INVALID_SOCKET)
3776 out = WSASocket(af, type, protocol,
NULL, 0, 0);
3777 if (out != INVALID_SOCKET)
3778 SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0);
3781 free(proto_buffers);
3797 if (!NtSocketsInitialized) {
3801 s = open_ifs_socket(af, type, protocol);
3802 if (s == INVALID_SOCKET) {
3807 fd = rb_w32_open_osfhandle(s, O_RDWR|
O_BINARY|O_NOINHERIT);
3817 #undef gethostbyaddr 3820 struct hostent * WSAAPI
3824 if (!NtSocketsInitialized) {
3828 r = gethostbyaddr(addr, len, type);
3835 #undef gethostbyname 3838 struct hostent * WSAAPI
3842 if (!NtSocketsInitialized) {
3846 r = gethostbyname(name);
3860 if (!NtSocketsInitialized) {
3864 r = gethostname(name, len);
3865 if (r == SOCKET_ERROR)
3871 #undef getprotobyname 3874 struct protoent * WSAAPI
3878 if (!NtSocketsInitialized) {
3882 r = getprotobyname(name);
3889 #undef getprotobynumber 3892 struct protoent * WSAAPI
3896 if (!NtSocketsInitialized) {
3900 r = getprotobynumber(num);
3907 #undef getservbyname 3910 struct servent * WSAAPI
3914 if (!NtSocketsInitialized) {
3918 r = getservbyname(name, proto);
3925 #undef getservbyport 3928 struct servent * WSAAPI
3932 if (!NtSocketsInitialized) {
3936 r = getservbyport(port, proto);
3945 socketpair_internal(
int af,
int type,
int protocol, SOCKET *sv)
3947 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
3948 struct sockaddr_in sock_in4;
3950 struct sockaddr_in6 sock_in6;
3952 struct sockaddr *addr;
3956 if (!NtSocketsInitialized) {
3962 #if defined PF_INET && PF_INET != AF_INET 3965 sock_in4.sin_family = AF_INET;
3966 sock_in4.sin_port = 0;
3968 addr = (
struct sockaddr *)&sock_in4;
3969 len =
sizeof(sock_in4);
3973 memset(&sock_in6, 0,
sizeof(sock_in6));
3974 sock_in6.sin6_family = AF_INET6;
3975 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
3976 addr = (
struct sockaddr *)&sock_in6;
3977 len =
sizeof(sock_in6);
3984 if (type != SOCK_STREAM) {
3989 sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
3990 sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
3993 svr = open_ifs_socket(af, type, protocol);
3994 if (svr == INVALID_SOCKET)
3996 if (bind(svr, addr, len) < 0)
3998 if (getsockname(svr, addr, &len) < 0)
4000 if (type == SOCK_STREAM)
4003 w = open_ifs_socket(af, type, protocol);
4004 if (w == INVALID_SOCKET)
4006 if (connect(w, addr, len) < 0)
4009 r = accept(svr, addr, &len);
4010 if (r == INVALID_SOCKET)
4012 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
4019 if (r != INVALID_SOCKET)
4021 if (w != INVALID_SOCKET)
4028 if (svr != INVALID_SOCKET)
4041 if (socketpair_internal(af, type, protocol, pair) < 0)
4043 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|
O_BINARY|O_NOINHERIT);
4045 closesocket(pair[0]);
4046 closesocket(pair[1]);
4049 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|
O_BINARY|O_NOINHERIT);
4052 closesocket(pair[1]);
4061 #if !defined(_MSC_VER) || _MSC_VER >= 1400 4064 str2guid(
const char *str, GUID *guid)
4066 #define hex2byte(str) \ 4067 ((isdigit(*(str)) ? *(str) - '0' : toupper(*(str)) - 'A' + 10) << 4 | (isdigit(*((str) + 1)) ? *((str) + 1) - '0' : toupper(*((str) + 1)) - 'A' + 10)) 4070 if (*str ==
'{') str++;
4071 guid->Data1 = (long)strtoul(str, &end, 16);
4073 guid->Data2 = (
unsigned short)strtoul(str, &end, 16);
4075 guid->Data3 = (
unsigned short)strtoul(str, &end, 16);
4081 for (i = 0; i < 6; i++) {
4082 guid->Data4[i + 2] =
hex2byte(str);
4088 #ifndef HAVE_TYPE_NET_LUID 4100 static cigl_t pConvertInterfaceGuidToLuid = (
cigl_t)-1;
4108 IP_ADAPTER_ADDRESSES *root, *addr;
4112 if (ret != ERROR_BUFFER_OVERFLOW) {
4117 ret = GetAdaptersAddresses(
AF_UNSPEC, 0,
NULL, root, &size);
4118 if (ret != ERROR_SUCCESS) {
4124 if (pConvertInterfaceGuidToLuid == (
cigl_t)-1)
4125 pConvertInterfaceGuidToLuid =
4126 (
cigl_t)get_proc_address(
"iphlpapi.dll",
4127 "ConvertInterfaceGuidToLuid",
NULL);
4128 if (pConvertInterfaceLuidToNameA == (
cilnA_t)-1)
4129 pConvertInterfaceLuidToNameA =
4130 (
cilnA_t)get_proc_address(
"iphlpapi.dll",
4131 "ConvertInterfaceLuidToNameA",
NULL);
4133 for (prev =
NULL, addr = root; addr; addr = addr->Next) {
4144 str2guid(addr->AdapterName, &guid);
4145 if (pConvertInterfaceGuidToLuid && pConvertInterfaceLuidToNameA &&
4146 pConvertInterfaceGuidToLuid(&guid, &luid) == NO_ERROR &&
4147 pConvertInterfaceLuidToNameA(&luid, name,
sizeof(name)) == NO_ERROR) {
4154 if (addr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
4156 if (addr->OperStatus == IfOperStatusUp) {
4159 if (addr->FirstUnicastAddress) {
4160 IP_ADAPTER_UNICAST_ADDRESS *cur;
4162 for (cur = addr->FirstUnicastAddress; cur; cur = cur->Next) {
4163 if (cur->Flags & IP_ADAPTER_ADDRESS_TRANSIENT ||
4164 cur->DadState == IpDadStateDeprecated) {
4175 memcpy(ifa->
ifa_addr, cur->Address.lpSockaddr,
4176 cur->Address.iSockaddrLength);
4232 setfl(SOCKET sock,
int arg)
4239 socklist_lookup(sock, &flag);
4247 flag &= ~O_NONBLOCK;
4251 ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
4263 dupfd(HANDLE hDup,
int flags,
int minfd)
4273 goto close_fds_and_return;
4276 goto close_fds_and_return;
4278 fds[filled++] = ret;
4279 }
while (filled < (
int)
numberof(fds));
4281 ret = dupfd(hDup, flags, minfd);
4283 close_fds_and_return:
4285 while (filled > 0) {
4286 int fd = fds[--filled];
4312 arg = va_arg(va,
int);
4314 return setfl(sock, arg);
4320 if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
4321 GetCurrentProcess(), &hDup, 0L,
4323 DUPLICATE_SAME_ACCESS))) {
4329 arg = va_arg(va,
int);
4335 flag &= ~FNOINHERIT;
4336 if ((ret = dupfd(hDup, flag, arg)) == -1)
4342 if (h == -1)
return -1;
4343 if (!GetHandleInformation((HANDLE)h, &flag)) {
4347 return (flag & HANDLE_FLAG_INHERIT) ? 0 :
FD_CLOEXEC;
4351 if (h == -1)
return -1;
4353 arg = va_arg(va,
int);
4355 if (!SetHandleInformation((HANDLE)h, HANDLE_FLAG_INHERIT,
4356 (arg &
FD_CLOEXEC) ? 0 : HANDLE_FLAG_INHERIT)) {
4360 if (arg & FD_CLOEXEC)
4380 else if (is_pipe(sock)) {
4382 if (!GetNamedPipeHandleState((HANDLE)sock, &state,
NULL,
NULL,
NULL,
NULL, 0)) {
4386 state |= PIPE_NOWAIT;
4387 if (!SetNamedPipeHandleState((HANDLE)sock, &state,
NULL,
NULL)) {
4405 poll_child_status(
struct ChildRecord *child,
int *stat_loc)
4410 if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
4412 err = GetLastError();
4414 case ERROR_INVALID_PARAMETER:
4417 case ERROR_INVALID_HANDLE:
4425 CloseChildHandle(child);
4428 if (exitcode != STILL_ACTIVE) {
4435 CloseChildHandle(child);
4437 *stat_loc = exitcode << 8;
4438 if (exitcode & 0xC0000000) {
4439 static const struct {
4443 {STATUS_ACCESS_VIOLATION, SIGSEGV},
4444 {STATUS_ILLEGAL_INSTRUCTION, SIGILL},
4445 {STATUS_PRIVILEGED_INSTRUCTION, SIGILL},
4446 {STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE},
4447 {STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE},
4448 {STATUS_FLOAT_INEXACT_RESULT, SIGFPE},
4449 {STATUS_FLOAT_INVALID_OPERATION, SIGFPE},
4450 {STATUS_FLOAT_OVERFLOW, SIGFPE},
4451 {STATUS_FLOAT_STACK_CHECK, SIGFPE},
4452 {STATUS_FLOAT_UNDERFLOW, SIGFPE},
4453 #ifdef STATUS_FLOAT_MULTIPLE_FAULTS 4454 {STATUS_FLOAT_MULTIPLE_FAULTS, SIGFPE},
4456 #ifdef STATUS_FLOAT_MULTIPLE_TRAPS 4457 {STATUS_FLOAT_MULTIPLE_TRAPS, SIGFPE},
4459 {STATUS_CONTROL_C_EXIT,
SIGINT},
4462 for (i = 0; i < (int)
numberof(table); i++) {
4463 if (table[i].status == exitcode) {
4464 *stat_loc |= table[i].sig;
4470 *stat_loc |= SIGSEGV;
4497 struct ChildRecord* cause;
4500 if (!child->pid || child->pid < 0)
continue;
4501 if ((pid = poll_child_status(child, stat_loc)))
return pid;
4502 events[count++] = child->hProcess;
4510 if (ret == WAIT_TIMEOUT)
return 0;
4511 if ((ret -= WAIT_OBJECT_0) == count) {
4519 cause = FindChildSlotByHandle(events[ret]);
4524 return poll_child_status(cause, stat_loc);
4527 struct ChildRecord* child = FindChildSlot(pid);
4534 while (!(pid = poll_child_status(child, stat_loc))) {
4537 if (ret == WAIT_OBJECT_0 + 1)
return -1;
4538 if (ret != WAIT_OBJECT_0) {
4547 if (pid == -1 && retried) pid = 0;
4553 #include <sys/timeb.h> 4557 filetime_to_timeval(
const FILETIME* ft,
struct timeval *tv)
4560 unsigned LONG_LONG
lt;
4562 tmp.LowPart = ft->dwLowDateTime;
4563 tmp.HighPart = ft->dwHighDateTime;
4571 lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000;
4573 tv->
tv_sec = (long)(lt / (1000 * 1000));
4574 tv->
tv_usec = (long)(lt % (1000 * 1000));
4576 return tv->
tv_sec > 0 ? 0 : -1;
4579 static void get_systemtime(FILETIME *ft)
4581 typedef void (WINAPI *get_time_func)(FILETIME *ft);
4582 static get_time_func func = (get_time_func)-1;
4584 if (func == (get_time_func)-1) {
4586 func = (get_time_func)get_proc_address(
"kernel32",
"GetSystemTimePreciseAsFileTime",
NULL);
4588 func = GetSystemTimeAsFileTime;
4600 get_systemtime(&ft);
4601 filetime_to_timeval(&ft, tv);
4622 LARGE_INTEGER
count;
4623 if (!QueryPerformanceFrequency(&freq)) {
4627 if (!QueryPerformanceCounter(&count)) {
4631 sp->
tv_sec = count.QuadPart / freq.QuadPart;
4632 if (freq.QuadPart < 1000000000)
4633 sp->
tv_nsec = (count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
4635 sp->
tv_nsec = (
long)((count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
4658 if (!QueryPerformanceFrequency(&freq)) {
4663 sp->
tv_nsec = (long)(1000000000.0 / freq.QuadPart);
4674 w32_getcwd(
char *buffer,
int size, UINT cp,
void *alloc(
int,
void *),
void *arg)
4679 len = GetCurrentDirectoryW(0,
NULL);
4685 if (buffer &&
size < len) {
4691 if (!GetCurrentDirectoryW(len, p)) {
4696 wlen = translate_wchar(p, L
'\\', L
'/') - p + 1;
4697 len = WideCharToMultiByte(cp, 0, p, wlen,
NULL, 0,
NULL,
NULL);
4705 buffer = (*alloc)(
len, arg);
4711 WideCharToMultiByte(cp, 0, p, wlen, buffer, len,
NULL,
NULL);
4718 getcwd_alloc(
int size,
void *dummy)
4727 return w32_getcwd(buffer, size,
filecp(), getcwd_alloc,
NULL);
4734 return w32_getcwd(buffer, size, CP_UTF8, getcwd_alloc,
NULL);
4739 getcwd_value(
int size,
void *arg)
4751 w32_getcwd(
NULL, 0, CP_UTF8, getcwd_value, &cwd);
4757 chown(
const char *path,
int owner,
int group)
4770 lchown(
const char *path,
int owner,
int group)
4788 if (pid < 0 || (pid == 0 && sig !=
SIGINT)) {
4793 if ((
unsigned int)pid == GetCurrentProcessId() &&
4794 (sig != 0 && sig !=
SIGKILL)) {
4795 if ((ret =
raise(sig)) != 0) {
4806 OpenProcess(PROCESS_QUERY_INFORMATION,
FALSE, (
DWORD)pid);
4807 if (hProc ==
NULL || hProc == INVALID_HANDLE_VALUE) {
4808 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4824 DWORD ctrlEvent = CTRL_C_EVENT;
4828 ctrlEvent = CTRL_BREAK_EVENT;
4830 if (!GenerateConsoleCtrlEvent(ctrlEvent, (
DWORD)pid)) {
4831 if ((err = GetLastError()) == 0)
4843 struct ChildRecord* child = FindChildSlot(pid);
4845 hProc = child->hProcess;
4848 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
FALSE, (
DWORD)pid);
4850 if (hProc ==
NULL || hProc == INVALID_HANDLE_VALUE) {
4851 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4861 if (!GetExitCodeProcess(hProc, &status)) {
4865 else if (status == STILL_ACTIVE) {
4866 if (!TerminateProcess(hProc, 0)) {
4893 wlink(
const WCHAR *from,
const WCHAR *to)
4895 if (!CreateHardLinkW(to, from,
NULL)) {
4917 ret = wlink(wfrom, wto);
4925 link(
const char *from,
const char *to)
4937 ret = wlink(wfrom, wto);
4944 #ifndef FILE_DEVICE_FILE_SYSTEM 4945 # define FILE_DEVICE_FILE_SYSTEM 0x00000009 4947 #ifndef FSCTL_GET_REPARSE_POINT 4948 # define FSCTL_GET_REPARSE_POINT ((0x9<<16)|(42<<2)) 4950 #ifndef IO_REPARSE_TAG_SYMLINK 4951 # define IO_REPARSE_TAG_SYMLINK 0xA000000CL 4962 f = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
4963 if (f == INVALID_HANDLE_VALUE) {
4964 return GetLastError();
4968 rp, size, &ret,
NULL)) {
4972 rp->
ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
4973 e = ERROR_INVALID_PARAMETER;
4990 if (e == ERROR_MORE_DATA) {
4998 case ERROR_MORE_DATA:
5007 size_t bufsize, WCHAR **result,
DWORD *
len)
5009 int e = reparse_symlink(path, rp, bufsize);
5012 if (!e || e == ERROR_MORE_DATA) {
5018 *len = ret /
sizeof(WCHAR);
5021 static const WCHAR *volume = L
"Volume{";
5025 volume_prefix_len *
sizeof(WCHAR));
5027 *len = ret /
sizeof(WCHAR);
5028 ret -= volume_prefix_len *
sizeof(WCHAR);
5029 if (ret >
sizeof(volume) - 1 *
sizeof(WCHAR) &&
5030 memcmp(name, volume,
sizeof(volume) - 1 *
sizeof(WCHAR)) == 0)
5035 if ((
char *)name + ret +
sizeof(WCHAR) > (
char *)rp + bufsize)
5039 ((WCHAR *)name)[ret/
sizeof(WCHAR)] = L
'\0';
5040 translate_wchar(name, L
'\\', L
'/');
5050 w32_readlink(UINT cp,
const char *path,
char *
buf,
size_t bufsize)
5053 DWORD len = MultiByteToWideChar(cp, 0, path, -1,
NULL, 0);
5055 WCHAR *wname, *wpath =
ALLOCV(wtmp, size +
sizeof(WCHAR) * len);
5060 MultiByteToWideChar(cp, 0, path, -1, wpath, len);
5062 if (e && e != ERROR_MORE_DATA) {
5067 len = lstrlenW(wname) + 1;
5068 ret = WideCharToMultiByte(cp, 0, wname, len,
buf, bufsize,
NULL,
NULL);
5085 return w32_readlink(CP_UTF8, path, buf, bufsize);
5092 return w32_readlink(
filecp(), path, buf, bufsize);
5095 #ifndef SYMBOLIC_LINK_FLAG_DIRECTORY 5096 #define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1) 5101 w32_symlink(UINT cp,
const char *src,
const char *
link)
5103 int atts, len1, len2;
5105 WCHAR *wsrc, *wlink;
5109 typedef BOOLEAN (WINAPI *create_symbolic_link_func)(WCHAR*, WCHAR*,
DWORD);
5110 static create_symbolic_link_func create_symbolic_link =
5111 (create_symbolic_link_func)-1;
5113 if (create_symbolic_link == (create_symbolic_link_func)-1) {
5114 create_symbolic_link = (create_symbolic_link_func)
5115 get_proc_address(
"kernel32",
"CreateSymbolicLinkW",
NULL);
5117 if (!create_symbolic_link) {
5122 len1 = MultiByteToWideChar(cp, 0, src, -1,
NULL, 0);
5123 len2 = MultiByteToWideChar(cp, 0, link, -1,
NULL, 0);
5124 wsrc =
ALLOCV_N(WCHAR, buf, len1+len2);
5125 wlink = wsrc + len1;
5126 MultiByteToWideChar(cp, 0, src, -1, wsrc, len1);
5127 MultiByteToWideChar(cp, 0, link, -1, wlink, len2);
5128 translate_wchar(wsrc, L
'/', L
'\\');
5130 atts = GetFileAttributesW(wsrc);
5131 if (atts != -1 && atts & FILE_ATTRIBUTE_DIRECTORY)
5133 ret = create_symbolic_link(wlink, wsrc, flag);
5137 int e = GetLastError();
5148 return w32_symlink(CP_UTF8, src, link);
5155 return w32_symlink(
filecp(), src, link);
5162 return waitpid(-1, status, 0);
5167 w32_getenv(
const char *
name, UINT cp)
5169 WCHAR *wenvarea, *wenv;
5174 if (len == 0)
return NULL;
5180 wenvarea = GetEnvironmentStringsW();
5185 for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
5186 wlen += lstrlenW(wenv) + 1;
5188 FreeEnvironmentStringsW(wenvarea);
5192 for (env = uenvarea; *
env; env +=
strlen(env) + 1)
5194 return env + len + 1;
5203 return w32_getenv(name, CP_UTF8);
5210 return w32_getenv(name, CP_ACP);
5215 get_attr_vsn(
const WCHAR *path,
DWORD *atts,
DWORD *vsn)
5217 BY_HANDLE_FILE_INFORMATION st = {0};
5219 HANDLE h = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5221 if (h == INVALID_HANDLE_VALUE) {
5222 ASSUME(e = GetLastError());
5225 if (!GetFileInformationByHandle(h, &st)) {
5226 ASSUME(e = GetLastError());
5229 *atts = st.dwFileAttributes;
5230 *vsn = st.dwVolumeSerialNumber;
5238 wrename(
const WCHAR *oldpath,
const WCHAR *newpath)
5242 DWORD oldvsn = 0, newvsn = 0, e;
5244 e = get_attr_vsn(oldpath, &oldatts, &oldvsn);
5249 if (oldatts & FILE_ATTRIBUTE_REPARSE_POINT) {
5250 HANDLE fh = open_special(oldpath, 0, 0);
5251 if (fh == INVALID_HANDLE_VALUE) {
5253 if (e == ERROR_CANT_RESOLVE_FILENAME) {
5260 get_attr_vsn(newpath, &newatts, &newvsn);
5263 if (newatts != (
DWORD)-1 && newatts & FILE_ATTRIBUTE_READONLY)
5264 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
5266 if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
5270 DWORD e = GetLastError();
5271 if ((e == ERROR_ACCESS_DENIED) && (oldatts & FILE_ATTRIBUTE_DIRECTORY) &&
5278 SetFileAttributesW(newpath, oldatts);
5297 ret = wrename(wfrom, wto);
5316 ret = wrename(wfrom, wto);
5324 isUNCRoot(
const WCHAR *path)
5326 if (path[0] == L
'\\' && path[1] == L
'\\') {
5327 const WCHAR *p = path + 2;
5328 if (p[0] == L
'?' && p[1] == L
'\\') {
5336 for (p++; *p; p++) {
5340 if (!p[0] || !p[1] || (p[1] == L
'.' && !p[2]))
5347 #define COPY_STAT(src, dest, size_cast) do { \ 5348 (dest).st_dev = (src).st_dev; \ 5349 (dest).st_ino = (src).st_ino; \ 5350 (dest).st_mode = (src).st_mode; \ 5351 (dest).st_nlink = (src).st_nlink; \ 5352 (dest).st_uid = (src).st_uid; \ 5353 (dest).st_gid = (src).st_gid; \ 5354 (dest).st_rdev = (src).st_rdev; \ 5355 (dest).st_size = size_cast(src).st_size; \ 5356 (dest).st_atime = (src).st_atime; \ 5357 (dest).st_mtime = (src).st_mtime; \ 5358 (dest).st_ctime = (src).st_ctime; \ 5361 static time_t filetime_to_unixtime(
const FILETIME *ft);
5362 static WCHAR *name_for_stat(WCHAR *
buf,
const WCHAR *path);
5363 static DWORD stati64_handle(HANDLE h,
struct stati64 *st);
5367 stati64_set_inode(BY_HANDLE_FILE_INFORMATION *pinfo,
struct stati64 *st)
5386 unsigned short *p2 = (
unsigned short *)st;
5387 unsigned int *p4 = (
unsigned int *)st;
5388 DWORD high = pinfo->nFileIndexHigh;
5390 p2[7] = high & 0xFFFF;
5391 p4[5] = pinfo->nFileIndexLow;
5396 stati64_set_inode_handle(HANDLE h,
struct stati64 *st)
5398 BY_HANDLE_FILE_INFORMATION info;
5401 if (GetFileInformationByHandle(h, &info)) {
5402 stati64_set_inode(&info, st);
5412 BY_HANDLE_FILE_INFORMATION info;
5413 int ret =
fstat(fd, st);
5415 if (ret)
return ret;
5416 if (GetEnvironmentVariableW(L
"TZ",
NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return ret;
5417 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
5418 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5419 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5420 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5432 if (GetEnvironmentVariableW(L
"TZ",
NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
5433 ret = _fstati64(fd, st);
5434 stati64_set_inode_handle((HANDLE)_get_osfhandle(fd), st);
5437 ret =
fstat(fd, &tmp);
5439 if (ret)
return ret;
5441 stati64_handle((HANDLE)_get_osfhandle(fd), st);
5447 stati64_handle(HANDLE h,
struct stati64 *st)
5449 BY_HANDLE_FILE_INFORMATION info;
5452 if (GetFileInformationByHandle(h, &info)) {
5453 st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
5454 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5455 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5456 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5457 st->st_nlink = info.nNumberOfLinks;
5458 attr = info.dwFileAttributes;
5459 stati64_set_inode(&info, st);
5466 filetime_to_unixtime(
const FILETIME *ft)
5470 if (filetime_to_timeval(ft, &tv) == (time_t)-1)
5478 fileattr_to_unixmode(
DWORD attr,
const WCHAR *path)
5482 if (attr & FILE_ATTRIBUTE_READONLY) {
5486 mode |= S_IREAD | S_IWRITE |
S_IWUSR;
5489 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5493 mode |= S_IFDIR | S_IEXEC;
5495 else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5496 mode |= S_IFDIR | S_IEXEC;
5502 if (path && (mode & S_IFREG)) {
5503 const WCHAR *end = path + lstrlenW(path);
5504 while (path < end) {
5505 end = CharPrevW(path, end);
5507 if ((_wcsicmp(end, L
".bat") == 0) ||
5508 (_wcsicmp(end, L
".cmd") == 0) ||
5509 (_wcsicmp(end, L
".com") == 0) ||
5510 (_wcsicmp(end, L
".exe") == 0)) {
5515 if (!iswalnum(*end))
break;
5519 mode |= (mode & 0500) >> 3;
5520 mode |= (mode & 0500) >> 6;
5527 check_valid_dir(
const WCHAR *path)
5529 WIN32_FIND_DATAW fd;
5537 if (!(p = wcsstr(path, L
"...")))
5539 q = p + wcsspn(p, L
".");
5540 if ((p == path || wcschr(L
":/\\", *(p - 1))) &&
5541 (!*q || wcschr(L
":/\\", *q))) {
5548 if (!GetFullPathNameW(path,
sizeof(full) /
sizeof(WCHAR), full, &dmy)) {
5552 if (full[1] == L
':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
5555 fh = open_dir_handle(path, &fd);
5556 if (fh == INVALID_HANDLE_VALUE)
5564 stat_by_find(
const WCHAR *path,
struct stati64 *st)
5567 WIN32_FIND_DATAW wfd;
5569 int e = GetLastError();
5571 if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
5572 || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
5578 h = FindFirstFileW(path, &wfd);
5579 if (h == INVALID_HANDLE_VALUE) {
5584 st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
5585 st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
5586 st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
5587 st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
5588 st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
5595 path_drive(
const WCHAR *path)
5597 return (iswalpha(path[0]) && path[1] == L
':') ?
5598 towupper(path[0]) - L
'A' : _getdrive() - 1;
5601 static const WCHAR namespace_prefix[] = {L
'\\', L
'\\', L
'?', L
'\\'};
5605 winnt_stat(
const WCHAR *path,
struct stati64 *st)
5610 memset(st, 0,
sizeof(*st));
5611 f = open_special(path, 0, 0);
5612 if (f != INVALID_HANDLE_VALUE) {
5613 const DWORD attr = stati64_handle(f, st);
5616 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5617 if (check_valid_dir(path))
return -1;
5619 st->st_mode = fileattr_to_unixmode(attr, path);
5621 finalname[min(len,
numberof(finalname)-1)] = L
'\0';
5623 if (wcsncmp(path, namespace_prefix,
numberof(namespace_prefix)) == 0)
5624 path +=
numberof(namespace_prefix);
5628 if (stat_by_find(path, st))
return -1;
5631 st->st_dev = st->st_rdev = path_drive(path);
5638 winnt_lstat(
const WCHAR *path,
struct stati64 *st)
5640 WIN32_FILE_ATTRIBUTE_DATA wfa;
5641 const WCHAR *p = path;
5643 memset(st, 0,
sizeof(*st));
5646 if (wcsncmp(p, namespace_prefix,
numberof(namespace_prefix)) == 0)
5648 if (wcspbrk(p, L
"?*")) {
5652 if (GetFileAttributesExW(path, GetFileExInfoStandard, (
void*)&wfa)) {
5653 if (wfa.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
5658 wfa.dwFileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
5660 if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
5661 if (check_valid_dir(path))
return -1;
5665 st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow;
5667 st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path);
5668 st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
5669 st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
5670 st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
5673 if (stat_by_find(path, st))
return -1;
5676 st->st_dev = st->st_rdev = path_drive(path);
5694 wstati64(
const WCHAR *path,
struct stati64 *st)
5704 size = lstrlenW(path) + 2;
5706 if (!(path = name_for_stat(buf1, path)))
5708 ret = winnt_stat(path, st);
5717 wlstati64(
const WCHAR *path,
struct stati64 *st)
5727 size = lstrlenW(path) + 2;
5729 if (!(path = name_for_stat(buf1, path)))
5731 ret = winnt_lstat(path, st);
5740 name_for_stat(WCHAR *buf1,
const WCHAR *path)
5746 for (p = path, s = buf1; *p; p++, s++) {
5754 if (!len || L
'\"' == *(--s)) {
5758 end = buf1 + len - 1;
5760 if (isUNCRoot(buf1)) {
5763 else if (*end != L
'\\')
5764 lstrcatW(buf1, L
"\\");
5766 else if (*end == L
'\\' || (buf1 + 1 == end && *end == L
':'))
5767 lstrcatW(buf1, L
".");
5776 return w32_stati64(path, st, CP_UTF8);
5783 return w32_stati64(path, st,
filecp());
5788 w32_stati64(
const char *path,
struct stati64 *st, UINT cp)
5795 ret = wstati64(wpath, st);
5804 return w32_lstati64(path, st, CP_UTF8);
5811 return w32_lstati64(path, st,
filecp());
5816 w32_lstati64(
const char *path,
struct stati64 *st, UINT cp)
5823 ret = wlstati64(wpath, st);
5832 struct stati64 stat;
5836 if ((stat.st_mode & mode) != mode) {
5847 struct stati64 stat;
5851 if ((stat.st_mode & mode) != mode) {
5862 long upos, lpos, usize, lsize;
5866 if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos),
SEEK_CUR)) == -1L &&
5867 (e = GetLastError())) {
5871 usize = (long)(size >> 32);
5873 if (SetFilePointer(h, lsize, &usize,
SEEK_SET) == (
DWORD)-1L &&
5874 (e = GetLastError())) {
5877 else if (!SetEndOfFile(h)) {
5883 SetFilePointer(h, lpos, &upos,
SEEK_SET);
5889 w32_truncate(
const char *path,
off_t length, UINT cp)
5897 h = CreateFileW(wpath, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
5898 if (h == INVALID_HANDLE_VALUE) {
5904 ret = rb_chsize(h, length);
5913 return w32_truncate(path, length, CP_UTF8);
5920 return w32_truncate(path, length,
filecp());
5929 h = (HANDLE)_get_osfhandle(fd);
5930 if (h == (HANDLE)-1)
return -1;
5931 return rb_chsize(h, length);
5936 filetime_to_clock(FILETIME *ft)
5938 __int64 qw = ft->dwHighDateTime;
5940 qw |= ft->dwLowDateTime;
5949 FILETIME create, exit, kernel, user;
5951 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
5952 tmbuf->
tms_utime = filetime_to_clock(&user);
5953 tmbuf->
tms_stime = filetime_to_clock(&kernel);
5968 #define yield_once() Sleep(0) 5969 #define yield_until(condition) do yield_once(); while (!(condition)) 5986 call_asynchronous(PVOID argp)
6002 BOOL interrupted =
FALSE;
6015 thr = CreateThread(
NULL, 0, call_asynchronous, &arg, 0, &val);
6023 if (TerminateThread(thr, intrval)) {
6028 GetExitCodeThread(thr, &val);
6033 MEMORY_BASIC_INFORMATION m;
6035 memset(&m, 0,
sizeof(m));
6036 if (!VirtualQuery(arg.
stackaddr, &m,
sizeof(m))) {
6037 Debug(fprintf(stderr,
"couldn't get stack base:%p:%d\n",
6040 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
6041 Debug(fprintf(stderr,
"couldn't release stack:%p:%d\n",
6042 m.AllocationBase, GetLastError()));
6053 rb_fatal(
"failed to launch waiter thread:%ld", GetLastError());
6063 WCHAR *envtop, *
env;
6064 char **myenvtop, **myenv;
6077 envtop = GetEnvironmentStringsW();
6078 for (env = envtop, num = 0; *
env; env += lstrlenW(env) + 1)
6079 if (*env !=
'=') num++;
6081 myenvtop = (
char **)
malloc(
sizeof(
char *) * (num + 1));
6082 for (env = envtop, myenv = myenvtop; *
env; env += lstrlenW(env) + 1) {
6091 FreeEnvironmentStringsW(envtop);
6102 while (*t)
free(*t++);
6110 return GetCurrentProcessId();
6118 typedef long (WINAPI query_func)(HANDLE, int,
void *, ULONG, ULONG *);
6119 static query_func *pNtQueryInformationProcess = (query_func *)-1;
6122 if (pNtQueryInformationProcess == (query_func *)-1)
6123 pNtQueryInformationProcess = (query_func *)get_proc_address(
"ntdll.dll",
"NtQueryInformationProcess",
NULL);
6124 if (pNtQueryInformationProcess) {
6127 void* PebBaseAddress;
6134 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi,
sizeof(pbi), &len);
6136 ppid = pbi.ParentProcessId;
6143 STATIC_ASSERT(std_handle, (STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)==(STD_ERROR_HANDLE-STD_OUTPUT_HANDLE));
6146 #define set_new_std_handle(newfd, handle) do { \ 6147 if ((unsigned)(newfd) > 2) break; \ 6148 SetStdHandle(STD_INPUT_HANDLE+(STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)*(newfd), \ 6151 #define set_new_std_fd(newfd) set_new_std_handle(newfd, (HANDLE)rb_w32_get_osfhandle(newfd)) 6159 if (oldfd == newfd)
return newfd;
6160 ret =
dup2(oldfd, newfd);
6161 if (ret < 0)
return ret;
6175 va_start(arg, oflag);
6176 pmode = va_arg(arg,
int);
6181 ret = w32_wopen(wfile, oflag, pmode);
6188 check_if_wdir(
const WCHAR *wfile)
6190 DWORD attr = GetFileAttributesW(wfile);
6191 if (attr == (
DWORD)-1L ||
6192 !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
6193 check_valid_dir(wfile)) {
6209 va_start(arg, oflag);
6210 pmode = va_arg(arg,
int);
6215 ret = w32_wopen(wfile, oflag, pmode);
6226 if (oflag & O_CREAT) {
6228 va_start(arg, oflag);
6229 pmode = va_arg(arg,
int);
6233 return w32_wopen(file, oflag, pmode);
6237 w32_wopen(
const WCHAR *file,
int oflag,
int pmode)
6243 DWORD attr = FILE_ATTRIBUTE_NORMAL;
6244 SECURITY_ATTRIBUTES sec;
6250 if ((oflag & O_TEXT) || !(oflag &
O_BINARY)) {
6251 fd = _wopen(file, oflag, pmode);
6255 check_if_wdir(file);
6265 sec.nLength =
sizeof(sec);
6266 sec.lpSecurityDescriptor =
NULL;
6267 if (oflag & O_NOINHERIT) {
6268 sec.bInheritHandle =
FALSE;
6272 sec.bInheritHandle =
TRUE;
6274 oflag &= ~O_NOINHERIT;
6277 oflag &= ~(O_BINARY | O_TEXT);
6279 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
6281 access = GENERIC_READ | GENERIC_WRITE;
6284 access = GENERIC_READ;
6287 access = GENERIC_WRITE;
6293 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
6295 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
6297 create = OPEN_ALWAYS;
6301 create = OPEN_EXISTING;
6303 case O_CREAT | O_EXCL:
6304 case O_CREAT | O_EXCL | O_TRUNC:
6305 create = CREATE_NEW;
6308 case O_TRUNC | O_EXCL:
6309 create = TRUNCATE_EXISTING;
6311 case O_CREAT | O_TRUNC:
6312 create = CREATE_ALWAYS;
6318 if (oflag & O_CREAT) {
6320 if (!(pmode & S_IWRITE))
6321 attr = FILE_ATTRIBUTE_READONLY;
6323 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
6325 if (oflag & O_TEMPORARY) {
6326 attr |= FILE_FLAG_DELETE_ON_CLOSE;
6329 oflag &= ~O_TEMPORARY;
6331 if (oflag & _O_SHORT_LIVED)
6332 attr |= FILE_ATTRIBUTE_TEMPORARY;
6333 oflag &= ~_O_SHORT_LIVED;
6335 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
6339 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
6342 attr |= FILE_FLAG_RANDOM_ACCESS;
6348 oflag &= ~(O_SEQUENTIAL | O_RANDOM);
6350 if (oflag & ~O_APPEND) {
6357 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6358 fd = _open_osfhandle((
intptr_t)h, 0);
6370 h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE | share_delete, &sec, create, attr,
NULL);
6371 if (h == INVALID_HANDLE_VALUE) {
6372 DWORD e = GetLastError();
6373 if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
6380 switch (GetFileType(h)) {
6381 case FILE_TYPE_CHAR:
6384 case FILE_TYPE_PIPE:
6387 case FILE_TYPE_UNKNOWN:
6394 if (!(flags & (
FDEV |
FPIPE)) && (oflag & O_APPEND))
6414 int save_errno =
errno;
6416 if (fflush(fp))
return -1;
6424 if (closesocket(sock) == SOCKET_ERROR) {
6435 static DWORD serial = 0;
6436 static const char prefix[] =
"\\\\.\\pipe\\ruby";
6438 width_of_prefix = (int)
sizeof(prefix) - 1,
6439 width_of_pid = (int)
sizeof(rb_pid_t) * 2,
6440 width_of_serial = (int)
sizeof(serial) * 2,
6441 width_of_ids = width_of_pid + 1 + width_of_serial + 1
6443 char name[
sizeof(prefix) + width_of_ids];
6444 SECURITY_ATTRIBUTES sec;
6445 HANDLE hRead, hWrite, h;
6446 int fdRead, fdWrite;
6449 memcpy(
name, prefix, width_of_prefix);
6450 snprintf(
name + width_of_prefix, width_of_ids,
"%.*"PRI_PIDT_PREFIX
"x-%.*lx",
6453 sec.nLength =
sizeof(sec);
6454 sec.lpSecurityDescriptor =
NULL;
6455 sec.bInheritHandle =
FALSE;
6458 hRead = CreateNamedPipe(
name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
6459 0, 2, 65536, 65536, 0, &sec);
6461 if (hRead == INVALID_HANDLE_VALUE) {
6463 if (err == ERROR_PIPE_BUSY)
6471 hWrite = CreateFile(
name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
6472 OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
NULL);
6474 if (hWrite == INVALID_HANDLE_VALUE) {
6482 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6483 fdRead = _open_osfhandle((
intptr_t)h, 0);
6487 CloseHandle(hWrite);
6502 h = CreateFile(
"NUL", 0, 0,
NULL, OPEN_ALWAYS, 0,
NULL);
6503 fdWrite = _open_osfhandle((
intptr_t)h, 0);
6505 if (fdWrite == -1) {
6507 CloseHandle(hWrite);
6529 console_emulator_p(
void)
6534 const void *
const func = WriteConsoleW;
6536 MEMORY_BASIC_INFORMATION m;
6538 memset(&m, 0,
sizeof(m));
6539 if (!VirtualQuery(func, &m,
sizeof(m))) {
6542 k = GetModuleHandle(
"kernel32.dll");
6543 if (!k)
return FALSE;
6544 return (HMODULE)m.AllocationBase != k;
6550 constat_handle(HANDLE h)
6555 if (console_emulator_p()) {
6568 CONSOLE_SCREEN_BUFFER_INFO csbi;
6571 p->
vt100.
attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6574 if (GetConsoleScreenBufferInfo(h, &csbi)) {
6584 constat_reset(HANDLE h)
6594 #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY) 6595 #define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY) 6597 #define constat_attr_color_reverse(attr) \ 6598 ((attr) & ~(FOREGROUND_MASK | BACKGROUND_MASK)) | \ 6599 (((attr) & FOREGROUND_MASK) << 4) | \ 6600 (((attr) & BACKGROUND_MASK) >> 4) 6604 constat_attr(
int count,
const int *
seq, WORD attr, WORD default_attr,
int *
reverse)
6609 if (!count)
return attr;
6611 bold = attr & FOREGROUND_INTENSITY;
6612 attr &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
6614 while (count-- > 0) {
6617 attr = default_attr;
6622 bold = FOREGROUND_INTENSITY;
6625 #ifndef COMMON_LVB_UNDERSCORE 6626 #define COMMON_LVB_UNDERSCORE 0x8000 6635 attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
6639 attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN)) | FOREGROUND_RED;
6643 attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_RED)) | FOREGROUND_GREEN;
6647 attr = (attr & ~FOREGROUND_BLUE) | FOREGROUND_GREEN | FOREGROUND_RED;
6651 attr = (attr & ~(FOREGROUND_GREEN | FOREGROUND_RED)) | FOREGROUND_BLUE;
6655 attr = (attr & ~FOREGROUND_GREEN) | FOREGROUND_BLUE | FOREGROUND_RED;
6659 attr = (attr & ~FOREGROUND_RED) | FOREGROUND_BLUE | FOREGROUND_GREEN;
6663 attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6667 attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
6670 attr = (attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN)) | BACKGROUND_RED;
6673 attr = (attr & ~(BACKGROUND_BLUE | BACKGROUND_RED)) | BACKGROUND_GREEN;
6676 attr = (attr & ~BACKGROUND_BLUE) | BACKGROUND_GREEN | BACKGROUND_RED;
6679 attr = (attr & ~(BACKGROUND_GREEN | BACKGROUND_RED)) | BACKGROUND_BLUE;
6682 attr = (attr & ~BACKGROUND_GREEN) | BACKGROUND_BLUE | BACKGROUND_RED;
6685 attr = (attr & ~BACKGROUND_RED) | BACKGROUND_BLUE | BACKGROUND_GREEN;
6688 attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
6700 constat_clear(HANDLE handle, WORD attr,
DWORD len, COORD pos)
6704 FillConsoleOutputAttribute(handle, attr, len, pos, &written);
6705 FillConsoleOutputCharacterW(handle, L
' ', len, pos, &written);
6710 constat_apply(HANDLE handle,
struct constat *s, WCHAR w)
6712 CONSOLE_SCREEN_BUFFER_INFO csbi;
6718 if (!GetConsoleScreenBufferInfo(handle, &csbi))
return;
6719 if (count > 0 && seq[0] > 0) arg1 = seq[0];
6722 SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->
vt100.
attr, &s->
vt100.
reverse));
6725 csbi.dwCursorPosition.X = 0;
6727 csbi.dwCursorPosition.Y -= arg1;
6728 if (csbi.dwCursorPosition.Y < csbi.srWindow.Top)
6729 csbi.dwCursorPosition.Y = csbi.srWindow.Top;
6730 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6733 csbi.dwCursorPosition.X = 0;
6736 csbi.dwCursorPosition.Y += arg1;
6737 if (csbi.dwCursorPosition.Y > csbi.srWindow.Bottom)
6738 csbi.dwCursorPosition.Y = csbi.srWindow.Bottom;
6739 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6742 csbi.dwCursorPosition.X += arg1;
6743 if (csbi.dwCursorPosition.X >= csbi.srWindow.Right)
6744 csbi.dwCursorPosition.X = csbi.srWindow.Right;
6745 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6748 csbi.dwCursorPosition.X -= arg1;
6749 if (csbi.dwCursorPosition.X < csbi.srWindow.Left)
6750 csbi.dwCursorPosition.X = csbi.srWindow.Left;
6751 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6755 arg1 += csbi.srWindow.Left;
6756 if (arg1 > csbi.srWindow.Right)
6757 arg1 = csbi.srWindow.Right;
6758 csbi.dwCursorPosition.X = arg1;
6759 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6762 arg1 += csbi.srWindow.Top;
6763 if (arg1 > csbi.srWindow.Bottom)
6764 arg1 = csbi.srWindow.Bottom;
6765 csbi.dwCursorPosition.Y = arg1;
6766 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6770 pos.Y = arg1 + csbi.srWindow.Top - 1;
6771 if (pos.Y > csbi.srWindow.Bottom) pos.Y = csbi.srWindow.Bottom;
6772 if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1;
6773 pos.X = arg1 + csbi.srWindow.Left - 1;
6774 if (pos.X > csbi.srWindow.Right) pos.X = csbi.srWindow.Right;
6775 SetConsoleCursorPosition(handle, pos);
6780 constat_clear(handle, csbi.wAttributes,
6781 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.dwCursorPosition.Y + 1)
6782 - csbi.dwCursorPosition.X),
6783 csbi.dwCursorPosition);
6787 pos.Y = csbi.srWindow.Top;
6788 constat_clear(handle, csbi.wAttributes,
6789 (csbi.dwSize.X * (csbi.dwCursorPosition.Y - csbi.srWindow.Top)
6790 + csbi.dwCursorPosition.X),
6795 pos.Y = csbi.srWindow.Top;
6796 constat_clear(handle, csbi.wAttributes,
6797 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1)),
6803 constat_clear(handle, csbi.wAttributes,
6804 (csbi.dwSize.X * csbi.dwSize.Y),
6812 constat_clear(handle, csbi.wAttributes,
6813 (csbi.dwSize.X - csbi.dwCursorPosition.X),
6814 csbi.dwCursorPosition);
6818 pos.Y = csbi.dwCursorPosition.Y;
6819 constat_clear(handle, csbi.wAttributes,
6820 csbi.dwCursorPosition.X, pos);
6824 pos.Y = csbi.dwCursorPosition.Y;
6825 constat_clear(handle, csbi.wAttributes,
6826 csbi.dwSize.X, pos);
6834 SetConsoleCursorPosition(handle, s->
vt100.
saved);
6837 if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
6838 CONSOLE_CURSOR_INFO cci;
6839 GetConsoleCursorInfo(handle, &cci);
6840 cci.bVisible =
TRUE;
6841 SetConsoleCursorInfo(handle, &cci);
6845 if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
6846 CONSOLE_CURSOR_INFO cci;
6847 GetConsoleCursorInfo(handle, &cci);
6848 cci.bVisible =
FALSE;
6849 SetConsoleCursorInfo(handle, &cci);
6857 constat_parse(HANDLE h,
struct constat *s,
const WCHAR **ptrp,
long *lenp)
6859 const WCHAR *ptr = *ptrp;
6860 long rest, len = *lenp;
6864 rest = *lenp - len - 1;
6869 if (len > 0 && *ptr != L
'[')
continue;
6878 rest = *lenp - len - 1;
6879 if (rest > 0) --rest;
6884 if (wc >= L
'0' && wc <= L
'9') {
6887 *seq = (*seq * 10) + (wc - L
'0');
6903 constat_apply(h, s, wc);
6928 int save_errno =
errno;
6932 constat_delete((HANDLE)sock);
6936 socklist_delete(&sock,
NULL);
6939 if (closesocket(sock) == SOCKET_ERROR) {
6947 setup_overlapped(OVERLAPPED *ol,
int fd,
int iswrite)
6949 memset(ol, 0,
sizeof(*ol));
6957 DWORD low = SetFilePointer((HANDLE)
_osfhnd(fd), 0, &high, method);
6958 #ifndef INVALID_SET_FILE_POINTER 6959 #define INVALID_SET_FILE_POINTER ((DWORD)-1) 6963 if (err != NO_ERROR) {
6969 ol->OffsetHigh = high;
6980 finish_overlapped(OVERLAPPED *ol,
int fd,
DWORD size)
6982 CloseHandle(ol->hEvent);
6985 LONG high = ol->OffsetHigh;
6987 if (low < ol->Offset)
6989 SetFilePointer((HANDLE)
_osfhnd(fd), low, &high, FILE_BEGIN);
7006 BOOL islineinput =
FALSE;
7013 if (_get_osfhandle(fd) == -1) {
7018 return _read(fd, buf, size);
7030 isconsole = is_console(
_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
7033 GetConsoleMode((HANDLE)
_osfhnd(fd),&mode);
7034 islineinput = (mode & ENABLE_LINE_INPUT) != 0;
7039 constat_reset((HANDLE)
_osfhnd(fd));
7051 if (setup_overlapped(&ol, fd,
FALSE)) {
7056 if (!ReadFile((HANDLE)
_osfhnd(fd), buf, len, &read, &ol)) {
7057 err = GetLastError();
7060 if (GetNamedPipeHandleState((HANDLE)
_osfhnd(fd), &state,
NULL,
NULL,
NULL,
NULL, 0) && (state & PIPE_NOWAIT)) {
7069 else if (err != ERROR_IO_PENDING) {
7070 CloseHandle(ol.hEvent);
7071 if (err == ERROR_ACCESS_DENIED)
7073 else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
7085 if (wait != WAIT_OBJECT_0) {
7086 if (wait == WAIT_OBJECT_0 + 1)
7090 CloseHandle(ol.hEvent);
7091 CancelIo((HANDLE)
_osfhnd(fd));
7096 if (!GetOverlappedResult((HANDLE)
_osfhnd(fd), &ol, &read,
TRUE) &&
7097 (err = GetLastError()) != ERROR_HANDLE_EOF) {
7099 if (err != ERROR_BROKEN_PIPE) {
7103 CloseHandle(ol.hEvent);
7104 CancelIo((HANDLE)
_osfhnd(fd));
7110 err = GetLastError();
7114 finish_overlapped(&ol, fd, read);
7118 buf = (
char *)buf + read;
7119 if (err != ERROR_OPERATION_ABORTED &&
7120 !(isconsole && len == 1 && (!islineinput || *((
char *)buf - 1) ==
'\n')) && size > 0)
7149 if (_get_osfhandle(fd) == -1) {
7155 return _write(fd, buf, size);
7172 if (setup_overlapped(&ol, fd,
TRUE)) {
7177 if (!WriteFile((HANDLE)
_osfhnd(fd), buf, len, &written, &ol)) {
7178 err = GetLastError();
7179 if (err != ERROR_IO_PENDING) {
7180 CloseHandle(ol.hEvent);
7181 if (err == ERROR_ACCESS_DENIED)
7191 if (wait != WAIT_OBJECT_0) {
7192 if (wait == WAIT_OBJECT_0 + 1)
7196 CloseHandle(ol.hEvent);
7197 CancelIo((HANDLE)
_osfhnd(fd));
7202 if (!GetOverlappedResult((HANDLE)
_osfhnd(fd), &ol, &written,
TRUE)) {
7204 CloseHandle(ol.hEvent);
7205 CancelIo((HANDLE)
_osfhnd(fd));
7211 finish_overlapped(&ol, fd, written);
7214 if (written == len) {
7215 buf = (
const char *)buf + len;
7220 size_t newlen = len / 2;
7222 size += len - newlen;
7240 DWORD dwMode, reslen;
7244 const WCHAR *ptr, *next;
7249 if (!GetConsoleMode(handle, &dwMode))
7252 s = constat_handle(handle);
7267 if (!ptr)
return -1L;
7276 if (!WriteConsoleW(handle, ptr, len, &reslen,
NULL))
7277 reslen = (
DWORD)-1L;
7281 long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
7282 reslen += next - ptr;
7285 if (!WriteConsoleW(handle, ptr, curlen, &written,
NULL)) {
7286 reslen = (
DWORD)-1L;
7294 if (wbuffer)
free(wbuffer);
7295 return (
long)reslen;
7300 unixtime_to_filetime(time_t time, FILETIME *ft)
7304 tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
7305 ft->dwLowDateTime = tmp.LowPart;
7306 ft->dwHighDateTime = tmp.HighPart;
7312 wutime(
const WCHAR *path,
const struct utimbuf *times)
7315 FILETIME atime, mtime;
7316 struct stati64 stat;
7319 if (wstati64(path, &stat)) {
7324 if (unixtime_to_filetime(times->
actime, &atime)) {
7327 if (unixtime_to_filetime(times->
modtime, &mtime)) {
7332 get_systemtime(&atime);
7337 const DWORD attr = GetFileAttributesW(path);
7338 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7339 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7340 hFile = open_special(path, GENERIC_WRITE, 0);
7341 if (hFile == INVALID_HANDLE_VALUE) {
7346 if (!SetFileTime(hFile,
NULL, &atime, &mtime)) {
7352 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7353 SetFileAttributesW(path, attr);
7368 ret = wutime(wpath, times);
7382 ret = wutime(wpath, times);
7396 ret = _wchdir(wpath);
7403 wmkdir(
const WCHAR *wpath,
int mode)
7408 if (CreateDirectoryW(wpath,
NULL) ==
FALSE) {
7412 if (_wchmod(wpath, mode) == -1) {
7413 RemoveDirectoryW(wpath);
7430 ret = wmkdir(wpath, mode);
7444 ret = wmkdir(wpath, mode);
7451 wrmdir(
const WCHAR *wpath)
7455 const DWORD attr = GetFileAttributesW(wpath);
7456 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7457 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
7459 if (RemoveDirectoryW(wpath) ==
FALSE) {
7462 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7463 SetFileAttributesW(wpath, attr);
7479 ret = wrmdir(wpath);
7493 ret = wrmdir(wpath);
7500 wunlink(
const WCHAR *path)
7503 const DWORD SYMLINKD = FILE_ATTRIBUTE_REPARSE_POINT|FILE_ATTRIBUTE_DIRECTORY;
7505 const DWORD attr = GetFileAttributesW(path);
7506 if (attr == (
DWORD)-1) {
7508 else if ((attr & SYMLINKD) == SYMLINKD) {
7509 ret = RemoveDirectoryW(path);
7512 if (attr & FILE_ATTRIBUTE_READONLY) {
7513 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7515 ret = DeleteFileW(path);
7520 if (attr != (
DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7521 SetFileAttributesW(path, attr);
7537 ret = wunlink(wpath);
7551 ret = wunlink(wpath);
7565 ret = _wchmod(wpath, mode);
7574 typedef BOOL (WINAPI *set_file_information_by_handle_func)
7575 (HANDLE, int,
void*,
DWORD);
7576 static set_file_information_by_handle_func set_file_info =
7577 (set_file_information_by_handle_func)-1;
7581 LARGE_INTEGER CreationTime;
7582 LARGE_INTEGER LastAccessTime;
7583 LARGE_INTEGER LastWriteTime;
7584 LARGE_INTEGER ChangeTime;
7585 DWORD FileAttributes;
7586 } info = {{{0}}, {{0}}, {{0}},};
7587 HANDLE h = (HANDLE)_get_osfhandle(fd);
7589 if (h == INVALID_HANDLE_VALUE) {
7593 if (set_file_info == (set_file_information_by_handle_func)-1) {
7594 set_file_info = (set_file_information_by_handle_func)
7595 get_proc_address(
"kernel32",
"SetFileInformationByHandle",
NULL);
7597 if (!set_file_info) {
7602 info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
7603 if (!(mode & 0200)) info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
7604 if (!set_file_info(h, 0, &info,
sizeof(info))) {
7618 if (_get_osfhandle(fd) == -1) {
7621 if (!GetConsoleMode((HANDLE)
_osfhnd(fd), &mode)) {
7628 #if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60 7629 extern long _ftol(
double);
7639 _ftol2_sse(
double d)
7650 int *ip = (
int *)(&x + 1) - 1;
7659 typedef char *(WSAAPI inet_ntop_t)(
int,
void *,
char *,
size_t);
7660 static inet_ntop_t *pInetNtop = (inet_ntop_t *)-1;
7661 if (pInetNtop == (inet_ntop_t *)-1)
7662 pInetNtop = (inet_ntop_t *)get_proc_address(
"ws2_32",
"inet_ntop",
NULL);
7664 return pInetNtop(af, (
void *)addr, numaddr, numaddr_len);
7668 memcpy(&in.s_addr, addr,
sizeof(in.s_addr));
7669 snprintf(numaddr, numaddr_len,
"%s", inet_ntoa(in));
7678 typedef int (WSAAPI inet_pton_t)(int,
const char*,
void *);
7679 static inet_pton_t *pInetPton = (inet_pton_t *)-1;
7680 if (pInetPton == (inet_pton_t *)-1)
7681 pInetPton = (inet_pton_t *)get_proc_address(
"ws2_32",
"inet_pton",
NULL);
7683 return pInetPton(af, src, dst);
7695 #if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S) 7698 unixtime_to_systemtime(
const time_t t, SYSTEMTIME *st)
7701 if (unixtime_to_filetime(t, &ft))
return -1;
7702 if (!FileTimeToSystemTime(&ft, st))
return -1;
7708 systemtime_to_tm(
const SYSTEMTIME *st,
struct tm *t)
7710 int y = st->wYear, m = st->wMonth, d = st->wDay;
7711 t->tm_sec = st->wSecond;
7712 t->tm_min = st->wMinute;
7713 t->tm_hour = st->wHour;
7714 t->tm_mday = st->wDay;
7715 t->tm_mon = st->wMonth - 1;
7716 t->tm_year = y - 1900;
7717 t->tm_wday = st->wDayOfWeek;
7725 d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
7726 d += ((m - 3) * 153 + 2) / 5;
7734 systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
7736 TIME_ZONE_INFORMATION stdtz;
7739 if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst))
return -1;
7741 GetTimeZoneInformation(&stdtz);
7744 if (tz->StandardBias == tz->DaylightBias)
return 0;
7745 if (!tz->StandardDate.wMonth)
return 0;
7746 if (!tz->DaylightDate.wMonth)
return 0;
7747 if (tz != &stdtz) stdtz = *tz;
7749 stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
7750 if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst))
return 0;
7751 if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
7757 #ifdef HAVE__GMTIME64_S 7758 # ifndef HAVE__LOCALTIME64_S 7760 # define HAVE__LOCALTIME64_S 1 7762 # ifndef MINGW_HAS_SECURE_API 7763 _CRTIMP errno_t __cdecl _gmtime64_s(
struct tm* tm,
const __time64_t *time);
7764 _CRTIMP errno_t __cdecl _localtime64_s(
struct tm* tm,
const __time64_t *time);
7766 # define gmtime_s _gmtime64_s 7767 # define localtime_s _localtime64_s 7780 #if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__GMTIME64_S) 7781 e = gmtime_s(rp, tp);
7782 if (e != 0)
goto error;
7786 if (unixtime_to_systemtime(*tp, &st))
goto error;
7788 systemtime_to_tm(&st, rp);
7804 #if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__LOCALTIME64_S) 7805 e = localtime_s(rp, tp);
7809 SYSTEMTIME gst, lst;
7810 if (unixtime_to_systemtime(*tp, &gst))
goto error;
7811 rp->tm_isdst = systemtime_to_localtime(
NULL, &gst, &lst);
7812 systemtime_to_tm(&lst, rp);
7823 int len =
sizeof(tmp);
7824 int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (
char *)&tmp, &len);
7825 if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
7828 flags &= ~O_NONBLOCK;
7831 socklist_insert((SOCKET)h, f);
7837 return rb_w32_open_osfhandle((
intptr_t)h, flags);
7848 constat_delete((HANDLE)sock);
7851 socklist_delete(&sock,
NULL);
7856 #if !defined(__MINGW64__) && defined(__MINGW64_VERSION_MAJOR) 7862 rb_w32_pow(
double x,
double y)
7866 unsigned int default_control = _controlfp(0, 0);
7867 _controlfp(_PC_64, _MCW_PC);
7870 _controlfp(default_control, _MCW_PC);
7879 typedef HRESULT (WINAPI *set_thread_description_func)(HANDLE, PCWSTR);
7880 static set_thread_description_func set_thread_description =
7881 (set_thread_description_func)-1;
7882 if (set_thread_description == (set_thread_description_func)-1) {
7883 set_thread_description = (set_thread_description_func)
7884 get_proc_address(
"kernel32",
"SetThreadDescription",
NULL);
7886 if (set_thread_description) {
7887 result = set_thread_description(th, name);
7895 int idx, result =
FALSE;
7918 #if RUBY_MSVCRT_VERSION < 120 struct tm * localtime_r(const time_t *tp, struct tm *rp)
void setnetent(int stayopen)
rb_pid_t rb_w32_uspawn(int mode, const char *cmd, const char *prog)
void rb_fatal(const char *fmt,...)
#define ENCINDEX_US_ASCII
int rb_enc_get_index(VALUE obj)
int rb_w32_set_nonblock(int fd)
char * rb_w32_ugetenv(const char *name)
rb_pid_t rb_w32_getppid(void)
rb_pid_t rb_w32_getpid(void)
uintptr_t(* func)(uintptr_t self, int argc, uintptr_t *argv)
int rb_w32_wait_events_blocking(HANDLE *events, int num, DWORD timeout)
int rb_w32_map_errno(DWORD winerr)
size_t strlen(const char *)
#define rb_w32_stati64(path, st)
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout)
int rb_w32_access(const char *path, int mode)
#define CSIDL_LOCAL_APPDATA
int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
struct servent *WSAAPI rb_w32_getservbyport(int port, const char *proto)
int rb_w32_umkdir(const char *path, int mode)
EXTERN_C _CRTIMP ioinfo * __pioinfo[]
STATIC_ASSERT(std_handle,(STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)==(STD_ERROR_HANDLE-STD_OUTPUT_HANDLE))
void rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
#define ENCINDEX_UTF_16LE
#define access(path, mode)
int rb_w32_pipe(int fds[2])
int rb_w32_wopen(const WCHAR *file, int oflag,...)
ssize_t rb_w32_read(int fd, void *buf, size_t size)
VALUE rb_str_cat(VALUE, const char *, long)
struct rb_w32_reparse_buffer_t::@145::@148 MountPointReparseBuffer
int WSAAPI rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
char * rb_w32_ugetcwd(char *buffer, int size)
DIR * rb_w32_uopendir(const char *filename)
int clock_getres(clockid_t clock_id, struct timespec *sp)
void rb_write_error2(const char *, long)
int rb_w32_io_cancelable_p(int fd)
void rb_w32_rewinddir(DIR *dirp)
int rb_w32_ulchown(const char *path, int owner, int group)
void rb_w32_fdset(int fd, fd_set *set)
int rb_w32_truncate(const char *path, off_t length)
int rb_w32_unwrap_io_handle(int fd)
int WSAAPI rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
ssize_t rb_w32_ureadlink(const char *path, char *buf, size_t bufsize)
struct servent *WSAAPI rb_w32_getservbyname(const char *name, const char *proto)
DWORD(WINAPI * get_final_path_func)(HANDLE, WCHAR *, DWORD, DWORD)
#define INVALID_SET_FILE_POINTER
uintptr_t(* asynchronous_func_t)(uintptr_t self, int argc, uintptr_t *argv)
if(len<=MAX_WORD_LENGTH &&len >=MIN_WORD_LENGTH)
rb_pid_t rb_w32_aspawn(int mode, const char *prog, char *const *argv)
int WSAAPI rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
void freeifaddrs(struct ifaddrs *ifp)
#define COPY_STAT(src, dest, size_cast)
void rb_w32_seekdir(DIR *dirp, long loc)
int rb_w32_urmdir(const char *path)
int rb_w32_set_thread_description(HANDLE th, const WCHAR *name)
#define STRNDUPV(ptr, v, src, len)
struct _NtCmdLineElement * next
#define IO_REPARSE_TAG_SYMLINK
int rb_w32_fclose(FILE *fp)
int rb_w32_open(const char *file, int oflag,...)
struct sockaddr * ifa_addr
#define msghdr_to_wsamsg(msg, wsamsg)
rb_encoding * rb_utf8_encoding(void)
struct protoent * getprotoent(void)
char * rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc)
VALUE rb_f_notimplement(int argc, const VALUE *argv, VALUE obj)
ssize_t rb_w32_write(int fd, const void *buf, size_t size)
#define filecp_to_wstr(str, plen)
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
int WSAAPI rb_w32_sendto(int fd, const char *buf, int len, int flags, const struct sockaddr *to, int tolen)
const char *WSAAPI rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
RUBY_EXTERN void * memmove(void *, const void *, size_t)
int recvmsg(int fd, struct msghdr *msg, int flags)
struct protoent *WSAAPI rb_w32_getprotobynumber(int num)
int rb_w32_wrap_io_handle(HANDLE h, int flags)
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
int rb_w32_ustati64(const char *path, struct stati64 *st)
VALUE rb_utf8_str_new(const char *, long)
#define FSCTL_GET_REPARSE_POINT
int fcntl(int fd, int cmd,...)
void * ruby_xcalloc(size_t n, size_t size)
int WSAAPI rb_w32_socket(int af, int type, int protocol)
#define wstr_to_utf8(str, plen)
#define MEMZERO(p, type, n)
#define FILE_FILENO(stream)
int rb_enc_to_index(rb_encoding *enc)
int rb_w32_lstati64(const char *path, struct stati64 *st)
unsigned long long uint64_t
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
struct ifaddrs * ifa_next
char * rb_w32_getenv(const char *name)
rb_pid_t waitpid(rb_pid_t pid, int *stat_loc, int options)
#define END_FOREACH_CHILD
#define SYMBOLIC_LINK_FLAG_DIRECTORY
DWORD(WINAPI * cilnA_t)(const NET_LUID *, char *, size_t)
char * ruby_strdup(const char *)
#define wstr_to_filecp(str, plen)
int rb_w32_stat(const char *path, struct stat *st)
int rb_w32_uaccess(const char *path, int mode)
#define ECONV_INVALID_REPLACE
long rb_w32_telldir(DIR *dirp)
int rb_w32_fstat(int fd, struct stat *st)
int rb_econv_has_convpath_p(const char *from_encoding, const char *to_encoding)
int rb_w32_uopen(const char *file, int oflag,...)
#define IOINFO_ARRAY_ELTS
int rb_w32_uchdir(const char *path)
void rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
int link(const char *from, const char *to)
int fchmod(int fd, int mode)
int WSAAPI rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
struct netent * getnetbyname(const char *name)
int rb_w32_isatty(int fd)
int rb_w32_sleep(unsigned long msec)
int rb_w32_rename(const char *from, const char *to)
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
#define ALLOCV_N(type, v, n)
int clock_gettime(clockid_t clock_id, struct timespec *sp)
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len)
#define ALLOCA_N(type, n)
int rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout, void *th)
#define MAKE_SOCKDATA(af, fl)
#define rb_acrt_lowio_lock_fh(i)
int rb_w32_utime(const char *path, const struct utimbuf *times)
#define MEMCPY(p1, p2, type, n)
rb_pid_t rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
void sethostent(int stayopen)
struct servent * getservent(void)
ssize_t readlink(const char *path, char *buf, size_t bufsize)
#define REALLOC_N(var, type, n)
struct rb_w32_reparse_buffer_t::@145::@147 SymbolicLinkReparseBuffer
char * rb_w32_wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen)
int WSAAPI rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
VALUE rb_sprintf(const char *format,...)
void setservent(int stayopen)
rb_pid_t rb_w32_spawn(int mode, const char *cmd, const char *prog)
DIR * rb_w32_opendir(const char *filename)
void rb_w32_sysinit(int *argc, char ***argv)
#define rb_strlen_lit(str)
VALUE(*const rb_f_notimplement_)(int, const VALUE *, VALUE)
int WSAAPI rb_w32_shutdown(int s, int how)
VALUE rb_str_vcatf(VALUE, const char *, va_list)
WCHAR * rb_w32_home_dir(void)
int ruby_glob_func(const char *, VALUE, void *)
struct netent * getnetent(void)
void setprotoent(int stayopen)
int rb_w32_set_thread_description_str(HANDLE th, VALUE name)
int sendmsg(int fd, const struct msghdr *msg, int flags)
int ioctl(int i, int u,...)
ONIG_EXTERN const OnigEncodingType OnigEncodingUTF_8
unsigned char buf[MIME_BUF_SIZE]
struct tm * gmtime_r(const time_t *tp, struct tm *rp)
int flock(int fd, int oper)
int __cdecl gettimeofday(struct timeval *tv, struct timezone *tz)
char * strchr(char *, char)
struct protoent *WSAAPI rb_w32_getprotobyname(const char *name)
#define utf8_to_wstr(str, plen)
int rb_w32_mkdir(const char *path, int mode)
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
int WSAAPI rb_w32_inet_pton(int af, const char *src, void *dst)
int rb_w32_unlink(const char *path)
int memcmp(const void *s1, const void *s2, size_t len)
int WSAAPI rb_w32_gethostname(char *name, int len)
int rb_w32_ulstati64(const char *path, struct stati64 *st)
int chown(const char *path, int owner, int group)
int rb_w32_fstati64(int fd, struct stati64 *st)
#define rb_w32_reparse_buffer_size(n)
int rb_w32_usymlink(const char *src, const char *link)
char * rb_w32_strerror(int e)
int rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait)
int rb_w32_uchown(const char *path, int owner, int group)
register unsigned int len
int rb_w32_rmdir(const char *path)
#define StringValueCStr(v)
int WSAAPI rb_w32_listen(int s, int backlog)
int kill(int pid, int sig)
void * ruby_xmalloc(size_t size)
#define ECONV_UNDEF_REPLACE
#define ENCODING_GET(obj)
uintptr_t rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self, int argc, uintptr_t *argv, uintptr_t intrval)
char ** rb_w32_get_environ(void)
rb_pid_t rb_w32_uaspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
#define set_new_std_fd(newfd)
void rb_w32_closedir(DIR *dirp)
VALUE rb_w32_special_folder(int type)
struct constat::@151 vt100
typedef HRESULT(STDAPICALLTYPE FNCOCREATEINSTANCEEX)(REFCLSID
int rb_w32_uchmod(const char *path, int mode)
int WSAAPI rb_w32_send(int fd, const char *buf, int len, int flags)
VALUE rb_dir_getwd_ospath(void)
int rb_w32_reparse_symlink_p(const WCHAR *path)
#define _set_osfhnd(fh, osfh)
struct hostent *WSAAPI rb_w32_gethostbyname(const char *name)
#define is_socket(fd, path)
int symlink(const char *src, const char *link)
RUBY_EXTERN char * strerror(int)
int socketpair(int af, int type, int protocol, int *sv)
int WSAAPI rb_w32_getsockname(int fd, struct sockaddr *addr, int *addrlen)
rb_encoding * rb_filesystem_encoding(void)
SOCKET rb_w32_get_osfhandle(int fh)
int rb_w32_uutime(const char *path, const struct utimbuf *times)
struct _NtCmdLineElement NtCmdLineElement
#define set_env_val(vname)
int WSAAPI rb_w32_recv(int fd, char *buf, int len, int flags)
rb_pid_t rb_w32_uaspawn(int mode, const char *prog, char *const *argv)
int getifaddrs(struct ifaddrs **ifap)
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
int rb_w32_is_socket(int fd)
long rb_w32_write_console(uintptr_t strarg, int fd)
RUBY_EXTERN size_t strlcat(char *, const char *, size_t)
#define COMMON_LVB_UNDERSCORE
RUBY_EXTERN int dup2(int, int)
#define constat_attr_color_reverse(attr)
#define rb_acrt_lowio_unlock_fh(i)
char * rb_w32_getcwd(char *buffer, int size)
#define yield_until(condition)
struct netent * getnetbyaddr(long net, int type)
int WSAAPI rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout)
int rb_w32_ulink(const char *from, const char *to)
int WSAAPI rb_w32_recvfrom(int fd, char *buf, int len, int flags, struct sockaddr *from, int *fromlen)
int rb_w32_dup2(int oldfd, int newfd)
int WSAAPI rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
int lchown(const char *path, int owner, int group)
int rb_w32_urename(const char *from, const char *to)
struct direct * rb_w32_readdir(DIR *dirp, rb_encoding *enc)
void rb_w32_free_environ(char **env)
int WSAAPI rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
DWORD(WINAPI * cigl_t)(const GUID *, NET_LUID *)
WCHAR * rb_w32_mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen)
int rb_w32_fdisset(int fd, fd_set *set)
int rb_w32_uunlink(const char *path)
int rb_w32_utruncate(const char *path, off_t length)
char rb_w32_fd_is_text(int fd)
int rb_w32_check_interrupt(void *)
int rb_w32_read_reparse_point(const WCHAR *path, rb_w32_reparse_buffer_t *rp, size_t bufsize, WCHAR **result, DWORD *len)
int rb_w32_times(struct tms *tmbuf)
void rb_w32_fdclr(int fd, fd_set *set)
int select(int num_fds, fd_set *in_fds, fd_set *out_fds, fd_set *ex_fds, struct timeval *timeout)
struct hostent *WSAAPI rb_w32_gethostbyaddr(const char *addr, int len, int type)
int rb_w32_ftruncate(int fd, off_t length)
#define _set_osflags(fh, flags)
rb_encoding * rb_enc_from_index(int index)