45#if defined _MSC_VER && _MSC_VER >= 1400
52#include "ruby/win32.h"
55#include "win32/file.h"
58#include "internal/enc.h"
59#include "internal/object.h"
60#include "internal/static_assert.h"
63#define isdirsep(x) ((x) == '/' || (x) == '\\')
65#if defined _MSC_VER && _MSC_VER <= 1200
66# define CharNextExA(cp, p, flags) CharNextExA((WORD)(cp), (p), (flags))
69static int w32_wopen(
const WCHAR *file,
int oflag,
int perm);
70static int w32_stati128(
const char *path,
struct stati128 *st, UINT cp, BOOL lstat);
71static char *w32_getenv(
const char *name, UINT cp);
77#define DLN_FIND_EXTRA_ARG_DECL ,UINT cp
78#define DLN_FIND_EXTRA_ARG ,cp
79#define rb_w32_stati128(path, st) w32_stati128(path, st, cp, FALSE)
80#define getenv(name) w32_getenv(name, cp)
82#define CharNext(p) CharNextExA(cp, (p), 0)
83#define dln_find_exe_r rb_w32_udln_find_exe_r
84#define dln_find_file_r rb_w32_udln_find_file_r
91#define dln_find_exe_r(fname, path, buf, size) rb_w32_udln_find_exe_r(fname, path, buf, size, cp)
92#define dln_find_file_r(fname, path, buf, size) rb_w32_udln_find_file_r(fname, path, buf, size, cp)
98# define PATH_MAX MAX_PATH
99# elif defined HAVE_SYS_PARAM_H
100# include <sys/param.h>
101# define PATH_MAX MAXPATHLEN
113#if RUBY_MSVCRT_VERSION >= 140
114# define _filbuf _fgetc_nolock
115# define _flsbuf _fputc_nolock
117#define enough_to_get(n) (--(n) >= 0)
118#define enough_to_put(n) (--(n) >= 0)
121#define Debug(something) something
123#define Debug(something)
126#define TO_SOCKET(x) _get_osfhandle(x)
128int rb_w32_reparse_symlink_p(
const WCHAR *path);
130static int has_redirection(
const char *, UINT);
131int rb_w32_wait_events(HANDLE *events,
int num, DWORD timeout);
132static int rb_w32_open_osfhandle(intptr_t osfhandle,
int flags);
133static int wstati128(
const WCHAR *path,
struct stati128 *st, BOOL lstat);
134VALUE rb_w32_conv_from_wchar(
const WCHAR *wstr,
rb_encoding *enc);
136static FARPROC get_proc_address(
const char *module,
const char *func, HANDLE *mh);
138#define RUBY_CRITICAL if (0) {} else
145 { ERROR_INVALID_FUNCTION, EINVAL },
146 { ERROR_FILE_NOT_FOUND, ENOENT },
147 { ERROR_PATH_NOT_FOUND, ENOENT },
148 { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
149 { ERROR_ACCESS_DENIED, EACCES },
150 { ERROR_INVALID_HANDLE, EBADF },
151 { ERROR_ARENA_TRASHED, ENOMEM },
152 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
153 { ERROR_INVALID_BLOCK, ENOMEM },
154 { ERROR_BAD_ENVIRONMENT, E2BIG },
155 { ERROR_BAD_FORMAT, ENOEXEC },
156 { ERROR_INVALID_ACCESS, EINVAL },
157 { ERROR_INVALID_DATA, EINVAL },
158 { ERROR_INVALID_DRIVE, ENOENT },
159 { ERROR_CURRENT_DIRECTORY, EACCES },
160 { ERROR_NOT_SAME_DEVICE, EXDEV },
161 { ERROR_NO_MORE_FILES, ENOENT },
162 { ERROR_WRITE_PROTECT, EROFS },
163 { ERROR_BAD_UNIT, ENODEV },
164 { ERROR_NOT_READY, ENXIO },
165 { ERROR_BAD_COMMAND, EACCES },
166 { ERROR_CRC, EACCES },
167 { ERROR_BAD_LENGTH, EACCES },
169 { ERROR_NOT_DOS_DISK, EACCES },
170 { ERROR_SECTOR_NOT_FOUND, EACCES },
171 { ERROR_OUT_OF_PAPER, EACCES },
172 { ERROR_WRITE_FAULT, EIO },
173 { ERROR_READ_FAULT, EIO },
174 { ERROR_GEN_FAILURE, EACCES },
175 { ERROR_LOCK_VIOLATION, EACCES },
176 { ERROR_SHARING_VIOLATION, EACCES },
177 { ERROR_WRONG_DISK, EACCES },
178 { ERROR_SHARING_BUFFER_EXCEEDED, EACCES },
179 { ERROR_BAD_NETPATH, ENOENT },
180 { ERROR_NETWORK_ACCESS_DENIED, EACCES },
181 { ERROR_BAD_NET_NAME, ENOENT },
182 { ERROR_FILE_EXISTS, EEXIST },
183 { ERROR_CANNOT_MAKE, EACCES },
184 { ERROR_FAIL_I24, EACCES },
185 { ERROR_INVALID_PARAMETER, EINVAL },
186 { ERROR_NO_PROC_SLOTS, EAGAIN },
187 { ERROR_DRIVE_LOCKED, EACCES },
188 { ERROR_BROKEN_PIPE, EPIPE },
189 { ERROR_DISK_FULL, ENOSPC },
190 { ERROR_INVALID_TARGET_HANDLE, EBADF },
191 { ERROR_INVALID_HANDLE, EINVAL },
192 { ERROR_WAIT_NO_CHILDREN, ECHILD },
193 { ERROR_CHILD_NOT_COMPLETE, ECHILD },
194 { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
195 { ERROR_NEGATIVE_SEEK, EINVAL },
196 { ERROR_SEEK_ON_DEVICE, EACCES },
197 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
198 { ERROR_DIRECTORY, ENOTDIR },
199 { ERROR_NOT_LOCKED, EACCES },
200 { ERROR_BAD_PATHNAME, ENOENT },
201 { ERROR_MAX_THRDS_REACHED, EAGAIN },
202 { ERROR_LOCK_FAILED, EACCES },
203 { ERROR_ALREADY_EXISTS, EEXIST },
204 { ERROR_INVALID_STARTING_CODESEG, ENOEXEC },
205 { ERROR_INVALID_STACKSEG, ENOEXEC },
206 { ERROR_INVALID_MODULETYPE, ENOEXEC },
207 { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC },
208 { ERROR_EXE_MARKED_INVALID, ENOEXEC },
209 { ERROR_BAD_EXE_FORMAT, ENOEXEC },
210 { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC },
211 { ERROR_INVALID_MINALLOCSIZE, ENOEXEC },
212 { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC },
213 { ERROR_IOPL_NOT_ENABLED, ENOEXEC },
214 { ERROR_INVALID_SEGDPL, ENOEXEC },
215 { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC },
216 { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC },
217 { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC },
218 { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC },
219 { ERROR_FILENAME_EXCED_RANGE, ENOENT },
220 { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
221#ifndef ERROR_PIPE_LOCAL
222#define ERROR_PIPE_LOCAL 229L
224 { ERROR_PIPE_LOCAL, EPIPE },
225 { ERROR_BAD_PIPE, EPIPE },
226 { ERROR_PIPE_BUSY, EAGAIN },
227 { ERROR_NO_DATA, EPIPE },
228 { ERROR_PIPE_NOT_CONNECTED, EPIPE },
229 { ERROR_OPERATION_ABORTED, EINTR },
230 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM },
231 { ERROR_MOD_NOT_FOUND, ENOENT },
232 { ERROR_PRIVILEGE_NOT_HELD, EACCES, },
233 { ERROR_CANT_RESOLVE_FILENAME, ELOOP, },
236 { WSAEACCES, EACCES },
237 { WSAEFAULT, EFAULT },
238 { WSAEINVAL, EINVAL },
239 { WSAEMFILE, EMFILE },
240 { WSAEWOULDBLOCK, EWOULDBLOCK },
241 { WSAEINPROGRESS, EINPROGRESS },
242 { WSAEALREADY, EALREADY },
243 { WSAENOTSOCK, ENOTSOCK },
244 { WSAEDESTADDRREQ, EDESTADDRREQ },
245 { WSAEMSGSIZE, EMSGSIZE },
246 { WSAEPROTOTYPE, EPROTOTYPE },
247 { WSAENOPROTOOPT, ENOPROTOOPT },
248 { WSAEPROTONOSUPPORT, EPROTONOSUPPORT },
249 { WSAESOCKTNOSUPPORT, ESOCKTNOSUPPORT },
250 { WSAEOPNOTSUPP, EOPNOTSUPP },
251 { WSAEPFNOSUPPORT, EPFNOSUPPORT },
252 { WSAEAFNOSUPPORT, EAFNOSUPPORT },
253 { WSAEADDRINUSE, EADDRINUSE },
254 { WSAEADDRNOTAVAIL, EADDRNOTAVAIL },
255 { WSAENETDOWN, ENETDOWN },
256 { WSAENETUNREACH, ENETUNREACH },
257 { WSAENETRESET, ENETRESET },
258 { WSAECONNABORTED, ECONNABORTED },
259 { WSAECONNRESET, ECONNRESET },
260 { WSAENOBUFS, ENOBUFS },
261 { WSAEISCONN, EISCONN },
262 { WSAENOTCONN, ENOTCONN },
263 { WSAESHUTDOWN, ESHUTDOWN },
264 { WSAETOOMANYREFS, ETOOMANYREFS },
265 { WSAETIMEDOUT, ETIMEDOUT },
266 { WSAECONNREFUSED, ECONNREFUSED },
268 { WSAENAMETOOLONG, ENAMETOOLONG },
269 { WSAEHOSTDOWN, EHOSTDOWN },
270 { WSAEHOSTUNREACH, EHOSTUNREACH },
271 { WSAEPROCLIM, EPROCLIM },
272 { WSAENOTEMPTY, ENOTEMPTY },
273 { WSAEUSERS, EUSERS },
274 { WSAEDQUOT, EDQUOT },
275 { WSAESTALE, ESTALE },
276 { WSAEREMOTE, EREMOTE },
281rb_w32_map_errno(DWORD winerr)
289 for (i = 0; i < (int)(
sizeof(errmap) /
sizeof(*errmap)); i++) {
290 if (errmap[i].winerr == winerr) {
291 return errmap[i].err;
295 if (winerr >= WSABASEERR) {
301#define map_errno rb_w32_map_errno
303static const char *NTLoginName;
305static OSVERSIONINFO osver;
311 memset(&osver, 0,
sizeof(OSVERSIONINFO));
312 osver.dwOSVersionInfoSize =
sizeof(OSVERSIONINFO);
313 GetVersionEx(&osver);
321 return osver.dwPlatformId;
329 return osver.dwMajorVersion;
340 DWORD err = GetLastError(); \
341 if (err == ERROR_LOCK_VIOLATION || err == ERROR_IO_PENDING) \
342 errno = EWOULDBLOCK; \
343 else if (err == ERROR_NOT_LOCKED) \
346 errno = map_errno(err); \
349#define LK_LEN ULONG_MAX
353flock_winnt(uintptr_t
self,
int argc, uintptr_t* argv)
357 const HANDLE fh = (HANDLE)
self;
358 const int oper = argc;
360 memset(&o, 0,
sizeof(o));
364 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, LK_LEN, &o), i);
367 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, LK_LEN, &o), i);
369 case LOCK_SH|LOCK_NB:
370 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i);
372 case LOCK_EX|LOCK_NB:
373 LK_ERR(LockFileEx(fh,
374 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
375 0, LK_LEN, LK_LEN, &o), i);
378 case LOCK_UN|LOCK_NB:
379 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, LK_LEN, &o), i);
392flock(
int fd,
int oper)
394 const asynchronous_func_t locker = flock_winnt;
396 return rb_w32_asynchronize(locker,
397 (VALUE)_get_osfhandle(fd), oper, NULL,
403translate_wchar(WCHAR *p,
int from,
int to)
414translate_char(
char *p,
int from,
int to, UINT cp)
417 if ((
unsigned char)*p == from)
419 p = CharNextExA(cp, p, 0);
424#ifndef CSIDL_LOCAL_APPDATA
425#define CSIDL_LOCAL_APPDATA 28
427#ifndef CSIDL_COMMON_APPDATA
428#define CSIDL_COMMON_APPDATA 35
431#define CSIDL_WINDOWS 36
434#define CSIDL_SYSTEM 37
437#define CSIDL_PROFILE 40
442get_special_folder(
int n, WCHAR *buf,
size_t len)
447 typedef BOOL (WINAPI *get_path_func)(LPITEMIDLIST, WCHAR*, DWORD, int);
448 static get_path_func func = (get_path_func)-1;
450 if (func == (get_path_func)-1) {
451 func = (get_path_func)
452 get_proc_address(
"shell32",
"SHGetPathFromIDListEx", NULL);
454 if (!func && len < MAX_PATH)
return FALSE;
456 if (SHGetSpecialFolderLocation(NULL, n, &pidl) == 0) {
458 f = func(pidl, buf, len, 0);
461 f = SHGetPathFromIDListW(pidl, buf);
464 alloc->lpVtbl->Free(alloc, pidl);
465 alloc->lpVtbl->Release(alloc);
472regulate_path(WCHAR *path)
474 WCHAR *p = translate_wchar(path, L
'\\', L
'/');
475 if (p - path == 2 && path[1] == L
':') {
483get_proc_address(
const char *module,
const char *func, HANDLE *mh)
489 h = LoadLibrary(module);
491 h = GetModuleHandle(module);
495 ptr = GetProcAddress(h, func);
507rb_w32_special_folder(
int type)
509 WCHAR path[PATH_MAX];
511 if (!get_special_folder(
type, path, numberof(path)))
return Qnil;
516#if defined _MSC_VER && _MSC_VER <= 1200
518#define GetSystemWindowsDirectoryW GetWindowsDirectoryW
523rb_w32_system_tmpdir(WCHAR *path, UINT len)
525 static const WCHAR temp[] = L
"temp";
528 if (!get_special_folder(CSIDL_LOCAL_APPDATA, path, len)) {
529 if (GetSystemWindowsDirectoryW(path, len))
return 0;
531 p = translate_wchar(path, L
'\\', L
'/');
532 if (*(p - 1) != L
'/') *p++ = L
'/';
533 if ((UINT)(p - path + numberof(temp)) >= len)
return 0;
534 memcpy(p, temp,
sizeof(temp));
535 return (UINT)(p - path + numberof(temp) - 1);
550 WCHAR *buffer = NULL;
551 size_t buffer_len = MAX_PATH, len = 0;
553 HOME_NONE, ENV_HOME, ENV_DRIVEPATH, ENV_USERPROFILE
554 } home_type = HOME_NONE;
556 if ((len = GetEnvironmentVariableW(L
"HOME", NULL, 0)) != 0) {
558 home_type = ENV_HOME;
560 else if ((len = GetEnvironmentVariableW(L
"HOMEDRIVE", NULL, 0)) != 0) {
562 if ((len = GetEnvironmentVariableW(L
"HOMEPATH", NULL, 0)) != 0) {
564 home_type = ENV_DRIVEPATH;
567 else if ((len = GetEnvironmentVariableW(L
"USERPROFILE", NULL, 0)) != 0) {
569 home_type = ENV_USERPROFILE;
573 buffer =
ALLOC_N(WCHAR, buffer_len);
577 GetEnvironmentVariableW(L
"HOME", buffer, buffer_len);
580 len = GetEnvironmentVariableW(L
"HOMEDRIVE", buffer, buffer_len);
581 GetEnvironmentVariableW(L
"HOMEPATH", buffer + len, buffer_len - len);
583 case ENV_USERPROFILE:
584 GetEnvironmentVariableW(L
"USERPROFILE", buffer, buffer_len);
587 if (!get_special_folder(CSIDL_PROFILE, buffer, buffer_len) &&
588 !get_special_folder(CSIDL_PERSONAL, buffer, buffer_len)) {
592 REALLOC_N(buffer, WCHAR, lstrlenW(buffer) + 1);
597 regulate_path(buffer);
606 static const WCHAR TMPDIR[] = L
"TMPDIR";
607 struct {WCHAR name[6], eq, val[ENV_MAX];} wk;
611#define set_env_val(vname) do { \
612 typedef char wk_name_offset[(numberof(wk.name) - (numberof(vname) - 1)) * 2 + 1]; \
613 WCHAR *const buf = wk.name + sizeof(wk_name_offset) / 2; \
614 MEMCPY(buf, vname, WCHAR, numberof(vname) - 1); \
620 if (!GetEnvironmentVariableW(L
"HOME", env, numberof(env))) {
622 if (GetEnvironmentVariableW(L
"HOMEDRIVE", env, numberof(env)))
626 if (GetEnvironmentVariableW(L
"HOMEPATH", env + len, numberof(env) - len) || len) {
629 else if (GetEnvironmentVariableW(L
"USERPROFILE", env, numberof(env))) {
632 else if (get_special_folder(CSIDL_PROFILE, env, numberof(env))) {
635 else if (get_special_folder(CSIDL_PERSONAL, env, numberof(env))) {
640 set_env_val(L
"HOME");
644 if (!GetEnvironmentVariableW(L
"USER", env, numberof(env))) {
645 if (!GetEnvironmentVariableW(L
"USERNAME", env, numberof(env)) &&
646 !GetUserNameW(env, (len = numberof(env), &len))) {
647 NTLoginName =
"<Unknown>";
650 set_env_val(L
"USER");
651 NTLoginName = rb_w32_wstr_to_mbstr(CP_UTF8, env, -1, NULL);
655 NTLoginName = rb_w32_wstr_to_mbstr(CP_UTF8, env, -1, NULL);
658 if (!GetEnvironmentVariableW(TMPDIR, env, numberof(env)) &&
659 !GetEnvironmentVariableW(L
"TMP", env, numberof(env)) &&
660 !GetEnvironmentVariableW(L
"TEMP", env, numberof(env)) &&
661 rb_w32_system_tmpdir(env, numberof(env))) {
669static void init_stdhandle(
void);
671#if RUBY_MSVCRT_VERSION >= 80
674invalid_parameter(
const wchar_t *expr,
const wchar_t *func,
const wchar_t *file,
unsigned int line, uintptr_t dummy)
679int ruby_w32_rtc_error;
683rtc_error_handler(
int e,
const char *src,
int line,
const char *exe,
const char *fmt, ...)
688 if (!ruby_w32_rtc_error)
return 0;
699static CRITICAL_SECTION select_mutex;
701static CRITICAL_SECTION socklist_mutex;
704static CRITICAL_SECTION conlist_mutex;
706#define conlist_disabled ((st_table *)-1)
708#define thread_exclusive(obj) \
709 for (bool exclusive_for_##obj = (EnterCriticalSection(&obj##_mutex), true); \
710 exclusive_for_##obj; \
711 exclusive_for_##obj = (LeaveCriticalSection(&obj##_mutex), false))
713static CRITICAL_SECTION uenvarea_mutex;
714static char *uenvarea;
719 int state, seq[16], reverse;
724enum {constat_init = -2, constat_esc = -1, constat_seq = 0};
728free_conlist(st_data_t key, st_data_t val, st_data_t arg)
736constat_delete(HANDLE h)
738 thread_exclusive(conlist) {
739 if (conlist && conlist != conlist_disabled) {
740 st_data_t key = (st_data_t)h, val;
741 st_delete(conlist, &key, &val);
752 DeleteCriticalSection(&select_mutex);
753 DeleteCriticalSection(&socklist_mutex);
754 DeleteCriticalSection(&conlist_mutex);
755 thread_exclusive(uenvarea) {
761 DeleteCriticalSection(&uenvarea_mutex);
768 EnterCriticalSection(&socklist_mutex);
770 st_free_table(socklist);
773 LeaveCriticalSection(&socklist_mutex);
775 EnterCriticalSection(&conlist_mutex);
776 if (conlist && conlist != conlist_disabled) {
778 st_free_table(conlist);
781 LeaveCriticalSection(&conlist_mutex);
784#define ATOMIC_LONG_CAS(var, oldval, newval) InterlockedCompareExchange(&(var), (newval), (oldval))
788install_vm_exit_handler(
void)
790 static LONG installed = 0;
793 while ((i = ATOMIC_LONG_CAS(installed, 0, -1)) != 1) {
799 ATOMIC_LONG_CAS(installed, -1, 1);
815 version = MAKEWORD(2, 0);
816 if (WSAStartup(version, &retdata))
817 rb_fatal(
"Unable to locate winsock library!");
818 if (LOBYTE(retdata.wVersion) != 2)
819 rb_fatal(
"could not find version 2 of winsock dll");
821 InitializeCriticalSection(&select_mutex);
822 InitializeCriticalSection(&socklist_mutex);
823 InitializeCriticalSection(&conlist_mutex);
825 atexit(exit_handler);
828#define MAKE_SOCKDATA(af, fl) ((int)((((int)af)<<4)|((fl)&0xFFFF)))
829#define GET_FAMILY(v) ((int)(((v)>>4)&0xFFFF))
830#define GET_FLAGS(v) ((int)((v)&0xFFFF))
834socklist_insert(SOCKET sock,
int flag)
838 thread_exclusive(socklist) {
840 socklist = st_init_numtable();
841 install_vm_exit_handler();
843 ret = st_insert(socklist, (st_data_t)sock, (st_data_t)flag);
851socklist_lookup(SOCKET sock,
int *flagp)
856 thread_exclusive(socklist) {
857 if (!socklist)
continue;
858 ret = st_lookup(socklist, (st_data_t)sock, (st_data_t *)&data);
868socklist_delete(SOCKET *sockp,
int *flagp)
874 thread_exclusive(socklist) {
875 if (!socklist)
continue;
876 key = (st_data_t)*sockp;
878 data = (st_data_t)*flagp;
879 ret = st_delete(socklist, &key, &data);
881 *sockp = (SOCKET)key;
890#if RUBY_MSVCRT_VERSION >= 80
892# define _CrtSetReportMode(type,mode) ((void)0)
893# define _RTC_SetErrorFunc(func) ((void)0)
895static void set_pioinfo_extra(
void);
897static int w32_cmdvector(
const WCHAR *,
char ***, UINT,
rb_encoding *);
903rb_w32_sysinit(
int *argc,
char ***argv)
905#if RUBY_MSVCRT_VERSION >= 80
907 _CrtSetReportMode(_CRT_ASSERT, 0);
908 _set_invalid_parameter_handler(invalid_parameter);
909 _RTC_SetErrorFunc(rtc_error_handler);
912 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
919 *argc = w32_cmdvector(GetCommandLineW(), argv, CP_UTF8, &OnigEncodingUTF_8);
927 InitializeCriticalSection(&uenvarea_mutex);
939 return (
char *)NTLoginName;
942#define MAXCHILDNUM 256
951#define FOREACH_CHILD(v) do { \
952 struct ChildRecord* v; \
953 for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
954#define END_FOREACH_CHILD } while (0)
958FindChildSlot(rb_pid_t pid)
961 FOREACH_CHILD(child) {
962 if (child->pid == pid) {
971FindChildSlotByHandle(HANDLE h)
974 FOREACH_CHILD(child) {
975 if (child->hProcess == h) {
986 HANDLE h = child->hProcess;
987 child->hProcess = NULL;
994FindFreeChildSlot(
void)
996 FOREACH_CHILD(child) {
999 child->hProcess = NULL;
1002 } END_FOREACH_CHILD;
1013#define InternalCmdsMax 8
1014static const char szInternalCmds[][InternalCmdsMax+2] = {
1068internal_match(
const void *key,
const void *elem)
1070 return strncmp(key, ((
const char *)elem) + 1, InternalCmdsMax);
1075is_command_com(
const char *interp)
1077 int i = strlen(interp) - 11;
1079 if ((i == 0 || (i > 0 && isdirsep(interp[i-1]))) &&
1080 strcasecmp(interp+i,
"command.com") == 0) {
1086static int internal_cmd_match(
const char *cmdname,
int nt);
1090is_internal_cmd(
const char *cmd,
int nt)
1092 char cmdname[9], *b = cmdname, c;
1095 if (!(c = *cmd++))
return 0;
1096 }
while (isspace(c));
1099 while (isalpha(c)) {
1101 if (b == cmdname +
sizeof(cmdname))
return 0;
1104 if (c ==
'.') c = *cmd;
1106 case '<':
case '>':
case '|':
1108 case '\0':
case ' ':
case '\t':
case '\n':
1114 return internal_cmd_match(cmdname, nt);
1119internal_cmd_match(
const char *cmdname,
int nt)
1123 nm = bsearch(cmdname, szInternalCmds,
1124 sizeof(szInternalCmds) /
sizeof(*szInternalCmds),
1125 sizeof(*szInternalCmds),
1127 if (!nm || !(nm[0] & (nt ? 2 : 1)))
1134rb_w32_get_osfhandle(
int fh)
1136 return _get_osfhandle(fh);
1141join_argv(
char *cmd,
char *
const *argv, BOOL escape, UINT cp,
int backslash)
1145 int len, n, bs, quote;
1147 for (t = argv, q = cmd, len = 0; (p = *t) != 0; t++) {
1150 if (!*p || strpbrk(p,
" \t\"'")) {
1155 for (bs = 0; *p; ++p) {
1169 memset(q,
'\\', bs);
1174 case '<':
case '>':
case '|':
case '^':
1175 if (escape && !quote) {
1176 len += (n = p - s) + 1;
1187 p = CharNextExA(cp, p, 0) - 1;
1191 len += (n = p - s) + 1;
1195 if (backslash > 0) {
1198 translate_char(q,
'/',
'\\', cp);
1201 if (quote) *q++ =
'"';
1214#define STRNDUPV(ptr, v, src, len) \
1215 (((char *)memcpy(((ptr) = ALLOCV((v), (len) + 1)), (src), (len)))[len] = 0)
1219check_spawn_mode(
int mode)
1241 if (mode == P_OVERLAY) {
1242 WaitForSingleObject(child->hProcess, INFINITE);
1243 GetExitCodeProcess(child->hProcess, &exitcode);
1244 CloseChildHandle(child);
1252CreateChild(
struct ChildRecord *child,
const WCHAR *cmd,
const WCHAR *prog, HANDLE hInput, HANDLE hOutput, HANDLE hError, DWORD dwCreationFlags)
1255 STARTUPINFOW aStartupInfo;
1256 PROCESS_INFORMATION aProcessInformation;
1257 SECURITY_ATTRIBUTES sa;
1259 if (!cmd && !prog) {
1269 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
1270 sa.lpSecurityDescriptor = NULL;
1271 sa.bInheritHandle = TRUE;
1273 memset(&aStartupInfo, 0,
sizeof(aStartupInfo));
1274 memset(&aProcessInformation, 0,
sizeof(aProcessInformation));
1275 aStartupInfo.cb =
sizeof(aStartupInfo);
1276 aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
1278 aStartupInfo.hStdInput = hInput;
1281 aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1284 aStartupInfo.hStdOutput = hOutput;
1287 aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1290 aStartupInfo.hStdError = hError;
1293 aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1296 dwCreationFlags |= NORMAL_PRIORITY_CLASS;
1298 if (lstrlenW(cmd) > 32767) {
1305 fRet = CreateProcessW(prog, (WCHAR *)cmd, &sa, &sa,
1306 sa.bInheritHandle, dwCreationFlags, NULL, NULL,
1307 &aStartupInfo, &aProcessInformation);
1308 errno = map_errno(GetLastError());
1316 CloseHandle(aProcessInformation.hThread);
1318 child->hProcess = aProcessInformation.hProcess;
1319 child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
1326is_batch(
const char *cmd)
1328 int len = strlen(cmd);
1329 if (len <= 4)
return 0;
1331 if (*cmd++ !=
'.')
return 0;
1332 if (strcasecmp(cmd,
"bat") == 0)
return 1;
1333 if (strcasecmp(cmd,
"cmd") == 0)
return 1;
1337#define filecp rb_w32_filecp
1338#define mbstr_to_wstr rb_w32_mbstr_to_wstr
1339#define wstr_to_mbstr rb_w32_wstr_to_mbstr
1340#define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen)
1341#define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen)
1342#define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen)
1343#define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen)
1344#define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen)
1345#define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen)
1348MJIT_FUNC_EXPORTED HANDLE
1349rb_w32_start_process(
const char *abspath,
char *
const *argv,
int out_fd)
1358 WCHAR *wcmd = NULL, *wprog = NULL;
1359 HANDLE outHandle = NULL;
1362 outHandle = (HANDLE)rb_w32_get_osfhandle(out_fd);
1365 len = join_argv(NULL, argv, FALSE, filecp(), 1);
1366 cmd = alloca(
sizeof(
char) * len);
1367 join_argv(cmd, argv, FALSE, filecp(), 1);
1369 if (!(wcmd = mbstr_to_wstr(filecp(), cmd, -1, NULL))) {
1373 if (!(wprog = mbstr_to_wstr(filecp(), abspath, -1, NULL))) {
1378 if (!CreateChild(&child, wcmd, wprog, NULL, outHandle, outHandle, 0)) {
1384 return child.hProcess;
1389w32_spawn(
int mode,
const char *cmd,
const char *prog, UINT cp)
1391 char fbuf[PATH_MAX];
1393 const char *shell = NULL;
1394 WCHAR *wcmd = NULL, *wshell = NULL;
1400 char *cmd_sep = NULL;
1402 if (check_spawn_mode(mode))
return -1;
1405 if (!(p = dln_find_exe_r(prog, NULL, fbuf,
sizeof(fbuf)))) {
1410 translate_char(p,
'/',
'\\', cp);
1417 if ((shell = w32_getenv(
"RUBYSHELL", cp)) && (redir = has_redirection(cmd, cp))) {
1418 size_t shell_len = strlen(shell);
1419 char *tmp =
ALLOCV(v, shell_len + strlen(cmd) +
sizeof(
" -c ") + 2);
1420 memcpy(tmp, shell, shell_len + 1);
1421 translate_char(tmp,
'/',
'\\', cp);
1422 sprintf(tmp + shell_len,
" -c \"%s\"", cmd);
1425 else if ((shell = w32_getenv(
"COMSPEC", cp)) &&
1426 (nt = !is_command_com(shell),
1427 (redir < 0 ? has_redirection(cmd, cp) : redir) ||
1428 is_internal_cmd(cmd, nt))) {
1429 char *tmp =
ALLOCV(v, strlen(shell) + strlen(cmd) +
sizeof(
" /c ") + (nt ? 2 : 0));
1430 sprintf(tmp, nt ?
"%s /c \"%s\"" :
"%s /c %s", shell, cmd);
1434 int len = 0, quote = (*cmd ==
'"') ?
'"' : (*cmd ==
'\'') ?
'\'' : 0;
1436 for (prog = cmd + !!quote;; prog = CharNextExA(cp, prog, 0)) {
1437 if (*prog ==
'/') slash = 1;
1441 STRNDUPV(p, v2, cmd, len);
1447 if ((
unsigned char)*prog == quote) {
1448 len = prog++ - cmd - 1;
1449 STRNDUPV(p, v2, cmd + 1, len);
1453 if (quote)
continue;
1454 if (
ISSPACE(*prog) || strchr(
"<>|*?\"", *prog)) {
1456 STRNDUPV(p, v2, cmd, len + (slash ? strlen(prog) : 0));
1459 sep = *(cmd_sep = &p[len]);
1466 shell = dln_find_exe_r(shell, NULL, fbuf,
sizeof(fbuf));
1467 if (p && slash) translate_char(p,
'/',
'\\', cp);
1469 shell = p ? p : cmd;
1472 len = strlen(shell);
1473 if (strchr(shell,
' ')) quote = -1;
1474 if (shell == fbuf) {
1477 else if (shell != p && strchr(shell,
'/')) {
1478 STRNDUPV(p, v2, shell, len);
1481 if (p) translate_char(p,
'/',
'\\', cp);
1482 if (is_batch(shell)) {
1483 int alen = strlen(prog);
1484 cmd = p =
ALLOCV(v, len + alen + (quote ? 2 : 0) + 1);
1485 if (quote) *p++ =
'"';
1486 memcpy(p, shell, len);
1488 if (quote) *p++ =
'"';
1489 memcpy(p, prog, alen + 1);
1496 if (!e && shell && !(wshell = mbstr_to_wstr(cp, shell, -1, NULL))) e = E2BIG;
1497 if (cmd_sep) *cmd_sep = sep;
1498 if (!e && cmd && !(wcmd = mbstr_to_wstr(cp, cmd, -1, NULL))) e = E2BIG;
1504 if (CreateChild(child, wcmd, wshell, NULL, NULL, NULL, 0)) {
1505 ret = child_result(child, mode);
1516rb_w32_spawn(
int mode,
const char *cmd,
const char *prog)
1519 return w32_spawn(mode, cmd, prog, filecp());
1524rb_w32_uspawn(
int mode,
const char *cmd,
const char *prog)
1526 return w32_spawn(mode, cmd, prog, CP_UTF8);
1531w32_aspawn_flags(
int mode,
const char *prog,
char *
const *argv, DWORD flags, UINT cp)
1535 BOOL ntcmd = FALSE, tmpnt;
1537 char *cmd, fbuf[PATH_MAX];
1538 WCHAR *wcmd = NULL, *wprog = NULL;
1543 if (check_spawn_mode(mode))
return -1;
1545 if (!prog) prog = argv[0];
1546 if ((shell = w32_getenv(
"COMSPEC", cp)) &&
1547 internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
1552 else if ((cmd = dln_find_exe_r(prog, NULL, fbuf,
sizeof(fbuf)))) {
1553 if (cmd == prog) strlcpy(cmd = fbuf, prog,
sizeof(fbuf));
1554 translate_char(cmd,
'/',
'\\', cp);
1557 else if (strchr(prog,
'/')) {
1559 if (len <
sizeof(fbuf))
1560 strlcpy(cmd = fbuf, prog,
sizeof(fbuf));
1562 STRNDUPV(cmd, v, prog, len);
1563 translate_char(cmd,
'/',
'\\', cp);
1566 if (c_switch || is_batch(prog)) {
1568 progs[0] = (
char *)prog;
1570 len = join_argv(NULL, progs, ntcmd, cp, 1);
1571 if (c_switch) len += 3;
1573 if (argv[0]) len += join_argv(NULL, argv, ntcmd, cp, 0);
1575 join_argv(cmd, progs, ntcmd, cp, 1);
1576 if (c_switch) strlcat(cmd,
" /c", len);
1577 if (argv[0]) join_argv(cmd + strlcat(cmd,
" ", len), argv, ntcmd, cp, 0);
1578 prog = c_switch ? shell : 0;
1581 len = join_argv(NULL, argv, FALSE, cp, 1);
1583 join_argv(cmd, argv, FALSE, cp, 1);
1586 if (!e && cmd && !(wcmd = mbstr_to_wstr(cp, cmd, -1, NULL))) e = E2BIG;
1588 if (!e && prog && !(wprog = mbstr_to_wstr(cp, prog, -1, NULL))) e = E2BIG;
1592 if (CreateChild(child, wcmd, wprog, NULL, NULL, NULL, flags)) {
1593 ret = child_result(child, mode);
1604rb_w32_aspawn_flags(
int mode,
const char *prog,
char *
const *argv, DWORD flags)
1607 return w32_aspawn_flags(mode, prog, argv, flags, filecp());
1612rb_w32_uaspawn_flags(
int mode,
const char *prog,
char *
const *argv, DWORD flags)
1614 return w32_aspawn_flags(mode, prog, argv, flags, CP_UTF8);
1619rb_w32_aspawn(
int mode,
const char *prog,
char *
const *argv)
1621 return w32_aspawn_flags(mode, prog, argv, 0, filecp());
1626rb_w32_uaspawn(
int mode,
const char *prog,
char *
const *argv)
1628 return rb_w32_uaspawn_flags(mode, prog, argv, 0);
1649insert(
const char *path, VALUE vinfo,
void *enc)
1655 if (!tmpcurr)
return -1;
1657 tmpcurr->len = strlen(path);
1658 tmpcurr->str =
strdup(path);
1659 if (!tmpcurr->str)
return -1;
1660 tmpcurr->flags |= NTMALLOC;
1662 *tail = &tmpcurr->next;
1671 char buffer[PATH_MAX], *buf = buffer;
1675 if (patt->len >= PATH_MAX)
1676 if (!(buf = malloc(patt->len + 1)))
return 0;
1678 memcpy(buf, patt->str, patt->len);
1679 buf[patt->len] =
'\0';
1680 translate_char(buf,
'\\',
'/', cp);
1681 status = ruby_brace_glob_with_enc(buf, 0, insert, (VALUE)&tail, enc);
1685 if (status || last == tail)
return 0;
1686 if (patt->flags & NTMALLOC)
1699has_redirection(
const char *cmd, UINT cp)
1709 for (ptr = cmd; *ptr;) {
1715 else if (quote == *ptr)
1731 if (*++ptr !=
'_' && !
ISALPHA(*ptr))
break;
1732 while (*++ptr ==
'_' ||
ISALNUM(*ptr));
1733 if (*ptr++ ==
'%')
return TRUE;
1739 ptr = CharNextExA(cp, ptr, 0);
1747static inline WCHAR *
1748skipspace(WCHAR *ptr)
1757w32_cmdvector(
const WCHAR *cmd,
char ***vec, UINT cp,
rb_encoding *enc)
1760 int elements, strsz, done;
1761 int slashes, escape;
1762 WCHAR *ptr, *base, *cmdline;
1763 char *cptr, *buffer;
1779 ptr = cmdline = wcsdup(cmd);
1790 while (*(ptr = skipspace(ptr))) {
1792 quote = slashes = globbing = escape = 0;
1793 for (done = 0; !done && *ptr; ) {
1802 if (quote != L
'\'') slashes++;
1842 if (!(slashes & 1)) {
1845 else if (quote == *ptr) {
1846 if (quote == L
'"' && quote == ptr[1])
1856 ptr = CharNextW(ptr);
1879 slashes = quote = 0;
1880 while (p < base + len) {
1884 if (quote != L
'\'') slashes++;
1889 if (!(slashes & 1) && quote && quote != c) {
1894 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
1895 sizeof(WCHAR) * (base + len - p));
1896 len -= ((slashes + 1) >> 1) + (~slashes & 1);
1897 p -= (slashes + 1) >> 1;
1898 if (!(slashes & 1)) {
1900 if (quote == L
'"' && quote == *p)
1921 if (!curr)
goto do_nothing;
1922 curr->str = rb_w32_wstr_to_mbstr(cp, base, len, &curr->len);
1923 curr->flags |= NTMALLOC;
1925 if (globbing && (tail = cmdglob(curr, cmdtail, cp, enc))) {
1930 cmdtail = &curr->next;
1940 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) {
1942 strsz += (curr->len + 1);
1945 len = (elements+1)*
sizeof(
char *) + strsz;
1946 buffer = (
char *)malloc(len);
1949 while ((curr = cmdhead) != 0) {
1950 cmdhead = curr->next;
1951 if (curr->flags & NTMALLOC) free(curr->str);
1955 for (vptr = *vec; *vptr; ++vptr);
1971 vptr = (
char **) buffer;
1973 cptr = buffer + (elements+1) *
sizeof(
char *);
1975 while ((curr = cmdhead) != 0) {
1976 memcpy(cptr, curr->str, curr->len);
1977 cptr[curr->len] =
'\0';
1979 cptr += curr->len + 1;
1980 cmdhead = curr->next;
1981 if (curr->flags & NTMALLOC) free(curr->str);
1986 *vec = (
char **) buffer;
1995typedef DWORD (WINAPI *get_final_path_func)(HANDLE, WCHAR*, DWORD, DWORD);
1996static get_final_path_func get_final_path;
1999get_final_path_fail(HANDLE f, WCHAR *buf, DWORD len, DWORD flag)
2005get_final_path_unknown(HANDLE f, WCHAR *buf, DWORD len, DWORD flag)
2008 get_final_path_func func = (get_final_path_func)
2009 get_proc_address(
"kernel32",
"GetFinalPathNameByHandleW", NULL);
2010 if (!func) func = get_final_path_fail;
2011 get_final_path = func;
2012 return func(f, buf, len, flag);
2015static get_final_path_func get_final_path = get_final_path_unknown;
2020open_special(
const WCHAR *path, DWORD access, DWORD flags)
2022 const DWORD share_mode =
2023 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2024 return CreateFileW(path, access, share_mode, NULL, OPEN_EXISTING,
2025 FILE_FLAG_BACKUP_SEMANTICS|flags, NULL);
2035#define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT))
2036#define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT))
2038#define BitOfIsDir(n) ((n) * 2)
2039#define BitOfIsRep(n) ((n) * 2 + 1)
2040#define DIRENT_PER_CHAR (CHAR_BIT / 2)
2042static const WCHAR namespace_prefix[] = {L
'\\', L
'\\', L
'?', L
'\\'};
2044enum {FINAL_PATH_MAX = PATH_MAX + numberof(namespace_prefix)};
2048open_dir_handle(
const WCHAR *filename, WIN32_FIND_DATAW *fd)
2059 fh = open_special(filename, 0, 0);
2060 if (fh != INVALID_HANDLE_VALUE) {
2061 len = get_final_path(fh, fullname, FINAL_PATH_MAX, 0);
2063 if (len >= FINAL_PATH_MAX) {
2064 errno = ENAMETOOLONG;
2065 return INVALID_HANDLE_VALUE;
2069 len = lstrlenW(filename);
2070 if (len >= PATH_MAX) {
2071 errno = ENAMETOOLONG;
2072 return INVALID_HANDLE_VALUE;
2074 MEMCPY(fullname, filename, WCHAR, len);
2076 p = &fullname[len-1];
2077 if (!(isdirsep(*p) || *p == L
':')) *++p = L
'\\';
2084 fh = FindFirstFileW(fullname, fd);
2085 if (fh == INVALID_HANDLE_VALUE) {
2086 errno = map_errno(GetLastError());
2093w32_wopendir(
const WCHAR *wpath)
2096 WIN32_FIND_DATAW fd;
2109 if (wstati128(wpath, &sbuf, FALSE) < 0) {
2112 if (!(sbuf.st_mode & S_IFDIR) &&
2113 (!
ISALPHA(wpath[0]) || wpath[1] != L
':' || wpath[2] != L
'\0' ||
2114 ((1 << ((wpath[0] & 0x5f) -
'A')) & GetLogicalDrives()) == 0)) {
2118 fh = open_dir_handle(wpath, &fd);
2119 if (fh == INVALID_HANDLE_VALUE) {
2126 p = calloc(
sizeof(
DIR), 1);
2130 pathlen = lstrlenW(wpath);
2140 len = lstrlenW(fd.cFileName) + 1;
2141 altlen = lstrlenW(fd.cAlternateFileName) + 1;
2147 tmpW = realloc(p->start, (idx + len + altlen) *
sizeof(WCHAR));
2157 memcpy(&p->start[idx], fd.cFileName, len *
sizeof(WCHAR));
2158 memcpy(&p->start[idx + len], fd.cAlternateFileName, altlen *
sizeof(WCHAR));
2160 if (p->nfiles % DIRENT_PER_CHAR == 0) {
2161 tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1);
2165 p->bits[p->nfiles / DIRENT_PER_CHAR] = 0;
2167 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2168 SetBit(p->bits, BitOfIsDir(p->nfiles));
2169 if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
2170 WCHAR *tmppath = malloc((pathlen + len + 1) *
sizeof(WCHAR));
2171 memcpy(tmppath, wpath, pathlen *
sizeof(WCHAR));
2172 tmppath[pathlen] = L
'\\';
2173 memcpy(tmppath + pathlen + 1, fd.cFileName, len *
sizeof(WCHAR));
2174 if (rb_w32_reparse_symlink_p(tmppath))
2175 SetBit(p->bits, BitOfIsRep(p->nfiles));
2180 idx += len + altlen;
2181 }
while (FindNextFileW(fh, &fd));
2192 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
2198rb_w32_wstr_to_mbstr(UINT cp,
const WCHAR *wstr,
int clen,
long *plen)
2201 int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL);
2202 if (!(ptr = malloc(len)))
return 0;
2203 WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, NULL, NULL);
2206 if (clen == -1) --len;
2214rb_w32_mbstr_to_wstr(UINT cp,
const char *str,
int clen,
long *plen)
2218 int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0);
2219 if (!(ptr = malloc(
sizeof(WCHAR) * len)))
return 0;
2220 MultiByteToWideChar(cp, 0, str, clen, ptr, len);
2223 if (clen == -1) --len;
2231rb_w32_opendir(
const char *filename)
2234 WCHAR *wpath = filecp_to_wstr(filename, NULL);
2237 ret = w32_wopendir(wpath);
2244rb_w32_uopendir(
const char *filename)
2247 WCHAR *wpath = utf8_to_wstr(filename, NULL);
2250 ret = w32_wopendir(wpath);
2261move_to_next_entry(
DIR *dirp)
2265 dirp->curr += lstrlenW(dirp->curr) + 1;
2266 dirp->curr += lstrlenW(dirp->curr) + 1;
2267 if (dirp->curr >= (dirp->start + dirp->size)) {
2279win32_direct_conv(
const WCHAR *file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2281 UINT cp = *((UINT *)enc);
2282 if (!(entry->d_name = wstr_to_mbstr(cp, file, -1, &entry->d_namlen)))
2286 entry->d_altname = wstr_to_mbstr(cp, alt, -1, &altlen);
2287 entry->d_altlen = altlen;
2294rb_w32_conv_from_wchar(
const WCHAR *wstr,
rb_encoding *enc)
2297 long len = lstrlenW(wstr);
2300 if (encindex == ENCINDEX_UTF_16LE) {
2304#if SIZEOF_INT < SIZEOF_LONG
2305# error long should equal to int on Windows
2308 len = WideCharToMultiByte(CP_UTF8, 0, wstr, clen, NULL, 0, NULL, NULL);
2310 WideCharToMultiByte(CP_UTF8, 0, wstr, clen,
RSTRING_PTR(src), len, NULL, NULL);
2313 case ENCINDEX_ASCII:
2314 case ENCINDEX_US_ASCII:
2316 case ENCINDEX_UTF_8:
2325rb_w32_conv_from_wstr(
const WCHAR *wstr,
long *lenp,
rb_encoding *enc)
2327 VALUE str = rb_w32_conv_from_wchar(wstr, enc);
2331 if (
NIL_P(str))
return wstr_to_utf8(wstr, lenp);
2333 memcpy(ptr = malloc(len + 1),
RSTRING_PTR(str), len);
2340ruby_direct_conv(
const WCHAR *file,
const WCHAR *alt,
struct direct *entry,
const void *enc)
2342 if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc)))
2346 entry->d_altname = rb_w32_conv_from_wstr(alt, &altlen, enc);
2347 entry->d_altlen = altlen;
2354readdir_internal(
DIR *dirp, BOOL (*conv)(
const WCHAR *,
const WCHAR *,
struct direct *,
const void *),
const void *enc)
2356 static long dummy_ino = 0;
2363 if (dirp->dirstr.d_name)
2364 free(dirp->dirstr.d_name);
2365 if (dirp->dirstr.d_altname)
2366 free(dirp->dirstr.d_altname);
2367 dirp->dirstr.d_altname = 0;
2368 dirp->dirstr.d_altlen = 0;
2369 conv(dirp->curr, dirp->curr + lstrlenW(dirp->curr) + 1, &dirp->dirstr, enc);
2374 dirp->dirstr.d_ino = (ino_t)(InterlockedIncrement(&dummy_ino) - 1);
2380 if (GetBit(dirp->bits, BitOfIsRep(dirp->loc)))
2381 dirp->dirstr.d_type = DT_LNK;
2382 else if (GetBit(dirp->bits, BitOfIsDir(dirp->loc)))
2383 dirp->dirstr.d_type = DT_DIR;
2385 dirp->dirstr.d_type = DT_REG;
2391 move_to_next_entry(dirp);
2393 return &(dirp->dirstr);
2405 if (idx == ENCINDEX_ASCII) {
2406 const UINT cp = filecp();
2407 return readdir_internal(dirp, win32_direct_conv, &cp);
2409 else if (idx == ENCINDEX_UTF_8) {
2410 const UINT cp = CP_UTF8;
2411 return readdir_internal(dirp, win32_direct_conv, &cp);
2414 return readdir_internal(dirp, ruby_direct_conv, enc);
2419rb_w32_ureaddir(
DIR *dirp)
2421 const UINT cp = CP_UTF8;
2422 return readdir_internal(dirp, win32_direct_conv, &cp);
2431rb_w32_telldir(
DIR *dirp)
2442rb_w32_seekdir(
DIR *dirp,
long loc)
2444 if (dirp->loc > loc) rb_w32_rewinddir(dirp);
2446 while (dirp->curr && dirp->loc < loc) {
2447 move_to_next_entry(dirp);
2457rb_w32_rewinddir(
DIR *dirp)
2459 dirp->curr = dirp->start;
2469rb_w32_closedir(
DIR *dirp)
2472 if (dirp->dirstr.d_name)
2473 free(dirp->dirstr.d_name);
2474 if (dirp->dirstr.d_altname)
2475 free(dirp->dirstr.d_altname);
2484#if RUBY_MSVCRT_VERSION >= 140
2499 CRITICAL_SECTION _lock;
2501#define FILE_COUNT(stream) ((vcruntime_file*)stream)->_cnt
2502#define FILE_READPTR(stream) ((vcruntime_file*)stream)->_ptr
2503#define FILE_FILENO(stream) ((vcruntime_file*)stream)->_file
2505#define FILE_COUNT(stream) stream->_cnt
2506#define FILE_READPTR(stream) stream->_ptr
2507#define FILE_FILENO(stream) stream->_file
2511#if RUBY_MSVCRT_VERSION >= 140
2512typedef char lowio_text_mode;
2513typedef char lowio_pipe_lookahead[3];
2516 CRITICAL_SECTION lock;
2519 unsigned char osfile;
2520 lowio_text_mode textmode;
2521 lowio_pipe_lookahead _pipe_lookahead;
2523 uint8_t unicode : 1;
2524 uint8_t utf8translations : 1;
2525 uint8_t dbcsBufferUsed : 1;
2534 CRITICAL_SECTION lock;
2535#if RUBY_MSVCRT_VERSION >= 80
2542#if !defined _CRTIMP || defined __MINGW32__
2544#define _CRTIMP __declspec(dllimport)
2547#if RUBY_MSVCRT_VERSION >= 140
2548static ioinfo ** __pioinfo = NULL;
2551EXTERN_C _CRTIMP
ioinfo * __pioinfo[];
2554static inline ioinfo* _pioinfo(
int);
2557#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
2558#define _osfhnd(i) (_pioinfo(i)->osfhnd)
2559#define _osfile(i) (_pioinfo(i)->osfile)
2560#define rb_acrt_lowio_lock_fh(i) EnterCriticalSection(&_pioinfo(i)->lock)
2561#define rb_acrt_lowio_unlock_fh(i) LeaveCriticalSection(&_pioinfo(i)->lock)
2563#if RUBY_MSVCRT_VERSION >= 80
2564static size_t pioinfo_extra = 0;
2568set_pioinfo_extra(
void)
2570#if RUBY_MSVCRT_VERSION >= 140
2571# define FUNCTION_RET 0xc3
2573# define UCRTBASE "ucrtbased.dll"
2575# define UCRTBASE "ucrtbase.dll"
2578 char *p = (
char*)get_proc_address(UCRTBASE,
"_isatty", NULL);
2586# define FUNCTION_BEFORE_RET_MARK "\x48\x83\xc4"
2587# define FUNCTION_SKIP_BYTES 1
2590# define PIOINFO_MARK "\x48\x8d\x0d"
2593# define PIOINFO_MARK "\x48\x8d\x15"
2598# define FUNCTION_BEFORE_RET_MARK "\x5d"
2599# define FUNCTION_SKIP_BYTES 0
2601# define PIOINFO_MARK "\x8B\x04\x85"
2604 for (pend += 10; pend < p + 300; pend++) {
2606 if (memcmp(pend, FUNCTION_BEFORE_RET_MARK,
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) == 0 &&
2607 (*(pend + (
sizeof(FUNCTION_BEFORE_RET_MARK) - 1) + FUNCTION_SKIP_BYTES) & FUNCTION_RET) == FUNCTION_RET) {
2609 for (pend -= (
sizeof(PIOINFO_MARK) - 1); pend > p; pend--) {
2610 if (memcmp(pend, PIOINFO_MARK,
sizeof(PIOINFO_MARK) - 1) == 0) {
2619 fprintf(stderr,
"unexpected " UCRTBASE
"\n");
2623 p +=
sizeof(PIOINFO_MARK) - 1;
2625 rel = *(int32_t*)(p);
2626 rip = p +
sizeof(int32_t);
2627 __pioinfo = (
ioinfo**)(rip + rel);
2629 __pioinfo = *(
ioinfo***)(p);
2634 fd = _open(
"NUL", O_RDONLY);
2635 for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra +=
sizeof(
void *)) {
2636 if (_osfhnd(fd) == _get_osfhandle(fd)) {
2642 if (pioinfo_extra > 64) {
2648#define pioinfo_extra 0
2654 const size_t sizeof_ioinfo =
sizeof(
ioinfo) + pioinfo_extra;
2655 return (
ioinfo*)((
char*)__pioinfo[fd >> IOINFO_L2E] +
2656 (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
2659#define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
2660#define _set_osflags(fh, flags) (_osfile(fh) = (flags))
2665#define FNOINHERIT 0x10
2670static int is_socket(SOCKET);
2671static int is_console(SOCKET);
2675rb_w32_io_cancelable_p(
int fd)
2677 return is_socket(TO_SOCKET(fd)) || !is_console(TO_SOCKET(fd));
2682rb_w32_open_osfhandle(intptr_t osfhandle,
int flags)
2691 if (flags & O_APPEND)
2692 fileflags |= FAPPEND;
2697 if (flags & O_NOINHERIT)
2698 fileflags |= FNOINHERIT;
2701 hF = CreateFile(
"NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2702 fh = _open_osfhandle((intptr_t)hF, 0);
2710 rb_acrt_lowio_lock_fh(fh);
2712 _set_osfhnd(fh, osfhandle);
2716 _set_osflags(fh, fileflags);
2717 rb_acrt_lowio_unlock_fh(fh);
2728#define open_null(fd) \
2730 (nullfd = open("NUL", O_RDWR)) : 0), \
2731 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \
2734 if (fileno(stdin) < 0) {
2735 FILE_FILENO(stdin) = open_null(0);
2738 setmode(fileno(stdin), O_BINARY);
2740 if (fileno(stdout) < 0) {
2741 FILE_FILENO(stdout) = open_null(1);
2743 if (fileno(stderr) < 0) {
2744 FILE_FILENO(stderr) = open_null(2);
2746 if (nullfd >= 0 && !keep) close(nullfd);
2747 setvbuf(stderr, NULL, _IONBF, 0);
2750 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
2752 if (GetConsoleMode(h, &m)) {
2753#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
2754#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
2756 SetConsoleMode(h, m | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
2765is_socket(SOCKET sock)
2767 if (socklist_lookup(sock, NULL))
2775rb_w32_is_socket(
int fd)
2777 return is_socket(TO_SOCKET(fd));
2790rb_w32_strerror(
int e)
2792 static char buffer[512];
2796 if (e < 0 || e > sys_nerr) {
2799#if WSAEWOULDBLOCK != EWOULDBLOCK
2800 else if (e >= EADDRINUSE && e <= EWOULDBLOCK) {
2804 for (s = 0; s < (int)(
sizeof(errmap)/
sizeof(*errmap)); s++)
2805 if (errmap[s].winerr == WSAEWOULDBLOCK)
2807 for (i = s; i < (int)(
sizeof(errmap)/
sizeof(*errmap)); i++)
2808 if (errmap[i].err == e) {
2809 e = errmap[i].winerr;
2814 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2815 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
2816 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
2817 buffer,
sizeof(buffer), NULL) == 0 &&
2818 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2819 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
2820 buffer,
sizeof(buffer), NULL) == 0)
2821 strlcpy(buffer,
"Unknown Error",
sizeof(buffer));
2824 strlcpy(buffer, strerror(e),
sizeof(buffer));
2827 while ((p = strpbrk(p,
"\r\n")) != NULL) {
2828 memmove(p, p + 1, strlen(p));
2879 return (uid == ROOT_UID ? 0 : -1);
2886 return (gid == ROOT_GID ? 0 : -1);
2895ioctl(
int i,
int u, ...)
2902rb_w32_fdset(
int fd,
fd_set *set)
2911rb_w32_fdclr(
int fd,
fd_set *set)
2914 SOCKET s = TO_SOCKET(fd);
2916 for (i = 0; i < set->fd_count; i++) {
2917 if (set->fd_array[i] == s) {
2918 memmove(&set->fd_array[i], &set->fd_array[i+1],
2919 sizeof(set->fd_array[0]) * (--set->fd_count - i));
2929rb_w32_fdisset(
int fd,
fd_set *set)
2932 SOCKET s = TO_SOCKET(fd);
2933 if (s == (SOCKET)INVALID_HANDLE_VALUE)
2935 RUBY_CRITICAL {ret = __WSAFDIsSet(s, set);}
2943 max = min(src->fd_count, (UINT)max);
2944 if ((UINT)dst->capa < (UINT)max) {
2945 dst->capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2946 dst->fdset =
xrealloc(dst->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2949 memcpy(dst->fdset->fd_array, src->fd_array,
2950 max *
sizeof(src->fd_array[0]));
2951 dst->fdset->fd_count = src->fd_count;
2958 if ((UINT)dst->capa < src->fdset->fd_count) {
2959 dst->capa = (src->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2960 dst->fdset =
xrealloc(dst->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
2963 memcpy(dst->fdset->fd_array, src->fdset->fd_array,
2964 src->fdset->fd_count *
sizeof(src->fdset->fd_array[0]));
2965 dst->fdset->fd_count = src->fdset->fd_count;
2984 while (s < src->fd_count) {
2985 SOCKET fd = src->fd_array[s];
2987 if (!func || (*func)(fd)) {
2991 for (d = 0; d < dst->fdset->fd_count; d++) {
2992 if (dst->fdset->fd_array[d] == fd)
2995 if (d == dst->fdset->fd_count) {
2996 if ((
int)dst->fdset->fd_count >= dst->capa) {
2997 dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2998 dst->fdset =
xrealloc(dst->fdset,
sizeof(
unsigned int) +
sizeof(SOCKET) * dst->capa);
3000 dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
3004 &src->fd_array[s+1],
3005 sizeof(src->fd_array[0]) * (--src->fd_count - s));
3015 return dst ? dst->fdset->fd_count : m;
3023 if (!src || !dst)
return 0;
3025 for (s = 0; s < src->fd_count; ++s) {
3026 SOCKET fd = src->fd_array[s];
3028 for (d = 0; d < dst->fd_count; ++d) {
3029 if (dst->fd_array[d] == fd)
3032 if (d == dst->fd_count && d < FD_SETSIZE) {
3033 dst->fd_array[dst->fd_count++] = fd;
3037 return dst->fd_count;
3042is_not_socket(SOCKET sock)
3044 return !is_socket(sock);
3054 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
3062is_readable_pipe(SOCKET sock)
3068 if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
3072 ret = (GetLastError() == ERROR_BROKEN_PIPE);
3081is_console(SOCKET sock)
3088 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n));
3096is_readable_console(SOCKET sock)
3103 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
3104 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
3105 ir.Event.KeyEvent.uChar.AsciiChar) {
3109 ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
3119is_invalid_handle(SOCKET sock)
3121 return (HANDLE)sock == INVALID_HANDLE_VALUE;
3133 rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
3135 rb_w32_sleep(INFINITE);
3139 thread_exclusive(select) {
3140 r = select(nfds, rd, wr, ex, timeout);
3142 if (r == SOCKET_ERROR) {
3143 errno = map_errno(WSAGetLastError());
3158rb_w32_time_subtract(
struct timeval *rest,
const struct timeval *wait)
3160 if (rest->tv_sec < wait->tv_sec) {
3163 while (rest->tv_usec < wait->tv_usec) {
3164 if (rest->tv_sec <= wait->tv_sec) {
3168 rest->tv_usec += 1000 * 1000;
3170 rest->tv_sec -= wait->tv_sec;
3171 rest->tv_usec -= wait->tv_usec;
3172 return rest->tv_sec != 0 || rest->tv_usec != 0;
3179 if (t1->tv_sec < t2->tv_sec)
3181 if (t1->tv_sec > t2->tv_sec)
3183 if (t1->tv_usec < t2->tv_usec)
3185 if (t1->tv_usec > t2->tv_usec)
3192int rb_w32_check_interrupt(
void *);
3198 struct timeval *timeout,
void *th)
3207 struct timeval limit = {0, 0};
3209 if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
3215 if (timeout->tv_sec < 0 ||
3216 timeout->tv_usec < 0 ||
3217 timeout->tv_usec >= 1000000) {
3221 gettimeofday(&limit, NULL);
3222 limit.tv_sec += timeout->tv_sec;
3223 limit.tv_usec += timeout->tv_usec;
3224 if (limit.tv_usec >= 1000000) {
3225 limit.tv_usec -= 1000000;
3237 nonsock += extract_fd(&else_rd, rd, is_not_socket);
3240 nonsock += extract_fd(&else_wr, wr, is_not_socket);
3243 if (extract_fd(NULL, else_rd.
fdset, is_invalid_handle) > 0 ||
3244 extract_fd(NULL, else_wr.
fdset, is_invalid_handle) > 0) {
3252 extract_fd(&pipe_rd, else_rd.
fdset, is_pipe);
3255 extract_fd(&cons_rd, else_rd.
fdset, is_console);
3258 extract_fd(&except, ex, is_not_socket);
3261 if (rd && (
int)rd->fd_count > r) r = (int)rd->fd_count;
3262 if (wr && (
int)wr->fd_count > r) r = (
int)wr->fd_count;
3263 if (ex && (
int)ex->fd_count > r) r = (
int)ex->fd_count;
3264 if (nfds > r) nfds = r;
3268 const struct timeval wait = {0, 10 * 1000};
3271 if (th && rb_w32_check_interrupt(th) != WAIT_TIMEOUT) {
3278 extract_fd(&else_rd, pipe_rd.
fdset, is_readable_pipe);
3279 extract_fd(&else_rd, cons_rd.
fdset, is_readable_console);
3282 if (else_rd.
fdset->fd_count || else_wr.
fdset->fd_count) {
3283 r = do_select(nfds, rd, wr, ex, &zero);
3285 r += copy_fd(rd, else_rd.
fdset);
3286 r += copy_fd(wr, else_wr.
fdset);
3292 const struct timeval *dowait = &wait;
3302 if (rd) copy_fd(&orig_rd, rd);
3303 if (wr) copy_fd(&orig_wr, wr);
3304 if (ex) copy_fd(&orig_ex, ex);
3305 r = do_select(nfds, rd, wr, ex, &zero);
3307 if (rd) copy_fd(rd, &orig_rd);
3308 if (wr) copy_fd(wr, &orig_wr);
3309 if (ex) copy_fd(ex, &orig_ex);
3313 gettimeofday(&now, NULL);
3315 if (!rb_w32_time_subtract(&rest, &now))
break;
3316 if (compare(&rest, &wait) < 0) dowait = &rest;
3318 Sleep(dowait->tv_sec * 1000 + (dowait->tv_usec + 999) / 1000);
3337 return rb_w32_select_with_thread(nfds, rd, wr, ex, timeout, 0);
3342get_wsa_extension_function(SOCKET s, GUID guid)
3347 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid,
sizeof(guid),
3348 &ptr,
sizeof(ptr), &dmy, NULL, NULL);
3358rb_w32_accept(
int s,
struct sockaddr *addr,
int *addrlen)
3364 r = accept(TO_SOCKET(s), addr, addrlen);
3365 if (r != INVALID_SOCKET) {
3366 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
3367 fd = rb_w32_open_osfhandle((intptr_t)r, O_RDWR|O_BINARY|O_NOINHERIT);
3369 socklist_insert(r, 0);
3374 errno = map_errno(WSAGetLastError());
3385rb_w32_bind(
int s,
const struct sockaddr *addr,
int addrlen)
3390 r = bind(TO_SOCKET(s), addr, addrlen);
3391 if (r == SOCKET_ERROR)
3392 errno = map_errno(WSAGetLastError());
3401rb_w32_connect(
int s,
const struct sockaddr *addr,
int addrlen)
3405 r = connect(TO_SOCKET(s), addr, addrlen);
3406 if (r == SOCKET_ERROR) {
3407 int err = WSAGetLastError();
3408 if (err != WSAEWOULDBLOCK)
3409 errno = map_errno(err);
3411 errno = EINPROGRESS;
3422rb_w32_getpeername(
int s,
struct sockaddr *addr,
int *addrlen)
3426 r = getpeername(TO_SOCKET(s), addr, addrlen);
3427 if (r == SOCKET_ERROR)
3428 errno = map_errno(WSAGetLastError());
3437rb_w32_getsockname(
int fd,
struct sockaddr *addr,
int *addrlen)
3442 sock = TO_SOCKET(fd);
3443 r = getsockname(sock, addr, addrlen);
3444 if (r == SOCKET_ERROR) {
3445 DWORD wsaerror = WSAGetLastError();
3446 if (wsaerror == WSAEINVAL) {
3448 if (socklist_lookup(sock, &flags)) {
3449 int af = GET_FAMILY(flags);
3451 memset(addr, 0, *addrlen);
3452 addr->sa_family = af;
3457 errno = map_errno(wsaerror);
3467rb_w32_getsockopt(
int s,
int level,
int optname,
char *optval,
int *optlen)
3471 r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
3472 if (r == SOCKET_ERROR)
3473 errno = map_errno(WSAGetLastError());
3482rb_w32_ioctlsocket(
int s,
long cmd, u_long *argp)
3486 r = ioctlsocket(TO_SOCKET(s), cmd, argp);
3487 if (r == SOCKET_ERROR)
3488 errno = map_errno(WSAGetLastError());
3497rb_w32_listen(
int s,
int backlog)
3501 r = listen(TO_SOCKET(s), backlog);
3502 if (r == SOCKET_ERROR)
3503 errno = map_errno(WSAGetLastError());
3515finish_overlapped_socket(BOOL input, SOCKET s, WSAOVERLAPPED *wol,
int result, DWORD *len, DWORD size)
3520 if (result != SOCKET_ERROR)
3522 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
3523 switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) {
3526 result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg);
3533 result = SOCKET_ERROR;
3536 if ((err = WSAGetLastError()) == WSAECONNABORTED && !input)
3538 else if (err == WSAEMSGSIZE && input) {
3544 errno = map_errno(err);
3546 case WAIT_OBJECT_0 + 1:
3549 CancelIo((HANDLE)s);
3554 if (err == WSAECONNABORTED && !input)
3557 errno = map_errno(err);
3560 CloseHandle(wol->hEvent);
3567overlapped_socket_io(BOOL input,
int fd,
char *buf,
int len,
int flags,
3568 struct sockaddr *addr,
int *addrlen)
3579 socklist_lookup(s, &mode);
3580 if (GET_FLAGS(mode) & O_NONBLOCK) {
3583 if (addr && addrlen)
3584 r = recvfrom(s, buf, len, flags, addr, addrlen);
3586 r = recv(s, buf, len, flags);
3587 if (r == SOCKET_ERROR)
3588 errno = map_errno(WSAGetLastError());
3591 if (addr && addrlen)
3592 r = sendto(s, buf, len, flags, addr, *addrlen);
3594 r = send(s, buf, len, flags);
3595 if (r == SOCKET_ERROR) {
3596 DWORD err = WSAGetLastError();
3597 if (err == WSAECONNABORTED)
3600 errno = map_errno(err);
3610 memset(&wol, 0,
sizeof(wol));
3612 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3615 if (addr && addrlen)
3616 ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
3619 ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL);
3622 if (addr && addrlen)
3623 ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
3626 ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL);
3630 finish_overlapped_socket(input, s, &wol, ret, &rlen, size);
3639rb_w32_recv(
int fd,
char *buf,
int len,
int flags)
3641 return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
3646rb_w32_recvfrom(
int fd,
char *buf,
int len,
int flags,
3647 struct sockaddr *from,
int *fromlen)
3649 return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
3654rb_w32_send(
int fd,
const char *buf,
int len,
int flags)
3656 return overlapped_socket_io(FALSE, fd, (
char *)buf, len, flags, NULL, NULL);
3661rb_w32_sendto(
int fd,
const char *buf,
int len,
int flags,
3662 const struct sockaddr *to,
int tolen)
3664 return overlapped_socket_io(FALSE, fd, (
char *)buf, len, flags,
3665 (
struct sockaddr *)to, &tolen);
3668#if !defined(MSG_TRUNC) && !defined(__MINGW32__)
3674 DWORD dwBufferCount;
3679#ifndef WSAID_WSARECVMSG
3680#define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
3682#ifndef WSAID_WSASENDMSG
3683#define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
3687#define msghdr_to_wsamsg(msg, wsamsg) \
3690 (wsamsg)->name = (msg)->msg_name; \
3691 (wsamsg)->namelen = (msg)->msg_namelen; \
3692 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
3693 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
3694 for (i = 0; i < (msg)->msg_iovlen; ++i) { \
3695 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
3696 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
3698 (wsamsg)->Control.buf = (msg)->msg_control; \
3699 (wsamsg)->Control.len = (msg)->msg_controllen; \
3700 (wsamsg)->dwFlags = (msg)->msg_flags; \
3705recvmsg(
int fd,
struct msghdr *msg,
int flags)
3707 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET,
WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3708 static WSARecvMsg_t pWSARecvMsg = NULL;
3718 static const GUID guid = WSAID_WSARECVMSG;
3719 pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, guid);
3724 msghdr_to_wsamsg(msg, &wsamsg);
3725 wsamsg.dwFlags |= flags;
3727 socklist_lookup(s, &mode);
3728 if (GET_FLAGS(mode) & O_NONBLOCK) {
3730 if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
3731 errno = map_errno(WSAGetLastError());
3739 memset(&wol, 0,
sizeof(wol));
3741 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3742 ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL);
3745 ret = finish_overlapped_socket(TRUE, s, &wol, ret, &len, size);
3747 if (ret == SOCKET_ERROR)
3751 msg->msg_name = wsamsg.name;
3752 msg->msg_namelen = wsamsg.namelen;
3753 msg->msg_flags = wsamsg.dwFlags;
3760sendmsg(
int fd,
const struct msghdr *msg,
int flags)
3762 typedef int (WSAAPI *WSASendMsg_t)(SOCKET,
const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
3763 static WSASendMsg_t pWSASendMsg = NULL;
3773 static const GUID guid = WSAID_WSASENDMSG;
3774 pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, guid);
3779 msghdr_to_wsamsg(msg, &wsamsg);
3781 socklist_lookup(s, &mode);
3782 if (GET_FLAGS(mode) & O_NONBLOCK) {
3784 if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
3785 errno = map_errno(WSAGetLastError());
3793 memset(&wol, 0,
sizeof(wol));
3795 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3796 ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL);
3799 finish_overlapped_socket(FALSE, s, &wol, ret, &len, size);
3809rb_w32_setsockopt(
int s,
int level,
int optname,
const char *optval,
int optlen)
3813 r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
3814 if (r == SOCKET_ERROR)
3815 errno = map_errno(WSAGetLastError());
3824rb_w32_shutdown(
int s,
int how)
3828 r = shutdown(TO_SOCKET(s), how);
3829 if (r == SOCKET_ERROR)
3830 errno = map_errno(WSAGetLastError());
3837open_ifs_socket(
int af,
int type,
int protocol)
3839 unsigned long proto_buffers_len = 0;
3841 SOCKET out = INVALID_SOCKET;
3843 if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) {
3844 error_code = WSAGetLastError();
3845 if (error_code == WSAENOBUFS) {
3846 WSAPROTOCOL_INFO *proto_buffers;
3847 int protocols_available = 0;
3849 proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len);
3850 if (!proto_buffers) {
3851 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
3852 return INVALID_SOCKET;
3855 protocols_available =
3856 WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len);
3857 if (protocols_available != SOCKET_ERROR) {
3859 for (i = 0; i < protocols_available; i++) {
3860 if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
3861 (
type != proto_buffers[i].iSocketType) ||
3862 (protocol != 0 && protocol != proto_buffers[i].iProtocol))
3865 if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
3868 out = WSASocket(af,
type, protocol, &(proto_buffers[i]), 0,
3869 WSA_FLAG_OVERLAPPED);
3872 if (out == INVALID_SOCKET)
3873 out = WSASocket(af,
type, protocol, NULL, 0, 0);
3874 if (out != INVALID_SOCKET)
3875 SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0);
3878 free(proto_buffers);
3889rb_w32_socket(
int af,
int type,
int protocol)
3895 s = open_ifs_socket(af,
type, protocol);
3896 if (s == INVALID_SOCKET) {
3897 errno = map_errno(WSAGetLastError());
3901 fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
3903 socklist_insert(s, MAKE_SOCKDATA(af, 0));
3914struct hostent * WSAAPI
3915rb_w32_gethostbyaddr(
const char *addr,
int len,
int type)
3919 r = gethostbyaddr(addr, len,
type);
3921 errno = map_errno(WSAGetLastError());
3929struct hostent * WSAAPI
3930rb_w32_gethostbyname(
const char *name)
3934 r = gethostbyname(name);
3936 errno = map_errno(WSAGetLastError());
3945rb_w32_gethostname(
char *name,
int len)
3949 r = gethostname(name, len);
3950 if (r == SOCKET_ERROR)
3951 errno = map_errno(WSAGetLastError());
3956#undef getprotobyname
3959struct protoent * WSAAPI
3960rb_w32_getprotobyname(
const char *name)
3964 r = getprotobyname(name);
3966 errno = map_errno(WSAGetLastError());
3971#undef getprotobynumber
3974struct protoent * WSAAPI
3975rb_w32_getprotobynumber(
int num)
3979 r = getprotobynumber(num);
3981 errno = map_errno(WSAGetLastError());
3989struct servent * WSAAPI
3990rb_w32_getservbyname(
const char *name,
const char *proto)
3994 r = getservbyname(name, proto);
3996 errno = map_errno(WSAGetLastError());
4004struct servent * WSAAPI
4005rb_w32_getservbyport(
int port,
const char *proto)
4009 r = getservbyport(port, proto);
4011 errno = map_errno(WSAGetLastError());
4018socketpair_internal(
int af,
int type,
int protocol, SOCKET *sv)
4020 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
4021 struct sockaddr_in sock_in4;
4023 struct sockaddr_in6 sock_in6;
4025 struct sockaddr *addr;
4031#if defined PF_INET && PF_INET != AF_INET
4034 sock_in4.sin_family = AF_INET;
4035 sock_in4.sin_port = 0;
4036 sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4037 addr = (
struct sockaddr *)&sock_in4;
4038 len =
sizeof(sock_in4);
4042 memset(&sock_in6, 0,
sizeof(sock_in6));
4043 sock_in6.sin6_family = AF_INET6;
4044 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
4045 addr = (
struct sockaddr *)&sock_in6;
4046 len =
sizeof(sock_in6);
4050 errno = EAFNOSUPPORT;
4053 if (
type != SOCK_STREAM) {
4058 sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
4059 sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
4062 svr = open_ifs_socket(af,
type, protocol);
4063 if (svr == INVALID_SOCKET)
4065 if (bind(svr, addr, len) < 0)
4067 if (getsockname(svr, addr, &len) < 0)
4069 if (
type == SOCK_STREAM)
4072 w = open_ifs_socket(af,
type, protocol);
4073 if (w == INVALID_SOCKET)
4075 if (connect(w, addr, len) < 0)
4078 r = accept(svr, addr, &len);
4079 if (r == INVALID_SOCKET)
4081 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
4087 errno = map_errno(WSAGetLastError());
4088 if (r != INVALID_SOCKET)
4090 if (w != INVALID_SOCKET)
4097 if (svr != INVALID_SOCKET)
4106socketpair(
int af,
int type,
int protocol,
int *sv)
4110 if (socketpair_internal(af,
type, protocol, pair) < 0)
4112 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
4114 closesocket(pair[0]);
4115 closesocket(pair[1]);
4118 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
4120 rb_w32_close(sv[0]);
4121 closesocket(pair[1]);
4124 socklist_insert(pair[0], MAKE_SOCKDATA(af, 0));
4125 socklist_insert(pair[1], MAKE_SOCKDATA(af, 0));
4130#if !defined(_MSC_VER) || _MSC_VER >= 1400
4133str2guid(
const char *str, GUID *guid)
4135#define hex2byte(str) \
4136 ((isdigit(*(str)) ? *(str) - '0' : toupper(*(str)) - 'A' + 10) << 4 | (isdigit(*((str) + 1)) ? *((str) + 1) - '0' : toupper(*((str) + 1)) - 'A' + 10))
4139 if (*str ==
'{') str++;
4140 guid->Data1 = (long)strtoul(str, &end, 16);
4142 guid->Data2 = (
unsigned short)strtoul(str, &end, 16);
4144 guid->Data3 = (
unsigned short)strtoul(str, &end, 16);
4146 guid->Data4[0] = hex2byte(str);
4148 guid->Data4[1] = hex2byte(str);
4150 for (i = 0; i < 6; i++) {
4151 guid->Data4[i + 2] = hex2byte(str);
4157#ifndef HAVE_TYPE_NET_LUID
4161 uint64_t Reserved :24;
4162 uint64_t NetLuidIndex :24;
4163 uint64_t IfType :16;
4167typedef DWORD (WINAPI *cigl_t)(
const GUID *,
NET_LUID *);
4168typedef DWORD (WINAPI *cilnA_t)(
const NET_LUID *,
char *, size_t);
4169static cigl_t pConvertInterfaceGuidToLuid = (cigl_t)-1;
4170static cilnA_t pConvertInterfaceLuidToNameA = (cilnA_t)-1;
4173getifaddrs(
struct ifaddrs **ifap)
4177 IP_ADAPTER_ADDRESSES *root, *addr;
4180 ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
4181 if (ret != ERROR_BUFFER_OVERFLOW) {
4182 errno = map_errno(ret);
4186 ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, root, &size);
4187 if (ret != ERROR_SUCCESS) {
4188 errno = map_errno(ret);
4193 if (pConvertInterfaceGuidToLuid == (cigl_t)-1)
4194 pConvertInterfaceGuidToLuid =
4195 (cigl_t)get_proc_address(
"iphlpapi.dll",
4196 "ConvertInterfaceGuidToLuid", NULL);
4197 if (pConvertInterfaceLuidToNameA == (cilnA_t)-1)
4198 pConvertInterfaceLuidToNameA =
4199 (cilnA_t)get_proc_address(
"iphlpapi.dll",
4200 "ConvertInterfaceLuidToNameA", NULL);
4202 for (prev = NULL, addr = root; addr; addr = addr->Next) {
4204 char name[IFNAMSIZ];
4209 prev->ifa_next = ifa;
4213 str2guid(addr->AdapterName, &guid);
4214 if (pConvertInterfaceGuidToLuid && pConvertInterfaceLuidToNameA &&
4215 pConvertInterfaceGuidToLuid(&guid, &luid) == NO_ERROR &&
4216 pConvertInterfaceLuidToNameA(&luid, name,
sizeof(name)) == NO_ERROR) {
4223 if (addr->IfType & IF_TYPE_SOFTWARE_LOOPBACK)
4224 ifa->ifa_flags |= IFF_LOOPBACK;
4225 if (addr->OperStatus == IfOperStatusUp) {
4226 ifa->ifa_flags |= IFF_UP;
4228 if (addr->FirstUnicastAddress) {
4229 IP_ADAPTER_UNICAST_ADDRESS *cur;
4231 for (cur = addr->FirstUnicastAddress; cur; cur = cur->Next) {
4232 if (cur->Flags & IP_ADAPTER_ADDRESS_TRANSIENT ||
4233 cur->DadState == IpDadStateDeprecated) {
4239 prev->ifa_next = ifa;
4241 ifa->ifa_flags = prev->ifa_flags;
4243 ifa->ifa_addr =
ruby_xmalloc(cur->Address.iSockaddrLength);
4244 memcpy(ifa->ifa_addr, cur->Address.lpSockaddr,
4245 cur->Address.iSockaddrLength);
4260freeifaddrs(
struct ifaddrs *ifp)
4263 struct ifaddrs *next = ifp->ifa_next;
4264 if (ifp->ifa_addr)
ruby_xfree(ifp->ifa_addr);
4265 if (ifp->ifa_name)
ruby_xfree(ifp->ifa_name);
4277void endhostent(
void) {}
4278void endnetent(
void) {}
4279void endprotoent(
void) {}
4280void endservent(
void) {}
4282struct netent *getnetent (
void) {
return (
struct netent *) NULL;}
4284struct netent *getnetbyaddr(
long net,
int type) {
return (
struct netent *)NULL;}
4286struct netent *getnetbyname(
const char *name) {
return (
struct netent *)NULL;}
4288struct protoent *getprotoent (
void) {
return (
struct protoent *) NULL;}
4290struct servent *getservent (
void) {
return (
struct servent *) NULL;}
4292void sethostent (
int stayopen) {}
4294void setnetent (
int stayopen) {}
4296void setprotoent (
int stayopen) {}
4298void setservent (
int stayopen) {}
4303setfl(SOCKET sock,
int arg)
4310 socklist_lookup(sock, &flag);
4311 af = GET_FAMILY(flag);
4312 flag = GET_FLAGS(flag);
4313 if (arg & O_NONBLOCK) {
4318 flag &= ~O_NONBLOCK;
4322 ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
4324 socklist_insert(sock, MAKE_SOCKDATA(af, flag));
4326 errno = map_errno(WSAGetLastError());
4334dupfd(HANDLE hDup,
int flags,
int minfd)
4342 ret = _open_osfhandle((intptr_t)hDup, flags | FOPEN);
4344 goto close_fds_and_return;
4347 goto close_fds_and_return;
4349 fds[filled++] = ret;
4350 }
while (filled < (
int)numberof(fds));
4352 ret = dupfd(hDup, flags, minfd);
4354 close_fds_and_return:
4356 while (filled > 0) {
4357 int fd = fds[--filled];
4358 _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
4368fcntl(
int fd,
int cmd, ...)
4376 SOCKET sock = TO_SOCKET(fd);
4377 if (!is_socket(sock)) {
4383 arg = va_arg(va,
int);
4385 return setfl(sock, arg);
4387 case F_DUPFD:
case F_DUPFD_CLOEXEC: {
4391 if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
4392 GetCurrentProcess(), &hDup, 0L,
4393 cmd == F_DUPFD && !(flag & FNOINHERIT),
4394 DUPLICATE_SAME_ACCESS))) {
4395 errno = map_errno(GetLastError());
4400 arg = va_arg(va,
int);
4406 flag &= ~FNOINHERIT;
4407 if ((ret = dupfd(hDup, flag, arg)) == -1)
4413 if (h == -1)
return -1;
4414 if (!GetHandleInformation((HANDLE)h, &flag)) {
4415 errno = map_errno(GetLastError());
4418 return (flag & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
4422 if (h == -1)
return -1;
4424 arg = va_arg(va,
int);
4426 if (!SetHandleInformation((HANDLE)h, HANDLE_FLAG_INHERIT,
4427 (arg & FD_CLOEXEC) ? 0 : HANDLE_FLAG_INHERIT)) {
4428 errno = map_errno(GetLastError());
4431 if (arg & FD_CLOEXEC)
4432 _osfile(fd) |= FNOINHERIT;
4434 _osfile(fd) &= ~FNOINHERIT;
4445rb_w32_set_nonblock2(
int fd,
int nonblock)
4447 SOCKET sock = TO_SOCKET(fd);
4448 if (is_socket(sock)) {
4449 return setfl(sock, nonblock ? O_NONBLOCK : 0);
4451 else if (is_pipe(sock)) {
4453 if (!GetNamedPipeHandleState((HANDLE)sock, &state, NULL, NULL, NULL, NULL, 0)) {
4454 errno = map_errno(GetLastError());
4458 state |= PIPE_NOWAIT;
4461 state &= ~PIPE_NOWAIT;
4463 if (!SetNamedPipeHandleState((HANDLE)sock, &state, NULL, NULL)) {
4464 errno = map_errno(GetLastError());
4476rb_w32_set_nonblock(
int fd)
4478 return rb_w32_set_nonblock2(fd, TRUE);
4487poll_child_status(
struct ChildRecord *child,
int *stat_loc)
4492 if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
4494 err = GetLastError();
4496 case ERROR_INVALID_PARAMETER:
4499 case ERROR_INVALID_HANDLE:
4503 errno = map_errno(err);
4507 CloseChildHandle(child);
4510 if (exitcode != STILL_ACTIVE) {
4513 if (rb_w32_wait_events_blocking(&child->hProcess, 1, INFINITE) != WAIT_OBJECT_0) {
4517 CloseChildHandle(child);
4519 *stat_loc = exitcode << 8;
4520 if (exitcode & 0xC0000000) {
4521 static const struct {
4525 {STATUS_ACCESS_VIOLATION, SIGSEGV},
4526 {STATUS_ILLEGAL_INSTRUCTION, SIGILL},
4527 {STATUS_PRIVILEGED_INSTRUCTION, SIGILL},
4528 {STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE},
4529 {STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE},
4530 {STATUS_FLOAT_INEXACT_RESULT, SIGFPE},
4531 {STATUS_FLOAT_INVALID_OPERATION, SIGFPE},
4532 {STATUS_FLOAT_OVERFLOW, SIGFPE},
4533 {STATUS_FLOAT_STACK_CHECK, SIGFPE},
4534 {STATUS_FLOAT_UNDERFLOW, SIGFPE},
4535#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
4536 {STATUS_FLOAT_MULTIPLE_FAULTS, SIGFPE},
4538#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
4539 {STATUS_FLOAT_MULTIPLE_TRAPS, SIGFPE},
4541 {STATUS_CONTROL_C_EXIT, SIGINT},
4544 for (i = 0; i < (int)numberof(table); i++) {
4545 if (table[i].status == exitcode) {
4546 *stat_loc |= table[i].sig;
4551 if (i >= (
int)numberof(table))
4552 *stat_loc |= SIGSEGV;
4562waitpid(rb_pid_t pid,
int *stat_loc,
int options)
4567 if (options == WNOHANG) {
4578 HANDLE events[MAXCHILDNUM];
4581 FOREACH_CHILD(child) {
4582 if (!child->pid || child->pid < 0)
continue;
4583 if ((pid = poll_child_status(child, stat_loc)))
return pid;
4584 events[count++] = child->hProcess;
4585 } END_FOREACH_CHILD;
4591 ret = rb_w32_wait_events_blocking(events, count, timeout);
4592 if (ret == WAIT_TIMEOUT)
return 0;
4593 if ((ret -= WAIT_OBJECT_0) == count) {
4597 errno = map_errno(GetLastError());
4601 cause = FindChildSlotByHandle(events[ret]);
4606 return poll_child_status(cause, stat_loc);
4616 while (!(pid = poll_child_status(child, stat_loc))) {
4618 int ret = rb_w32_wait_events_blocking(&child->hProcess, 1, timeout);
4619 if (ret == WAIT_OBJECT_0 + 1)
return -1;
4620 if (ret != WAIT_OBJECT_0) {
4622 if (options & WNOHANG) {
4629 if (pid == -1 && retried) pid = 0;
4635#include <sys/timeb.h>
4637static int have_precisetime = -1;
4640get_systemtime(FILETIME *ft)
4642 typedef void (WINAPI *get_time_func)(FILETIME *ft);
4643 static get_time_func func = (get_time_func)-1;
4645 if (func == (get_time_func)-1) {
4647 func = (get_time_func)get_proc_address(
"kernel32",
"GetSystemTimePreciseAsFileTime", NULL);
4649 func = GetSystemTimeAsFileTime;
4650 have_precisetime = 0;
4653 have_precisetime = 1;
4662filetime_split(
const FILETIME* ft,
long *subsec)
4668 tmp.LowPart = ft->dwLowDateTime;
4669 tmp.HighPart = ft->dwHighDateTime;
4676 lt -= (
LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * subsec_unit;
4678 *subsec = (long)(lt % subsec_unit);
4679 return (time_t)(lt / subsec_unit);
4689 get_systemtime(&ft);
4690 tv->tv_sec = filetime_split(&ft, &subsec);
4691 tv->tv_usec = subsec / 10;
4698clock_gettime(clockid_t clock_id,
struct timespec *sp)
4701 case CLOCK_REALTIME:
4706 get_systemtime(&ft);
4707 sp->tv_sec = filetime_split(&ft, &subsec);
4708 sp->tv_nsec = subsec * 100;
4711 case CLOCK_MONOTONIC:
4714 LARGE_INTEGER count;
4715 if (!QueryPerformanceFrequency(&freq)) {
4716 errno = map_errno(GetLastError());
4719 if (!QueryPerformanceCounter(&count)) {
4720 errno = map_errno(GetLastError());
4723 sp->tv_sec = count.QuadPart / freq.QuadPart;
4724 if (freq.QuadPart < 1000000000)
4725 sp->tv_nsec = (count.QuadPart % freq.QuadPart) * 1000000000 / freq.QuadPart;
4727 sp->tv_nsec = (
long)((count.QuadPart % freq.QuadPart) * (1000000000.0 / freq.QuadPart));
4738clock_getres(clockid_t clock_id,
struct timespec *sp)
4741 case CLOCK_REALTIME:
4747 case CLOCK_MONOTONIC:
4750 if (!QueryPerformanceFrequency(&freq)) {
4751 errno = map_errno(GetLastError());
4755 sp->tv_nsec = (long)(1000000000.0 / freq.QuadPart);
4766w32_getcwd(
char *buffer,
int size, UINT cp,
void *alloc(
int,
void *),
void *arg)
4771 len = GetCurrentDirectoryW(0, NULL);
4773 errno = map_errno(GetLastError());
4777 if (buffer && size < len) {
4783 if (!GetCurrentDirectoryW(len, p)) {
4784 errno = map_errno(GetLastError());
4788 wlen = translate_wchar(p, L
'\\', L
'/') - p + 1;
4789 len = WideCharToMultiByte(cp, 0, p, wlen, NULL, 0, NULL, NULL);
4797 buffer = (*alloc)(len, arg);
4803 WideCharToMultiByte(cp, 0, p, wlen, buffer, len, NULL, NULL);
4810getcwd_alloc(
int size,
void *dummy)
4812 return malloc(size);
4817rb_w32_getcwd(
char *buffer,
int size)
4819 return w32_getcwd(buffer, size, filecp(), getcwd_alloc, NULL);
4824rb_w32_ugetcwd(
char *buffer,
int size)
4826 return w32_getcwd(buffer, size, CP_UTF8, getcwd_alloc, NULL);
4831getcwd_value(
int size,
void *arg)
4839rb_dir_getwd_ospath(
void)
4842 w32_getcwd(NULL, 0, CP_UTF8, getcwd_value, &cwd);
4848chown(
const char *path,
int owner,
int group)
4855rb_w32_uchown(
const char *path,
int owner,
int group)
4861lchown(
const char *path,
int owner,
int group)
4867rb_w32_ulchown(
const char *path,
int owner,
int group)
4874kill(
int pid,
int sig)
4879 if (pid < 0 || (pid == 0 && sig != SIGINT)) {
4884 if ((
unsigned int)pid == GetCurrentProcessId() &&
4885 (sig != 0 && sig != SIGKILL)) {
4886 if ((ret =
raise(sig)) != 0) {
4897 OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
4898 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
4899 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4915 DWORD ctrlEvent = CTRL_C_EVENT;
4919 ctrlEvent = CTRL_BREAK_EVENT;
4921 if (!GenerateConsoleCtrlEvent(ctrlEvent, (DWORD)pid)) {
4922 if ((err = GetLastError()) == 0)
4925 errno = map_errno(GetLastError());
4936 hProc = child->hProcess;
4939 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
4941 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
4942 if (GetLastError() == ERROR_INVALID_PARAMETER) {
4952 if (!GetExitCodeProcess(hProc, &status)) {
4953 errno = map_errno(GetLastError());
4956 else if (status == STILL_ACTIVE) {
4957 if (!TerminateProcess(hProc, 0)) {
4984wlink(
const WCHAR *from,
const WCHAR *to)
4986 if (!CreateHardLinkW(to, from, NULL)) {
4987 errno = map_errno(GetLastError());
4996rb_w32_ulink(
const char *from,
const char *to)
5002 if (!(wfrom = utf8_to_wstr(from, NULL)))
5004 if (!(wto = utf8_to_wstr(to, NULL))) {
5008 ret = wlink(wfrom, wto);
5016link(
const char *from,
const char *to)
5022 if (!(wfrom = filecp_to_wstr(from, NULL)))
5024 if (!(wto = filecp_to_wstr(to, NULL))) {
5028 ret = wlink(wfrom, wto);
5035#ifndef FILE_DEVICE_FILE_SYSTEM
5036# define FILE_DEVICE_FILE_SYSTEM 0x00000009
5038#ifndef FSCTL_GET_REPARSE_POINT
5039# define FSCTL_GET_REPARSE_POINT ((0x9<<16)|(42<<2))
5041#ifndef IO_REPARSE_TAG_SYMLINK
5042# define IO_REPARSE_TAG_SYMLINK 0xA000000CL
5053 f = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5054 if (f == INVALID_HANDLE_VALUE) {
5055 return GetLastError();
5058 if (!DeviceIoControl(f, FSCTL_GET_REPARSE_POINT, NULL, 0,
5059 rp, size, &ret, NULL)) {
5062 else if (rp->ReparseTag != IO_REPARSE_TAG_SYMLINK &&
5063 rp->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
5064 e = ERROR_INVALID_PARAMETER;
5072rb_w32_reparse_symlink_p(
const WCHAR *path)
5080 e = rb_w32_read_reparse_point(path, rp,
sizeof(rbuf), &wbuf, &len);
5081 if (e == ERROR_MORE_DATA) {
5082 size_t size = rb_w32_reparse_buffer_size(len + 1);
5084 e = rb_w32_read_reparse_point(path, rp, size, &wbuf, &len);
5089 case ERROR_MORE_DATA:
5098 size_t bufsize, WCHAR **result, DWORD *len)
5100 int e = reparse_symlink(path, rp, bufsize);
5103 if (!e || e == ERROR_MORE_DATA) {
5105 if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
5106 name = ((
char *)rp->SymbolicLinkReparseBuffer.PathBuffer +
5107 rp->SymbolicLinkReparseBuffer.PrintNameOffset);
5108 ret = rp->SymbolicLinkReparseBuffer.PrintNameLength;
5109 *len = ret /
sizeof(WCHAR);
5111 else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
5112 static const WCHAR volume[] = L
"Volume{";
5114 name = ((
char *)rp->MountPointReparseBuffer.PathBuffer +
5115 rp->MountPointReparseBuffer.SubstituteNameOffset +
5116 volume_prefix_len *
sizeof(WCHAR));
5117 ret = rp->MountPointReparseBuffer.SubstituteNameLength;
5118 *len = ret /
sizeof(WCHAR);
5119 ret -= volume_prefix_len *
sizeof(WCHAR);
5120 if (ret >
sizeof(volume) - 1 *
sizeof(WCHAR) &&
5121 memcmp(name, volume,
sizeof(volume) - 1 *
sizeof(WCHAR)) == 0)
5129 if ((
char *)name + ret +
sizeof(WCHAR) > (
char *)rp + bufsize)
5133 ((WCHAR *)name)[ret/
sizeof(WCHAR)] = L
'\0';
5134 translate_wchar(name, L
'\\', L
'/');
5144w32_readlink(UINT cp,
const char *path,
char *buf,
size_t bufsize)
5147 DWORD len = MultiByteToWideChar(cp, 0, path, -1, NULL, 0);
5148 size_t size = rb_w32_reparse_buffer_size(len);
5149 WCHAR *wname, *wpath =
ALLOCV(wtmp, size +
sizeof(WCHAR) * len);
5154 MultiByteToWideChar(cp, 0, path, -1, wpath, len);
5155 e = rb_w32_read_reparse_point(wpath, rp, size, &wname, &len);
5156 if (e && e != ERROR_MORE_DATA) {
5158 errno = map_errno(e);
5161 len = lstrlenW(wname) + 1;
5162 ret = WideCharToMultiByte(cp, 0, wname, len, buf, bufsize, NULL, NULL);
5169 errno = map_errno(e);
5177rb_w32_ureadlink(
const char *path,
char *buf,
size_t bufsize)
5179 return w32_readlink(CP_UTF8, path, buf, bufsize);
5184readlink(
const char *path,
char *buf,
size_t bufsize)
5186 return w32_readlink(filecp(), path, buf, bufsize);
5189#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
5190#define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1)
5192#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
5193#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
5198w32_symlink(UINT cp,
const char *src,
const char *link)
5200 int atts, len1, len2;
5202 WCHAR *wsrc, *wlink;
5207 typedef BOOLEAN (WINAPI *create_symbolic_link_func)(WCHAR*, WCHAR*, DWORD);
5208 static create_symbolic_link_func create_symbolic_link =
5209 (create_symbolic_link_func)-1;
5210 static DWORD create_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
5212 if (create_symbolic_link == (create_symbolic_link_func)-1) {
5214 create_symbolic_link = (create_symbolic_link_func)
5215 get_proc_address(
"kernel32",
"CreateSymbolicLinkW", NULL);
5217 if (!create_symbolic_link) {
5230 len1 = MultiByteToWideChar(cp, 0, src, -1, NULL, 0);
5231 len2 = MultiByteToWideChar(cp, 0, link, -1, NULL, 0);
5232 wsrc =
ALLOCV_N(WCHAR, buf, len1+len2);
5233 wlink = wsrc + len1;
5234 MultiByteToWideChar(cp, 0, src, -1, wsrc, len1);
5235 MultiByteToWideChar(cp, 0, link, -1, wlink, len2);
5236 translate_wchar(wsrc, L
'/', L
'\\');
5238 atts = GetFileAttributesW(wsrc);
5239 if (atts != -1 && atts & FILE_ATTRIBUTE_DIRECTORY)
5240 flag = SYMBOLIC_LINK_FLAG_DIRECTORY;
5241 ret = create_symbolic_link(wlink, wsrc, flag |= create_flag);
5243 (e = GetLastError()) == ERROR_INVALID_PARAMETER &&
5244 (flag & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) {
5246 flag &= ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
5247 ret = create_symbolic_link(wlink, wsrc, flag);
5248 if (!ret) e = GetLastError();
5253 errno = map_errno(e);
5261rb_w32_usymlink(
const char *src,
const char *link)
5263 return w32_symlink(CP_UTF8, src, link);
5268symlink(
const char *src,
const char *link)
5270 return w32_symlink(filecp(), src, link);
5277 return waitpid(-1, status, 0);
5282w32_getenv(
const char *name, UINT cp)
5284 WCHAR *wenvarea, *wenv;
5285 int len = strlen(name);
5286 char *env, *found = NULL;
5289 if (len == 0)
return NULL;
5294 return getenv(name);
5297 thread_exclusive(uenvarea) {
5302 wenvarea = GetEnvironmentStringsW();
5304 map_errno(GetLastError());
5307 for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
5308 wlen += lstrlenW(wenv) + 1;
5309 uenvarea = wstr_to_mbstr(cp, wenvarea, wlen, NULL);
5310 FreeEnvironmentStringsW(wenvarea);
5314 for (env = uenvarea; *env; env += strlen(env) + 1) {
5315 if (strncasecmp(env, name, len) == 0 && *(env + len) ==
'=') {
5316 found = env + len + 1;
5327rb_w32_ugetenv(
const char *name)
5329 return w32_getenv(name, CP_UTF8);
5334rb_w32_getenv(
const char *name)
5336 return w32_getenv(name, CP_ACP);
5341get_attr_vsn(
const WCHAR *path, DWORD *atts, DWORD *vsn)
5343 BY_HANDLE_FILE_INFORMATION st = {0};
5345 HANDLE h = open_special(path, 0, FILE_FLAG_OPEN_REPARSE_POINT);
5347 if (h == INVALID_HANDLE_VALUE) {
5352 if (!GetFileInformationByHandle(h, &st)) {
5357 *atts = st.dwFileAttributes;
5358 *vsn = st.dwVolumeSerialNumber;
5366wrename(
const WCHAR *oldpath,
const WCHAR *newpath)
5369 DWORD oldatts = 0, newatts = (DWORD)-1;
5370 DWORD oldvsn = 0, newvsn = 0, e;
5372 e = get_attr_vsn(oldpath, &oldatts, &oldvsn);
5374 errno = map_errno(e);
5377 if (oldatts & FILE_ATTRIBUTE_REPARSE_POINT) {
5378 HANDLE fh = open_special(oldpath, 0, 0);
5379 if (fh == INVALID_HANDLE_VALUE) {
5381 if (e == ERROR_CANT_RESOLVE_FILENAME) {
5388 get_attr_vsn(newpath, &newatts, &newvsn);
5391 if (newatts != (DWORD)-1 && newatts & FILE_ATTRIBUTE_READONLY)
5392 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
5394 if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
5398 DWORD e = GetLastError();
5399 if ((e == ERROR_ACCESS_DENIED) && (oldatts & FILE_ATTRIBUTE_DIRECTORY) &&
5403 errno = map_errno(e);
5406 SetFileAttributesW(newpath, oldatts);
5413int rb_w32_urename(
const char *from,
const char *to)
5419 if (!(wfrom = utf8_to_wstr(from, NULL)))
5421 if (!(wto = utf8_to_wstr(to, NULL))) {
5425 ret = wrename(wfrom, wto);
5432int rb_w32_rename(
const char *from,
const char *to)
5438 if (!(wfrom = filecp_to_wstr(from, NULL)))
5440 if (!(wto = filecp_to_wstr(to, NULL))) {
5444 ret = wrename(wfrom, wto);
5452isUNCRoot(
const WCHAR *path)
5454 if (path[0] == L
'\\' && path[1] == L
'\\') {
5455 const WCHAR *p = path + 2;
5456 if (p[0] == L
'?' && p[1] == L
'\\') {
5464 for (p++; *p; p++) {
5468 if (!p[0] || !p[1] || (p[1] == L
'.' && !p[2]))
5475#define COPY_STAT(src, dest, size_cast) do { \
5476 (dest).st_dev = (src).st_dev; \
5477 (dest).st_ino = (src).st_ino; \
5478 (dest).st_mode = (src).st_mode; \
5479 (dest).st_nlink = (src).st_nlink; \
5480 (dest).st_uid = (src).st_uid; \
5481 (dest).st_gid = (src).st_gid; \
5482 (dest).st_rdev = (src).st_rdev; \
5483 (dest).st_size = size_cast(src).st_size; \
5484 (dest).st_atime = (src).st_atime; \
5485 (dest).st_mtime = (src).st_mtime; \
5486 (dest).st_ctime = (src).st_ctime; \
5489static time_t filetime_to_unixtime(
const FILETIME *ft);
5490static long filetime_to_nsec(
const FILETIME *ft);
5491static WCHAR *name_for_stat(WCHAR *buf,
const WCHAR *path);
5492static DWORD stati128_handle(HANDLE h,
struct stati128 *st);
5497rb_w32_fstat(
int fd,
struct stat *st)
5499 BY_HANDLE_FILE_INFORMATION info;
5500 int ret = fstat(fd, st);
5502 if (ret)
return ret;
5503 if (GetEnvironmentVariableW(L
"TZ", NULL, 0) == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return ret;
5504 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
5505 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5506 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5507 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5514rb_w32_fstati128(
int fd,
struct stati128 *st)
5517 int ret = fstat(fd, &tmp);
5519 if (ret)
return ret;
5520 COPY_STAT(tmp, *st, +);
5521 stati128_handle((HANDLE)_get_osfhandle(fd), st);
5525#if !defined FILE_INVALID_FILE_ID && !defined __MINGW32__
5527 BYTE Identifier[16];
5531#if !defined(_WIN32_WINNT_WIN8) || _WIN32_WINNT < 0x602
5532#define FileIdInfo 0x12
5543 typedef BOOL (WINAPI *gfibhe_t)(HANDLE, int,
void *, DWORD);
5544 static gfibhe_t pGetFileInformationByHandleEx = (gfibhe_t)-1;
5546 if (pGetFileInformationByHandleEx == (gfibhe_t)-1)
5548 pGetFileInformationByHandleEx = (gfibhe_t)get_proc_address(
"kernel32",
"GetFileInformationByHandleEx", NULL);
5550 if (pGetFileInformationByHandleEx) {
5551 if (pGetFileInformationByHandleEx(h, FileIdInfo,
id,
sizeof(*
id)))
5554 return GetLastError();
5556 return ERROR_INVALID_PARAMETER;
5561stati128_handle(HANDLE h,
struct stati128 *st)
5563 BY_HANDLE_FILE_INFORMATION info;
5564 DWORD attr = (DWORD)-1;
5566 if (GetFileInformationByHandle(h, &info)) {
5568 st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
5569 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
5570 st->st_atimensec = filetime_to_nsec(&info.ftLastAccessTime);
5571 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
5572 st->st_mtimensec = filetime_to_nsec(&info.ftLastWriteTime);
5573 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
5574 st->st_ctimensec = filetime_to_nsec(&info.ftCreationTime);
5575 st->st_nlink = info.nNumberOfLinks;
5576 attr = info.dwFileAttributes;
5577 if (!get_ino(h, &fii)) {
5578 st->st_ino = *((
unsigned __int64 *)&fii.FileId);
5579 st->st_inohigh = *((__int64 *)&fii.FileId + 1);
5582 st->st_ino = ((__int64)info.nFileIndexHigh << 32) | info.nFileIndexLow;
5591filetime_to_unixtime(
const FILETIME *ft)
5594 time_t t = filetime_split(ft, &subsec);
5596 if (t < 0)
return 0;
5602filetime_to_nsec(
const FILETIME *ft)
5604 if (have_precisetime <= 0)
5608 tmp.LowPart = ft->dwLowDateTime;
5609 tmp.HighPart = ft->dwHighDateTime;
5610 return (
long)(tmp.QuadPart % 10000000) * 100;
5616fileattr_to_unixmode(DWORD attr,
const WCHAR *path,
unsigned mode)
5618 if (attr & FILE_ATTRIBUTE_READONLY) {
5622 mode |= S_IREAD | S_IWRITE | S_IWUSR;
5625 if (mode & S_IFMT) {
5628 else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5629 if (rb_w32_reparse_symlink_p(path))
5630 mode |= S_IFLNK | S_IEXEC;
5632 mode |= S_IFDIR | S_IEXEC;
5634 else if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5635 mode |= S_IFDIR | S_IEXEC;
5641 if (path && (mode & S_IFREG)) {
5642 const WCHAR *end = path + lstrlenW(path);
5643 while (path < end) {
5644 end = CharPrevW(path, end);
5646 if ((_wcsicmp(end, L
".bat") == 0) ||
5647 (_wcsicmp(end, L
".cmd") == 0) ||
5648 (_wcsicmp(end, L
".com") == 0) ||
5649 (_wcsicmp(end, L
".exe") == 0)) {
5654 if (!iswalnum(*end))
break;
5658 mode |= (mode & 0500) >> 3;
5659 mode |= (mode & 0500) >> 6;
5666check_valid_dir(
const WCHAR *path)
5668 WIN32_FIND_DATAW fd;
5670 WCHAR full[PATH_MAX];
5676 if (!(p = wcsstr(path, L
"...")))
5678 q = p + wcsspn(p, L
".");
5679 if ((p == path || wcschr(L
":/\\", *(p - 1))) &&
5680 (!*q || wcschr(L
":/\\", *q))) {
5687 if (!GetFullPathNameW(path,
sizeof(full) /
sizeof(WCHAR), full, &dmy)) {
5688 errno = map_errno(GetLastError());
5691 if (full[1] == L
':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
5694 fh = open_dir_handle(path, &fd);
5695 if (fh == INVALID_HANDLE_VALUE)
5703stat_by_find(
const WCHAR *path,
struct stati128 *st)
5706 WIN32_FIND_DATAW wfd;
5708 int e = GetLastError();
5710 if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
5711 || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
5712 errno = map_errno(e);
5717 h = FindFirstFileW(path, &wfd);
5718 if (h == INVALID_HANDLE_VALUE) {
5719 errno = map_errno(GetLastError());
5723 st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path, 0);
5724 st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
5725 st->st_atimensec = filetime_to_nsec(&wfd.ftLastAccessTime);
5726 st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
5727 st->st_mtimensec = filetime_to_nsec(&wfd.ftLastWriteTime);
5728 st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
5729 st->st_ctimensec = filetime_to_nsec(&wfd.ftCreationTime);
5730 st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
5737path_drive(
const WCHAR *path)
5739 return (iswalpha(path[0]) && path[1] == L
':') ?
5740 towupper(path[0]) - L
'A' : _getdrive() - 1;
5745winnt_stat(
const WCHAR *path,
struct stati128 *st, BOOL lstat)
5747 DWORD flags = lstat ? FILE_FLAG_OPEN_REPARSE_POINT : 0;
5749 WCHAR finalname[PATH_MAX];
5751 memset(st, 0,
sizeof(*st));
5752 f = open_special(path, 0, flags);
5753 if (f != INVALID_HANDLE_VALUE) {
5754 DWORD attr = stati128_handle(f, st);
5755 const DWORD len = get_final_path(f, finalname, numberof(finalname), 0);
5757 switch (GetFileType(f)) {
5758 case FILE_TYPE_CHAR:
5761 case FILE_TYPE_PIPE:
5766 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
5768 if (rb_w32_reparse_symlink_p(path))
5771 attr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
5773 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
5774 if (check_valid_dir(path))
return -1;
5776 st->st_mode = fileattr_to_unixmode(attr, path, mode);
5778 finalname[min(len, numberof(finalname)-1)] = L
'\0';
5780 if (wcsncmp(path, namespace_prefix, numberof(namespace_prefix)) == 0)
5781 path += numberof(namespace_prefix);
5785 if (stat_by_find(path, st))
return -1;
5788 st->st_dev = st->st_rdev = path_drive(path);
5795rb_w32_stat(
const char *path,
struct stat *st)
5799 if (w32_stati128(path, &tmp, filecp(), FALSE))
return -1;
5800 COPY_STAT(tmp, *st, (_off_t));
5806wstati128(
const WCHAR *path,
struct stati128 *st, BOOL lstat)
5816 size = lstrlenW(path) + 2;
5818 if (!(path = name_for_stat(buf1, path)))
5820 ret = winnt_stat(path, st, lstat);
5829name_for_stat(WCHAR *buf1,
const WCHAR *path)
5835 for (p = path, s = buf1; *p; p++, s++) {
5843 if (!len || L
'\"' == *(--s)) {
5847 end = buf1 + len - 1;
5849 if (isUNCRoot(buf1)) {
5852 else if (*end != L
'\\')
5853 lstrcatW(buf1, L
"\\");
5855 else if (*end == L
'\\' || (buf1 + 1 == end && *end == L
':'))
5856 lstrcatW(buf1, L
".");
5863rb_w32_ustati128(
const char *path,
struct stati128 *st)
5865 return w32_stati128(path, st, CP_UTF8, FALSE);
5870rb_w32_stati128(
const char *path,
struct stati128 *st)
5872 return w32_stati128(path, st, filecp(), FALSE);
5877w32_stati128(
const char *path,
struct stati128 *st, UINT cp, BOOL lstat)
5882 if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
5884 ret = wstati128(wpath, st, lstat);
5891rb_w32_ulstati128(
const char *path,
struct stati128 *st)
5893 return w32_stati128(path, st, CP_UTF8, TRUE);
5898rb_w32_lstati128(
const char *path,
struct stati128 *st)
5900 return w32_stati128(path, st, filecp(), TRUE);
5905rb_w32_lseek(
int fd, off_t ofs,
int whence)
5907 SOCKET sock = TO_SOCKET(fd);
5908 if (is_socket(sock) || is_pipe(sock)) {
5912 return _lseeki64(fd, ofs, whence);
5917w32_access(
const char *path,
int mode, UINT cp)
5920 if (w32_stati128(path, &
stat, cp, FALSE) != 0)
5923 if ((
stat.st_mode & mode) != mode) {
5932rb_w32_access(
const char *path,
int mode)
5934 return w32_access(path, mode, filecp());
5939rb_w32_uaccess(
const char *path,
int mode)
5941 return w32_access(path, mode, CP_UTF8);
5946rb_chsize(HANDLE h, off_t size)
5948 long upos, lpos, usize, lsize;
5952 if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
5953 (e = GetLastError())) {
5954 errno = map_errno(e);
5957 usize = (long)(size >> 32);
5959 if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L &&
5960 (e = GetLastError())) {
5961 errno = map_errno(e);
5963 else if (!SetEndOfFile(h)) {
5964 errno = map_errno(GetLastError());
5969 SetFilePointer(h, lpos, &upos, SEEK_SET);
5975w32_truncate(
const char *path, off_t length, UINT cp)
5981 if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
5983 h = CreateFileW(wpath, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
5984 if (h == INVALID_HANDLE_VALUE) {
5985 errno = map_errno(GetLastError());
5990 ret = rb_chsize(h, length);
5997rb_w32_utruncate(
const char *path, off_t length)
5999 return w32_truncate(path, length, CP_UTF8);
6004rb_w32_truncate(
const char *path, off_t length)
6006 return w32_truncate(path, length, filecp());
6011rb_w32_ftruncate(
int fd, off_t length)
6015 h = (HANDLE)_get_osfhandle(fd);
6016 if (h == (HANDLE)-1)
return -1;
6017 return rb_chsize(h, length);
6022filetime_to_clock(FILETIME *ft)
6024 __int64 qw = ft->dwHighDateTime;
6026 qw |= ft->dwLowDateTime;
6033rb_w32_times(
struct tms *tmbuf)
6035 FILETIME create, exit, kernel, user;
6037 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
6038 tmbuf->tms_utime = filetime_to_clock(&user);
6039 tmbuf->tms_stime = filetime_to_clock(&kernel);
6040 tmbuf->tms_cutime = 0;
6041 tmbuf->tms_cstime = 0;
6044 tmbuf->tms_utime = clock();
6045 tmbuf->tms_stime = 0;
6046 tmbuf->tms_cutime = 0;
6047 tmbuf->tms_cstime = 0;
6054#define yield_once() Sleep(0)
6055#define yield_until(condition) do yield_once(); while (!(condition))
6064 uintptr_t (*func)(uintptr_t
self,
int argc, uintptr_t* argv);
6072call_asynchronous(PVOID argp)
6076 arg->stackaddr = &argp;
6077 ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
6078 arg->errnum = errno;
6084rb_w32_asynchronize(asynchronous_func_t func, uintptr_t
self,
6085 int argc, uintptr_t* argv, uintptr_t intrval)
6088 BOOL interrupted = FALSE;
6094 arg.stackaddr = NULL;
6101 thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
6104 yield_until(arg.stackaddr);
6106 if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
6109 if (TerminateThread(thr, intrval)) {
6114 GetExitCodeThread(thr, &val);
6119 MEMORY_BASIC_INFORMATION m;
6121 memset(&m, 0,
sizeof(m));
6122 if (!VirtualQuery(arg.stackaddr, &m,
sizeof(m))) {
6123 Debug(fprintf(stderr,
"couldn't get stack base:%p:%d\n",
6124 arg.stackaddr, GetLastError()));
6126 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
6127 Debug(fprintf(stderr,
"couldn't release stack:%p:%d\n",
6128 m.AllocationBase, GetLastError()));
6139 rb_fatal(
"failed to launch waiter thread:%ld", GetLastError());
6147rb_w32_get_environ(
void)
6149 WCHAR *envtop, *env;
6150 char **myenvtop, **myenv;
6163 envtop = GetEnvironmentStringsW();
6164 for (env = envtop, num = 0; *env; env += lstrlenW(env) + 1)
6165 if (*env !=
'=') num++;
6167 myenvtop = (
char **)malloc(
sizeof(
char *) * (num + 1));
6168 for (env = envtop, myenv = myenvtop; *env; env += lstrlenW(env) + 1) {
6170 if (!(*myenv = wstr_to_utf8(env, NULL))) {
6177 FreeEnvironmentStringsW(envtop);
6184rb_w32_free_environ(
char **env)
6188 while (*t) free(*t++);
6196 return GetCurrentProcessId();
6204 typedef long (WINAPI query_func)(HANDLE, int,
void *, ULONG, ULONG *);
6205 static query_func *pNtQueryInformationProcess = (query_func *)-1;
6208 if (pNtQueryInformationProcess == (query_func *)-1)
6209 pNtQueryInformationProcess = (query_func *)get_proc_address(
"ntdll.dll",
"NtQueryInformationProcess", NULL);
6210 if (pNtQueryInformationProcess) {
6213 void* PebBaseAddress;
6214 uintptr_t AffinityMask;
6215 uintptr_t BasePriority;
6216 uintptr_t UniqueProcessId;
6217 uintptr_t ParentProcessId;
6220 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi,
sizeof(pbi), &len);
6222 ppid = pbi.ParentProcessId;
6229STATIC_ASSERT(std_handle, (STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)==(STD_ERROR_HANDLE-STD_OUTPUT_HANDLE));
6232#define set_new_std_handle(newfd, handle) do { \
6233 if ((unsigned)(newfd) > 2) break; \
6234 SetStdHandle(STD_INPUT_HANDLE+(STD_OUTPUT_HANDLE-STD_INPUT_HANDLE)*(newfd), \
6237#define set_new_std_fd(newfd) set_new_std_handle(newfd, (HANDLE)rb_w32_get_osfhandle(newfd))
6241rb_w32_dup2(
int oldfd,
int newfd)
6245 if (oldfd == newfd)
return newfd;
6246 ret = dup2(oldfd, newfd);
6247 if (ret < 0)
return ret;
6248 set_new_std_fd(newfd);
6254rb_w32_uopen(
const char *file,
int oflag, ...)
6261 va_start(arg, oflag);
6262 pmode = va_arg(arg,
int);
6265 if (!(wfile = utf8_to_wstr(file, NULL)))
6267 ret = w32_wopen(wfile, oflag, pmode);
6274check_if_wdir(
const WCHAR *wfile)
6276 DWORD attr = GetFileAttributesW(wfile);
6277 if (attr == (DWORD)-1L ||
6278 !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
6279 check_valid_dir(wfile)) {
6288rb_w32_open(
const char *file,
int oflag, ...)
6295 va_start(arg, oflag);
6296 pmode = va_arg(arg,
int);
6299 if (!(wfile = filecp_to_wstr(file, NULL)))
6301 ret = w32_wopen(wfile, oflag, pmode);
6308rb_w32_wopen(
const WCHAR *file,
int oflag, ...)
6312 if (oflag & O_CREAT) {
6314 va_start(arg, oflag);
6315 pmode = va_arg(arg,
int);
6319 return w32_wopen(file, oflag, pmode);
6323w32_wopen(
const WCHAR *file,
int oflag,
int pmode)
6329 DWORD attr = FILE_ATTRIBUTE_NORMAL;
6330 SECURITY_ATTRIBUTES sec;
6334 share_delete = oflag & O_SHARE_DELETE ? FILE_SHARE_DELETE : 0;
6335 oflag &= ~O_SHARE_DELETE;
6336 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
6337 fd = _wopen(file, oflag, pmode);
6341 check_if_wdir(file);
6344 errno = map_errno(GetLastError());
6351 sec.nLength =
sizeof(sec);
6352 sec.lpSecurityDescriptor = NULL;
6353 if (oflag & O_NOINHERIT) {
6354 sec.bInheritHandle = FALSE;
6355 flags |= FNOINHERIT;
6358 sec.bInheritHandle = TRUE;
6360 oflag &= ~O_NOINHERIT;
6363 oflag &= ~(O_BINARY | O_TEXT);
6365 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
6367 access = GENERIC_READ | GENERIC_WRITE;
6370 access = GENERIC_READ;
6373 access = GENERIC_WRITE;
6379 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
6381 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
6383 create = OPEN_ALWAYS;
6387 create = OPEN_EXISTING;
6389 case O_CREAT | O_EXCL:
6390 case O_CREAT | O_EXCL | O_TRUNC:
6391 create = CREATE_NEW;
6394 case O_TRUNC | O_EXCL:
6395 create = TRUNCATE_EXISTING;
6397 case O_CREAT | O_TRUNC:
6398 create = CREATE_ALWAYS;
6404 if (oflag & O_CREAT) {
6406 if (!(pmode & S_IWRITE))
6407 attr = FILE_ATTRIBUTE_READONLY;
6409 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
6411 if (oflag & O_TEMPORARY) {
6412 attr |= FILE_FLAG_DELETE_ON_CLOSE;
6415 oflag &= ~O_TEMPORARY;
6417 if (oflag & _O_SHORT_LIVED)
6418 attr |= FILE_ATTRIBUTE_TEMPORARY;
6419 oflag &= ~_O_SHORT_LIVED;
6421 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
6425 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
6428 attr |= FILE_FLAG_RANDOM_ACCESS;
6434 oflag &= ~(O_SEQUENTIAL | O_RANDOM);
6436 if (oflag & ~O_APPEND) {
6443 h = CreateFile(
"NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
6444 fd = _open_osfhandle((intptr_t)h, 0);
6452 rb_acrt_lowio_lock_fh(fd);
6453 _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
6454 _set_osflags(fd, 0);
6456 h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE | share_delete, &sec, create, attr, NULL);
6457 if (h == INVALID_HANDLE_VALUE) {
6458 DWORD e = GetLastError();
6459 if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
6460 errno = map_errno(e);
6461 rb_acrt_lowio_unlock_fh(fd);
6466 switch (GetFileType(h)) {
6467 case FILE_TYPE_CHAR:
6470 case FILE_TYPE_PIPE:
6473 case FILE_TYPE_UNKNOWN:
6474 errno = map_errno(GetLastError());
6476 rb_acrt_lowio_unlock_fh(fd);
6480 if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
6483 _set_osfhnd(fd, (intptr_t)h);
6484 _set_osflags(fd, flags | FOPEN);
6486 rb_acrt_lowio_unlock_fh(fd);
6496rb_w32_fclose(
FILE *fp)
6498 int fd = fileno(fp);
6499 SOCKET sock = TO_SOCKET(fd);
6500 int save_errno = errno;
6502 if (fflush(fp))
return -1;
6503 if (!is_socket(sock)) {
6504 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
6507 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
6510 if (closesocket(sock) == SOCKET_ERROR) {
6511 errno = map_errno(WSAGetLastError());
6519rb_w32_pipe(
int fds[2])
6521 static long serial = 0;
6522 static const char prefix[] =
"\\\\.\\pipe\\ruby";
6524 width_of_prefix = (int)
sizeof(prefix) - 1,
6525 width_of_pid = (int)
sizeof(rb_pid_t) * 2,
6526 width_of_serial = (int)
sizeof(serial) * 2,
6527 width_of_ids = width_of_pid + 1 + width_of_serial + 1
6529 char name[
sizeof(prefix) + width_of_ids];
6530 SECURITY_ATTRIBUTES sec;
6531 HANDLE hRead, hWrite, h;
6532 int fdRead, fdWrite;
6535 memcpy(name, prefix, width_of_prefix);
6536 snprintf(name + width_of_prefix, width_of_ids,
"%.*"PRI_PIDT_PREFIX"x-%.*lx",
6537 width_of_pid, rb_w32_getpid(), width_of_serial, InterlockedIncrement(&serial)-1);
6539 sec.nLength =
sizeof(sec);
6540 sec.lpSecurityDescriptor = NULL;
6541 sec.bInheritHandle = FALSE;
6544 hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
6545 0, 2, 65536, 65536, 0, &sec);
6547 if (hRead == INVALID_HANDLE_VALUE) {
6548 DWORD err = GetLastError();
6549 if (err == ERROR_PIPE_BUSY)
6552 errno = map_errno(GetLastError());
6557 hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
6558 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
6560 if (hWrite == INVALID_HANDLE_VALUE) {
6561 errno = map_errno(GetLastError());
6568 h = CreateFile(
"NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
6569 fdRead = _open_osfhandle((intptr_t)h, 0);
6573 CloseHandle(hWrite);
6579 rb_acrt_lowio_lock_fh(fdRead);
6580 _set_osfhnd(fdRead, (intptr_t)hRead);
6581 _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
6582 rb_acrt_lowio_unlock_fh(fdRead);
6588 h = CreateFile(
"NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
6589 fdWrite = _open_osfhandle((intptr_t)h, 0);
6591 if (fdWrite == -1) {
6593 CloseHandle(hWrite);
6597 rb_acrt_lowio_lock_fh(fdWrite);
6598 _set_osfhnd(fdWrite, (intptr_t)hWrite);
6599 _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
6600 rb_acrt_lowio_unlock_fh(fdWrite);
6603 rb_w32_close(fdRead);
6615console_emulator_p(
void)
6620 const void *
const func = WriteConsoleW;
6622 MEMORY_BASIC_INFORMATION m;
6624 memset(&m, 0,
sizeof(m));
6625 if (!VirtualQuery(func, &m,
sizeof(m))) {
6628 k = GetModuleHandle(
"kernel32.dll");
6629 if (!k)
return FALSE;
6630 return (HMODULE)m.AllocationBase != k;
6636constat_handle(HANDLE h)
6640 thread_exclusive(conlist) {
6642 if (console_emulator_p()) {
6643 conlist = conlist_disabled;
6646 conlist = st_init_numtable();
6647 install_vm_exit_handler();
6649 else if (conlist == conlist_disabled) {
6652 if (st_lookup(conlist, (st_data_t)h, &data)) {
6656 CONSOLE_SCREEN_BUFFER_INFO csbi;
6658 p->vt100.state = constat_init;
6659 p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6660 p->vt100.reverse = 0;
6661 p->vt100.saved.X = p->vt100.saved.Y = 0;
6662 if (GetConsoleScreenBufferInfo(h, &csbi)) {
6663 p->vt100.attr = csbi.wAttributes;
6665 st_insert(conlist, (st_data_t)h, (st_data_t)p);
6673constat_reset(HANDLE h)
6677 thread_exclusive(conlist) {
6678 if (!conlist || conlist == conlist_disabled)
continue;
6679 if (!st_lookup(conlist, (st_data_t)h, &data))
continue;
6681 p->vt100.state = constat_init;
6685#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
6686#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
6688#define constat_attr_color_reverse(attr) \
6689 ((attr) & ~(FOREGROUND_MASK | BACKGROUND_MASK)) | \
6690 (((attr) & FOREGROUND_MASK) << 4) | \
6691 (((attr) & BACKGROUND_MASK) >> 4)
6695constat_attr(
int count,
const int *seq, WORD attr, WORD default_attr,
int *reverse)
6700 if (!count)
return attr;
6701 if (rev) attr = constat_attr_color_reverse(attr);
6702 bold = attr & FOREGROUND_INTENSITY;
6703 attr &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
6705 while (count-- > 0) {
6708 attr = default_attr;
6713 bold = FOREGROUND_INTENSITY;
6716#ifndef COMMON_LVB_UNDERSCORE
6717#define COMMON_LVB_UNDERSCORE 0x8000
6719 attr |= COMMON_LVB_UNDERSCORE;
6726 attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
6730 attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN)) | FOREGROUND_RED;
6734 attr = (attr & ~(FOREGROUND_BLUE | FOREGROUND_RED)) | FOREGROUND_GREEN;
6738 attr = (attr & ~FOREGROUND_BLUE) | FOREGROUND_GREEN | FOREGROUND_RED;
6742 attr = (attr & ~(FOREGROUND_GREEN | FOREGROUND_RED)) | FOREGROUND_BLUE;
6746 attr = (attr & ~FOREGROUND_GREEN) | FOREGROUND_BLUE | FOREGROUND_RED;
6750 attr = (attr & ~FOREGROUND_RED) | FOREGROUND_BLUE | FOREGROUND_GREEN;
6754 attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
6758 attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
6761 attr = (attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN)) | BACKGROUND_RED;
6764 attr = (attr & ~(BACKGROUND_BLUE | BACKGROUND_RED)) | BACKGROUND_GREEN;
6767 attr = (attr & ~BACKGROUND_BLUE) | BACKGROUND_GREEN | BACKGROUND_RED;
6770 attr = (attr & ~(BACKGROUND_GREEN | BACKGROUND_RED)) | BACKGROUND_BLUE;
6773 attr = (attr & ~BACKGROUND_GREEN) | BACKGROUND_BLUE | BACKGROUND_RED;
6776 attr = (attr & ~BACKGROUND_RED) | BACKGROUND_BLUE | BACKGROUND_GREEN;
6779 attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
6784 if (rev) attr = constat_attr_color_reverse(attr);
6791constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
6795 FillConsoleOutputAttribute(handle, attr, len, pos, &written);
6796 FillConsoleOutputCharacterW(handle, L
' ', len, pos, &written);
6801constat_apply(HANDLE handle,
struct constat *s, WCHAR w)
6803 CONSOLE_SCREEN_BUFFER_INFO csbi;
6804 const int *seq = s->vt100.seq;
6805 int count = s->vt100.state;
6809 if (!GetConsoleScreenBufferInfo(handle, &csbi))
return;
6810 arg0 = (count > 0 && seq[0] > 0);
6811 if (arg0) arg1 = seq[0];
6814 SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr, &s->vt100.reverse));
6817 csbi.dwCursorPosition.X = 0;
6819 csbi.dwCursorPosition.Y -= arg1;
6820 if (csbi.dwCursorPosition.Y < csbi.srWindow.Top)
6821 csbi.dwCursorPosition.Y = csbi.srWindow.Top;
6822 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6825 csbi.dwCursorPosition.X = 0;
6828 csbi.dwCursorPosition.Y += arg1;
6829 if (csbi.dwCursorPosition.Y > csbi.srWindow.Bottom)
6830 csbi.dwCursorPosition.Y = csbi.srWindow.Bottom;
6831 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6834 csbi.dwCursorPosition.X += arg1;
6835 if (csbi.dwCursorPosition.X >= csbi.srWindow.Right)
6836 csbi.dwCursorPosition.X = csbi.srWindow.Right;
6837 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6840 csbi.dwCursorPosition.X -= arg1;
6841 if (csbi.dwCursorPosition.X < csbi.srWindow.Left)
6842 csbi.dwCursorPosition.X = csbi.srWindow.Left;
6843 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6847 arg1 += csbi.srWindow.Left;
6848 if (arg1 > csbi.srWindow.Right)
6849 arg1 = csbi.srWindow.Right;
6850 csbi.dwCursorPosition.X = arg1;
6851 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6854 arg1 += csbi.srWindow.Top;
6855 if (arg1 > csbi.srWindow.Bottom)
6856 arg1 = csbi.srWindow.Bottom;
6857 csbi.dwCursorPosition.Y = arg1;
6858 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
6862 pos.Y = arg1 + csbi.srWindow.Top - 1;
6863 if (pos.Y > csbi.srWindow.Bottom) pos.Y = csbi.srWindow.Bottom;
6864 if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1;
6865 pos.X = arg1 + csbi.srWindow.Left - 1;
6866 if (pos.X > csbi.srWindow.Right) pos.X = csbi.srWindow.Right;
6867 SetConsoleCursorPosition(handle, pos);
6870 switch (arg0 ? arg1 : 0) {
6872 constat_clear(handle, csbi.wAttributes,
6873 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.dwCursorPosition.Y + 1)
6874 - csbi.dwCursorPosition.X),
6875 csbi.dwCursorPosition);
6879 pos.Y = csbi.srWindow.Top;
6880 constat_clear(handle, csbi.wAttributes,
6881 (csbi.dwSize.X * (csbi.dwCursorPosition.Y - csbi.srWindow.Top)
6882 + csbi.dwCursorPosition.X + 1),
6887 pos.Y = csbi.srWindow.Top;
6888 constat_clear(handle, csbi.wAttributes,
6889 (csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1)),
6895 constat_clear(handle, csbi.wAttributes,
6896 (csbi.dwSize.X * csbi.dwSize.Y),
6902 switch (arg0 ? arg1 : 0) {
6904 constat_clear(handle, csbi.wAttributes,
6905 (csbi.dwSize.X - csbi.dwCursorPosition.X),
6906 csbi.dwCursorPosition);
6910 pos.Y = csbi.dwCursorPosition.Y;
6911 constat_clear(handle, csbi.wAttributes,
6912 csbi.dwCursorPosition.X + 1, pos);
6916 pos.Y = csbi.dwCursorPosition.Y;
6917 constat_clear(handle, csbi.wAttributes,
6918 csbi.dwSize.X, pos);
6923 s->vt100.saved = csbi.dwCursorPosition;
6926 SetConsoleCursorPosition(handle, s->vt100.saved);
6929 if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
6930 CONSOLE_CURSOR_INFO cci;
6931 GetConsoleCursorInfo(handle, &cci);
6932 cci.bVisible = TRUE;
6933 SetConsoleCursorInfo(handle, &cci);
6937 if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
6938 CONSOLE_CURSOR_INFO cci;
6939 GetConsoleCursorInfo(handle, &cci);
6940 cci.bVisible = FALSE;
6941 SetConsoleCursorInfo(handle, &cci);
6949static const long MAXSIZE_CONSOLE_WRITING = 31366;
6953constat_parse(HANDLE h,
struct constat *s,
const WCHAR **ptrp,
long *lenp)
6955 const WCHAR *ptr = *ptrp;
6956 long rest, len = *lenp;
6960 rest = *lenp - len - 1;
6961 if (s->vt100.state == constat_esc) {
6964 s->vt100.state = constat_init;
6965 if (len > 0 && *ptr != L
'[')
continue;
6966 s->vt100.state = constat_esc;
6968 else if (s->vt100.state == constat_esc) {
6971 s->vt100.state = constat_init;
6974 rest = *lenp - len - 1;
6975 if (rest > 0) --rest;
6976 s->vt100.state = constat_seq;
6977 s->vt100.seq[0] = 0;
6979 else if (s->vt100.state >= constat_seq) {
6980 if (wc >= L
'0' && wc <= L
'9') {
6981 if (s->vt100.state < (
int)numberof(s->vt100.seq)) {
6982 int *seq = &s->vt100.seq[s->vt100.state];
6983 *seq = (*seq * 10) + (wc - L
'0');
6986 else if (s->vt100.state == constat_seq && s->vt100.seq[0] == 0 && wc == L
'?') {
6987 s->vt100.seq[s->vt100.state++] = -1;
6991 if (++s->vt100.state < (
int)numberof(s->vt100.seq)) {
6992 s->vt100.seq[s->vt100.state] = 0;
6995 s->vt100.state = (int)numberof(s->vt100.seq);
6999 constat_apply(h, s, wc);
7000 s->vt100.state = constat_init;
7005 else if ((rest = *lenp - len) < MAXSIZE_CONSOLE_WRITING) {
7023 SOCKET sock = TO_SOCKET(fd);
7024 int save_errno = errno;
7026 if (!is_socket(sock)) {
7027 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
7028 constat_delete((HANDLE)sock);
7031 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
7032 socklist_delete(&sock, NULL);
7035 if (closesocket(sock) == SOCKET_ERROR) {
7036 errno = map_errno(WSAGetLastError());
7043setup_overlapped(OVERLAPPED *ol,
int fd,
int iswrite)
7045 memset(ol, 0,
sizeof(*ol));
7046 if (!(_osfile(fd) & (FDEV | FPIPE))) {
7052 DWORD method = ((_osfile(fd) & FAPPEND) && iswrite) ? FILE_END : FILE_CURRENT;
7053 DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
7054#ifndef INVALID_SET_FILE_POINTER
7055#define INVALID_SET_FILE_POINTER ((DWORD)-1)
7057 if (low == INVALID_SET_FILE_POINTER) {
7058 DWORD err = GetLastError();
7059 if (err != NO_ERROR) {
7060 errno = map_errno(err);
7065 ol->OffsetHigh = high;
7067 ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
7069 errno = map_errno(GetLastError());
7076finish_overlapped(OVERLAPPED *ol,
int fd, DWORD size)
7078 CloseHandle(ol->hEvent);
7080 if (!(_osfile(fd) & (FDEV | FPIPE))) {
7081 LONG high = ol->OffsetHigh;
7082 DWORD low = ol->Offset + size;
7083 if (low < ol->Offset)
7085 SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
7092rb_w32_read(
int fd,
void *buf,
size_t size)
7094 SOCKET sock = TO_SOCKET(fd);
7102 BOOL islineinput = FALSE;
7105 if (is_socket(sock))
7106 return rb_w32_recv(fd, buf, size, 0);
7109 if (_get_osfhandle(fd) == -1) {
7113 if (_osfile(fd) & FTEXT) {
7114 return _read(fd, buf, size);
7117 rb_acrt_lowio_lock_fh(fd);
7119 if (!size || _osfile(fd) & FEOFLAG) {
7120 _set_osflags(fd, _osfile(fd) & ~FEOFLAG);
7121 rb_acrt_lowio_unlock_fh(fd);
7126 isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
7129 GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
7130 islineinput = (mode & ENABLE_LINE_INPUT) != 0;
7135 constat_reset((HANDLE)_osfhnd(fd));
7147 if (setup_overlapped(&ol, fd, FALSE)) {
7148 rb_acrt_lowio_unlock_fh(fd);
7152 if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, &ol)) {
7153 err = GetLastError();
7154 if (err == ERROR_NO_DATA && (_osfile(fd) & FPIPE)) {
7156 if (GetNamedPipeHandleState((HANDLE)_osfhnd(fd), &state, NULL, NULL, NULL, NULL, 0) && (state & PIPE_NOWAIT)) {
7157 errno = EWOULDBLOCK;
7160 errno = map_errno(err);
7162 rb_acrt_lowio_unlock_fh(fd);
7165 else if (err != ERROR_IO_PENDING) {
7166 CloseHandle(ol.hEvent);
7167 if (err == ERROR_ACCESS_DENIED)
7169 else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
7170 rb_acrt_lowio_unlock_fh(fd);
7174 errno = map_errno(err);
7176 rb_acrt_lowio_unlock_fh(fd);
7180 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
7181 if (wait != WAIT_OBJECT_0) {
7182 if (wait == WAIT_OBJECT_0 + 1)
7185 errno = map_errno(GetLastError());
7186 CloseHandle(ol.hEvent);
7187 CancelIo((HANDLE)_osfhnd(fd));
7188 rb_acrt_lowio_unlock_fh(fd);
7192 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
7193 (err = GetLastError()) != ERROR_HANDLE_EOF) {
7195 if (err != ERROR_BROKEN_PIPE) {
7196 errno = map_errno(err);
7199 CloseHandle(ol.hEvent);
7200 CancelIo((HANDLE)_osfhnd(fd));
7201 rb_acrt_lowio_unlock_fh(fd);
7206 err = GetLastError();
7207 errno = map_errno(err);
7210 finish_overlapped(&ol, fd, read);
7214 buf = (
char *)buf + read;
7215 if (err != ERROR_OPERATION_ABORTED &&
7216 !(isconsole && len == 1 && (!islineinput || *((
char *)buf - 1) ==
'\n')) && size > 0)
7220 _set_osflags(fd, _osfile(fd) | FEOFLAG);
7223 rb_acrt_lowio_unlock_fh(fd);
7231rb_w32_write(
int fd,
const void *buf,
size_t size)
7233 SOCKET sock = TO_SOCKET(fd);
7241 if (is_socket(sock))
7242 return rb_w32_send(fd, buf, size, 0);
7245 if (_get_osfhandle(fd) == -1) {
7249 if ((_osfile(fd) & FTEXT) &&
7250 (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) {
7251 ssize_t w = _write(fd, buf, size);
7252 if (w == (ssize_t)-1 && errno == EINVAL) {
7253 errno = map_errno(GetLastError());
7258 rb_acrt_lowio_lock_fh(fd);
7260 if (!size || _osfile(fd) & FEOFLAG) {
7261 rb_acrt_lowio_unlock_fh(fd);
7267 len = (_osfile(fd) & FDEV) ? min(MAXSIZE_CONSOLE_WRITING, size) : size;
7271 if (setup_overlapped(&ol, fd, TRUE)) {
7272 rb_acrt_lowio_unlock_fh(fd);
7276 if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, &ol)) {
7277 err = GetLastError();
7278 if (err != ERROR_IO_PENDING) {
7279 CloseHandle(ol.hEvent);
7280 if (err == ERROR_ACCESS_DENIED)
7283 errno = map_errno(err);
7285 rb_acrt_lowio_unlock_fh(fd);
7289 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
7290 if (wait != WAIT_OBJECT_0) {
7291 if (wait == WAIT_OBJECT_0 + 1)
7294 errno = map_errno(GetLastError());
7295 CloseHandle(ol.hEvent);
7296 CancelIo((HANDLE)_osfhnd(fd));
7297 rb_acrt_lowio_unlock_fh(fd);
7301 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written, TRUE)) {
7302 errno = map_errno(GetLastError());
7303 CloseHandle(ol.hEvent);
7304 CancelIo((HANDLE)_osfhnd(fd));
7305 rb_acrt_lowio_unlock_fh(fd);
7310 finish_overlapped(&ol, fd, written);
7313 if (written == len) {
7314 buf = (
const char *)buf + len;
7319 size_t newlen = len / 2;
7321 size += len - newlen;
7326 errno = EWOULDBLOCK;
7329 rb_acrt_lowio_unlock_fh(fd);
7336rb_w32_write_console(uintptr_t strarg,
int fd)
7339 DWORD dwMode, reslen;
7343 const WCHAR *ptr, *next;
7347 handle = (HANDLE)_osfhnd(fd);
7348 if (!GetConsoleMode(handle, &dwMode))
7351 s = constat_handle(handle);
7361 case ENCINDEX_US_ASCII:
7362 case ENCINDEX_ASCII:
7364 case ENCINDEX_UTF_8:
7366 if (!ptr)
return -1L;
7368 case ENCINDEX_UTF_16LE:
7374 if (dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) {
7375 if (!WriteConsoleW(handle, ptr, len, &reslen, NULL))
7376 reslen = (DWORD)-1L;
7380 long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
7381 reslen += next - ptr;
7384 if (!WriteConsoleW(handle, ptr, curlen, &written, NULL)) {
7385 reslen = (DWORD)-1L;
7393 if (wbuffer) free(wbuffer);
7394 return (
long)reslen;
7397#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7400unixtime_to_filetime(time_t time, FILETIME *ft)
7404 tmp.QuadPart = ((
LONG_LONG)time + (
LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
7405 ft->dwLowDateTime = tmp.LowPart;
7406 ft->dwHighDateTime = tmp.HighPart;
7413timespec_to_filetime(
const struct timespec *ts, FILETIME *ft)
7417 tmp.QuadPart = ((
LONG_LONG)ts->tv_sec + (
LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
7418 tmp.QuadPart += ts->tv_nsec / 100;
7419 ft->dwLowDateTime = tmp.LowPart;
7420 ft->dwHighDateTime = tmp.HighPart;
7426wutimensat(
int dirfd,
const WCHAR *path,
const struct timespec *times,
int flags)
7429 FILETIME atime, mtime;
7434 if (dirfd != AT_FDCWD) {
7444 if (wstati128(path, &
stat, FALSE)) {
7449 if (timespec_to_filetime(×[0], &atime)) {
7452 if (timespec_to_filetime(×[1], &mtime)) {
7457 get_systemtime(&atime);
7462 const DWORD attr = GetFileAttributesW(path);
7463 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7464 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7465 hFile = open_special(path, GENERIC_WRITE, 0);
7466 if (hFile == INVALID_HANDLE_VALUE) {
7467 errno = map_errno(GetLastError());
7471 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
7472 errno = map_errno(GetLastError());
7477 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
7478 SetFileAttributesW(path, attr);
7486w32_utimensat(
int dirfd,
const char *path,
const struct timespec *times,
int flags, UINT cp)
7488 WCHAR *wpath = mbstr_to_wstr(cp, path, -1, NULL);
7492 ret = wutimensat(dirfd, wpath, times, flags);
7500rb_w32_uutime(
const char *path,
const struct utimbuf *times)
7504 ts[0].tv_sec = times->actime;
7506 ts[1].tv_sec = times->modtime;
7508 return w32_utimensat(AT_FDCWD, path, ts, 0, CP_UTF8);
7513rb_w32_utime(
const char *path,
const struct utimbuf *times)
7517 ts[0].tv_sec = times->actime;
7519 ts[1].tv_sec = times->modtime;
7521 return w32_utimensat(AT_FDCWD, path, ts, 0, filecp());
7526rb_w32_uutimes(
const char *path,
const struct timeval *times)
7530 ts[0].tv_sec = times[0].tv_sec;
7531 ts[0].tv_nsec = times[0].tv_usec * 1000;
7532 ts[1].tv_sec = times[1].tv_sec;
7533 ts[1].tv_nsec = times[1].tv_usec * 1000;
7534 return w32_utimensat(AT_FDCWD, path, ts, 0, CP_UTF8);
7539rb_w32_utimes(
const char *path,
const struct timeval *times)
7543 ts[0].tv_sec = times[0].tv_sec;
7544 ts[0].tv_nsec = times[0].tv_usec * 1000;
7545 ts[1].tv_sec = times[1].tv_sec;
7546 ts[1].tv_nsec = times[1].tv_usec * 1000;
7547 return w32_utimensat(AT_FDCWD, path, ts, 0, filecp());
7552rb_w32_uutimensat(
int dirfd,
const char *path,
const struct timespec *times,
int flags)
7554 return w32_utimensat(dirfd, path, times, flags, CP_UTF8);
7559rb_w32_utimensat(
int dirfd,
const char *path,
const struct timespec *times,
int flags)
7561 return w32_utimensat(dirfd, path, times, flags, filecp());
7566rb_w32_uchdir(
const char *path)
7571 if (!(wpath = utf8_to_wstr(path, NULL)))
7573 ret = _wchdir(wpath);
7580wmkdir(
const WCHAR *wpath,
int mode)
7585 if (CreateDirectoryW(wpath, NULL) == FALSE) {
7586 errno = map_errno(GetLastError());
7589 if (_wchmod(wpath, mode) == -1) {
7590 RemoveDirectoryW(wpath);
7600rb_w32_umkdir(
const char *path,
int mode)
7605 if (!(wpath = utf8_to_wstr(path, NULL)))
7607 ret = wmkdir(wpath, mode);
7614rb_w32_mkdir(
const char *path,
int mode)
7619 if (!(wpath = filecp_to_wstr(path, NULL)))
7621 ret = wmkdir(wpath, mode);
7628wrmdir(
const WCHAR *wpath)
7632 const DWORD attr = GetFileAttributesW(wpath);
7633 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7634 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
7636 if (RemoveDirectoryW(wpath) == FALSE) {
7637 errno = map_errno(GetLastError());
7639 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7640 SetFileAttributesW(wpath, attr);
7649rb_w32_rmdir(
const char *path)
7654 if (!(wpath = filecp_to_wstr(path, NULL)))
7656 ret = wrmdir(wpath);
7663rb_w32_urmdir(
const char *path)
7668 if (!(wpath = utf8_to_wstr(path, NULL)))
7670 ret = wrmdir(wpath);
7677wunlink(
const WCHAR *path)
7680 const DWORD SYMLINKD = FILE_ATTRIBUTE_REPARSE_POINT|FILE_ATTRIBUTE_DIRECTORY;
7682 const DWORD attr = GetFileAttributesW(path);
7683 if (attr == (DWORD)-1) {
7685 else if ((attr & SYMLINKD) == SYMLINKD) {
7686 ret = RemoveDirectoryW(path);
7689 if (attr & FILE_ATTRIBUTE_READONLY) {
7690 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
7692 ret = DeleteFileW(path);
7695 errno = map_errno(GetLastError());
7697 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
7698 SetFileAttributesW(path, attr);
7707rb_w32_uunlink(
const char *path)
7712 if (!(wpath = utf8_to_wstr(path, NULL)))
7714 ret = wunlink(wpath);
7721rb_w32_unlink(
const char *path)
7726 if (!(wpath = filecp_to_wstr(path, NULL)))
7728 ret = wunlink(wpath);
7735rb_w32_uchmod(
const char *path,
int mode)
7740 if (!(wpath = utf8_to_wstr(path, NULL)))
7742 ret = _wchmod(wpath, mode);
7749fchmod(
int fd,
int mode)
7751 typedef BOOL (WINAPI *set_file_information_by_handle_func)
7752 (HANDLE, int,
void*, DWORD);
7753 static set_file_information_by_handle_func set_file_info =
7754 (set_file_information_by_handle_func)-1;
7758 LARGE_INTEGER CreationTime;
7759 LARGE_INTEGER LastAccessTime;
7760 LARGE_INTEGER LastWriteTime;
7761 LARGE_INTEGER ChangeTime;
7762 DWORD FileAttributes;
7763 } info = {{{0}}, {{0}}, {{0}},};
7764 HANDLE h = (HANDLE)_get_osfhandle(fd);
7766 if (h == INVALID_HANDLE_VALUE) {
7770 if (set_file_info == (set_file_information_by_handle_func)-1) {
7772 set_file_info = (set_file_information_by_handle_func)
7773 get_proc_address(
"kernel32",
"SetFileInformationByHandle", NULL);
7775 if (!set_file_info) {
7780 info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
7781 if (!(mode & 0200)) info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
7782 if (!set_file_info(h, 0, &info,
sizeof(info))) {
7783 errno = map_errno(GetLastError());
7791rb_w32_isatty(
int fd)
7796 if (_get_osfhandle(fd) == -1) {
7799 if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) {
7806#if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
7807extern long _ftol(
double);
7828 int *ip = (
int *)(&x + 1) - 1;
7835rb_w32_inet_ntop(
int af,
const void *addr,
char *numaddr,
size_t numaddr_len)
7837 typedef char *(WSAAPI inet_ntop_t)(
int,
void *,
char *,
size_t);
7838 static inet_ntop_t *pInetNtop = (inet_ntop_t *)-1;
7839 if (pInetNtop == (inet_ntop_t *)-1)
7840 pInetNtop = (inet_ntop_t *)get_proc_address(
"ws2_32",
"inet_ntop", NULL);
7842 return pInetNtop(af, (
void *)addr, numaddr, numaddr_len);
7846 memcpy(&in.s_addr, addr,
sizeof(in.s_addr));
7847 snprintf(numaddr, numaddr_len,
"%s", inet_ntoa(in));
7854rb_w32_inet_pton(
int af,
const char *src,
void *dst)
7856 typedef int (WSAAPI inet_pton_t)(int,
const char*,
void *);
7857 static inet_pton_t *pInetPton = (inet_pton_t *)-1;
7858 if (pInetPton == (inet_pton_t *)-1)
7859 pInetPton = (inet_pton_t *)get_proc_address(
"ws2_32",
"inet_pton", NULL);
7861 return pInetPton(af, src, dst);
7868rb_w32_fd_is_text(
int fd)
7870 return _osfile(fd) & FTEXT;
7873#if RUBY_MSVCRT_VERSION < 80 && !defined(HAVE__GMTIME64_S)
7876unixtime_to_systemtime(
const time_t t, SYSTEMTIME *st)
7879 if (unixtime_to_filetime(t, &ft))
return -1;
7880 if (!FileTimeToSystemTime(&ft, st))
return -1;
7886systemtime_to_tm(
const SYSTEMTIME *st,
struct tm *t)
7888 int y = st->wYear, m = st->wMonth, d = st->wDay;
7889 t->tm_sec = st->wSecond;
7890 t->tm_min = st->wMinute;
7891 t->tm_hour = st->wHour;
7892 t->tm_mday = st->wDay;
7893 t->tm_mon = st->wMonth - 1;
7894 t->tm_year = y - 1900;
7895 t->tm_wday = st->wDayOfWeek;
7903 d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
7904 d += ((m - 3) * 153 + 2) / 5;
7912systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
7914 TIME_ZONE_INFORMATION stdtz;
7917 if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst))
return -1;
7919 GetTimeZoneInformation(&stdtz);
7922 if (tz->StandardBias == tz->DaylightBias)
return 0;
7923 if (!tz->StandardDate.wMonth)
return 0;
7924 if (!tz->DaylightDate.wMonth)
return 0;
7925 if (tz != &stdtz) stdtz = *tz;
7927 stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
7928 if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst))
return 0;
7929 if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
7935#ifdef HAVE__GMTIME64_S
7936# ifndef HAVE__LOCALTIME64_S
7938# define HAVE__LOCALTIME64_S 1
7940# ifndef MINGW_HAS_SECURE_API
7941 _CRTIMP errno_t __cdecl _gmtime64_s(
struct tm*
tm,
const __time64_t *time);
7942 _CRTIMP errno_t __cdecl _localtime64_s(
struct tm*
tm,
const __time64_t *time);
7944# define gmtime_s _gmtime64_s
7945# define localtime_s _localtime64_s
7950gmtime_r(
const time_t *tp,
struct tm *rp)
7958#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__GMTIME64_S)
7959 e = gmtime_s(rp, tp);
7960 if (e != 0)
goto error;
7964 if (unixtime_to_systemtime(*tp, &st))
goto error;
7966 systemtime_to_tm(&st, rp);
7974localtime_r(
const time_t *tp,
struct tm *rp)
7982#if RUBY_MSVCRT_VERSION >= 80 || defined(HAVE__LOCALTIME64_S)
7983 e = localtime_s(rp, tp);
7987 SYSTEMTIME gst, lst;
7988 if (unixtime_to_systemtime(*tp, &gst))
goto error;
7989 rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
7990 systemtime_to_tm(&lst, rp);
7998rb_w32_wrap_io_handle(HANDLE h,
int flags)
8001 int len =
sizeof(tmp);
8002 int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (
char *)&tmp, &len);
8003 if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
8005 if (flags & O_NONBLOCK) {
8006 flags &= ~O_NONBLOCK;
8009 socklist_insert((SOCKET)h, f);
8011 else if (flags & O_NONBLOCK) {
8015 return rb_w32_open_osfhandle((intptr_t)h, flags);
8020rb_w32_unwrap_io_handle(
int fd)
8022 SOCKET sock = TO_SOCKET(fd);
8023 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
8024 if (!is_socket(sock)) {
8025 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
8026 constat_delete((HANDLE)sock);
8029 socklist_delete(&sock, NULL);
8034#if !defined(__MINGW64__) && defined(__MINGW64_VERSION_MAJOR)
8040rb_w32_pow(
double x,
double y)
8044 unsigned int default_control = _controlfp(0, 0);
8045 _controlfp(_PC_64, _MCW_PC);
8048 _controlfp(default_control, _MCW_PC);
8056 BY_HANDLE_FILE_INFORMATION bhfi;
8067 tmp = rb_check_convert_type_with_id(*file,
T_FILE,
"IO", idTo_io);
8072 f = (HANDLE)rb_w32_get_osfhandle(fptr->
fd);
8073 if (f == (HANDLE)-1)
return INVALID_HANDLE_VALUE;
8083 len = MultiByteToWideChar(CP_UTF8, 0,
RSTRING_PTR(tmp), -1, NULL, 0);
8085 MultiByteToWideChar(CP_UTF8, 0,
RSTRING_PTR(tmp), -1, ptr, len);
8086 f = CreateFileW(ptr, 0,
8087 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
8088 FILE_FLAG_BACKUP_SEMANTICS, NULL);
8090 if (f == INVALID_HANDLE_VALUE)
return f;
8093 if (GetFileType(f) == FILE_TYPE_DISK) {
8095 ZeroMemory(st,
sizeof(*st));
8096 err = get_ino(f, &st->info.fii);
8098 st->file_id_p = TRUE;
8101 else if (err != ERROR_INVALID_PARAMETER) {
8103 return INVALID_HANDLE_VALUE;
8107 if (GetFileInformationByHandle(f, &st->info.bhfi)) {
8108 st->file_id_p = FALSE;
8112 if (ret) CloseHandle(ret);
8113 return INVALID_HANDLE_VALUE;
8117close_handle(VALUE h)
8119 CloseHandle((HANDLE)h);
8129call_w32_io_info(VALUE arg)
8132 return (VALUE)w32_io_info(p->fname, p->st);
8136rb_w32_file_identical_p(VALUE fname1, VALUE fname2)
8139 HANDLE f1 = 0, f2 = 0;
8141 f1 = w32_io_info(&fname1, &st1);
8142 if (f1 == INVALID_HANDLE_VALUE)
return Qfalse;
8145 arg.fname = &fname2;
8147 f2 = (HANDLE)
rb_ensure(call_w32_io_info, (VALUE)&arg, close_handle, (
VALUE)f1);
8150 f2 = w32_io_info(&fname2, &st2);
8152 if (f2 == INVALID_HANDLE_VALUE)
return Qfalse;
8153 if (f2) CloseHandle(f2);
8155 if (st1.file_id_p != st2.file_id_p)
return Qfalse;
8156 if (!st1.file_id_p) {
8157 if (st1.info.bhfi.dwVolumeSerialNumber == st2.info.bhfi.dwVolumeSerialNumber &&
8158 st1.info.bhfi.nFileIndexHigh == st2.info.bhfi.nFileIndexHigh &&
8159 st1.info.bhfi.nFileIndexLow == st2.info.bhfi.nFileIndexLow)
8163 if (st1.info.fii.VolumeSerialNumber == st2.info.fii.VolumeSerialNumber &&
8164 memcmp(&st1.info.fii.FileId, &st2.info.fii.FileId,
sizeof(
FILE_ID_128)) == 0)
8171rb_w32_set_thread_description(HANDLE th,
const WCHAR *name)
8174 typedef HRESULT (WINAPI *set_thread_description_func)(HANDLE, PCWSTR);
8175 static set_thread_description_func set_thread_description =
8176 (set_thread_description_func)-1;
8177 if (set_thread_description == (set_thread_description_func)-1) {
8179 set_thread_description = (set_thread_description_func)
8180 get_proc_address(
"kernel32",
"SetThreadDescription", NULL);
8182 if (set_thread_description) {
8183 result = set_thread_description(th, name);
8189rb_w32_set_thread_description_str(HANDLE th, VALUE name)
8191 int idx, result = FALSE;
8195 return rb_w32_set_thread_description(th, L
"");
8199 if (idx == ENCINDEX_UTF_16LE) {
8200 result = rb_w32_set_thread_description(th, s);
8205 result = rb_w32_set_thread_description(th, s);
8214#if RUBY_MSVCRT_VERSION < 120
8215#include "missing/nextafter.c"
int ruby_glob_func(const char *path, VALUE arg, void *enc)
Type of a glob callback function.
#define T_FILE
Old name of RUBY_T_FILE.
#define REALLOC_N
Old name of RB_REALLOC_N.
#define ALLOCV
Old name of RB_ALLOCV.
#define ISSPACE
Old name of rb_isspace.
#define ALLOC
Old name of RB_ALLOC.
#define xfree
Old name of ruby_xfree.
#define xrealloc
Old name of ruby_xrealloc.
#define ECONV_UNDEF_REPLACE
Old name of RUBY_ECONV_UNDEF_REPLACE.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define ECONV_INVALID_REPLACE
Old name of RUBY_ECONV_INVALID_REPLACE.
#define ASSUME
Old name of RBIMPL_ASSUME.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define ISALPHA
Old name of rb_isalpha.
#define Qtrue
Old name of RUBY_Qtrue.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define ISALNUM
Old name of rb_isalnum.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
int rb_enc_get_index(VALUE obj)
Queries the index of the encoding of the passed object, if any.
rb_encoding * rb_utf8_encoding(void)
Queries the encoding that represents UTF-8.
rb_encoding * rb_filesystem_encoding(void)
Queries the "filesystem" encoding.
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
int rb_enc_to_index(rb_encoding *enc)
Queries the index of the encoding.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
Identical to rb_str_conv_enc(), except it additionally takes IO encoder options.
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
int rb_econv_has_convpath_p(const char *from_encoding, const char *to_encoding)
Queries if there is more than one way to convert between the passed two encodings.
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
VALUE rb_utf8_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "UTF-8" encoding.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
#define rb_strlen_lit(str)
Length of a string literal.
VALUE rb_f_notimplement(int argc, const VALUE *argv, VALUE obj, VALUE marker)
Raises rb_eNotImpError.
#define GetOpenFile
This is an old name of RB_IO_POINTER.
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
#define strdup(s)
Just another name of ruby_strdup.
void ruby_vm_at_exit(void(*func)(ruby_vm_t *))
ruby_vm_at_exit registers a function func to be invoked when a VM passed away.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_vcatf(VALUE dst, const char *fmt, va_list ap)
Identical to rb_str_catf(), except it takes a va_list.
void rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
Identical to rb_w32_fd_copy(), except it copies unlimited number of file descriptors.
void rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
Destructively overwrites an fdset with another.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define rb_long2int
Just another name of rb_long2int_inline.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define ALLOCA_N(type, n)
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
VALUE type(ANYARGS)
ANYARGS-ed function type.
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
#define PRI_PIDT_PREFIX
A rb_sprintf() format prefix to be used for a pid_t parameter.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define FilePathValue(v)
Ensures that the parameter object is a path.
The data structure which wraps the fd_set bitmap used by select(2).
fd_set * fdset
File descriptors buffer.
Ruby's IO, metadata and buffers.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t VALUE
Type that represents a Ruby object.
void ruby_xfree(void *ptr)
Deallocates a storage instance.
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
void * ruby_xcalloc(size_t nelems, size_t elemsiz)
Identical to ruby_xmalloc2(), except it returns a zero-filled storage instance.