64
64
#define TO_SOCKET(x) _get_osfhandle(x)
66
static struct ChildRecord *CreateChild(const char *, const char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
66
static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
67
67
static int has_redirection(const char *);
68
68
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
69
69
static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
454
get_proc_address(const char *module, const char *func, HANDLE *mh)
460
h = LoadLibrary(module);
462
h = GetModuleHandle(module);
466
ptr = GetProcAddress(h, func);
454
477
get_system_directory(WCHAR *path, UINT len)
456
HANDLE hKernel = GetModuleHandle("kernel32.dll");
459
typedef UINT WINAPI wgetdir_func(WCHAR*, UINT);
460
FARPROC ptr = GetProcAddress(hKernel, "GetSystemWindowsDirectoryW");
462
return (*(wgetdir_func *)ptr)(path, len);
479
typedef UINT WINAPI wgetdir_func(WCHAR*, UINT);
481
get_proc_address("kernel32", "GetSystemWindowsDirectoryW", NULL);
483
return (*(wgetdir_func *)ptr)(path, len);
465
484
return GetWindowsDirectoryW(path, len);
1018
memset(&aStartupInfo, 0, sizeof (STARTUPINFO));
1019
memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION));
1020
aStartupInfo.cb = sizeof (STARTUPINFO);
1038
memset(&aStartupInfo, 0, sizeof(aStartupInfo));
1039
memset(&aProcessInformation, 0, sizeof(aProcessInformation));
1040
aStartupInfo.cb = sizeof(aStartupInfo);
1021
1041
aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
1023
1043
aStartupInfo.hStdInput = hInput;
1049
1069
RUBY_CRITICAL({
1050
fRet = CreateProcess(prog, (char *)cmd, psa, psa,
1051
psa->bInheritHandle, dwCreationFlags, NULL, NULL,
1052
&aStartupInfo, &aProcessInformation);
1070
fRet = CreateProcessW(prog, (WCHAR *)cmd, psa, psa,
1071
psa->bInheritHandle, dwCreationFlags, NULL, NULL,
1072
&aStartupInfo, &aProcessInformation);
1053
1073
errno = map_errno(GetLastError());
1106
static UINT filecp(void);
1107
static WCHAR *mbstr_to_wstr(UINT, const char *, int, long *);
1108
static char *wstr_to_mbstr(UINT, const WCHAR *, int, long *);
1109
#define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen)
1110
#define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen)
1111
#define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen)
1112
#define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen)
1113
#define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen)
1114
#define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen)
1087
1117
rb_w32_spawn(int mode, const char *cmd, const char *prog)
1089
1119
char fbuf[MAXPATHLEN];
1090
1120
char *p = NULL;
1091
1121
const char *shell = NULL;
1122
WCHAR *wcmd, *wshell;
1093
1127
if (check_spawn_mode(mode)) return -1;
1223
1268
len = join_argv(NULL, argv, FALSE);
1224
cmd = ALLOCA_N(char, len);
1269
cmd = ALLOCV(v, len);
1225
1270
join_argv(cmd, argv, FALSE);
1228
return child_result(CreateChild(cmd, prog, NULL, NULL, NULL, NULL), mode);
1274
wcmd = cmd ? acp_to_wstr(cmd, NULL) : NULL;
1275
if (v) ALLOCV_END(v);
1276
wprog = prog ? acp_to_wstr(prog, NULL) : NULL;
1278
ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL), mode);
1231
1284
typedef struct _NtCmdLineElement {
1689
1760
p->bits[p->nfiles / DIRENT_PER_CHAR] = 0;
1691
if (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1762
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1692
1763
SetBit(p->bits, BitOfIsDir(p->nfiles));
1693
if (fd->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1764
if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
1694
1765
SetBit(p->bits, BitOfIsRep(p->nfiles));
1698
} while (FindNextFileW(fh, fd));
1769
} while (FindNextFileW(fh, &fd));
1701
1772
p->curr = p->start;
1706
wstr_to_filecp(const WCHAR *wstr, long *plen)
1708
UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
1710
int len = WideCharToMultiByte(cp, 0, wstr, -1, NULL, 0, NULL, NULL) - 1;
1711
if (!(ptr = malloc(len + 1))) return 0;
1712
WideCharToMultiByte(cp, 0, wstr, -1, ptr, len + 1, NULL, NULL);
1713
if (plen) *plen = len;
1718
filecp_to_wstr(const char *str, long *plen)
1720
UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
1722
int len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0) - 1;
1723
if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0;
1724
MultiByteToWideChar(cp, 0, str, -1, ptr, len + 1);
1725
if (plen) *plen = len;
1730
wstr_to_utf8(const WCHAR *wstr, long *plen)
1733
int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL) - 1;
1734
if (!(ptr = malloc(len + 1))) return 0;
1735
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, ptr, len + 1, NULL, NULL);
1736
if (plen) *plen = len;
1741
utf8_to_wstr(const char *str, long *plen)
1744
int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0) - 1;
1745
if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0;
1746
MultiByteToWideChar(CP_UTF8, 0, str, -1, ptr, len + 1);
1779
UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
1784
wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen)
1787
int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL) - 1;
1788
if (!(ptr = malloc(len + 1))) return 0;
1789
WideCharToMultiByte(cp, 0, wstr, clen, ptr, len + 1, NULL, NULL);
1790
if (plen) *plen = len;
1795
mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen)
1798
int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0) - 1;
1799
if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0;
1800
MultiByteToWideChar(cp, 0, str, clen, ptr, len + 1);
1747
1801
if (plen) *plen = len;
1752
1806
rb_w32_opendir(const char *filename)
1754
struct stati64 sbuf;
1755
WIN32_FIND_DATAW fd;
1759
if (!(wpath = filecp_to_wstr(filename, NULL)))
1763
// check to see if we've got a directory
1765
if (wstati64(wpath, &sbuf) < 0) {
1769
if (!(sbuf.st_mode & S_IFDIR) &&
1770
(!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' ||
1771
((1 << ((filename[0] & 0x5f) - 'A')) & GetLogicalDrives()) == 0)) {
1777
fh = open_dir_handle(wpath, &fd);
1779
return opendir_internal(fh, &fd);
1809
WCHAR *wpath = filecp_to_wstr(filename, NULL);
1812
ret = opendir_internal(wpath, filename);
1818
rb_w32_uopendir(const char *filename)
1821
WCHAR *wpath = utf8_to_wstr(filename, NULL);
1824
ret = opendir_internal(wpath, filename);
2198
2239
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2240
FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
2241
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
2242
buffer, sizeof(buffer), NULL) == 0 &&
2243
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
2199
2244
FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
2200
2245
buffer, sizeof(buffer), NULL) == 0)
2201
2246
strlcpy(buffer, "Unknown Error", sizeof(buffer));
2371
rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
2373
max = min(src->fd_count, (UINT)max);
2374
if ((UINT)dst->capa < (UINT)max) {
2375
dst->capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2376
dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
2379
memcpy(dst->fdset->fd_array, src->fd_array,
2380
max * sizeof(src->fd_array[0]));
2381
dst->fdset->fd_count = src->fd_count;
2384
/* License: Ruby's */
2386
rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
2388
if ((UINT)dst->capa < src->fdset->fd_count) {
2389
dst->capa = (src->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2390
dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
2393
memcpy(dst->fdset->fd_array, src->fdset->fd_array,
2394
src->fdset->fd_count * sizeof(src->fdset->fd_array[0]));
2395
dst->fdset->fd_count = src->fdset->fd_count;
2326
2399
// Networking trampolines
2327
// These are used to avoid socket startup/shutdown overhead in case
2400
// These are used to avoid socket startup/shutdown overhead in case
2328
2401
// the socket routines aren't used.
2334
2407
extract_fd(rb_fdset_t *dst, fd_set *src, int (*func)(SOCKET))
2336
2409
unsigned int s = 0;
2337
if (!src || !dst) return 0;
2339
2413
while (s < src->fd_count) {
2340
2414
SOCKET fd = src->fd_array[s];
2342
if (!func || (*func)(fd)) { /* move it to dst */
2416
if (!func || (*func)(fd)) {
2417
if (dst) { /* move it to dst */
2345
for (d = 0; d < dst->fdset->fd_count; d++) {
2346
if (dst->fdset->fd_array[d] == fd)
2349
if (d == dst->fdset->fd_count) {
2350
if ((int)dst->fdset->fd_count >= dst->capa) {
2351
dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2352
dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
2354
dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
2358
&src->fd_array[s+1],
2359
sizeof(src->fd_array[0]) * (--src->fd_count - s));
2420
for (d = 0; d < dst->fdset->fd_count; d++) {
2421
if (dst->fdset->fd_array[d] == fd)
2424
if (d == dst->fdset->fd_count) {
2425
if ((int)dst->fdset->fd_count >= dst->capa) {
2426
dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
2427
dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
2429
dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
2433
&src->fd_array[s+1],
2434
sizeof(src->fd_array[0]) * (--src->fd_count - s));
2364
return dst->fdset->fd_count;
2444
return dst ? dst->fdset->fd_count : m;
2564
2658
rb_fd_init(&else_rd);
2565
2659
nonsock += extract_fd(&else_rd, rd, is_not_socket);
2661
rb_fd_init(&else_wr);
2662
nonsock += extract_fd(&else_wr, wr, is_not_socket);
2664
// check invalid handles
2665
if (extract_fd(NULL, else_rd.fdset, is_invalid_handle) > 0 ||
2666
extract_fd(NULL, else_wr.fdset, is_invalid_handle) > 0) {
2667
rb_fd_term(&else_wr);
2668
rb_fd_term(&else_rd);
2567
2673
rb_fd_init(&pipe_rd);
2568
2674
extract_fd(&pipe_rd, else_rd.fdset, is_pipe); // should not call is_pipe for socket
2570
2676
rb_fd_init(&cons_rd);
2571
2677
extract_fd(&cons_rd, else_rd.fdset, is_console); // ditto
2573
rb_fd_init(&else_wr);
2574
nonsock += extract_fd(&else_wr, wr, is_not_socket);
2576
2679
rb_fd_init(&except);
2577
2680
extract_fd(&except, ex, is_not_socket); // drop only
2635
2742
rb_fd_term(&except);
2636
rb_fd_term(&else_wr);
2637
2743
rb_fd_term(&cons_rd);
2638
2744
rb_fd_term(&pipe_rd);
2745
rb_fd_term(&else_wr);
2639
2746
rb_fd_term(&else_rd);
2752
rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
2753
struct timeval *timeout)
2755
return rb_w32_select_with_thread(nfds, rd, wr, ex, timeout, 0);
2759
get_wsa_extension_function(SOCKET s, GUID *guid)
2764
WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, guid, sizeof(*guid),
2765
&ptr, sizeof(ptr), &dmy, NULL, NULL);
2936
finish_overlapped_socket(SOCKET s, WSAOVERLAPPED *wol, int result, DWORD *len, DWORD size)
2941
if (result != SOCKET_ERROR)
2943
else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
2944
switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) {
2947
result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg)
2955
errno = map_errno(WSAGetLastError());
2957
case WAIT_OBJECT_0 + 1:
2960
cancel_io((HANDLE)s);
2965
errno = map_errno(err);
2968
CloseHandle(wol->hEvent);
2809
2974
overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
2810
2975
struct sockaddr *addr, int *addrlen)
3008
3141
WSAOVERLAPPED wol;
3009
3142
memset(&wol, 0, sizeof(wol));
3010
3143
RUBY_CRITICAL({
3011
3144
wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3012
ret = pWSARecvMsg(s, &wsamsg, &len, &wol, NULL);
3145
ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL);
3015
if (ret != SOCKET_ERROR) {
3018
else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
3020
switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
3023
ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
3031
errno = map_errno(WSAGetLastError());
3033
case WAIT_OBJECT_0 + 1:
3036
cancel_io((HANDLE)s);
3041
errno = map_errno(err);
3044
CloseHandle(wol.hEvent);
3148
ret = finish_overlapped_socket(s, &wol, ret, &len, size);
3046
3150
if (ret == SOCKET_ERROR)
3100
3199
WSAOVERLAPPED wol;
3101
3200
memset(&wol, 0, sizeof(wol));
3102
3201
RUBY_CRITICAL({
3103
3202
wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
3104
ret = pWSASendMsg(s, &wsamsg, flags, &len, &wol, NULL);
3203
ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL);
3107
if (ret != SOCKET_ERROR) {
3110
else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
3112
switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
3115
ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
3123
errno = map_errno(WSAGetLastError());
3125
case WAIT_OBJECT_0 + 1:
3128
cancel_io((HANDLE)s);
3133
errno = map_errno(err);
3136
CloseHandle(wol.hEvent);
3206
finish_overlapped_socket(s, &wol, ret, &len, size);
3825
3916
wlink(const WCHAR *from, const WCHAR *to)
3827
static BOOL (WINAPI *pCreateHardLinkW)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES) = NULL;
3918
typedef BOOL (WINAPI link_func)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
3919
static link_func *pCreateHardLinkW = NULL;
3828
3920
static int myerrno = 0;
3830
3922
if (!pCreateHardLinkW && !myerrno) {
3833
hKernel = GetModuleHandle("kernel32.dll");
3835
pCreateHardLinkW = (BOOL (WINAPI *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))GetProcAddress(hKernel, "CreateHardLinkW");
3836
if (!pCreateHardLinkW) {
3841
myerrno = map_errno(GetLastError());
3923
pCreateHardLinkW = (link_func *)get_proc_address("kernel32", "CreateHardLinkW", NULL);
3924
if (!pCreateHardLinkW)
3844
3927
if (!pCreateHardLinkW) {
3845
3928
errno = myerrno;
4681
4767
rb_w32_getppid(void)
4683
static long (WINAPI *pNtQueryInformationProcess)(HANDLE, int, void *, ULONG, ULONG *) = NULL;
4769
typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *);
4770
static query_func *pNtQueryInformationProcess = NULL;
4684
4771
rb_pid_t ppid = 0;
4686
4773
if (!IsWin95() && rb_w32_osver() >= 5) {
4687
if (!pNtQueryInformationProcess) {
4688
HANDLE hNtDll = GetModuleHandle("ntdll.dll");
4690
pNtQueryInformationProcess = (long (WINAPI *)(HANDLE, int, void *, ULONG, ULONG *))GetProcAddress(hNtDll, "NtQueryInformationProcess");
4774
if (!pNtQueryInformationProcess)
4775
pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL);
4693
4776
if (pNtQueryInformationProcess) {
4695
4778
long ExitStatus;
4696
4779
void* PebBaseAddress;
4699
ULONG UniqueProcessId;
4700
ULONG ParentProcessId;
4780
uintptr_t AffinityMask;
4781
uintptr_t BasePriority;
4782
uintptr_t UniqueProcessId;
4783
uintptr_t ParentProcessId;
4703
4786
long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
5425
rb_w32_write_console(uintptr_t strarg, int fd)
5429
DWORD dwMode, reslen;
5432
if (disable) return -1L;
5433
handle = (HANDLE)_osfhnd(fd);
5434
if (!GetConsoleMode(handle, &dwMode) ||
5435
!rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE"))
5438
str = rb_str_encode(str, rb_enc_from_encoding(rb_enc_find("UTF-16LE")),
5439
ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
5440
if (!WriteConsoleW(handle, (LPWSTR)RSTRING_PTR(str), RSTRING_LEN(str)/2,
5442
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
5446
return (long)reslen;
5342
5450
unixtime_to_filetime(time_t time, FILETIME *ft)
5690
5800
return *ip < 0;
5805
rb_w32_inet_ntop(int af, void *addr, char *numaddr, size_t numaddr_len)
5807
typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t);
5808
inet_ntop_t *pInetNtop;
5809
pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL);
5811
return pInetNtop(af,addr,numaddr,numaddr_len);
5814
memcpy(&in.s_addr, addr, sizeof(in.s_addr));
5815
snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));