1/* 2 * Copyright (c) 1993, Intergraph Corporation 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Artistic License, as specified in the perl README file. 6 * 7 * Various Unix compatibility functions and NT specific functions. 8 * 9 * Some of this code was derived from the MSDOS port(s) and the OS/2 port. 10 * 11 */ 12/* 13 The parts licensed under above copyright notice are marked as "Artistic or 14 GPL". 15 Another parts are licensed under Ruby's License. 16 17 Copyright (C) 1993-2011 Yukihiro Matsumoto 18 Copyright (C) 2000 Network Applied Communication Laboratory, Inc. 19 Copyright (C) 2000 Information-technology Promotion Agency, Japan 20 */ 21 22#include "ruby/ruby.h" 23#include "ruby/encoding.h" 24#include "dln.h" 25#include <fcntl.h> 26#include <process.h> 27#include <sys/stat.h> 28/* #include <sys/wait.h> */ 29#include <stdio.h> 30#include <stdlib.h> 31#include <errno.h> 32#include <assert.h> 33#include <ctype.h> 34 35#include <windows.h> 36#include <winbase.h> 37#include <wincon.h> 38#include <share.h> 39#include <shlobj.h> 40#include <mbstring.h> 41#if _MSC_VER >= 1400 42#include <crtdbg.h> 43#include <rtcapi.h> 44#endif 45#ifdef __MINGW32__ 46#include <mswsock.h> 47#endif 48#include "ruby/win32.h" 49#include "win32/dir.h" 50#define isdirsep(x) ((x) == '/' || (x) == '\\') 51 52#undef stat 53#undef fclose 54#undef close 55#undef setsockopt 56 57#if defined __BORLANDC__ 58# define _filbuf _fgetc 59# define _flsbuf _fputc 60# define enough_to_get(n) (--(n) >= 0) 61# define enough_to_put(n) (++(n) < 0) 62#else 63# define enough_to_get(n) (--(n) >= 0) 64# define enough_to_put(n) (--(n) >= 0) 65#endif 66 67#ifdef WIN32_DEBUG 68#define Debug(something) something 69#else 70#define Debug(something) /* nothing */ 71#endif 72 73#define TO_SOCKET(x) _get_osfhandle(x) 74 75static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE, DWORD); 76static int has_redirection(const char *); 77int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout); 78static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags); 79static int wstati64(const WCHAR *path, struct stati64 *st); 80VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc); 81 82#define RUBY_CRITICAL(expr) do { expr; } while (0) 83 84/* errno mapping */ 85static struct { 86 DWORD winerr; 87 int err; 88} errmap[] = { 89 { ERROR_INVALID_FUNCTION, EINVAL }, 90 { ERROR_FILE_NOT_FOUND, ENOENT }, 91 { ERROR_PATH_NOT_FOUND, ENOENT }, 92 { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, 93 { ERROR_ACCESS_DENIED, EACCES }, 94 { ERROR_INVALID_HANDLE, EBADF }, 95 { ERROR_ARENA_TRASHED, ENOMEM }, 96 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, 97 { ERROR_INVALID_BLOCK, ENOMEM }, 98 { ERROR_BAD_ENVIRONMENT, E2BIG }, 99 { ERROR_BAD_FORMAT, ENOEXEC }, 100 { ERROR_INVALID_ACCESS, EINVAL }, 101 { ERROR_INVALID_DATA, EINVAL }, 102 { ERROR_INVALID_DRIVE, ENOENT }, 103 { ERROR_CURRENT_DIRECTORY, EACCES }, 104 { ERROR_NOT_SAME_DEVICE, EXDEV }, 105 { ERROR_NO_MORE_FILES, ENOENT }, 106 { ERROR_WRITE_PROTECT, EROFS }, 107 { ERROR_BAD_UNIT, ENODEV }, 108 { ERROR_NOT_READY, ENXIO }, 109 { ERROR_BAD_COMMAND, EACCES }, 110 { ERROR_CRC, EACCES }, 111 { ERROR_BAD_LENGTH, EACCES }, 112 { ERROR_SEEK, EIO }, 113 { ERROR_NOT_DOS_DISK, EACCES }, 114 { ERROR_SECTOR_NOT_FOUND, EACCES }, 115 { ERROR_OUT_OF_PAPER, EACCES }, 116 { ERROR_WRITE_FAULT, EIO }, 117 { ERROR_READ_FAULT, EIO }, 118 { ERROR_GEN_FAILURE, EACCES }, 119 { ERROR_LOCK_VIOLATION, EACCES }, 120 { ERROR_SHARING_VIOLATION, EACCES }, 121 { ERROR_WRONG_DISK, EACCES }, 122 { ERROR_SHARING_BUFFER_EXCEEDED, EACCES }, 123 { ERROR_BAD_NETPATH, ENOENT }, 124 { ERROR_NETWORK_ACCESS_DENIED, EACCES }, 125 { ERROR_BAD_NET_NAME, ENOENT }, 126 { ERROR_FILE_EXISTS, EEXIST }, 127 { ERROR_CANNOT_MAKE, EACCES }, 128 { ERROR_FAIL_I24, EACCES }, 129 { ERROR_INVALID_PARAMETER, EINVAL }, 130 { ERROR_NO_PROC_SLOTS, EAGAIN }, 131 { ERROR_DRIVE_LOCKED, EACCES }, 132 { ERROR_BROKEN_PIPE, EPIPE }, 133 { ERROR_DISK_FULL, ENOSPC }, 134 { ERROR_INVALID_TARGET_HANDLE, EBADF }, 135 { ERROR_INVALID_HANDLE, EINVAL }, 136 { ERROR_WAIT_NO_CHILDREN, ECHILD }, 137 { ERROR_CHILD_NOT_COMPLETE, ECHILD }, 138 { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, 139 { ERROR_NEGATIVE_SEEK, EINVAL }, 140 { ERROR_SEEK_ON_DEVICE, EACCES }, 141 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, 142 { ERROR_DIRECTORY, ENOTDIR }, 143 { ERROR_NOT_LOCKED, EACCES }, 144 { ERROR_BAD_PATHNAME, ENOENT }, 145 { ERROR_MAX_THRDS_REACHED, EAGAIN }, 146 { ERROR_LOCK_FAILED, EACCES }, 147 { ERROR_ALREADY_EXISTS, EEXIST }, 148 { ERROR_INVALID_STARTING_CODESEG, ENOEXEC }, 149 { ERROR_INVALID_STACKSEG, ENOEXEC }, 150 { ERROR_INVALID_MODULETYPE, ENOEXEC }, 151 { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC }, 152 { ERROR_EXE_MARKED_INVALID, ENOEXEC }, 153 { ERROR_BAD_EXE_FORMAT, ENOEXEC }, 154 { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC }, 155 { ERROR_INVALID_MINALLOCSIZE, ENOEXEC }, 156 { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC }, 157 { ERROR_IOPL_NOT_ENABLED, ENOEXEC }, 158 { ERROR_INVALID_SEGDPL, ENOEXEC }, 159 { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC }, 160 { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC }, 161 { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC }, 162 { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC }, 163 { ERROR_FILENAME_EXCED_RANGE, ENOENT }, 164 { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, 165#ifndef ERROR_PIPE_LOCAL 166#define ERROR_PIPE_LOCAL 229L 167#endif 168 { ERROR_PIPE_LOCAL, EPIPE }, 169 { ERROR_BAD_PIPE, EPIPE }, 170 { ERROR_PIPE_BUSY, EAGAIN }, 171 { ERROR_NO_DATA, EPIPE }, 172 { ERROR_PIPE_NOT_CONNECTED, EPIPE }, 173 { ERROR_OPERATION_ABORTED, EINTR }, 174 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM }, 175 { ERROR_MOD_NOT_FOUND, ENOENT }, 176 { WSAEINTR, EINTR }, 177 { WSAEBADF, EBADF }, 178 { WSAEACCES, EACCES }, 179 { WSAEFAULT, EFAULT }, 180 { WSAEINVAL, EINVAL }, 181 { WSAEMFILE, EMFILE }, 182 { WSAEWOULDBLOCK, EWOULDBLOCK }, 183 { WSAEINPROGRESS, EINPROGRESS }, 184 { WSAEALREADY, EALREADY }, 185 { WSAENOTSOCK, ENOTSOCK }, 186 { WSAEDESTADDRREQ, EDESTADDRREQ }, 187 { WSAEMSGSIZE, EMSGSIZE }, 188 { WSAEPROTOTYPE, EPROTOTYPE }, 189 { WSAENOPROTOOPT, ENOPROTOOPT }, 190 { WSAEPROTONOSUPPORT, EPROTONOSUPPORT }, 191 { WSAESOCKTNOSUPPORT, ESOCKTNOSUPPORT }, 192 { WSAEOPNOTSUPP, EOPNOTSUPP }, 193 { WSAEPFNOSUPPORT, EPFNOSUPPORT }, 194 { WSAEAFNOSUPPORT, EAFNOSUPPORT }, 195 { WSAEADDRINUSE, EADDRINUSE }, 196 { WSAEADDRNOTAVAIL, EADDRNOTAVAIL }, 197 { WSAENETDOWN, ENETDOWN }, 198 { WSAENETUNREACH, ENETUNREACH }, 199 { WSAENETRESET, ENETRESET }, 200 { WSAECONNABORTED, ECONNABORTED }, 201 { WSAECONNRESET, ECONNRESET }, 202 { WSAENOBUFS, ENOBUFS }, 203 { WSAEISCONN, EISCONN }, 204 { WSAENOTCONN, ENOTCONN }, 205 { WSAESHUTDOWN, ESHUTDOWN }, 206 { WSAETOOMANYREFS, ETOOMANYREFS }, 207 { WSAETIMEDOUT, ETIMEDOUT }, 208 { WSAECONNREFUSED, ECONNREFUSED }, 209 { WSAELOOP, ELOOP }, 210 { WSAENAMETOOLONG, ENAMETOOLONG }, 211 { WSAEHOSTDOWN, EHOSTDOWN }, 212 { WSAEHOSTUNREACH, EHOSTUNREACH }, 213 { WSAEPROCLIM, EPROCLIM }, 214 { WSAENOTEMPTY, ENOTEMPTY }, 215 { WSAEUSERS, EUSERS }, 216 { WSAEDQUOT, EDQUOT }, 217 { WSAESTALE, ESTALE }, 218 { WSAEREMOTE, EREMOTE }, 219}; 220 221/* License: Ruby's */ 222int 223rb_w32_map_errno(DWORD winerr) 224{ 225 int i; 226 227 if (winerr == 0) { 228 return 0; 229 } 230 231 for (i = 0; i < (int)(sizeof(errmap) / sizeof(*errmap)); i++) { 232 if (errmap[i].winerr == winerr) { 233 return errmap[i].err; 234 } 235 } 236 237 if (winerr >= WSABASEERR) { 238 return winerr; 239 } 240 return EINVAL; 241} 242 243#define map_errno rb_w32_map_errno 244 245static const char *NTLoginName; 246 247static OSVERSIONINFO osver; 248 249/* License: Artistic or GPL */ 250static void 251get_version(void) 252{ 253 memset(&osver, 0, sizeof(OSVERSIONINFO)); 254 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 255 GetVersionEx(&osver); 256} 257 258#ifdef _M_IX86 259/* License: Artistic or GPL */ 260DWORD 261rb_w32_osid(void) 262{ 263 return osver.dwPlatformId; 264} 265#endif 266 267/* License: Artistic or GPL */ 268DWORD 269rb_w32_osver(void) 270{ 271 return osver.dwMajorVersion; 272} 273 274/* simulate flock by locking a range on the file */ 275 276/* License: Artistic or GPL */ 277#define LK_ERR(f,i) \ 278 do { \ 279 if (f) \ 280 i = 0; \ 281 else { \ 282 DWORD err = GetLastError(); \ 283 if (err == ERROR_LOCK_VIOLATION || err == ERROR_IO_PENDING) \ 284 errno = EWOULDBLOCK; \ 285 else if (err == ERROR_NOT_LOCKED) \ 286 i = 0; \ 287 else \ 288 errno = map_errno(err); \ 289 } \ 290 } while (0) 291#define LK_LEN ULONG_MAX 292 293/* License: Artistic or GPL */ 294static uintptr_t 295flock_winnt(uintptr_t self, int argc, uintptr_t* argv) 296{ 297 OVERLAPPED o; 298 int i = -1; 299 const HANDLE fh = (HANDLE)self; 300 const int oper = argc; 301 302 memset(&o, 0, sizeof(o)); 303 304 switch(oper) { 305 case LOCK_SH: /* shared lock */ 306 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, LK_LEN, &o), i); 307 break; 308 case LOCK_EX: /* exclusive lock */ 309 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, LK_LEN, &o), i); 310 break; 311 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */ 312 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i); 313 break; 314 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */ 315 LK_ERR(LockFileEx(fh, 316 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 317 0, LK_LEN, LK_LEN, &o), i); 318 break; 319 case LOCK_UN: /* unlock lock */ 320 case LOCK_UN|LOCK_NB: /* unlock is always non-blocking, I hope */ 321 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, LK_LEN, &o), i); 322 break; 323 default: /* unknown */ 324 errno = EINVAL; 325 break; 326 } 327 return i; 328} 329 330#undef LK_ERR 331 332/* License: Artistic or GPL */ 333int 334flock(int fd, int oper) 335{ 336 const asynchronous_func_t locker = flock_winnt; 337 338 return rb_w32_asynchronize(locker, 339 (VALUE)_get_osfhandle(fd), oper, NULL, 340 (DWORD)-1); 341} 342 343/* License: Ruby's */ 344static inline WCHAR * 345translate_wchar(WCHAR *p, int from, int to) 346{ 347 for (; *p; p++) { 348 if (*p == from) 349 *p = to; 350 } 351 return p; 352} 353 354/* License: Ruby's */ 355static inline char * 356translate_char(char *p, int from, int to) 357{ 358 while (*p) { 359 if ((unsigned char)*p == from) 360 *p = to; 361 p = CharNext(p); 362 } 363 return p; 364} 365 366#ifndef CSIDL_LOCAL_APPDATA 367#define CSIDL_LOCAL_APPDATA 28 368#endif 369#ifndef CSIDL_COMMON_APPDATA 370#define CSIDL_COMMON_APPDATA 35 371#endif 372#ifndef CSIDL_WINDOWS 373#define CSIDL_WINDOWS 36 374#endif 375#ifndef CSIDL_SYSTEM 376#define CSIDL_SYSTEM 37 377#endif 378#ifndef CSIDL_PROFILE 379#define CSIDL_PROFILE 40 380#endif 381 382/* License: Ruby's */ 383static BOOL 384get_special_folder(int n, WCHAR *env) 385{ 386 LPITEMIDLIST pidl; 387 LPMALLOC alloc; 388 BOOL f = FALSE; 389 if (SHGetSpecialFolderLocation(NULL, n, &pidl) == 0) { 390 f = SHGetPathFromIDListW(pidl, env); 391 SHGetMalloc(&alloc); 392 alloc->lpVtbl->Free(alloc, pidl); 393 alloc->lpVtbl->Release(alloc); 394 } 395 return f; 396} 397 398/* License: Ruby's */ 399static void 400regulate_path(WCHAR *path) 401{ 402 WCHAR *p = translate_wchar(path, L'\\', L'/'); 403 if (p - path == 2 && path[1] == L':') { 404 *p++ = L'/'; 405 *p = L'\0'; 406 } 407} 408 409/* License: Ruby's */ 410static FARPROC 411get_proc_address(const char *module, const char *func, HANDLE *mh) 412{ 413 HANDLE h; 414 FARPROC ptr; 415 416 if (mh) 417 h = LoadLibrary(module); 418 else 419 h = GetModuleHandle(module); 420 if (!h) 421 return NULL; 422 423 ptr = GetProcAddress(h, func); 424 if (mh) { 425 if (ptr) 426 *mh = h; 427 else 428 FreeLibrary(h); 429 } 430 return ptr; 431} 432 433/* License: Ruby's */ 434static UINT 435get_system_directory(WCHAR *path, UINT len) 436{ 437 typedef UINT WINAPI wgetdir_func(WCHAR*, UINT); 438 FARPROC ptr = 439 get_proc_address("kernel32", "GetSystemWindowsDirectoryW", NULL); 440 if (ptr) 441 return (*(wgetdir_func *)ptr)(path, len); 442 return GetWindowsDirectoryW(path, len); 443} 444 445#define numberof(array) (sizeof(array) / sizeof(*array)) 446 447/* License: Ruby's */ 448VALUE 449rb_w32_special_folder(int type) 450{ 451 WCHAR path[_MAX_PATH]; 452 453 if (!get_special_folder(type, path)) return Qnil; 454 regulate_path(path); 455 return rb_w32_conv_from_wchar(path, rb_filesystem_encoding()); 456} 457 458/* License: Ruby's */ 459UINT 460rb_w32_system_tmpdir(WCHAR *path, UINT len) 461{ 462 static const WCHAR temp[] = L"temp"; 463 WCHAR *p; 464 465 if (!get_special_folder(CSIDL_LOCAL_APPDATA, path)) { 466 if (get_system_directory(path, len)) return 0; 467 } 468 p = translate_wchar(path, L'\\', L'/'); 469 if (*(p - 1) != L'/') *p++ = L'/'; 470 if (p - path + numberof(temp) >= len) return 0; 471 memcpy(p, temp, sizeof(temp)); 472 return p - path + numberof(temp) - 1; 473} 474 475/* License: Ruby's */ 476static void 477init_env(void) 478{ 479 static const WCHAR TMPDIR[] = L"TMPDIR"; 480 struct {WCHAR name[6], eq, val[_MAX_PATH];} wk; 481 DWORD len; 482 BOOL f; 483#define env wk.val 484#define set_env_val(vname) do { \ 485 typedef char namesizecheck[numberof(wk.name) < numberof(vname) - 1 ? -1 : 1]; \ 486 WCHAR *const buf = wk.name + numberof(wk.name) - numberof(vname) + 1; \ 487 MEMCPY(buf, vname, WCHAR, numberof(vname) - 1); \ 488 _wputenv(buf); \ 489 } while (0) 490 491 wk.eq = L'='; 492 493 if (!GetEnvironmentVariableW(L"HOME", env, numberof(env))) { 494 f = FALSE; 495 if (GetEnvironmentVariableW(L"HOMEDRIVE", env, numberof(env))) 496 len = lstrlenW(env); 497 else 498 len = 0; 499 if (GetEnvironmentVariableW(L"HOMEPATH", env + len, numberof(env) - len) || len) { 500 f = TRUE; 501 } 502 else if (GetEnvironmentVariableW(L"USERPROFILE", env, numberof(env))) { 503 f = TRUE; 504 } 505 else if (get_special_folder(CSIDL_PROFILE, env)) { 506 f = TRUE; 507 } 508 else if (get_special_folder(CSIDL_PERSONAL, env)) { 509 f = TRUE; 510 } 511 if (f) { 512 regulate_path(env); 513 set_env_val(L"HOME"); 514 } 515 } 516 517 if (!GetEnvironmentVariableW(L"USER", env, numberof(env))) { 518 if (!GetEnvironmentVariableW(L"USERNAME", env, numberof(env)) && 519 !GetUserNameW(env, (len = numberof(env), &len))) { 520 NTLoginName = "<Unknown>"; 521 return; 522 } 523 set_env_val(L"USER"); 524 } 525 NTLoginName = strdup(rb_w32_getenv("USER")); 526 527 if (!GetEnvironmentVariableW(TMPDIR, env, numberof(env)) && 528 !GetEnvironmentVariableW(L"TMP", env, numberof(env)) && 529 !GetEnvironmentVariableW(L"TEMP", env, numberof(env)) && 530 rb_w32_system_tmpdir(env, numberof(env))) { 531 set_env_val(TMPDIR); 532 } 533 534#undef env 535#undef set_env_val 536} 537 538 539typedef BOOL (WINAPI *cancel_io_t)(HANDLE); 540static cancel_io_t cancel_io = NULL; 541 542/* License: Ruby's */ 543static void 544init_func(void) 545{ 546 if (!cancel_io) 547 cancel_io = (cancel_io_t)get_proc_address("kernel32", "CancelIo", NULL); 548} 549 550static void init_stdhandle(void); 551 552#if RUBY_MSVCRT_VERSION >= 80 553/* License: Ruby's */ 554static void 555invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, unsigned int line, uintptr_t dummy) 556{ 557 // nothing to do 558} 559 560int ruby_w32_rtc_error; 561 562/* License: Ruby's */ 563static int __cdecl 564rtc_error_handler(int e, const char *src, int line, const char *exe, const char *fmt, ...) 565{ 566 va_list ap; 567 VALUE str; 568 569 if (!ruby_w32_rtc_error) return 0; 570 str = rb_sprintf("%s:%d: ", src, line); 571 va_start(ap, fmt); 572 rb_str_vcatf(str, fmt, ap); 573 va_end(ap); 574 rb_str_cat(str, "\n", 1); 575 rb_write_error2(RSTRING_PTR(str), RSTRING_LEN(str)); 576 return 0; 577} 578#endif 579 580static CRITICAL_SECTION select_mutex; 581static int NtSocketsInitialized = 0; 582static st_table *socklist = NULL; 583static st_table *conlist = NULL; 584static char *envarea; 585static char *uenvarea; 586 587/* License: Ruby's */ 588struct constat { 589 struct { 590 int state, seq[16]; 591 WORD attr; 592 COORD saved; 593 } vt100; 594}; 595enum {constat_init = -2, constat_esc = -1, constat_seq = 0}; 596 597/* License: Ruby's */ 598static int 599free_conlist(st_data_t key, st_data_t val, st_data_t arg) 600{ 601 xfree((struct constat *)val); 602 return ST_DELETE; 603} 604 605/* License: Ruby's */ 606static void 607constat_delete(HANDLE h) 608{ 609 if (conlist) { 610 st_data_t key = (st_data_t)h, val; 611 st_delete(conlist, &key, &val); 612 xfree((struct constat *)val); 613 } 614} 615 616/* License: Ruby's */ 617static void 618exit_handler(void) 619{ 620 if (NtSocketsInitialized) { 621 WSACleanup(); 622 if (socklist) { 623 st_free_table(socklist); 624 socklist = NULL; 625 } 626 DeleteCriticalSection(&select_mutex); 627 NtSocketsInitialized = 0; 628 } 629 if (conlist) { 630 st_foreach(conlist, free_conlist, 0); 631 st_free_table(conlist); 632 conlist = NULL; 633 } 634 if (envarea) { 635 FreeEnvironmentStrings(envarea); 636 envarea = NULL; 637 } 638 if (uenvarea) { 639 free(uenvarea); 640 uenvarea = NULL; 641 } 642} 643 644/* License: Artistic or GPL */ 645static void 646StartSockets(void) 647{ 648 WORD version; 649 WSADATA retdata; 650 651 // 652 // initalize the winsock interface and insure that it's 653 // cleaned up at exit. 654 // 655 version = MAKEWORD(2, 0); 656 if (WSAStartup(version, &retdata)) 657 rb_fatal ("Unable to locate winsock library!\n"); 658 if (LOBYTE(retdata.wVersion) != 2) 659 rb_fatal("could not find version 2 of winsock dll\n"); 660 661 InitializeCriticalSection(&select_mutex); 662 663 NtSocketsInitialized = 1; 664} 665 666#define MAKE_SOCKDATA(af, fl) ((int)((((int)af)<<4)|((fl)&0xFFFF))) 667#define GET_FAMILY(v) ((int)(((v)>>4)&0xFFFF)) 668#define GET_FLAGS(v) ((int)((v)&0xFFFF)) 669 670/* License: Ruby's */ 671static inline int 672socklist_insert(SOCKET sock, int flag) 673{ 674 if (!socklist) 675 socklist = st_init_numtable(); 676 return st_insert(socklist, (st_data_t)sock, (st_data_t)flag); 677} 678 679/* License: Ruby's */ 680static inline int 681socklist_lookup(SOCKET sock, int *flagp) 682{ 683 st_data_t data; 684 int ret; 685 686 if (!socklist) 687 return 0; 688 ret = st_lookup(socklist, (st_data_t)sock, (st_data_t *)&data); 689 if (ret && flagp) 690 *flagp = (int)data; 691 692 return ret; 693} 694 695/* License: Ruby's */ 696static inline int 697socklist_delete(SOCKET *sockp, int *flagp) 698{ 699 st_data_t key; 700 st_data_t data; 701 int ret; 702 703 if (!socklist) 704 return 0; 705 key = (st_data_t)*sockp; 706 if (flagp) 707 data = (st_data_t)*flagp; 708 ret = st_delete(socklist, &key, &data); 709 if (ret) { 710 *sockp = (SOCKET)key; 711 if (flagp) 712 *flagp = (int)data; 713 } 714 715 return ret; 716} 717 718// 719// Initialization stuff 720// 721/* License: Ruby's */ 722void 723rb_w32_sysinit(int *argc, char ***argv) 724{ 725#if RUBY_MSVCRT_VERSION >= 80 726 static void set_pioinfo_extra(void); 727 728 _CrtSetReportMode(_CRT_ASSERT, 0); 729 _set_invalid_parameter_handler(invalid_parameter); 730 _RTC_SetErrorFunc(rtc_error_handler); 731 set_pioinfo_extra(); 732#else 733 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX); 734#endif 735 736 get_version(); 737 738 // 739 // subvert cmd.exe's feeble attempt at command line parsing 740 // 741 *argc = rb_w32_cmdvector(GetCommandLine(), argv); 742 743 // 744 // Now set up the correct time stuff 745 // 746 747 tzset(); 748 749 init_env(); 750 751 init_func(); 752 753 init_stdhandle(); 754 755 atexit(exit_handler); 756 757 // Initialize Winsock 758 StartSockets(); 759} 760 761char * 762getlogin(void) 763{ 764 return (char *)NTLoginName; 765} 766 767#define MAXCHILDNUM 256 /* max num of child processes */ 768 769/* License: Ruby's */ 770static struct ChildRecord { 771 HANDLE hProcess; /* process handle */ 772 rb_pid_t pid; /* process id */ 773} ChildRecord[MAXCHILDNUM]; 774 775/* License: Ruby's */ 776#define FOREACH_CHILD(v) do { \ 777 struct ChildRecord* v; \ 778 for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v) 779#define END_FOREACH_CHILD } while (0) 780 781/* License: Ruby's */ 782static struct ChildRecord * 783FindChildSlot(rb_pid_t pid) 784{ 785 786 FOREACH_CHILD(child) { 787 if (child->pid == pid) { 788 return child; 789 } 790 } END_FOREACH_CHILD; 791 return NULL; 792} 793 794/* License: Ruby's */ 795static struct ChildRecord * 796FindChildSlotByHandle(HANDLE h) 797{ 798 799 FOREACH_CHILD(child) { 800 if (child->hProcess == h) { 801 return child; 802 } 803 } END_FOREACH_CHILD; 804 return NULL; 805} 806 807/* License: Ruby's */ 808static void 809CloseChildHandle(struct ChildRecord *child) 810{ 811 HANDLE h = child->hProcess; 812 child->hProcess = NULL; 813 child->pid = 0; 814 CloseHandle(h); 815} 816 817/* License: Ruby's */ 818static struct ChildRecord * 819FindFreeChildSlot(void) 820{ 821 FOREACH_CHILD(child) { 822 if (!child->pid) { 823 child->pid = -1; /* lock the slot */ 824 child->hProcess = NULL; 825 return child; 826 } 827 } END_FOREACH_CHILD; 828 return NULL; 829} 830 831 832/* 833 ruby -lne 'BEGIN{$cmds = Hash.new(0); $mask = 1}' 834 -e '$cmds[$_.downcase] |= $mask' -e '$mask <<= 1 if ARGF.eof' 835 -e 'END{$cmds.sort.each{|n,f|puts " \"\\#{f.to_s(8)}\" #{n.dump} + 1,"}}' 836 98cmd ntcmd 837 */ 838static const char *const szInternalCmds[] = { 839 "\2" "assoc", 840 "\3" "break", 841 "\3" "call", 842 "\3" "cd", 843 "\1" "chcp", 844 "\3" "chdir", 845 "\3" "cls", 846 "\2" "color", 847 "\3" "copy", 848 "\1" "ctty", 849 "\3" "date", 850 "\3" "del", 851 "\3" "dir", 852 "\3" "echo", 853 "\2" "endlocal", 854 "\3" "erase", 855 "\3" "exit", 856 "\3" "for", 857 "\2" "ftype", 858 "\3" "goto", 859 "\3" "if", 860 "\1" "lfnfor", 861 "\1" "lh", 862 "\1" "lock", 863 "\3" "md", 864 "\3" "mkdir", 865 "\2" "move", 866 "\3" "path", 867 "\3" "pause", 868 "\2" "popd", 869 "\3" "prompt", 870 "\2" "pushd", 871 "\3" "rd", 872 "\3" "rem", 873 "\3" "ren", 874 "\3" "rename", 875 "\3" "rmdir", 876 "\3" "set", 877 "\2" "setlocal", 878 "\3" "shift", 879 "\2" "start", 880 "\3" "time", 881 "\2" "title", 882 "\1" "truename", 883 "\3" "type", 884 "\1" "unlock", 885 "\3" "ver", 886 "\3" "verify", 887 "\3" "vol", 888}; 889 890/* License: Ruby's */ 891static int 892internal_match(const void *key, const void *elem) 893{ 894 return strcmp(key, (*(const char *const *)elem) + 1); 895} 896 897/* License: Ruby's */ 898static int 899is_command_com(const char *interp) 900{ 901 int i = strlen(interp) - 11; 902 903 if ((i == 0 || i > 0 && isdirsep(interp[i-1])) && 904 strcasecmp(interp+i, "command.com") == 0) { 905 return 1; 906 } 907 return 0; 908} 909 910static int internal_cmd_match(const char *cmdname, int nt); 911 912/* License: Ruby's */ 913static int 914is_internal_cmd(const char *cmd, int nt) 915{ 916 char cmdname[9], *b = cmdname, c; 917 918 do { 919 if (!(c = *cmd++)) return 0; 920 } while (isspace(c)); 921 if (c == '@') 922 return 1; 923 while (isalpha(c)) { 924 *b++ = tolower(c); 925 if (b == cmdname + sizeof(cmdname)) return 0; 926 c = *cmd++; 927 } 928 if (c == '.') c = *cmd; 929 switch (c) { 930 case '<': case '>': case '|': 931 return 1; 932 case '\0': case ' ': case '\t': case '\n': 933 break; 934 default: 935 return 0; 936 } 937 *b = 0; 938 return internal_cmd_match(cmdname, nt); 939} 940 941/* License: Ruby's */ 942static int 943internal_cmd_match(const char *cmdname, int nt) 944{ 945 char **nm; 946 947 nm = bsearch(cmdname, szInternalCmds, 948 sizeof(szInternalCmds) / sizeof(*szInternalCmds), 949 sizeof(*szInternalCmds), 950 internal_match); 951 if (!nm || !(nm[0][0] & (nt ? 2 : 1))) 952 return 0; 953 return 1; 954} 955 956/* License: Ruby's */ 957SOCKET 958rb_w32_get_osfhandle(int fh) 959{ 960 return _get_osfhandle(fh); 961} 962 963/* License: Ruby's */ 964static int 965join_argv(char *cmd, char *const *argv, BOOL escape) 966{ 967 const char *p, *s; 968 char *q, *const *t; 969 int len, n, bs, quote; 970 971 for (t = argv, q = cmd, len = 0; p = *t; t++) { 972 quote = 0; 973 s = p; 974 if (!*p || strpbrk(p, " \t\"'")) { 975 quote = 1; 976 len++; 977 if (q) *q++ = '"'; 978 } 979 for (bs = 0; *p; ++p) { 980 switch (*p) { 981 case '\\': 982 ++bs; 983 break; 984 case '"': 985 len += n = p - s; 986 if (q) { 987 memcpy(q, s, n); 988 q += n; 989 } 990 s = p; 991 len += ++bs; 992 if (q) { 993 memset(q, '\\', bs); 994 q += bs; 995 } 996 bs = 0; 997 break; 998 case '<': case '>': case '|': case '^': 999 if (escape && !quote) { 1000 len += (n = p - s) + 1; 1001 if (q) { 1002 memcpy(q, s, n); 1003 q += n; 1004 *q++ = '^'; 1005 } 1006 s = p; 1007 break; 1008 } 1009 default: 1010 bs = 0; 1011 p = CharNext(p) - 1; 1012 break; 1013 } 1014 } 1015 len += (n = p - s) + 1; 1016 if (quote) len++; 1017 if (q) { 1018 memcpy(q, s, n); 1019 q += n; 1020 if (quote) *q++ = '"'; 1021 *q++ = ' '; 1022 } 1023 } 1024 if (q > cmd) --len; 1025 if (q) { 1026 if (q > cmd) --q; 1027 *q = '\0'; 1028 } 1029 return len; 1030} 1031 1032#ifdef HAVE_SYS_PARAM_H 1033# include <sys/param.h> 1034#else 1035# define MAXPATHLEN 512 1036#endif 1037 1038/* License: Ruby's */ 1039#define STRNDUPV(ptr, v, src, len) \ 1040 (((char *)memcpy(((ptr) = ALLOCV((v), (len) + 1)), (src), (len)))[len] = 0) 1041 1042/* License: Ruby's */ 1043static int 1044check_spawn_mode(int mode) 1045{ 1046 switch (mode) { 1047 case P_NOWAIT: 1048 case P_OVERLAY: 1049 return 0; 1050 default: 1051 errno = EINVAL; 1052 return -1; 1053 } 1054} 1055 1056/* License: Ruby's */ 1057static rb_pid_t 1058child_result(struct ChildRecord *child, int mode) 1059{ 1060 DWORD exitcode; 1061 1062 if (!child) { 1063 return -1; 1064 } 1065 1066 if (mode == P_OVERLAY) { 1067 WaitForSingleObject(child->hProcess, INFINITE); 1068 GetExitCodeProcess(child->hProcess, &exitcode); 1069 CloseChildHandle(child); 1070 _exit(exitcode); 1071 } 1072 return child->pid; 1073} 1074 1075/* License: Ruby's */ 1076static struct ChildRecord * 1077CreateChild(const WCHAR *cmd, const WCHAR *prog, SECURITY_ATTRIBUTES *psa, 1078 HANDLE hInput, HANDLE hOutput, HANDLE hError, DWORD dwCreationFlags) 1079{ 1080 BOOL fRet; 1081 STARTUPINFOW aStartupInfo; 1082 PROCESS_INFORMATION aProcessInformation; 1083 SECURITY_ATTRIBUTES sa; 1084 struct ChildRecord *child; 1085 1086 if (!cmd && !prog) { 1087 errno = EFAULT; 1088 return NULL; 1089 } 1090 1091 child = FindFreeChildSlot(); 1092 if (!child) { 1093 errno = EAGAIN; 1094 return NULL; 1095 } 1096 1097 if (!psa) { 1098 sa.nLength = sizeof (SECURITY_ATTRIBUTES); 1099 sa.lpSecurityDescriptor = NULL; 1100 sa.bInheritHandle = TRUE; 1101 psa = &sa; 1102 } 1103 1104 memset(&aStartupInfo, 0, sizeof(aStartupInfo)); 1105 memset(&aProcessInformation, 0, sizeof(aProcessInformation)); 1106 aStartupInfo.cb = sizeof(aStartupInfo); 1107 aStartupInfo.dwFlags = STARTF_USESTDHANDLES; 1108 if (hInput) { 1109 aStartupInfo.hStdInput = hInput; 1110 } 1111 else { 1112 aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 1113 } 1114 if (hOutput) { 1115 aStartupInfo.hStdOutput = hOutput; 1116 } 1117 else { 1118 aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 1119 } 1120 if (hError) { 1121 aStartupInfo.hStdError = hError; 1122 } 1123 else { 1124 aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); 1125 } 1126 1127 dwCreationFlags |= NORMAL_PRIORITY_CLASS; 1128 1129 if (lstrlenW(cmd) > 32767) { 1130 child->pid = 0; /* release the slot */ 1131 errno = E2BIG; 1132 return NULL; 1133 } 1134 1135 RUBY_CRITICAL({ 1136 fRet = CreateProcessW(prog, (WCHAR *)cmd, psa, psa, 1137 psa->bInheritHandle, dwCreationFlags, NULL, NULL, 1138 &aStartupInfo, &aProcessInformation); 1139 errno = map_errno(GetLastError()); 1140 }); 1141 1142 if (!fRet) { 1143 child->pid = 0; /* release the slot */ 1144 return NULL; 1145 } 1146 1147 CloseHandle(aProcessInformation.hThread); 1148 1149 child->hProcess = aProcessInformation.hProcess; 1150 child->pid = (rb_pid_t)aProcessInformation.dwProcessId; 1151 1152 return child; 1153} 1154 1155/* License: Ruby's */ 1156static int 1157is_batch(const char *cmd) 1158{ 1159 int len = strlen(cmd); 1160 if (len <= 4) return 0; 1161 cmd += len - 4; 1162 if (*cmd++ != '.') return 0; 1163 if (strcasecmp(cmd, "bat") == 0) return 1; 1164 if (strcasecmp(cmd, "cmd") == 0) return 1; 1165 return 0; 1166} 1167 1168static UINT filecp(void); 1169static WCHAR *mbstr_to_wstr(UINT, const char *, int, long *); 1170static char *wstr_to_mbstr(UINT, const WCHAR *, int, long *); 1171#define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen) 1172#define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen) 1173#define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen) 1174#define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen) 1175#define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen) 1176#define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen) 1177 1178/* License: Artistic or GPL */ 1179rb_pid_t 1180rb_w32_spawn(int mode, const char *cmd, const char *prog) 1181{ 1182 char fbuf[MAXPATHLEN]; 1183 char *p = NULL; 1184 const char *shell = NULL; 1185 WCHAR *wcmd = NULL, *wshell = NULL; 1186 int e = 0; 1187 rb_pid_t ret = -1; 1188 VALUE v = 0; 1189 VALUE v2 = 0; 1190 1191 if (check_spawn_mode(mode)) return -1; 1192 1193 if (prog) { 1194 if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) { 1195 shell = prog; 1196 } 1197 else { 1198 shell = p; 1199 translate_char(p, '/', '\\'); 1200 } 1201 } 1202 else { 1203 int redir = -1; 1204 int nt; 1205 while (ISSPACE(*cmd)) cmd++; 1206 if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) { 1207 char *tmp = ALLOCV(v, strlen(shell) + strlen(cmd) + sizeof(" -c ") + 2); 1208 sprintf(tmp, "%s -c \"%s\"", shell, cmd); 1209 cmd = tmp; 1210 } 1211 else if ((shell = getenv("COMSPEC")) && 1212 (nt = !is_command_com(shell), 1213 (redir < 0 ? has_redirection(cmd) : redir) || 1214 is_internal_cmd(cmd, nt))) { 1215 char *tmp = ALLOCV(v, strlen(shell) + strlen(cmd) + sizeof(" /c ") + (nt ? 2 : 0)); 1216 sprintf(tmp, nt ? "%s /c \"%s\"" : "%s /c %s", shell, cmd); 1217 cmd = tmp; 1218 } 1219 else { 1220 int len = 0, quote = (*cmd == '"') ? '"' : (*cmd == '\'') ? '\'' : 0; 1221 for (prog = cmd + !!quote;; prog = CharNext(prog)) { 1222 if (!*prog) { 1223 len = prog - cmd; 1224 shell = cmd; 1225 break; 1226 } 1227 if ((unsigned char)*prog == quote) { 1228 len = prog++ - cmd - 1; 1229 STRNDUPV(p, v2, cmd + 1, len); 1230 shell = p; 1231 break; 1232 } 1233 if (quote) continue; 1234 if (ISSPACE(*prog) || strchr("<>|*?\"", *prog)) { 1235 len = prog - cmd; 1236 STRNDUPV(p, v2, cmd, len); 1237 shell = p; 1238 break; 1239 } 1240 } 1241 shell = dln_find_exe_r(shell, NULL, fbuf, sizeof(fbuf)); 1242 if (!shell) { 1243 shell = p ? p : cmd; 1244 } 1245 else { 1246 len = strlen(shell); 1247 if (strchr(shell, ' ')) quote = -1; 1248 if (shell == fbuf) { 1249 p = fbuf; 1250 } 1251 else if (shell != p && strchr(shell, '/')) { 1252 STRNDUPV(p, v2, shell, len); 1253 shell = p; 1254 } 1255 if (p) translate_char(p, '/', '\\'); 1256 if (is_batch(shell)) { 1257 int alen = strlen(prog); 1258 cmd = p = ALLOCV(v, len + alen + (quote ? 2 : 0) + 1); 1259 if (quote) *p++ = '"'; 1260 memcpy(p, shell, len); 1261 p += len; 1262 if (quote) *p++ = '"'; 1263 memcpy(p, prog, alen + 1); 1264 shell = 0; 1265 } 1266 } 1267 } 1268 } 1269 1270 /* assume ACP */ 1271 if (!e && cmd && !(wcmd = acp_to_wstr(cmd, NULL))) e = E2BIG; 1272 if (v) ALLOCV_END(v); 1273 if (!e && shell && !(wshell = acp_to_wstr(shell, NULL))) e = E2BIG; 1274 if (v2) ALLOCV_END(v2); 1275 1276 if (!e) { 1277 ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL, 0), mode); 1278 } 1279 free(wshell); 1280 free(wcmd); 1281 if (e) errno = e; 1282 return ret; 1283} 1284 1285/* License: Artistic or GPL */ 1286rb_pid_t 1287rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags) 1288{ 1289 int c_switch = 0; 1290 size_t len; 1291 BOOL ntcmd = FALSE, tmpnt; 1292 const char *shell; 1293 char *cmd, fbuf[MAXPATHLEN]; 1294 WCHAR *wcmd = NULL, *wprog = NULL; 1295 int e = 0; 1296 rb_pid_t ret = -1; 1297 VALUE v = 0; 1298 1299 if (check_spawn_mode(mode)) return -1; 1300 1301 if (!prog) prog = argv[0]; 1302 if ((shell = getenv("COMSPEC")) && 1303 internal_cmd_match(prog, tmpnt = !is_command_com(shell))) { 1304 ntcmd = tmpnt; 1305 prog = shell; 1306 c_switch = 1; 1307 } 1308 else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) { 1309 if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf)); 1310 translate_char(cmd, '/', '\\'); 1311 prog = cmd; 1312 } 1313 else if (strchr(prog, '/')) { 1314 len = strlen(prog); 1315 if (len < sizeof(fbuf)) 1316 strlcpy(cmd = fbuf, prog, sizeof(fbuf)); 1317 else 1318 STRNDUPV(cmd, v, prog, len); 1319 translate_char(cmd, '/', '\\'); 1320 prog = cmd; 1321 } 1322 if (c_switch || is_batch(prog)) { 1323 char *progs[2]; 1324 progs[0] = (char *)prog; 1325 progs[1] = NULL; 1326 len = join_argv(NULL, progs, ntcmd); 1327 if (c_switch) len += 3; 1328 else ++argv; 1329 if (argv[0]) len += join_argv(NULL, argv, ntcmd); 1330 cmd = ALLOCV(v, len); 1331 join_argv(cmd, progs, ntcmd); 1332 if (c_switch) strlcat(cmd, " /c", len); 1333 if (argv[0]) join_argv(cmd + strlcat(cmd, " ", len), argv, ntcmd); 1334 prog = c_switch ? shell : 0; 1335 } 1336 else { 1337 len = join_argv(NULL, argv, FALSE); 1338 cmd = ALLOCV(v, len); 1339 join_argv(cmd, argv, FALSE); 1340 } 1341 1342 /* assume ACP */ 1343 if (!e && cmd && !(wcmd = acp_to_wstr(cmd, NULL))) e = E2BIG; 1344 if (v) ALLOCV_END(v); 1345 if (!e && prog && !(wprog = acp_to_wstr(prog, NULL))) e = E2BIG; 1346 1347 if (!e) { 1348 ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL, flags), mode); 1349 } 1350 free(wprog); 1351 free(wcmd); 1352 if (e) errno = e; 1353 return ret; 1354} 1355 1356rb_pid_t 1357rb_w32_aspawn(int mode, const char *prog, char *const *argv) 1358{ 1359 return rb_w32_aspawn_flags(mode, prog, argv, 0); 1360} 1361 1362/* License: Artistic or GPL */ 1363typedef struct _NtCmdLineElement { 1364 struct _NtCmdLineElement *next; 1365 char *str; 1366 int len; 1367 int flags; 1368} NtCmdLineElement; 1369 1370// 1371// Possible values for flags 1372// 1373 1374#define NTGLOB 0x1 // element contains a wildcard 1375#define NTMALLOC 0x2 // string in element was malloc'ed 1376#define NTSTRING 0x4 // element contains a quoted string 1377 1378/* License: Ruby's */ 1379static int 1380insert(const char *path, VALUE vinfo, void *enc) 1381{ 1382 NtCmdLineElement *tmpcurr; 1383 NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo; 1384 1385 tmpcurr = (NtCmdLineElement *)malloc(sizeof(NtCmdLineElement)); 1386 if (!tmpcurr) return -1; 1387 MEMZERO(tmpcurr, NtCmdLineElement, 1); 1388 tmpcurr->len = strlen(path); 1389 tmpcurr->str = strdup(path); 1390 if (!tmpcurr->str) return -1; 1391 tmpcurr->flags |= NTMALLOC; 1392 **tail = tmpcurr; 1393 *tail = &tmpcurr->next; 1394 1395 return 0; 1396} 1397 1398/* License: Artistic or GPL */ 1399static NtCmdLineElement ** 1400cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail) 1401{ 1402 char buffer[MAXPATHLEN], *buf = buffer; 1403 char *p; 1404 NtCmdLineElement **last = tail; 1405 int status; 1406 1407 if (patt->len >= MAXPATHLEN) 1408 if (!(buf = malloc(patt->len + 1))) return 0; 1409 1410 strlcpy(buf, patt->str, patt->len + 1); 1411 buf[patt->len] = '\0'; 1412 for (p = buf; *p; p = CharNext(p)) 1413 if (*p == '\\') 1414 *p = '/'; 1415 status = ruby_brace_glob(buf, 0, insert, (VALUE)&tail); 1416 if (buf != buffer) 1417 free(buf); 1418 1419 if (status || last == tail) return 0; 1420 if (patt->flags & NTMALLOC) 1421 free(patt->str); 1422 free(patt); 1423 return tail; 1424} 1425 1426// 1427// Check a command string to determine if it has I/O redirection 1428// characters that require it to be executed by a command interpreter 1429// 1430 1431/* License: Artistic or GPL */ 1432static int 1433has_redirection(const char *cmd) 1434{ 1435 char quote = '\0'; 1436 const char *ptr; 1437 1438 // 1439 // Scan the string, looking for redirection characters (< or >), pipe 1440 // character (|) or newline (\n) that are not in a quoted string 1441 // 1442 1443 for (ptr = cmd; *ptr;) { 1444 switch (*ptr) { 1445 case '\'': 1446 case '\"': 1447 if (!quote) 1448 quote = *ptr; 1449 else if (quote == *ptr) 1450 quote = '\0'; 1451 ptr++; 1452 break; 1453 1454 case '>': 1455 case '<': 1456 case '|': 1457 case '&': 1458 case '\n': 1459 if (!quote) 1460 return TRUE; 1461 ptr++; 1462 break; 1463 1464 case '%': 1465 if (*++ptr != '_' && !ISALPHA(*ptr)) break; 1466 while (*++ptr == '_' || ISALNUM(*ptr)); 1467 if (*ptr++ == '%') return TRUE; 1468 break; 1469 1470 case '\\': 1471 ptr++; 1472 default: 1473 ptr = CharNext(ptr); 1474 break; 1475 } 1476 } 1477 return FALSE; 1478} 1479 1480/* License: Ruby's */ 1481static inline char * 1482skipspace(char *ptr) 1483{ 1484 while (ISSPACE(*ptr)) 1485 ptr++; 1486 return ptr; 1487} 1488 1489/* License: Artistic or GPL */ 1490int 1491rb_w32_cmdvector(const char *cmd, char ***vec) 1492{ 1493 int globbing, len; 1494 int elements, strsz, done; 1495 int slashes, escape; 1496 char *ptr, *base, *buffer, *cmdline; 1497 char **vptr; 1498 char quote; 1499 NtCmdLineElement *curr, **tail; 1500 NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead; 1501 1502 // 1503 // just return if we don't have a command line 1504 // 1505 1506 while (ISSPACE(*cmd)) 1507 cmd++; 1508 if (!*cmd) { 1509 *vec = NULL; 1510 return 0; 1511 } 1512 1513 ptr = cmdline = strdup(cmd); 1514 1515 // 1516 // Ok, parse the command line, building a list of CmdLineElements. 1517 // When we've finished, and it's an input command (meaning that it's 1518 // the processes argv), we'll do globing and then build the argument 1519 // vector. 1520 // The outer loop does one interation for each element seen. 1521 // The inner loop does one interation for each character in the element. 1522 // 1523 1524 while (*(ptr = skipspace(ptr))) { 1525 base = ptr; 1526 quote = slashes = globbing = escape = 0; 1527 for (done = 0; !done && *ptr; ) { 1528 // 1529 // Switch on the current character. We only care about the 1530 // white-space characters, the wild-card characters, and the 1531 // quote characters. 1532 // 1533 1534 switch (*ptr) { 1535 case '\\': 1536 if (quote != '\'') slashes++; 1537 break; 1538 1539 case ' ': 1540 case '\t': 1541 case '\n': 1542 // 1543 // if we're not in a string, then we're finished with this 1544 // element 1545 // 1546 1547 if (!quote) { 1548 *ptr = 0; 1549 done = 1; 1550 } 1551 break; 1552 1553 case '*': 1554 case '?': 1555 case '[': 1556 case '{': 1557 // 1558 // record the fact that this element has a wildcard character 1559 // N.B. Don't glob if inside a single quoted string 1560 // 1561 1562 if (quote != '\'') 1563 globbing++; 1564 slashes = 0; 1565 break; 1566 1567 case '\'': 1568 case '\"': 1569 // 1570 // if we're already in a string, see if this is the 1571 // terminating close-quote. If it is, we're finished with 1572 // the string, but not neccessarily with the element. 1573 // If we're not already in a string, start one. 1574 // 1575 1576 if (!(slashes & 1)) { 1577 if (!quote) 1578 quote = *ptr; 1579 else if (quote == *ptr) { 1580 if (quote == '"' && quote == ptr[1]) 1581 ptr++; 1582 quote = '\0'; 1583 } 1584 } 1585 escape++; 1586 slashes = 0; 1587 break; 1588 1589 default: 1590 ptr = CharNext(ptr); 1591 slashes = 0; 1592 continue; 1593 } 1594 ptr++; 1595 } 1596 1597 // 1598 // when we get here, we've got a pair of pointers to the element, 1599 // base and ptr. Base points to the start of the element while ptr 1600 // points to the character following the element. 1601 // 1602 1603 len = ptr - base; 1604 if (done) --len; 1605 1606 // 1607 // if it's an input vector element and it's enclosed by quotes, 1608 // we can remove them. 1609 // 1610 1611 if (escape) { 1612 char *p = base, c; 1613 slashes = quote = 0; 1614 while (p < base + len) { 1615 switch (c = *p) { 1616 case '\\': 1617 p++; 1618 if (quote != '\'') slashes++; 1619 break; 1620 1621 case '\'': 1622 case '"': 1623 if (!(slashes & 1) && quote && quote != c) { 1624 p++; 1625 slashes = 0; 1626 break; 1627 } 1628 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1), 1629 base + len - p); 1630 len -= ((slashes + 1) >> 1) + (~slashes & 1); 1631 p -= (slashes + 1) >> 1; 1632 if (!(slashes & 1)) { 1633 if (quote) { 1634 if (quote == '"' && quote == *p) 1635 p++; 1636 quote = '\0'; 1637 } 1638 else 1639 quote = c; 1640 } 1641 else 1642 p++; 1643 slashes = 0; 1644 break; 1645 1646 default: 1647 p = CharNext(p); 1648 slashes = 0; 1649 break; 1650 } 1651 } 1652 } 1653 1654 curr = (NtCmdLineElement *)calloc(sizeof(NtCmdLineElement), 1); 1655 if (!curr) goto do_nothing; 1656 curr->str = base; 1657 curr->len = len; 1658 1659 if (globbing && (tail = cmdglob(curr, cmdtail))) { 1660 cmdtail = tail; 1661 } 1662 else { 1663 *cmdtail = curr; 1664 cmdtail = &curr->next; 1665 } 1666 } 1667 1668 // 1669 // Almost done! 1670 // Count up the elements, then allocate space for a vector of pointers 1671 // (argv) and a string table for the elements. 1672 // 1673 1674 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) { 1675 elements++; 1676 strsz += (curr->len + 1); 1677 } 1678 1679 len = (elements+1)*sizeof(char *) + strsz; 1680 buffer = (char *)malloc(len); 1681 if (!buffer) { 1682 do_nothing: 1683 while (curr = cmdhead) { 1684 cmdhead = curr->next; 1685 if (curr->flags & NTMALLOC) free(curr->str); 1686 free(curr); 1687 } 1688 free(cmdline); 1689 for (vptr = *vec; *vptr; ++vptr); 1690 return vptr - *vec; 1691 } 1692 1693 // 1694 // make vptr point to the start of the buffer 1695 // and ptr point to the area we'll consider the string table. 1696 // 1697 // buffer (*vec) 1698 // | 1699 // V ^---------------------V 1700 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 1701 // | | | .... | NULL | | ..... |\0 | | ..... |\0 |... 1702 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 1703 // |- elements+1 -| ^ 1st element ^ 2nd element 1704 1705 vptr = (char **) buffer; 1706 1707 ptr = buffer + (elements+1) * sizeof(char *); 1708 1709 while (curr = cmdhead) { 1710 strlcpy(ptr, curr->str, curr->len + 1); 1711 *vptr++ = ptr; 1712 ptr += curr->len + 1; 1713 cmdhead = curr->next; 1714 if (curr->flags & NTMALLOC) free(curr->str); 1715 free(curr); 1716 } 1717 *vptr = 0; 1718 1719 *vec = (char **) buffer; 1720 free(cmdline); 1721 return elements; 1722} 1723 1724// 1725// UNIX compatible directory access functions for NT 1726// 1727 1728#define PATHLEN 1024 1729 1730// 1731// The idea here is to read all the directory names into a string table 1732// (separated by nulls) and when one of the other dir functions is called 1733// return the pointer to the current file name. 1734// 1735 1736/* License: Ruby's */ 1737#define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT)) 1738#define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT)) 1739 1740#define BitOfIsDir(n) ((n) * 2) 1741#define BitOfIsRep(n) ((n) * 2 + 1) 1742#define DIRENT_PER_CHAR (CHAR_BIT / 2) 1743 1744/* License: Artistic or GPL */ 1745static HANDLE 1746open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd) 1747{ 1748 HANDLE fh; 1749 static const WCHAR wildcard[] = L"\\*"; 1750 WCHAR *scanname; 1751 WCHAR *p; 1752 int len; 1753 VALUE v; 1754 1755 // 1756 // Create the search pattern 1757 // 1758 len = lstrlenW(filename); 1759 scanname = ALLOCV_N(WCHAR, v, len + sizeof(wildcard) / sizeof(WCHAR)); 1760 lstrcpyW(scanname, filename); 1761 p = CharPrevW(scanname, scanname + len); 1762 if (*p == L'/' || *p == L'\\' || *p == L':') 1763 lstrcatW(scanname, wildcard + 1); 1764 else 1765 lstrcatW(scanname, wildcard); 1766 1767 // 1768 // do the FindFirstFile call 1769 // 1770 fh = FindFirstFileW(scanname, fd); 1771 ALLOCV_END(v); 1772 if (fh == INVALID_HANDLE_VALUE) { 1773 errno = map_errno(GetLastError()); 1774 } 1775 return fh; 1776} 1777 1778/* License: Artistic or GPL */ 1779static DIR * 1780opendir_internal(WCHAR *wpath, const char *filename) 1781{ 1782 struct stati64 sbuf; 1783 WIN32_FIND_DATAW fd; 1784 HANDLE fh; 1785 DIR *p; 1786 long len; 1787 long idx; 1788 WCHAR *tmpW; 1789 char *tmp; 1790 1791 // 1792 // check to see if we've got a directory 1793 // 1794 if (wstati64(wpath, &sbuf) < 0) { 1795 return NULL; 1796 } 1797 if (!(sbuf.st_mode & S_IFDIR) && 1798 (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' || 1799 ((1 << ((filename[0] & 0x5f) - 'A')) & GetLogicalDrives()) == 0)) { 1800 errno = ENOTDIR; 1801 return NULL; 1802 } 1803 fh = open_dir_handle(wpath, &fd); 1804 if (fh == INVALID_HANDLE_VALUE) { 1805 return NULL; 1806 } 1807 1808 // 1809 // Get us a DIR structure 1810 // 1811 p = calloc(sizeof(DIR), 1); 1812 if (p == NULL) 1813 return NULL; 1814 1815 idx = 0; 1816 1817 // 1818 // loop finding all the files that match the wildcard 1819 // (which should be all of them in this directory!). 1820 // the variable idx should point one past the null terminator 1821 // of the previous string found. 1822 // 1823 do { 1824 len = lstrlenW(fd.cFileName) + 1; 1825 1826 // 1827 // bump the string table size by enough for the 1828 // new name and it's null terminator 1829 // 1830 tmpW = realloc(p->start, (idx + len) * sizeof(WCHAR)); 1831 if (!tmpW) { 1832 error: 1833 rb_w32_closedir(p); 1834 FindClose(fh); 1835 errno = ENOMEM; 1836 return NULL; 1837 } 1838 1839 p->start = tmpW; 1840 memcpy(&p->start[idx], fd.cFileName, len * sizeof(WCHAR)); 1841 1842 if (p->nfiles % DIRENT_PER_CHAR == 0) { 1843 tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1); 1844 if (!tmp) 1845 goto error; 1846 p->bits = tmp; 1847 p->bits[p->nfiles / DIRENT_PER_CHAR] = 0; 1848 } 1849 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 1850 SetBit(p->bits, BitOfIsDir(p->nfiles)); 1851 if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) 1852 SetBit(p->bits, BitOfIsRep(p->nfiles)); 1853 1854 p->nfiles++; 1855 idx += len; 1856 } while (FindNextFileW(fh, &fd)); 1857 FindClose(fh); 1858 p->size = idx; 1859 p->curr = p->start; 1860 return p; 1861} 1862 1863/* License: Ruby's */ 1864static inline UINT 1865filecp(void) 1866{ 1867 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP; 1868 return cp; 1869} 1870 1871/* License: Ruby's */ 1872static char * 1873wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen) 1874{ 1875 char *ptr; 1876 int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL) - 1; 1877 if (!(ptr = malloc(len + 1))) return 0; 1878 WideCharToMultiByte(cp, 0, wstr, clen, ptr, len + 1, NULL, NULL); 1879 if (plen) *plen = len; 1880 return ptr; 1881} 1882 1883/* License: Ruby's */ 1884static WCHAR * 1885mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen) 1886{ 1887 WCHAR *ptr; 1888 int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0) - 1; 1889 if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0; 1890 MultiByteToWideChar(cp, 0, str, clen, ptr, len + 1); 1891 if (plen) *plen = len; 1892 return ptr; 1893} 1894 1895/* License: Ruby's */ 1896DIR * 1897rb_w32_opendir(const char *filename) 1898{ 1899 DIR *ret; 1900 WCHAR *wpath = filecp_to_wstr(filename, NULL); 1901 if (!wpath) 1902 return NULL; 1903 ret = opendir_internal(wpath, filename); 1904 free(wpath); 1905 return ret; 1906} 1907 1908/* License: Ruby's */ 1909DIR * 1910rb_w32_uopendir(const char *filename) 1911{ 1912 DIR *ret; 1913 WCHAR *wpath = utf8_to_wstr(filename, NULL); 1914 if (!wpath) 1915 return NULL; 1916 ret = opendir_internal(wpath, filename); 1917 free(wpath); 1918 return ret; 1919} 1920 1921// 1922// Move to next entry 1923// 1924 1925/* License: Artistic or GPL */ 1926static void 1927move_to_next_entry(DIR *dirp) 1928{ 1929 if (dirp->curr) { 1930 dirp->loc++; 1931 dirp->curr += lstrlenW(dirp->curr) + 1; 1932 if (dirp->curr >= (dirp->start + dirp->size)) { 1933 dirp->curr = NULL; 1934 } 1935 } 1936} 1937 1938// 1939// Readdir just returns the current string pointer and bumps the 1940// string pointer to the next entry. 1941// 1942/* License: Ruby's */ 1943static BOOL 1944win32_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *dummy) 1945{ 1946 if (!(entry->d_name = wstr_to_filecp(file, &entry->d_namlen))) 1947 return FALSE; 1948 return TRUE; 1949} 1950 1951/* License: Ruby's */ 1952VALUE 1953rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc) 1954{ 1955 static rb_encoding *utf16 = (rb_encoding *)-1; 1956 VALUE src; 1957 1958 if (utf16 == (rb_encoding *)-1) { 1959 utf16 = rb_enc_find("UTF-16LE"); 1960 if (utf16 == rb_ascii8bit_encoding()) 1961 utf16 = NULL; 1962 } 1963 if (!utf16) 1964 /* maybe miniruby */ 1965 return Qnil; 1966 1967 src = rb_enc_str_new((char *)wstr, lstrlenW(wstr) * sizeof(WCHAR), utf16); 1968 return rb_str_encode(src, rb_enc_from_encoding(enc), ECONV_UNDEF_REPLACE, Qnil); 1969} 1970 1971/* License: Ruby's */ 1972char * 1973rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc) 1974{ 1975 VALUE str = rb_w32_conv_from_wchar(wstr, enc); 1976 long len; 1977 char *ptr; 1978 1979 if (NIL_P(str)) return wstr_to_filecp(wstr, lenp); 1980 *lenp = len = RSTRING_LEN(str); 1981 memcpy(ptr = malloc(len + 1), RSTRING_PTR(str), len); 1982 ptr[len] = '\0'; 1983 return ptr; 1984} 1985 1986/* License: Ruby's */ 1987static BOOL 1988ruby_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *enc) 1989{ 1990 if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc))) 1991 return FALSE; 1992 return TRUE; 1993} 1994 1995/* License: Artistic or GPL */ 1996static struct direct * 1997readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, struct direct *, rb_encoding *), rb_encoding *enc) 1998{ 1999 static int dummy = 0; 2000 2001 if (dirp->curr) { 2002 2003 // 2004 // first set up the structure to return 2005 // 2006 if (dirp->dirstr.d_name) 2007 free(dirp->dirstr.d_name); 2008 conv(dirp->curr, &dirp->dirstr, enc); 2009 2010 // 2011 // Fake inode 2012 // 2013 dirp->dirstr.d_ino = dummy++; 2014 2015 // 2016 // Attributes 2017 // 2018 dirp->dirstr.d_isdir = GetBit(dirp->bits, BitOfIsDir(dirp->loc)); 2019 dirp->dirstr.d_isrep = GetBit(dirp->bits, BitOfIsRep(dirp->loc)); 2020 2021 // 2022 // Now set up for the next call to readdir 2023 // 2024 2025 move_to_next_entry(dirp); 2026 2027 return &(dirp->dirstr); 2028 2029 } 2030 else 2031 return NULL; 2032} 2033 2034/* License: Ruby's */ 2035struct direct * 2036rb_w32_readdir(DIR *dirp, rb_encoding *enc) 2037{ 2038 if (!enc || enc == rb_ascii8bit_encoding()) 2039 return readdir_internal(dirp, win32_direct_conv, NULL); 2040 else 2041 return readdir_internal(dirp, ruby_direct_conv, enc); 2042} 2043 2044// 2045// Telldir returns the current string pointer position 2046// 2047 2048/* License: Artistic or GPL */ 2049long 2050rb_w32_telldir(DIR *dirp) 2051{ 2052 return dirp->loc; 2053} 2054 2055// 2056// Seekdir moves the string pointer to a previously saved position 2057// (Saved by telldir). 2058 2059/* License: Ruby's */ 2060void 2061rb_w32_seekdir(DIR *dirp, long loc) 2062{ 2063 if (dirp->loc > loc) rb_w32_rewinddir(dirp); 2064 2065 while (dirp->curr && dirp->loc < loc) { 2066 move_to_next_entry(dirp); 2067 } 2068} 2069 2070// 2071// Rewinddir resets the string pointer to the start 2072// 2073 2074/* License: Artistic or GPL */ 2075void 2076rb_w32_rewinddir(DIR *dirp) 2077{ 2078 dirp->curr = dirp->start; 2079 dirp->loc = 0; 2080} 2081 2082// 2083// This just free's the memory allocated by opendir 2084// 2085 2086/* License: Artistic or GPL */ 2087void 2088rb_w32_closedir(DIR *dirp) 2089{ 2090 if (dirp) { 2091 if (dirp->dirstr.d_name) 2092 free(dirp->dirstr.d_name); 2093 if (dirp->start) 2094 free(dirp->start); 2095 if (dirp->bits) 2096 free(dirp->bits); 2097 free(dirp); 2098 } 2099} 2100 2101#if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__ 2102#define MSVCRT_THREADS 2103#endif 2104#ifdef MSVCRT_THREADS 2105# define MTHREAD_ONLY(x) x 2106# define STHREAD_ONLY(x) 2107#elif defined(__BORLANDC__) 2108# define MTHREAD_ONLY(x) 2109# define STHREAD_ONLY(x) 2110#else 2111# define MTHREAD_ONLY(x) 2112# define STHREAD_ONLY(x) x 2113#endif 2114 2115/* License: Ruby's */ 2116typedef struct { 2117 intptr_t osfhnd; /* underlying OS file HANDLE */ 2118 char osfile; /* attributes of file (e.g., open in text mode?) */ 2119 char pipech; /* one char buffer for handles opened on pipes */ 2120#ifdef MSVCRT_THREADS 2121 int lockinitflag; 2122 CRITICAL_SECTION lock; 2123#endif 2124#if RUBY_MSVCRT_VERSION >= 80 2125 char textmode; 2126 char pipech2[2]; 2127#endif 2128} ioinfo; 2129 2130#if !defined _CRTIMP || defined __MINGW32__ 2131#undef _CRTIMP 2132#define _CRTIMP __declspec(dllimport) 2133#endif 2134 2135#if !defined(__BORLANDC__) 2136EXTERN_C _CRTIMP ioinfo * __pioinfo[]; 2137static inline ioinfo* _pioinfo(int); 2138 2139#define IOINFO_L2E 5 2140#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) 2141#define _osfhnd(i) (_pioinfo(i)->osfhnd) 2142#define _osfile(i) (_pioinfo(i)->osfile) 2143#define _pipech(i) (_pioinfo(i)->pipech) 2144 2145#if RUBY_MSVCRT_VERSION >= 80 2146static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */ 2147 2148/* License: Ruby's */ 2149static void 2150set_pioinfo_extra(void) 2151{ 2152 int fd; 2153 2154 fd = _open("NUL", O_RDONLY); 2155 for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra += sizeof(void *)) { 2156 if (_osfhnd(fd) == _get_osfhandle(fd)) { 2157 break; 2158 } 2159 } 2160 _close(fd); 2161 2162 if (pioinfo_extra > 64) { 2163 /* not found, maybe something wrong... */ 2164 pioinfo_extra = 0; 2165 } 2166} 2167#else 2168#define pioinfo_extra 0 2169#endif 2170 2171static inline ioinfo* 2172_pioinfo(int fd) 2173{ 2174 const size_t sizeof_ioinfo = sizeof(ioinfo) + pioinfo_extra; 2175 return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] + 2176 (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo); 2177} 2178 2179#define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh) 2180#define _set_osflags(fh, flags) (_osfile(fh) = (flags)) 2181 2182#define FOPEN 0x01 /* file handle open */ 2183#define FEOFLAG 0x02 /* end of file has been encountered */ 2184#define FPIPE 0x08 /* file handle refers to a pipe */ 2185#define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */ 2186#define FAPPEND 0x20 /* file handle opened O_APPEND */ 2187#define FDEV 0x40 /* file handle refers to device */ 2188#define FTEXT 0x80 /* file handle is in text mode */ 2189 2190static int is_socket(SOCKET); 2191static int is_console(SOCKET); 2192 2193/* License: Ruby's */ 2194int 2195rb_w32_io_cancelable_p(int fd) 2196{ 2197 return cancel_io != NULL && (is_socket(TO_SOCKET(fd)) || !is_console(TO_SOCKET(fd))); 2198} 2199 2200/* License: Ruby's */ 2201static int 2202rb_w32_open_osfhandle(intptr_t osfhandle, int flags) 2203{ 2204 int fh; 2205 char fileflags; /* _osfile flags */ 2206 HANDLE hF; 2207 2208 /* copy relevant flags from second parameter */ 2209 fileflags = FDEV; 2210 2211 if (flags & O_APPEND) 2212 fileflags |= FAPPEND; 2213 2214 if (flags & O_TEXT) 2215 fileflags |= FTEXT; 2216 2217 if (flags & O_NOINHERIT) 2218 fileflags |= FNOINHERIT; 2219 2220 /* attempt to allocate a C Runtime file handle */ 2221 hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 2222 fh = _open_osfhandle((intptr_t)hF, 0); 2223 CloseHandle(hF); 2224 if (fh == -1) { 2225 errno = EMFILE; /* too many open files */ 2226 _doserrno = 0L; /* not an OS error */ 2227 } 2228 else { 2229 2230 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock))); 2231 /* the file is open. now, set the info in _osfhnd array */ 2232 _set_osfhnd(fh, osfhandle); 2233 2234 fileflags |= FOPEN; /* mark as open */ 2235 2236 _set_osflags(fh, fileflags); /* set osfile entry */ 2237 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock)); 2238 } 2239 return fh; /* return handle */ 2240} 2241 2242/* License: Ruby's */ 2243static void 2244init_stdhandle(void) 2245{ 2246 int nullfd = -1; 2247 int keep = 0; 2248#define open_null(fd) \ 2249 (((nullfd < 0) ? \ 2250 (nullfd = open("NUL", O_RDWR)) : 0), \ 2251 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \ 2252 (fd)) 2253 2254 if (fileno(stdin) < 0) { 2255 stdin->_file = open_null(0); 2256 } 2257 else { 2258 setmode(fileno(stdin), O_BINARY); 2259 } 2260 if (fileno(stdout) < 0) { 2261 stdout->_file = open_null(1); 2262 } 2263 if (fileno(stderr) < 0) { 2264 stderr->_file = open_null(2); 2265 } 2266 if (nullfd >= 0 && !keep) close(nullfd); 2267 setvbuf(stderr, NULL, _IONBF, 0); 2268} 2269#else 2270 2271#define _set_osfhnd(fh, osfh) (void)((fh), (osfh)) 2272#define _set_osflags(fh, flags) (void)((fh), (flags)) 2273 2274/* License: Ruby's */ 2275static void 2276init_stdhandle(void) 2277{ 2278} 2279#endif 2280 2281/* License: Ruby's */ 2282#ifdef __BORLANDC__ 2283static int 2284rb_w32_open_osfhandle(intptr_t osfhandle, int flags) 2285{ 2286 int fd = _open_osfhandle(osfhandle, flags); 2287 if (fd == -1) { 2288 errno = EMFILE; /* too many open files */ 2289 _doserrno = 0L; /* not an OS error */ 2290 } 2291 return fd; 2292} 2293#endif 2294 2295#undef getsockopt 2296 2297/* License: Ruby's */ 2298static int 2299is_socket(SOCKET sock) 2300{ 2301 if (socklist_lookup(sock, NULL)) 2302 return TRUE; 2303 else 2304 return FALSE; 2305} 2306 2307/* License: Ruby's */ 2308int 2309rb_w32_is_socket(int fd) 2310{ 2311 return is_socket(TO_SOCKET(fd)); 2312} 2313 2314// 2315// Since the errors returned by the socket error function 2316// WSAGetLastError() are not known by the library routine strerror 2317// we have to roll our own. 2318// 2319 2320#undef strerror 2321 2322/* License: Artistic or GPL */ 2323char * 2324rb_w32_strerror(int e) 2325{ 2326 static char buffer[512]; 2327 DWORD source = 0; 2328 char *p; 2329 2330#if defined __BORLANDC__ && defined ENOTEMPTY // _sys_errlist is broken 2331 switch (e) { 2332 case ENAMETOOLONG: 2333 return "Filename too long"; 2334 case ENOTEMPTY: 2335 return "Directory not empty"; 2336 } 2337#endif 2338 2339 if (e < 0 || e > sys_nerr) { 2340 if (e < 0) 2341 e = GetLastError(); 2342#if WSAEWOULDBLOCK != EWOULDBLOCK 2343 else if (e >= EADDRINUSE && e <= EWOULDBLOCK) { 2344 static int s = -1; 2345 int i; 2346 if (s < 0) 2347 for (s = 0; s < (int)(sizeof(errmap)/sizeof(*errmap)); s++) 2348 if (errmap[s].winerr == WSAEWOULDBLOCK) 2349 break; 2350 for (i = s; i < (int)(sizeof(errmap)/sizeof(*errmap)); i++) 2351 if (errmap[i].err == e) { 2352 e = errmap[i].winerr; 2353 break; 2354 } 2355 } 2356#endif 2357 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 2358 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 2359 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 2360 buffer, sizeof(buffer), NULL) == 0 && 2361 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 2362 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0, 2363 buffer, sizeof(buffer), NULL) == 0) 2364 strlcpy(buffer, "Unknown Error", sizeof(buffer)); 2365 } 2366 else 2367 strlcpy(buffer, strerror(e), sizeof(buffer)); 2368 2369 p = buffer; 2370 while ((p = strpbrk(p, "\r\n")) != NULL) { 2371 memmove(p, p + 1, strlen(p)); 2372 } 2373 return buffer; 2374} 2375 2376// 2377// various stubs 2378// 2379 2380 2381// Ownership 2382// 2383// Just pretend that everyone is a superuser. NT will let us know if 2384// we don't really have permission to do something. 2385// 2386 2387#define ROOT_UID 0 2388#define ROOT_GID 0 2389 2390/* License: Artistic or GPL */ 2391rb_uid_t 2392getuid(void) 2393{ 2394 return ROOT_UID; 2395} 2396 2397/* License: Artistic or GPL */ 2398rb_uid_t 2399geteuid(void) 2400{ 2401 return ROOT_UID; 2402} 2403 2404/* License: Artistic or GPL */ 2405rb_gid_t 2406getgid(void) 2407{ 2408 return ROOT_GID; 2409} 2410 2411/* License: Artistic or GPL */ 2412rb_gid_t 2413getegid(void) 2414{ 2415 return ROOT_GID; 2416} 2417 2418/* License: Artistic or GPL */ 2419int 2420setuid(rb_uid_t uid) 2421{ 2422 return (uid == ROOT_UID ? 0 : -1); 2423} 2424 2425/* License: Artistic or GPL */ 2426int 2427setgid(rb_gid_t gid) 2428{ 2429 return (gid == ROOT_GID ? 0 : -1); 2430} 2431 2432// 2433// File system stuff 2434// 2435 2436/* License: Artistic or GPL */ 2437int 2438ioctl(int i, int u, ...) 2439{ 2440 errno = EINVAL; 2441 return -1; 2442} 2443 2444void 2445rb_w32_fdset(int fd, fd_set *set) 2446{ 2447 FD_SET(fd, set); 2448} 2449 2450#undef FD_CLR 2451 2452/* License: Ruby's */ 2453void 2454rb_w32_fdclr(int fd, fd_set *set) 2455{ 2456 unsigned int i; 2457 SOCKET s = TO_SOCKET(fd); 2458 2459 for (i = 0; i < set->fd_count; i++) { 2460 if (set->fd_array[i] == s) { 2461 memmove(&set->fd_array[i], &set->fd_array[i+1], 2462 sizeof(set->fd_array[0]) * (--set->fd_count - i)); 2463 break; 2464 } 2465 } 2466} 2467 2468#undef FD_ISSET 2469 2470/* License: Ruby's */ 2471int 2472rb_w32_fdisset(int fd, fd_set *set) 2473{ 2474 int ret; 2475 SOCKET s = TO_SOCKET(fd); 2476 if (s == (SOCKET)INVALID_HANDLE_VALUE) 2477 return 0; 2478 RUBY_CRITICAL(ret = __WSAFDIsSet(s, set)); 2479 return ret; 2480} 2481 2482/* License: Ruby's */ 2483void 2484rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max) 2485{ 2486 max = min(src->fd_count, (UINT)max); 2487 if ((UINT)dst->capa < (UINT)max) { 2488 dst->capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE; 2489 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa); 2490 } 2491 2492 memcpy(dst->fdset->fd_array, src->fd_array, 2493 max * sizeof(src->fd_array[0])); 2494 dst->fdset->fd_count = src->fd_count; 2495} 2496 2497/* License: Ruby's */ 2498void 2499rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src) 2500{ 2501 if ((UINT)dst->capa < src->fdset->fd_count) { 2502 dst->capa = (src->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE; 2503 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa); 2504 } 2505 2506 memcpy(dst->fdset->fd_array, src->fdset->fd_array, 2507 src->fdset->fd_count * sizeof(src->fdset->fd_array[0])); 2508 dst->fdset->fd_count = src->fdset->fd_count; 2509} 2510 2511// 2512// Networking trampolines 2513// These are used to avoid socket startup/shutdown overhead in case 2514// the socket routines aren't used. 2515// 2516 2517#undef select 2518 2519/* License: Ruby's */ 2520static int 2521extract_fd(rb_fdset_t *dst, fd_set *src, int (*func)(SOCKET)) 2522{ 2523 unsigned int s = 0; 2524 unsigned int m = 0; 2525 if (!src) return 0; 2526 2527 while (s < src->fd_count) { 2528 SOCKET fd = src->fd_array[s]; 2529 2530 if (!func || (*func)(fd)) { 2531 if (dst) { /* move it to dst */ 2532 unsigned int d; 2533 2534 for (d = 0; d < dst->fdset->fd_count; d++) { 2535 if (dst->fdset->fd_array[d] == fd) 2536 break; 2537 } 2538 if (d == dst->fdset->fd_count) { 2539 if ((int)dst->fdset->fd_count >= dst->capa) { 2540 dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE; 2541 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa); 2542 } 2543 dst->fdset->fd_array[dst->fdset->fd_count++] = fd; 2544 } 2545 memmove( 2546 &src->fd_array[s], 2547 &src->fd_array[s+1], 2548 sizeof(src->fd_array[0]) * (--src->fd_count - s)); 2549 } 2550 else { 2551 m++; 2552 s++; 2553 } 2554 } 2555 else s++; 2556 } 2557 2558 return dst ? dst->fdset->fd_count : m; 2559} 2560 2561/* License: Ruby's */ 2562static int 2563copy_fd(fd_set *dst, fd_set *src) 2564{ 2565 unsigned int s; 2566 if (!src || !dst) return 0; 2567 2568 for (s = 0; s < src->fd_count; ++s) { 2569 SOCKET fd = src->fd_array[s]; 2570 unsigned int d; 2571 for (d = 0; d < dst->fd_count; ++d) { 2572 if (dst->fd_array[d] == fd) 2573 break; 2574 } 2575 if (d == dst->fd_count && d < FD_SETSIZE) { 2576 dst->fd_array[dst->fd_count++] = fd; 2577 } 2578 } 2579 2580 return dst->fd_count; 2581} 2582 2583/* License: Ruby's */ 2584static int 2585is_not_socket(SOCKET sock) 2586{ 2587 return !is_socket(sock); 2588} 2589 2590/* License: Ruby's */ 2591static int 2592is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */ 2593{ 2594 int ret; 2595 2596 RUBY_CRITICAL({ 2597 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE); 2598 }); 2599 2600 return ret; 2601} 2602 2603/* License: Ruby's */ 2604static int 2605is_readable_pipe(SOCKET sock) /* call this for pipe only */ 2606{ 2607 int ret; 2608 DWORD n = 0; 2609 2610 RUBY_CRITICAL( 2611 if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) { 2612 ret = (n > 0); 2613 } 2614 else { 2615 ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */ 2616 } 2617 ); 2618 2619 return ret; 2620} 2621 2622/* License: Ruby's */ 2623static int 2624is_console(SOCKET sock) /* DONT call this for SOCKET! */ 2625{ 2626 int ret; 2627 DWORD n = 0; 2628 INPUT_RECORD ir; 2629 2630 RUBY_CRITICAL( 2631 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n)) 2632 ); 2633 2634 return ret; 2635} 2636 2637/* License: Ruby's */ 2638static int 2639is_readable_console(SOCKET sock) /* call this for console only */ 2640{ 2641 int ret = 0; 2642 DWORD n = 0; 2643 INPUT_RECORD ir; 2644 2645 RUBY_CRITICAL( 2646 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) { 2647 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown && 2648 ir.Event.KeyEvent.uChar.AsciiChar) { 2649 ret = 1; 2650 } 2651 else { 2652 ReadConsoleInput((HANDLE)sock, &ir, 1, &n); 2653 } 2654 } 2655 ); 2656 2657 return ret; 2658} 2659 2660/* License: Ruby's */ 2661static int 2662is_invalid_handle(SOCKET sock) 2663{ 2664 return (HANDLE)sock == INVALID_HANDLE_VALUE; 2665} 2666 2667/* License: Artistic or GPL */ 2668static int 2669do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, 2670 struct timeval *timeout) 2671{ 2672 int r = 0; 2673 2674 if (nfds == 0) { 2675 if (timeout) 2676 rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000); 2677 else 2678 rb_w32_sleep(INFINITE); 2679 } 2680 else { 2681 if (!NtSocketsInitialized) 2682 StartSockets(); 2683 2684 RUBY_CRITICAL( 2685 EnterCriticalSection(&select_mutex); 2686 r = select(nfds, rd, wr, ex, timeout); 2687 LeaveCriticalSection(&select_mutex); 2688 if (r == SOCKET_ERROR) { 2689 errno = map_errno(WSAGetLastError()); 2690 r = -1; 2691 } 2692 ); 2693 } 2694 2695 return r; 2696} 2697 2698/* 2699 * rest -= wait 2700 * return 0 if rest is smaller than wait. 2701 */ 2702/* License: Ruby's */ 2703int 2704rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait) 2705{ 2706 if (rest->tv_sec < wait->tv_sec) { 2707 return 0; 2708 } 2709 while (rest->tv_usec < wait->tv_usec) { 2710 if (rest->tv_sec <= wait->tv_sec) { 2711 return 0; 2712 } 2713 rest->tv_sec -= 1; 2714 rest->tv_usec += 1000 * 1000; 2715 } 2716 rest->tv_sec -= wait->tv_sec; 2717 rest->tv_usec -= wait->tv_usec; 2718 return rest->tv_sec != 0 || rest->tv_usec != 0; 2719} 2720 2721/* License: Ruby's */ 2722static inline int 2723compare(const struct timeval *t1, const struct timeval *t2) 2724{ 2725 if (t1->tv_sec < t2->tv_sec) 2726 return -1; 2727 if (t1->tv_sec > t2->tv_sec) 2728 return 1; 2729 if (t1->tv_usec < t2->tv_usec) 2730 return -1; 2731 if (t1->tv_usec > t2->tv_usec) 2732 return 1; 2733 return 0; 2734} 2735 2736#undef Sleep 2737 2738int rb_w32_check_interrupt(void *); /* @internal */ 2739 2740/* @internal */ 2741/* License: Ruby's */ 2742int 2743rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, 2744 struct timeval *timeout, void *th) 2745{ 2746 int r; 2747 rb_fdset_t pipe_rd; 2748 rb_fdset_t cons_rd; 2749 rb_fdset_t else_rd; 2750 rb_fdset_t else_wr; 2751 rb_fdset_t except; 2752 int nonsock = 0; 2753 struct timeval limit = {0, 0}; 2754 2755 if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) { 2756 errno = EINVAL; 2757 return -1; 2758 } 2759 2760 if (timeout) { 2761 if (timeout->tv_sec < 0 || 2762 timeout->tv_usec < 0 || 2763 timeout->tv_usec >= 1000000) { 2764 errno = EINVAL; 2765 return -1; 2766 } 2767 gettimeofday(&limit, NULL); 2768 limit.tv_sec += timeout->tv_sec; 2769 limit.tv_usec += timeout->tv_usec; 2770 if (limit.tv_usec >= 1000000) { 2771 limit.tv_usec -= 1000000; 2772 limit.tv_sec++; 2773 } 2774 } 2775 2776 // assume else_{rd,wr} (other than socket, pipe reader, console reader) 2777 // are always readable/writable. but this implementation still has 2778 // problem. if pipe's buffer is full, writing to pipe will block 2779 // until some data is read from pipe. but ruby is single threaded system, 2780 // so whole system will be blocked forever. 2781 2782 rb_fd_init(&else_rd); 2783 nonsock += extract_fd(&else_rd, rd, is_not_socket); 2784 2785 rb_fd_init(&else_wr); 2786 nonsock += extract_fd(&else_wr, wr, is_not_socket); 2787 2788 // check invalid handles 2789 if (extract_fd(NULL, else_rd.fdset, is_invalid_handle) > 0 || 2790 extract_fd(NULL, else_wr.fdset, is_invalid_handle) > 0) { 2791 rb_fd_term(&else_wr); 2792 rb_fd_term(&else_rd); 2793 errno = EBADF; 2794 return -1; 2795 } 2796 2797 rb_fd_init(&pipe_rd); 2798 extract_fd(&pipe_rd, else_rd.fdset, is_pipe); // should not call is_pipe for socket 2799 2800 rb_fd_init(&cons_rd); 2801 extract_fd(&cons_rd, else_rd.fdset, is_console); // ditto 2802 2803 rb_fd_init(&except); 2804 extract_fd(&except, ex, is_not_socket); // drop only 2805 2806 r = 0; 2807 if (rd && (int)rd->fd_count > r) r = (int)rd->fd_count; 2808 if (wr && (int)wr->fd_count > r) r = (int)wr->fd_count; 2809 if (ex && (int)ex->fd_count > r) r = (int)ex->fd_count; 2810 if (nfds > r) nfds = r; 2811 2812 { 2813 struct timeval rest; 2814 struct timeval wait; 2815 struct timeval zero; 2816 wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms 2817 zero.tv_sec = 0; zero.tv_usec = 0; // 0ms 2818 for (;;) { 2819 if (th && rb_w32_check_interrupt(th) != WAIT_TIMEOUT) { 2820 r = -1; 2821 break; 2822 } 2823 if (nonsock) { 2824 // modifying {else,pipe,cons}_rd is safe because 2825 // if they are modified, function returns immediately. 2826 extract_fd(&else_rd, pipe_rd.fdset, is_readable_pipe); 2827 extract_fd(&else_rd, cons_rd.fdset, is_readable_console); 2828 } 2829 2830 if (else_rd.fdset->fd_count || else_wr.fdset->fd_count) { 2831 r = do_select(nfds, rd, wr, ex, &zero); // polling 2832 if (r < 0) break; // XXX: should I ignore error and return signaled handles? 2833 r += copy_fd(rd, else_rd.fdset); 2834 r += copy_fd(wr, else_wr.fdset); 2835 if (ex) 2836 r += ex->fd_count; 2837 break; 2838 } 2839 else { 2840 struct timeval *dowait = &wait; 2841 2842 fd_set orig_rd; 2843 fd_set orig_wr; 2844 fd_set orig_ex; 2845 2846 FD_ZERO(&orig_rd); 2847 FD_ZERO(&orig_wr); 2848 FD_ZERO(&orig_ex); 2849 2850 if (rd) copy_fd(&orig_rd, rd); 2851 if (wr) copy_fd(&orig_wr, wr); 2852 if (ex) copy_fd(&orig_ex, ex); 2853 r = do_select(nfds, rd, wr, ex, &zero); // polling 2854 if (r != 0) break; // signaled or error 2855 if (rd) copy_fd(rd, &orig_rd); 2856 if (wr) copy_fd(wr, &orig_wr); 2857 if (ex) copy_fd(ex, &orig_ex); 2858 2859 if (timeout) { 2860 struct timeval now; 2861 gettimeofday(&now, NULL); 2862 rest = limit; 2863 if (!rb_w32_time_subtract(&rest, &now)) break; 2864 if (compare(&rest, &wait) < 0) dowait = &rest; 2865 } 2866 Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000); 2867 } 2868 } 2869 } 2870 2871 rb_fd_term(&except); 2872 rb_fd_term(&cons_rd); 2873 rb_fd_term(&pipe_rd); 2874 rb_fd_term(&else_wr); 2875 rb_fd_term(&else_rd); 2876 2877 return r; 2878} 2879 2880/* License: Ruby's */ 2881int WSAAPI 2882rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, 2883 struct timeval *timeout) 2884{ 2885 return rb_w32_select_with_thread(nfds, rd, wr, ex, timeout, 0); 2886} 2887 2888/* License: Ruby's */ 2889static FARPROC 2890get_wsa_extension_function(SOCKET s, GUID *guid) 2891{ 2892 DWORD dmy; 2893 FARPROC ptr = NULL; 2894 2895 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, guid, sizeof(*guid), 2896 &ptr, sizeof(ptr), &dmy, NULL, NULL); 2897 if (!ptr) 2898 errno = ENOSYS; 2899 return ptr; 2900} 2901 2902#undef accept 2903 2904/* License: Artistic or GPL */ 2905int WSAAPI 2906rb_w32_accept(int s, struct sockaddr *addr, int *addrlen) 2907{ 2908 SOCKET r; 2909 int fd; 2910 2911 if (!NtSocketsInitialized) { 2912 StartSockets(); 2913 } 2914 RUBY_CRITICAL({ 2915 HANDLE h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 2916 fd = rb_w32_open_osfhandle((intptr_t)h, O_RDWR|O_BINARY|O_NOINHERIT); 2917 if (fd != -1) { 2918 r = accept(TO_SOCKET(s), addr, addrlen); 2919 if (r != INVALID_SOCKET) { 2920 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0); 2921 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 2922 _set_osfhnd(fd, r); 2923 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 2924 CloseHandle(h); 2925 socklist_insert(r, 0); 2926 } 2927 else { 2928 errno = map_errno(WSAGetLastError()); 2929 close(fd); 2930 fd = -1; 2931 } 2932 } 2933 else 2934 CloseHandle(h); 2935 }); 2936 return fd; 2937} 2938 2939#undef bind 2940 2941/* License: Artistic or GPL */ 2942int WSAAPI 2943rb_w32_bind(int s, const struct sockaddr *addr, int addrlen) 2944{ 2945 int r; 2946 2947 if (!NtSocketsInitialized) { 2948 StartSockets(); 2949 } 2950 RUBY_CRITICAL({ 2951 r = bind(TO_SOCKET(s), addr, addrlen); 2952 if (r == SOCKET_ERROR) 2953 errno = map_errno(WSAGetLastError()); 2954 }); 2955 return r; 2956} 2957 2958#undef connect 2959 2960/* License: Artistic or GPL */ 2961int WSAAPI 2962rb_w32_connect(int s, const struct sockaddr *addr, int addrlen) 2963{ 2964 int r; 2965 if (!NtSocketsInitialized) { 2966 StartSockets(); 2967 } 2968 RUBY_CRITICAL({ 2969 r = connect(TO_SOCKET(s), addr, addrlen); 2970 if (r == SOCKET_ERROR) { 2971 int err = WSAGetLastError(); 2972 if (err != WSAEWOULDBLOCK) 2973 errno = map_errno(err); 2974 else 2975 errno = EINPROGRESS; 2976 } 2977 }); 2978 return r; 2979} 2980 2981 2982#undef getpeername 2983 2984/* License: Artistic or GPL */ 2985int WSAAPI 2986rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen) 2987{ 2988 int r; 2989 if (!NtSocketsInitialized) { 2990 StartSockets(); 2991 } 2992 RUBY_CRITICAL({ 2993 r = getpeername(TO_SOCKET(s), addr, addrlen); 2994 if (r == SOCKET_ERROR) 2995 errno = map_errno(WSAGetLastError()); 2996 }); 2997 return r; 2998} 2999 3000#undef getsockname 3001 3002/* License: Artistic or GPL */ 3003int WSAAPI 3004rb_w32_getsockname(int fd, struct sockaddr *addr, int *addrlen) 3005{ 3006 int sock; 3007 int r; 3008 if (!NtSocketsInitialized) { 3009 StartSockets(); 3010 } 3011 RUBY_CRITICAL({ 3012 sock = TO_SOCKET(fd); 3013 r = getsockname(sock, addr, addrlen); 3014 if (r == SOCKET_ERROR) { 3015 DWORD wsaerror = WSAGetLastError(); 3016 if (wsaerror == WSAEINVAL) { 3017 int flags; 3018 if (socklist_lookup(sock, &flags)) { 3019 int af = GET_FAMILY(flags); 3020 if (af) { 3021 memset(addr, 0, *addrlen); 3022 addr->sa_family = af; 3023 return 0; 3024 } 3025 } 3026 } 3027 errno = map_errno(wsaerror); 3028 } 3029 }); 3030 return r; 3031} 3032 3033#undef getsockopt 3034 3035/* License: Artistic or GPL */ 3036int WSAAPI 3037rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen) 3038{ 3039 int r; 3040 if (!NtSocketsInitialized) { 3041 StartSockets(); 3042 } 3043 RUBY_CRITICAL({ 3044 r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen); 3045 if (r == SOCKET_ERROR) 3046 errno = map_errno(WSAGetLastError()); 3047 }); 3048 return r; 3049} 3050 3051#undef ioctlsocket 3052 3053/* License: Artistic or GPL */ 3054int WSAAPI 3055rb_w32_ioctlsocket(int s, long cmd, u_long *argp) 3056{ 3057 int r; 3058 if (!NtSocketsInitialized) { 3059 StartSockets(); 3060 } 3061 RUBY_CRITICAL({ 3062 r = ioctlsocket(TO_SOCKET(s), cmd, argp); 3063 if (r == SOCKET_ERROR) 3064 errno = map_errno(WSAGetLastError()); 3065 }); 3066 return r; 3067} 3068 3069#undef listen 3070 3071/* License: Artistic or GPL */ 3072int WSAAPI 3073rb_w32_listen(int s, int backlog) 3074{ 3075 int r; 3076 if (!NtSocketsInitialized) { 3077 StartSockets(); 3078 } 3079 RUBY_CRITICAL({ 3080 r = listen(TO_SOCKET(s), backlog); 3081 if (r == SOCKET_ERROR) 3082 errno = map_errno(WSAGetLastError()); 3083 }); 3084 return r; 3085} 3086 3087#undef recv 3088#undef recvfrom 3089#undef send 3090#undef sendto 3091 3092/* License: Ruby's */ 3093static int 3094finish_overlapped_socket(BOOL input, SOCKET s, WSAOVERLAPPED *wol, int result, DWORD *len, DWORD size) 3095{ 3096 DWORD flg; 3097 int err; 3098 3099 if (result != SOCKET_ERROR) 3100 *len = size; 3101 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) { 3102 switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) { 3103 case WAIT_OBJECT_0: 3104 RUBY_CRITICAL( 3105 result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg) 3106 ); 3107 if (result) { 3108 *len = size; 3109 break; 3110 } 3111 /* thru */ 3112 default: 3113 if ((err = WSAGetLastError()) == WSAECONNABORTED && !input) 3114 errno = EPIPE; 3115 else 3116 errno = map_errno(WSAGetLastError()); 3117 /* thru */ 3118 case WAIT_OBJECT_0 + 1: 3119 /* interrupted */ 3120 *len = -1; 3121 cancel_io((HANDLE)s); 3122 break; 3123 } 3124 } 3125 else { 3126 if (err == WSAECONNABORTED && !input) 3127 errno = EPIPE; 3128 else 3129 errno = map_errno(err); 3130 *len = -1; 3131 } 3132 CloseHandle(wol->hEvent); 3133 3134 return result; 3135} 3136 3137/* License: Artistic or GPL */ 3138static int 3139overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags, 3140 struct sockaddr *addr, int *addrlen) 3141{ 3142 int r; 3143 int ret; 3144 int mode = 0; 3145 DWORD flg; 3146 WSAOVERLAPPED wol; 3147 WSABUF wbuf; 3148 SOCKET s; 3149 3150 if (!NtSocketsInitialized) 3151 StartSockets(); 3152 3153 s = TO_SOCKET(fd); 3154 socklist_lookup(s, &mode); 3155 if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) { 3156 RUBY_CRITICAL({ 3157 if (input) { 3158 if (addr && addrlen) 3159 r = recvfrom(s, buf, len, flags, addr, addrlen); 3160 else 3161 r = recv(s, buf, len, flags); 3162 if (r == SOCKET_ERROR) 3163 errno = map_errno(WSAGetLastError()); 3164 } 3165 else { 3166 if (addr && addrlen) 3167 r = sendto(s, buf, len, flags, addr, *addrlen); 3168 else 3169 r = send(s, buf, len, flags); 3170 if (r == SOCKET_ERROR) { 3171 DWORD err = WSAGetLastError(); 3172 if (err == WSAECONNABORTED) 3173 errno = EPIPE; 3174 else 3175 errno = map_errno(err); 3176 } 3177 } 3178 }); 3179 } 3180 else { 3181 DWORD size; 3182 DWORD rlen; 3183 wbuf.len = len; 3184 wbuf.buf = buf; 3185 memset(&wol, 0, sizeof(wol)); 3186 RUBY_CRITICAL({ 3187 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 3188 if (input) { 3189 flg = flags; 3190 if (addr && addrlen) 3191 ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen, 3192 &wol, NULL); 3193 else 3194 ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL); 3195 } 3196 else { 3197 if (addr && addrlen) 3198 ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen, 3199 &wol, NULL); 3200 else 3201 ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL); 3202 } 3203 }); 3204 3205 finish_overlapped_socket(input, s, &wol, ret, &rlen, size); 3206 r = (int)rlen; 3207 } 3208 3209 return r; 3210} 3211 3212/* License: Ruby's */ 3213int WSAAPI 3214rb_w32_recv(int fd, char *buf, int len, int flags) 3215{ 3216 return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL); 3217} 3218 3219/* License: Ruby's */ 3220int WSAAPI 3221rb_w32_recvfrom(int fd, char *buf, int len, int flags, 3222 struct sockaddr *from, int *fromlen) 3223{ 3224 return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen); 3225} 3226 3227/* License: Ruby's */ 3228int WSAAPI 3229rb_w32_send(int fd, const char *buf, int len, int flags) 3230{ 3231 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL); 3232} 3233 3234/* License: Ruby's */ 3235int WSAAPI 3236rb_w32_sendto(int fd, const char *buf, int len, int flags, 3237 const struct sockaddr *to, int tolen) 3238{ 3239 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, 3240 (struct sockaddr *)to, &tolen); 3241} 3242 3243#if !defined(MSG_TRUNC) && !defined(__MINGW32__) 3244/* License: Ruby's */ 3245typedef struct { 3246 SOCKADDR *name; 3247 int namelen; 3248 WSABUF *lpBuffers; 3249 DWORD dwBufferCount; 3250 WSABUF Control; 3251 DWORD dwFlags; 3252} WSAMSG; 3253#endif 3254#ifndef WSAID_WSARECVMSG 3255#define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} 3256#endif 3257#ifndef WSAID_WSASENDMSG 3258#define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} 3259#endif 3260 3261/* License: Ruby's */ 3262#define msghdr_to_wsamsg(msg, wsamsg) \ 3263 do { \ 3264 int i; \ 3265 (wsamsg)->name = (msg)->msg_name; \ 3266 (wsamsg)->namelen = (msg)->msg_namelen; \ 3267 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \ 3268 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \ 3269 for (i = 0; i < (msg)->msg_iovlen; ++i) { \ 3270 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \ 3271 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \ 3272 } \ 3273 (wsamsg)->Control.buf = (msg)->msg_control; \ 3274 (wsamsg)->Control.len = (msg)->msg_controllen; \ 3275 (wsamsg)->dwFlags = (msg)->msg_flags; \ 3276 } while (0) 3277 3278/* License: Ruby's */ 3279int 3280recvmsg(int fd, struct msghdr *msg, int flags) 3281{ 3282 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE); 3283 static WSARecvMsg_t pWSARecvMsg = NULL; 3284 WSAMSG wsamsg; 3285 SOCKET s; 3286 int mode = 0; 3287 DWORD len; 3288 int ret; 3289 3290 if (!NtSocketsInitialized) 3291 StartSockets(); 3292 3293 s = TO_SOCKET(fd); 3294 3295 if (!pWSARecvMsg) { 3296 static GUID guid = WSAID_WSARECVMSG; 3297 pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid); 3298 if (!pWSARecvMsg) 3299 return -1; 3300 } 3301 3302 msghdr_to_wsamsg(msg, &wsamsg); 3303 wsamsg.dwFlags |= flags; 3304 3305 socklist_lookup(s, &mode); 3306 if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) { 3307 RUBY_CRITICAL({ 3308 if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) { 3309 errno = map_errno(WSAGetLastError()); 3310 len = -1; 3311 } 3312 }); 3313 } 3314 else { 3315 DWORD size; 3316 WSAOVERLAPPED wol; 3317 memset(&wol, 0, sizeof(wol)); 3318 RUBY_CRITICAL({ 3319 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 3320 ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL); 3321 }); 3322 3323 ret = finish_overlapped_socket(TRUE, s, &wol, ret, &len, size); 3324 } 3325 if (ret == SOCKET_ERROR) 3326 return -1; 3327 3328 /* WSAMSG to msghdr */ 3329 msg->msg_name = wsamsg.name; 3330 msg->msg_namelen = wsamsg.namelen; 3331 msg->msg_flags = wsamsg.dwFlags; 3332 3333 return len; 3334} 3335 3336/* License: Ruby's */ 3337int 3338sendmsg(int fd, const struct msghdr *msg, int flags) 3339{ 3340 typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE); 3341 static WSASendMsg_t pWSASendMsg = NULL; 3342 WSAMSG wsamsg; 3343 SOCKET s; 3344 int mode = 0; 3345 DWORD len; 3346 int ret; 3347 3348 if (!NtSocketsInitialized) 3349 StartSockets(); 3350 3351 s = TO_SOCKET(fd); 3352 3353 if (!pWSASendMsg) { 3354 static GUID guid = WSAID_WSASENDMSG; 3355 pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid); 3356 if (!pWSASendMsg) 3357 return -1; 3358 } 3359 3360 msghdr_to_wsamsg(msg, &wsamsg); 3361 3362 socklist_lookup(s, &mode); 3363 if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) { 3364 RUBY_CRITICAL({ 3365 if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) { 3366 errno = map_errno(WSAGetLastError()); 3367 len = -1; 3368 } 3369 }); 3370 } 3371 else { 3372 DWORD size; 3373 WSAOVERLAPPED wol; 3374 memset(&wol, 0, sizeof(wol)); 3375 RUBY_CRITICAL({ 3376 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 3377 ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL); 3378 }); 3379 3380 finish_overlapped_socket(FALSE, s, &wol, ret, &len, size); 3381 } 3382 3383 return len; 3384} 3385 3386#undef setsockopt 3387 3388/* License: Artistic or GPL */ 3389int WSAAPI 3390rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen) 3391{ 3392 int r; 3393 if (!NtSocketsInitialized) { 3394 StartSockets(); 3395 } 3396 RUBY_CRITICAL({ 3397 r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen); 3398 if (r == SOCKET_ERROR) 3399 errno = map_errno(WSAGetLastError()); 3400 }); 3401 return r; 3402} 3403 3404#undef shutdown 3405 3406/* License: Artistic or GPL */ 3407int WSAAPI 3408rb_w32_shutdown(int s, int how) 3409{ 3410 int r; 3411 if (!NtSocketsInitialized) { 3412 StartSockets(); 3413 } 3414 RUBY_CRITICAL({ 3415 r = shutdown(TO_SOCKET(s), how); 3416 if (r == SOCKET_ERROR) 3417 errno = map_errno(WSAGetLastError()); 3418 }); 3419 return r; 3420} 3421 3422/* License: Ruby's */ 3423static SOCKET 3424open_ifs_socket(int af, int type, int protocol) 3425{ 3426 unsigned long proto_buffers_len = 0; 3427 int error_code; 3428 SOCKET out = INVALID_SOCKET; 3429 3430 if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) { 3431 error_code = WSAGetLastError(); 3432 if (error_code == WSAENOBUFS) { 3433 WSAPROTOCOL_INFO *proto_buffers; 3434 int protocols_available = 0; 3435 3436 proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len); 3437 if (!proto_buffers) { 3438 WSASetLastError(WSA_NOT_ENOUGH_MEMORY); 3439 return INVALID_SOCKET; 3440 } 3441 3442 protocols_available = 3443 WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len); 3444 if (protocols_available != SOCKET_ERROR) { 3445 int i; 3446 for (i = 0; i < protocols_available; i++) { 3447 if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) || 3448 (type != proto_buffers[i].iSocketType) || 3449 (protocol != 0 && protocol != proto_buffers[i].iProtocol)) 3450 continue; 3451 3452 if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0) 3453 continue; 3454 3455 out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0, 3456 WSA_FLAG_OVERLAPPED); 3457 break; 3458 } 3459 if (out == INVALID_SOCKET) 3460 out = WSASocket(af, type, protocol, NULL, 0, 0); 3461 if (out != INVALID_SOCKET) 3462 SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0); 3463 } 3464 3465 free(proto_buffers); 3466 } 3467 } 3468 3469 return out; 3470} 3471 3472#undef socket 3473 3474/* License: Artistic or GPL */ 3475int WSAAPI 3476rb_w32_socket(int af, int type, int protocol) 3477{ 3478 SOCKET s; 3479 int fd; 3480 3481 if (!NtSocketsInitialized) { 3482 StartSockets(); 3483 } 3484 RUBY_CRITICAL({ 3485 s = open_ifs_socket(af, type, protocol); 3486 if (s == INVALID_SOCKET) { 3487 errno = map_errno(WSAGetLastError()); 3488 fd = -1; 3489 } 3490 else { 3491 fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT); 3492 if (fd != -1) 3493 socklist_insert(s, MAKE_SOCKDATA(af, 0)); 3494 else 3495 closesocket(s); 3496 } 3497 }); 3498 return fd; 3499} 3500 3501#undef gethostbyaddr 3502 3503/* License: Artistic or GPL */ 3504struct hostent * WSAAPI 3505rb_w32_gethostbyaddr(const char *addr, int len, int type) 3506{ 3507 struct hostent *r; 3508 if (!NtSocketsInitialized) { 3509 StartSockets(); 3510 } 3511 RUBY_CRITICAL({ 3512 r = gethostbyaddr(addr, len, type); 3513 if (r == NULL) 3514 errno = map_errno(WSAGetLastError()); 3515 }); 3516 return r; 3517} 3518 3519#undef gethostbyname 3520 3521/* License: Artistic or GPL */ 3522struct hostent * WSAAPI 3523rb_w32_gethostbyname(const char *name) 3524{ 3525 struct hostent *r; 3526 if (!NtSocketsInitialized) { 3527 StartSockets(); 3528 } 3529 RUBY_CRITICAL({ 3530 r = gethostbyname(name); 3531 if (r == NULL) 3532 errno = map_errno(WSAGetLastError()); 3533 }); 3534 return r; 3535} 3536 3537#undef gethostname 3538 3539/* License: Artistic or GPL */ 3540int WSAAPI 3541rb_w32_gethostname(char *name, int len) 3542{ 3543 int r; 3544 if (!NtSocketsInitialized) { 3545 StartSockets(); 3546 } 3547 RUBY_CRITICAL({ 3548 r = gethostname(name, len); 3549 if (r == SOCKET_ERROR) 3550 errno = map_errno(WSAGetLastError()); 3551 }); 3552 return r; 3553} 3554 3555#undef getprotobyname 3556 3557/* License: Artistic or GPL */ 3558struct protoent * WSAAPI 3559rb_w32_getprotobyname(const char *name) 3560{ 3561 struct protoent *r; 3562 if (!NtSocketsInitialized) { 3563 StartSockets(); 3564 } 3565 RUBY_CRITICAL({ 3566 r = getprotobyname(name); 3567 if (r == NULL) 3568 errno = map_errno(WSAGetLastError()); 3569 }); 3570 return r; 3571} 3572 3573#undef getprotobynumber 3574 3575/* License: Artistic or GPL */ 3576struct protoent * WSAAPI 3577rb_w32_getprotobynumber(int num) 3578{ 3579 struct protoent *r; 3580 if (!NtSocketsInitialized) { 3581 StartSockets(); 3582 } 3583 RUBY_CRITICAL({ 3584 r = getprotobynumber(num); 3585 if (r == NULL) 3586 errno = map_errno(WSAGetLastError()); 3587 }); 3588 return r; 3589} 3590 3591#undef getservbyname 3592 3593/* License: Artistic or GPL */ 3594struct servent * WSAAPI 3595rb_w32_getservbyname(const char *name, const char *proto) 3596{ 3597 struct servent *r; 3598 if (!NtSocketsInitialized) { 3599 StartSockets(); 3600 } 3601 RUBY_CRITICAL({ 3602 r = getservbyname(name, proto); 3603 if (r == NULL) 3604 errno = map_errno(WSAGetLastError()); 3605 }); 3606 return r; 3607} 3608 3609#undef getservbyport 3610 3611/* License: Artistic or GPL */ 3612struct servent * WSAAPI 3613rb_w32_getservbyport(int port, const char *proto) 3614{ 3615 struct servent *r; 3616 if (!NtSocketsInitialized) { 3617 StartSockets(); 3618 } 3619 RUBY_CRITICAL({ 3620 r = getservbyport(port, proto); 3621 if (r == NULL) 3622 errno = map_errno(WSAGetLastError()); 3623 }); 3624 return r; 3625} 3626 3627/* License: Ruby's */ 3628static int 3629socketpair_internal(int af, int type, int protocol, SOCKET *sv) 3630{ 3631 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET; 3632 struct sockaddr_in sock_in4; 3633#ifdef INET6 3634 struct sockaddr_in6 sock_in6; 3635#endif 3636 struct sockaddr *addr; 3637 int ret = -1; 3638 int len; 3639 3640 if (!NtSocketsInitialized) { 3641 StartSockets(); 3642 } 3643 3644 switch (af) { 3645 case AF_INET: 3646#if defined PF_INET && PF_INET != AF_INET 3647 case PF_INET: 3648#endif 3649 sock_in4.sin_family = AF_INET; 3650 sock_in4.sin_port = 0; 3651 sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3652 addr = (struct sockaddr *)&sock_in4; 3653 len = sizeof(sock_in4); 3654 break; 3655#ifdef INET6 3656 case AF_INET6: 3657 memset(&sock_in6, 0, sizeof(sock_in6)); 3658 sock_in6.sin6_family = AF_INET6; 3659 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT; 3660 addr = (struct sockaddr *)&sock_in6; 3661 len = sizeof(sock_in6); 3662 break; 3663#endif 3664 default: 3665 errno = EAFNOSUPPORT; 3666 return -1; 3667 } 3668 if (type != SOCK_STREAM) { 3669 errno = EPROTOTYPE; 3670 return -1; 3671 } 3672 3673 sv[0] = (SOCKET)INVALID_HANDLE_VALUE; 3674 sv[1] = (SOCKET)INVALID_HANDLE_VALUE; 3675 RUBY_CRITICAL({ 3676 do { 3677 svr = open_ifs_socket(af, type, protocol); 3678 if (svr == INVALID_SOCKET) 3679 break; 3680 if (bind(svr, addr, len) < 0) 3681 break; 3682 if (getsockname(svr, addr, &len) < 0) 3683 break; 3684 if (type == SOCK_STREAM) 3685 listen(svr, 5); 3686 3687 w = open_ifs_socket(af, type, protocol); 3688 if (w == INVALID_SOCKET) 3689 break; 3690 if (connect(w, addr, len) < 0) 3691 break; 3692 3693 r = accept(svr, addr, &len); 3694 if (r == INVALID_SOCKET) 3695 break; 3696 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0); 3697 3698 ret = 0; 3699 } while (0); 3700 3701 if (ret < 0) { 3702 errno = map_errno(WSAGetLastError()); 3703 if (r != INVALID_SOCKET) 3704 closesocket(r); 3705 if (w != INVALID_SOCKET) 3706 closesocket(w); 3707 } 3708 else { 3709 sv[0] = r; 3710 sv[1] = w; 3711 } 3712 if (svr != INVALID_SOCKET) 3713 closesocket(svr); 3714 }); 3715 3716 return ret; 3717} 3718 3719/* License: Ruby's */ 3720int 3721rb_w32_socketpair(int af, int type, int protocol, int *sv) 3722{ 3723 SOCKET pair[2]; 3724 3725 if (socketpair_internal(af, type, protocol, pair) < 0) 3726 return -1; 3727 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT); 3728 if (sv[0] == -1) { 3729 closesocket(pair[0]); 3730 closesocket(pair[1]); 3731 return -1; 3732 } 3733 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT); 3734 if (sv[1] == -1) { 3735 rb_w32_close(sv[0]); 3736 closesocket(pair[1]); 3737 return -1; 3738 } 3739 socklist_insert(pair[0], MAKE_SOCKDATA(af, 0)); 3740 socklist_insert(pair[1], MAKE_SOCKDATA(af, 0)); 3741 3742 return 0; 3743} 3744 3745// 3746// Networking stubs 3747// 3748 3749void endhostent(void) {} 3750void endnetent(void) {} 3751void endprotoent(void) {} 3752void endservent(void) {} 3753 3754struct netent *getnetent (void) {return (struct netent *) NULL;} 3755 3756struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;} 3757 3758struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;} 3759 3760struct protoent *getprotoent (void) {return (struct protoent *) NULL;} 3761 3762struct servent *getservent (void) {return (struct servent *) NULL;} 3763 3764void sethostent (int stayopen) {} 3765 3766void setnetent (int stayopen) {} 3767 3768void setprotoent (int stayopen) {} 3769 3770void setservent (int stayopen) {} 3771 3772/* License: Ruby's */ 3773static int 3774setfl(SOCKET sock, int arg) 3775{ 3776 int ret; 3777 int af = 0; 3778 int flag = 0; 3779 u_long ioctlArg; 3780 3781 socklist_lookup(sock, &flag); 3782 af = GET_FAMILY(flag); 3783 flag = GET_FLAGS(flag); 3784 if (arg & O_NONBLOCK) { 3785 flag |= O_NONBLOCK; 3786 ioctlArg = 1; 3787 } 3788 else { 3789 flag &= ~O_NONBLOCK; 3790 ioctlArg = 0; 3791 } 3792 RUBY_CRITICAL({ 3793 ret = ioctlsocket(sock, FIONBIO, &ioctlArg); 3794 if (ret == 0) 3795 socklist_insert(sock, MAKE_SOCKDATA(af, flag)); 3796 else 3797 errno = map_errno(WSAGetLastError()); 3798 }); 3799 3800 return ret; 3801} 3802 3803/* License: Ruby's */ 3804static int 3805dupfd(HANDLE hDup, char flags, int minfd) 3806{ 3807 int save_errno; 3808 int ret; 3809 int fds[32]; 3810 int filled = 0; 3811 3812 do { 3813 ret = _open_osfhandle((intptr_t)hDup, flags | FOPEN); 3814 if (ret == -1) { 3815 goto close_fds_and_return; 3816 } 3817 if (ret >= minfd) { 3818 goto close_fds_and_return; 3819 } 3820 fds[filled++] = ret; 3821 } while (filled < (int)numberof(fds)); 3822 3823 ret = dupfd(hDup, flags, minfd); 3824 3825 close_fds_and_return: 3826 save_errno = errno; 3827 while (filled > 0) { 3828 int fd = fds[--filled]; 3829 _osfhnd(fd) = (intptr_t)INVALID_HANDLE_VALUE; 3830 close(fd); 3831 } 3832 errno = save_errno; 3833 3834 return ret; 3835} 3836 3837/* License: Ruby's */ 3838int 3839fcntl(int fd, int cmd, ...) 3840{ 3841 va_list va; 3842 int arg; 3843 3844 if (cmd == F_SETFL) { 3845 SOCKET sock = TO_SOCKET(fd); 3846 if (!is_socket(sock)) { 3847 errno = EBADF; 3848 return -1; 3849 } 3850 3851 va_start(va, cmd); 3852 arg = va_arg(va, int); 3853 va_end(va); 3854 return setfl(sock, arg); 3855 } 3856 else if (cmd == F_DUPFD) { 3857 int ret; 3858 HANDLE hDup; 3859 if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), 3860 GetCurrentProcess(), &hDup, 0L, 3861 !(_osfile(fd) & FNOINHERIT), 3862 DUPLICATE_SAME_ACCESS))) { 3863 errno = map_errno(GetLastError()); 3864 return -1; 3865 } 3866 3867 va_start(va, cmd); 3868 arg = va_arg(va, int); 3869 va_end(va); 3870 3871 if ((ret = dupfd(hDup, _osfile(fd), arg)) == -1) 3872 CloseHandle(hDup); 3873 return ret; 3874 } 3875 else { 3876 errno = EINVAL; 3877 return -1; 3878 } 3879} 3880 3881#ifndef WNOHANG 3882#define WNOHANG -1 3883#endif 3884 3885/* License: Ruby's */ 3886static rb_pid_t 3887poll_child_status(struct ChildRecord *child, int *stat_loc) 3888{ 3889 DWORD exitcode; 3890 DWORD err; 3891 3892 if (!GetExitCodeProcess(child->hProcess, &exitcode)) { 3893 /* If an error occured, return immediatly. */ 3894 error_exit: 3895 err = GetLastError(); 3896 if (err == ERROR_INVALID_PARAMETER) 3897 errno = ECHILD; 3898 else { 3899 if (GetLastError() == ERROR_INVALID_HANDLE) 3900 errno = EINVAL; 3901 else 3902 errno = map_errno(GetLastError()); 3903 } 3904 CloseChildHandle(child); 3905 return -1; 3906 } 3907 if (exitcode != STILL_ACTIVE) { 3908 rb_pid_t pid; 3909 /* If already died, wait process's real termination. */ 3910 if (rb_w32_wait_events_blocking(&child->hProcess, 1, INFINITE) != WAIT_OBJECT_0) { 3911 goto error_exit; 3912 } 3913 pid = child->pid; 3914 CloseChildHandle(child); 3915 if (stat_loc) *stat_loc = exitcode << 8; 3916 return pid; 3917 } 3918 return 0; 3919} 3920 3921/* License: Artistic or GPL */ 3922rb_pid_t 3923waitpid(rb_pid_t pid, int *stat_loc, int options) 3924{ 3925 DWORD timeout; 3926 3927 /* Artistic or GPL part start */ 3928 if (options == WNOHANG) { 3929 timeout = 0; 3930 } 3931 else { 3932 timeout = INFINITE; 3933 } 3934 /* Artistic or GPL part end */ 3935 3936 if (pid == -1) { 3937 int count = 0; 3938 int ret; 3939 HANDLE events[MAXCHILDNUM]; 3940 struct ChildRecord* cause; 3941 3942 FOREACH_CHILD(child) { 3943 if (!child->pid || child->pid < 0) continue; 3944 if ((pid = poll_child_status(child, stat_loc))) return pid; 3945 events[count++] = child->hProcess; 3946 } END_FOREACH_CHILD; 3947 if (!count) { 3948 errno = ECHILD; 3949 return -1; 3950 } 3951 3952 ret = rb_w32_wait_events_blocking(events, count, timeout); 3953 if (ret == WAIT_TIMEOUT) return 0; 3954 if ((ret -= WAIT_OBJECT_0) == count) { 3955 return -1; 3956 } 3957 if (ret > count) { 3958 errno = map_errno(GetLastError()); 3959 return -1; 3960 } 3961 3962 cause = FindChildSlotByHandle(events[ret]); 3963 if (!cause) { 3964 errno = ECHILD; 3965 return -1; 3966 } 3967 return poll_child_status(cause, stat_loc); 3968 } 3969 else { 3970 struct ChildRecord* child = FindChildSlot(pid); 3971 if (!child) { 3972 errno = ECHILD; 3973 return -1; 3974 } 3975 3976 while (!(pid = poll_child_status(child, stat_loc))) { 3977 /* wait... */ 3978 if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) { 3979 /* still active */ 3980 pid = 0; 3981 break; 3982 } 3983 } 3984 } 3985 3986 return pid; 3987} 3988 3989#include <sys/timeb.h> 3990 3991/* License: Ruby's */ 3992static int 3993filetime_to_timeval(const FILETIME* ft, struct timeval *tv) 3994{ 3995 ULARGE_INTEGER tmp; 3996 unsigned LONG_LONG lt; 3997 3998 tmp.LowPart = ft->dwLowDateTime; 3999 tmp.HighPart = ft->dwHighDateTime; 4000 lt = tmp.QuadPart; 4001 4002 /* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC, 4003 convert it into UNIX time (since 1970/01/01 00:00:00 UTC). 4004 the first leap second is at 1972/06/30, so we doesn't need to think 4005 about it. */ 4006 lt /= 10; /* to usec */ 4007 lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000; 4008 4009 tv->tv_sec = (long)(lt / (1000 * 1000)); 4010 tv->tv_usec = (long)(lt % (1000 * 1000)); 4011 4012 return tv->tv_sec > 0 ? 0 : -1; 4013} 4014 4015/* License: Ruby's */ 4016int _cdecl 4017gettimeofday(struct timeval *tv, struct timezone *tz) 4018{ 4019 FILETIME ft; 4020 4021 GetSystemTimeAsFileTime(&ft); 4022 filetime_to_timeval(&ft, tv); 4023 4024 return 0; 4025} 4026 4027/* License: Ruby's */ 4028char * 4029rb_w32_getcwd(char *buffer, int size) 4030{ 4031 char *p = buffer; 4032 int len; 4033 4034 len = GetCurrentDirectory(0, NULL); 4035 if (!len) { 4036 errno = map_errno(GetLastError()); 4037 return NULL; 4038 } 4039 4040 if (p) { 4041 if (size < len) { 4042 errno = ERANGE; 4043 return NULL; 4044 } 4045 } 4046 else { 4047 p = malloc(len); 4048 size = len; 4049 if (!p) { 4050 errno = ENOMEM; 4051 return NULL; 4052 } 4053 } 4054 4055 if (!GetCurrentDirectory(size, p)) { 4056 errno = map_errno(GetLastError()); 4057 if (!buffer) 4058 free(p); 4059 return NULL; 4060 } 4061 4062 translate_char(p, '\\', '/'); 4063 4064 return p; 4065} 4066 4067/* License: Artistic or GPL */ 4068int 4069chown(const char *path, int owner, int group) 4070{ 4071 return 0; 4072} 4073 4074/* License: Artistic or GPL */ 4075int 4076rb_w32_uchown(const char *path, int owner, int group) 4077{ 4078 return 0; 4079} 4080 4081/* License: Ruby's */ 4082int 4083kill(int pid, int sig) 4084{ 4085 int ret = 0; 4086 DWORD err; 4087 4088 if (pid < 0 || pid == 0 && sig != SIGINT) { 4089 errno = EINVAL; 4090 return -1; 4091 } 4092 4093 if ((unsigned int)pid == GetCurrentProcessId() && 4094 (sig != 0 && sig != SIGKILL)) { 4095 if ((ret = raise(sig)) != 0) { 4096 /* MSVCRT doesn't set errno... */ 4097 errno = EINVAL; 4098 } 4099 return ret; 4100 } 4101 4102 switch (sig) { 4103 case 0: 4104 RUBY_CRITICAL({ 4105 HANDLE hProc = 4106 OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid); 4107 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) { 4108 if (GetLastError() == ERROR_INVALID_PARAMETER) { 4109 errno = ESRCH; 4110 } 4111 else { 4112 errno = EPERM; 4113 } 4114 ret = -1; 4115 } 4116 else { 4117 CloseHandle(hProc); 4118 } 4119 }); 4120 break; 4121 4122 case SIGINT: 4123 RUBY_CRITICAL({ 4124 DWORD ctrlEvent = CTRL_C_EVENT; 4125 if (pid != 0) { 4126 /* CTRL+C signal cannot be generated for process groups. 4127 * Instead, we use CTRL+BREAK signal. */ 4128 ctrlEvent = CTRL_BREAK_EVENT; 4129 } 4130 if (!GenerateConsoleCtrlEvent(ctrlEvent, (DWORD)pid)) { 4131 if ((err = GetLastError()) == 0) 4132 errno = EPERM; 4133 else 4134 errno = map_errno(GetLastError()); 4135 ret = -1; 4136 } 4137 }); 4138 break; 4139 4140 case SIGKILL: 4141 RUBY_CRITICAL({ 4142 HANDLE hProc; 4143 struct ChildRecord* child = FindChildSlot(pid); 4144 if (child) { 4145 hProc = child->hProcess; 4146 } 4147 else { 4148 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid); 4149 } 4150 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) { 4151 if (GetLastError() == ERROR_INVALID_PARAMETER) { 4152 errno = ESRCH; 4153 } 4154 else { 4155 errno = EPERM; 4156 } 4157 ret = -1; 4158 } 4159 else { 4160 DWORD status; 4161 if (!GetExitCodeProcess(hProc, &status)) { 4162 errno = map_errno(GetLastError()); 4163 ret = -1; 4164 } 4165 else if (status == STILL_ACTIVE) { 4166 if (!TerminateProcess(hProc, 0)) { 4167 errno = EPERM; 4168 ret = -1; 4169 } 4170 } 4171 else { 4172 errno = ESRCH; 4173 ret = -1; 4174 } 4175 if (!child) { 4176 CloseHandle(hProc); 4177 } 4178 } 4179 }); 4180 break; 4181 4182 default: 4183 errno = EINVAL; 4184 ret = -1; 4185 break; 4186 } 4187 4188 return ret; 4189} 4190 4191/* License: Ruby's */ 4192static int 4193wlink(const WCHAR *from, const WCHAR *to) 4194{ 4195 typedef BOOL (WINAPI link_func)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); 4196 static link_func *pCreateHardLinkW = NULL; 4197 static int myerrno = 0; 4198 4199 if (!pCreateHardLinkW && !myerrno) { 4200 pCreateHardLinkW = (link_func *)get_proc_address("kernel32", "CreateHardLinkW", NULL); 4201 if (!pCreateHardLinkW) 4202 myerrno = ENOSYS; 4203 } 4204 if (!pCreateHardLinkW) { 4205 errno = myerrno; 4206 return -1; 4207 } 4208 4209 if (!pCreateHardLinkW(to, from, NULL)) { 4210 errno = map_errno(GetLastError()); 4211 return -1; 4212 } 4213 4214 return 0; 4215} 4216 4217/* License: Ruby's */ 4218int 4219rb_w32_ulink(const char *from, const char *to) 4220{ 4221 WCHAR *wfrom; 4222 WCHAR *wto; 4223 int ret; 4224 4225 if (!(wfrom = utf8_to_wstr(from, NULL))) 4226 return -1; 4227 if (!(wto = utf8_to_wstr(to, NULL))) { 4228 free(wfrom); 4229 return -1; 4230 } 4231 ret = wlink(wfrom, wto); 4232 free(wto); 4233 free(wfrom); 4234 return ret; 4235} 4236 4237/* License: Ruby's */ 4238int 4239link(const char *from, const char *to) 4240{ 4241 WCHAR *wfrom; 4242 WCHAR *wto; 4243 int ret; 4244 4245 if (!(wfrom = filecp_to_wstr(from, NULL))) 4246 return -1; 4247 if (!(wto = filecp_to_wstr(to, NULL))) { 4248 free(wfrom); 4249 return -1; 4250 } 4251 ret = wlink(wfrom, wto); 4252 free(wto); 4253 free(wfrom); 4254 return ret; 4255} 4256 4257/* License: Ruby's */ 4258int 4259wait(int *status) 4260{ 4261 return waitpid(-1, status, 0); 4262} 4263 4264/* License: Ruby's */ 4265char * 4266rb_w32_ugetenv(const char *name) 4267{ 4268 WCHAR *wenvarea, *wenv; 4269 int len = strlen(name); 4270 char *env; 4271 int wlen; 4272 4273 if (len == 0) return NULL; 4274 4275 if (uenvarea) { 4276 free(uenvarea); 4277 uenvarea = NULL; 4278 } 4279 if (envarea) { 4280 FreeEnvironmentStrings(envarea); 4281 envarea = NULL; 4282 } 4283 wenvarea = GetEnvironmentStringsW(); 4284 if (!wenvarea) { 4285 map_errno(GetLastError()); 4286 return NULL; 4287 } 4288 for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1) 4289 wlen += lstrlenW(wenv) + 1; 4290 uenvarea = wstr_to_mbstr(CP_UTF8, wenvarea, wlen, NULL); 4291 FreeEnvironmentStringsW(wenvarea); 4292 if (!uenvarea) 4293 return NULL; 4294 4295 for (env = uenvarea; *env; env += strlen(env) + 1) 4296 if (strncasecmp(env, name, len) == 0 && *(env + len) == '=') 4297 return env + len + 1; 4298 4299 return NULL; 4300} 4301 4302/* License: Ruby's */ 4303char * 4304rb_w32_getenv(const char *name) 4305{ 4306 int len = strlen(name); 4307 char *env; 4308 4309 if (len == 0) return NULL; 4310 if (uenvarea) { 4311 free(uenvarea); 4312 uenvarea = NULL; 4313 } 4314 if (envarea) { 4315 FreeEnvironmentStrings(envarea); 4316 envarea = NULL; 4317 } 4318 envarea = GetEnvironmentStrings(); 4319 if (!envarea) { 4320 map_errno(GetLastError()); 4321 return NULL; 4322 } 4323 4324 for (env = envarea; *env; env += strlen(env) + 1) 4325 if (strncasecmp(env, name, len) == 0 && *(env + len) == '=') 4326 return env + len + 1; 4327 4328 return NULL; 4329} 4330 4331/* License: Artistic or GPL */ 4332static int 4333wrename(const WCHAR *oldpath, const WCHAR *newpath) 4334{ 4335 int res = 0; 4336 int oldatts; 4337 int newatts; 4338 4339 oldatts = GetFileAttributesW(oldpath); 4340 newatts = GetFileAttributesW(newpath); 4341 4342 if (oldatts == -1) { 4343 errno = map_errno(GetLastError()); 4344 return -1; 4345 } 4346 4347 RUBY_CRITICAL({ 4348 if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY) 4349 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY); 4350 4351 if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) 4352 res = -1; 4353 4354 if (res) 4355 errno = map_errno(GetLastError()); 4356 else 4357 SetFileAttributesW(newpath, oldatts); 4358 }); 4359 4360 return res; 4361} 4362 4363/* License: Ruby's */ 4364int rb_w32_urename(const char *from, const char *to) 4365{ 4366 WCHAR *wfrom; 4367 WCHAR *wto; 4368 int ret = -1; 4369 4370 if (!(wfrom = utf8_to_wstr(from, NULL))) 4371 return -1; 4372 if (!(wto = utf8_to_wstr(to, NULL))) { 4373 free(wfrom); 4374 return -1; 4375 } 4376 ret = wrename(wfrom, wto); 4377 free(wto); 4378 free(wfrom); 4379 return ret; 4380} 4381 4382/* License: Ruby's */ 4383int rb_w32_rename(const char *from, const char *to) 4384{ 4385 WCHAR *wfrom; 4386 WCHAR *wto; 4387 int ret = -1; 4388 4389 if (!(wfrom = filecp_to_wstr(from, NULL))) 4390 return -1; 4391 if (!(wto = filecp_to_wstr(to, NULL))) { 4392 free(wfrom); 4393 return -1; 4394 } 4395 ret = wrename(wfrom, wto); 4396 free(wto); 4397 free(wfrom); 4398 return ret; 4399} 4400 4401/* License: Ruby's */ 4402static int 4403isUNCRoot(const WCHAR *path) 4404{ 4405 if (path[0] == L'\\' && path[1] == L'\\') { 4406 const WCHAR *p = path + 2; 4407 if (p[0] == L'?' && p[1] == L'\\') { 4408 p += 2; 4409 } 4410 for (; *p; p++) { 4411 if (*p == L'\\') 4412 break; 4413 } 4414 if (p[0] && p[1]) { 4415 for (p++; *p; p++) { 4416 if (*p == L'\\') 4417 break; 4418 } 4419 if (!p[0] || !p[1] || (p[1] == L'.' && !p[2])) 4420 return 1; 4421 } 4422 } 4423 return 0; 4424} 4425 4426#define COPY_STAT(src, dest, size_cast) do { \ 4427 (dest).st_dev = (src).st_dev; \ 4428 (dest).st_ino = (src).st_ino; \ 4429 (dest).st_mode = (src).st_mode; \ 4430 (dest).st_nlink = (src).st_nlink; \ 4431 (dest).st_uid = (src).st_uid; \ 4432 (dest).st_gid = (src).st_gid; \ 4433 (dest).st_rdev = (src).st_rdev; \ 4434 (dest).st_size = size_cast(src).st_size; \ 4435 (dest).st_atime = (src).st_atime; \ 4436 (dest).st_mtime = (src).st_mtime; \ 4437 (dest).st_ctime = (src).st_ctime; \ 4438 } while (0) 4439 4440static time_t filetime_to_unixtime(const FILETIME *ft); 4441 4442#undef fstat 4443/* License: Ruby's */ 4444int 4445rb_w32_fstat(int fd, struct stat *st) 4446{ 4447 BY_HANDLE_FILE_INFORMATION info; 4448 int ret = fstat(fd, st); 4449 4450 if (ret) return ret; 4451#ifdef __BORLANDC__ 4452 st->st_mode &= ~(S_IWGRP | S_IWOTH); 4453#endif 4454 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) { 4455#ifdef __BORLANDC__ 4456 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { 4457 st->st_mode |= S_IWUSR; 4458 } 4459#endif 4460 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime); 4461 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime); 4462 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime); 4463 } 4464 return ret; 4465} 4466 4467/* License: Ruby's */ 4468int 4469rb_w32_fstati64(int fd, struct stati64 *st) 4470{ 4471 BY_HANDLE_FILE_INFORMATION info; 4472 struct stat tmp; 4473 int ret = fstat(fd, &tmp); 4474 4475 if (ret) return ret; 4476#ifdef __BORLANDC__ 4477 tmp.st_mode &= ~(S_IWGRP | S_IWOTH); 4478#endif 4479 COPY_STAT(tmp, *st, +); 4480 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) { 4481#ifdef __BORLANDC__ 4482 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { 4483 st->st_mode |= S_IWUSR; 4484 } 4485#endif 4486 st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow; 4487 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime); 4488 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime); 4489 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime); 4490 } 4491 return ret; 4492} 4493 4494/* License: Ruby's */ 4495static time_t 4496filetime_to_unixtime(const FILETIME *ft) 4497{ 4498 struct timeval tv; 4499 4500 if (filetime_to_timeval(ft, &tv) == (time_t)-1) 4501 return 0; 4502 else 4503 return tv.tv_sec; 4504} 4505 4506/* License: Ruby's */ 4507static unsigned 4508fileattr_to_unixmode(DWORD attr, const WCHAR *path) 4509{ 4510 unsigned mode = 0; 4511 4512 if (attr & FILE_ATTRIBUTE_READONLY) { 4513 mode |= S_IREAD; 4514 } 4515 else { 4516 mode |= S_IREAD | S_IWRITE | S_IWUSR; 4517 } 4518 4519 if (attr & FILE_ATTRIBUTE_DIRECTORY) { 4520 mode |= S_IFDIR | S_IEXEC; 4521 } 4522 else { 4523 mode |= S_IFREG; 4524 } 4525 4526 if (path && (mode & S_IFREG)) { 4527 const WCHAR *end = path + lstrlenW(path); 4528 while (path < end) { 4529 end = CharPrevW(path, end); 4530 if (*end == L'.') { 4531 if ((_wcsicmp(end, L".bat") == 0) || 4532 (_wcsicmp(end, L".cmd") == 0) || 4533 (_wcsicmp(end, L".com") == 0) || 4534 (_wcsicmp(end, L".exe") == 0)) { 4535 mode |= S_IEXEC; 4536 } 4537 break; 4538 } 4539 } 4540 } 4541 4542 mode |= (mode & 0700) >> 3; 4543 mode |= (mode & 0700) >> 6; 4544 4545 return mode; 4546} 4547 4548/* License: Ruby's */ 4549static int 4550check_valid_dir(const WCHAR *path) 4551{ 4552 WIN32_FIND_DATAW fd; 4553 HANDLE fh; 4554 WCHAR full[MAX_PATH]; 4555 WCHAR *dmy; 4556 WCHAR *p, *q; 4557 4558 /* GetFileAttributes() determines "..." as directory. */ 4559 /* We recheck it by FindFirstFile(). */ 4560 if (!(p = wcsstr(path, L"..."))) 4561 return 0; 4562 q = p + wcsspn(p, L"."); 4563 if ((p == path || wcschr(L":/\\", *(p - 1))) && 4564 (!*q || wcschr(L":/\\", *q))) { 4565 errno = ENOENT; 4566 return -1; 4567 } 4568 4569 /* if the specified path is the root of a drive and the drive is empty, */ 4570 /* FindFirstFile() returns INVALID_HANDLE_VALUE. */ 4571 if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) { 4572 errno = map_errno(GetLastError()); 4573 return -1; 4574 } 4575 if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR) 4576 return 0; 4577 4578 fh = open_dir_handle(path, &fd); 4579 if (fh == INVALID_HANDLE_VALUE) 4580 return -1; 4581 FindClose(fh); 4582 return 0; 4583} 4584 4585/* License: Ruby's */ 4586static int 4587winnt_stat(const WCHAR *path, struct stati64 *st) 4588{ 4589 HANDLE h; 4590 WIN32_FIND_DATAW wfd; 4591 WIN32_FILE_ATTRIBUTE_DATA wfa; 4592 const WCHAR *p = path; 4593 4594 memset(st, 0, sizeof(*st)); 4595 st->st_nlink = 1; 4596 4597 if (wcsncmp(p, L"\\\\?\\", 4) == 0) p += 4; 4598 if (wcspbrk(p, L"?*")) { 4599 errno = ENOENT; 4600 return -1; 4601 } 4602 if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) { 4603 if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 4604 if (check_valid_dir(path)) return -1; 4605 st->st_size = 0; 4606 } 4607 else { 4608 st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow; 4609 } 4610 st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path); 4611 st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime); 4612 st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime); 4613 st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime); 4614 } 4615 else { 4616 /* GetFileAttributesEx failed; check why. */ 4617 int e = GetLastError(); 4618 4619 if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME) 4620 || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) { 4621 errno = map_errno(e); 4622 return -1; 4623 } 4624 4625 /* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */ 4626 h = FindFirstFileW(path, &wfd); 4627 if (h != INVALID_HANDLE_VALUE) { 4628 FindClose(h); 4629 st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path); 4630 st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime); 4631 st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime); 4632 st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime); 4633 st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow; 4634 } 4635 else { 4636 errno = map_errno(GetLastError()); 4637 return -1; 4638 } 4639 } 4640 4641 st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ? 4642 towupper(path[0]) - L'A' : _getdrive() - 1; 4643 4644 return 0; 4645} 4646 4647/* License: Ruby's */ 4648int 4649rb_w32_stat(const char *path, struct stat *st) 4650{ 4651 struct stati64 tmp; 4652 4653 if (rb_w32_stati64(path, &tmp)) return -1; 4654 COPY_STAT(tmp, *st, (_off_t)); 4655 return 0; 4656} 4657 4658/* License: Ruby's */ 4659static int 4660wstati64(const WCHAR *path, struct stati64 *st) 4661{ 4662 const WCHAR *p; 4663 WCHAR *buf1, *s, *end; 4664 int len, size; 4665 int ret; 4666 VALUE v; 4667 4668 if (!path || !st) { 4669 errno = EFAULT; 4670 return -1; 4671 } 4672 size = lstrlenW(path) + 2; 4673 buf1 = ALLOCV_N(WCHAR, v, size); 4674 for (p = path, s = buf1; *p; p++, s++) { 4675 if (*p == L'/') 4676 *s = L'\\'; 4677 else 4678 *s = *p; 4679 } 4680 *s = '\0'; 4681 len = s - buf1; 4682 if (!len || L'\"' == *(--s)) { 4683 errno = ENOENT; 4684 return -1; 4685 } 4686 end = buf1 + len - 1; 4687 4688 if (isUNCRoot(buf1)) { 4689 if (*end == L'.') 4690 *end = L'\0'; 4691 else if (*end != L'\\') 4692 lstrcatW(buf1, L"\\"); 4693 } 4694 else if (*end == L'\\' || (buf1 + 1 == end && *end == L':')) 4695 lstrcatW(buf1, L"."); 4696 4697 ret = winnt_stat(buf1, st); 4698 if (ret == 0) { 4699 st->st_mode &= ~(S_IWGRP | S_IWOTH); 4700 } 4701 if (v) 4702 ALLOCV_END(v); 4703 4704 return ret; 4705} 4706 4707/* License: Ruby's */ 4708int 4709rb_w32_ustati64(const char *path, struct stati64 *st) 4710{ 4711 WCHAR *wpath; 4712 int ret; 4713 4714 if (!(wpath = utf8_to_wstr(path, NULL))) 4715 return -1; 4716 ret = wstati64(wpath, st); 4717 free(wpath); 4718 return ret; 4719} 4720 4721/* License: Ruby's */ 4722int 4723rb_w32_stati64(const char *path, struct stati64 *st) 4724{ 4725 WCHAR *wpath; 4726 int ret; 4727 4728 if (!(wpath = filecp_to_wstr(path, NULL))) 4729 return -1; 4730 ret = wstati64(wpath, st); 4731 free(wpath); 4732 return ret; 4733} 4734 4735/* License: Ruby's */ 4736int 4737rb_w32_access(const char *path, int mode) 4738{ 4739 struct stati64 stat; 4740 if (rb_w32_stati64(path, &stat) != 0) 4741 return -1; 4742 mode <<= 6; 4743 if ((stat.st_mode & mode) != mode) { 4744 errno = EACCES; 4745 return -1; 4746 } 4747 return 0; 4748} 4749 4750/* License: Ruby's */ 4751int 4752rb_w32_uaccess(const char *path, int mode) 4753{ 4754 struct stati64 stat; 4755 if (rb_w32_ustati64(path, &stat) != 0) 4756 return -1; 4757 mode <<= 6; 4758 if ((stat.st_mode & mode) != mode) { 4759 errno = EACCES; 4760 return -1; 4761 } 4762 return 0; 4763} 4764 4765/* License: Ruby's */ 4766static int 4767rb_chsize(HANDLE h, off_t size) 4768{ 4769 long upos, lpos, usize, lsize; 4770 int ret = -1; 4771 DWORD e; 4772 4773 if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L && 4774 (e = GetLastError())) { 4775 errno = map_errno(e); 4776 return -1; 4777 } 4778 usize = (long)(size >> 32); 4779 lsize = (long)size; 4780 if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L && 4781 (e = GetLastError())) { 4782 errno = map_errno(e); 4783 } 4784 else if (!SetEndOfFile(h)) { 4785 errno = map_errno(GetLastError()); 4786 } 4787 else { 4788 ret = 0; 4789 } 4790 SetFilePointer(h, lpos, &upos, SEEK_SET); 4791 return ret; 4792} 4793 4794/* License: Ruby's */ 4795int 4796rb_w32_truncate(const char *path, off_t length) 4797{ 4798 HANDLE h; 4799 int ret; 4800 h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); 4801 if (h == INVALID_HANDLE_VALUE) { 4802 errno = map_errno(GetLastError()); 4803 return -1; 4804 } 4805 ret = rb_chsize(h, length); 4806 CloseHandle(h); 4807 return ret; 4808} 4809 4810/* License: Ruby's */ 4811int 4812rb_w32_ftruncate(int fd, off_t length) 4813{ 4814 HANDLE h; 4815 4816 h = (HANDLE)_get_osfhandle(fd); 4817 if (h == (HANDLE)-1) return -1; 4818 return rb_chsize(h, length); 4819} 4820 4821#ifdef __BORLANDC__ 4822/* License: Ruby's */ 4823off_t 4824_filelengthi64(int fd) 4825{ 4826 DWORD u, l; 4827 int e; 4828 4829 l = GetFileSize((HANDLE)_get_osfhandle(fd), &u); 4830 if (l == (DWORD)-1L && (e = GetLastError())) { 4831 errno = map_errno(e); 4832 return (off_t)-1; 4833 } 4834 return ((off_t)u << 32) | l; 4835} 4836 4837/* License: Ruby's */ 4838off_t 4839_lseeki64(int fd, off_t offset, int whence) 4840{ 4841 long u, l; 4842 int e; 4843 HANDLE h = (HANDLE)_get_osfhandle(fd); 4844 4845 if (!h) { 4846 errno = EBADF; 4847 return -1; 4848 } 4849 u = (long)(offset >> 32); 4850 if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L && 4851 (e = GetLastError())) { 4852 errno = map_errno(e); 4853 return -1; 4854 } 4855 return ((off_t)u << 32) | l; 4856} 4857#endif 4858 4859/* License: Ruby's */ 4860int 4861fseeko(FILE *stream, off_t offset, int whence) 4862{ 4863 off_t pos; 4864 switch (whence) { 4865 case SEEK_CUR: 4866 if (fgetpos(stream, (fpos_t *)&pos)) 4867 return -1; 4868 pos += offset; 4869 break; 4870 case SEEK_END: 4871 if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1) 4872 return -1; 4873 pos += offset; 4874 break; 4875 default: 4876 pos = offset; 4877 break; 4878 } 4879 return fsetpos(stream, (fpos_t *)&pos); 4880} 4881 4882/* License: Ruby's */ 4883off_t 4884rb_w32_ftello(FILE *stream) 4885{ 4886 off_t pos; 4887 if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1; 4888 return pos; 4889} 4890 4891/* License: Ruby's */ 4892static long 4893filetime_to_clock(FILETIME *ft) 4894{ 4895 __int64 qw = ft->dwHighDateTime; 4896 qw <<= 32; 4897 qw |= ft->dwLowDateTime; 4898 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */ 4899 return (long) qw; 4900} 4901 4902/* License: Ruby's */ 4903int 4904rb_w32_times(struct tms *tmbuf) 4905{ 4906 FILETIME create, exit, kernel, user; 4907 4908 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) { 4909 tmbuf->tms_utime = filetime_to_clock(&user); 4910 tmbuf->tms_stime = filetime_to_clock(&kernel); 4911 tmbuf->tms_cutime = 0; 4912 tmbuf->tms_cstime = 0; 4913 } 4914 else { 4915 tmbuf->tms_utime = clock(); 4916 tmbuf->tms_stime = 0; 4917 tmbuf->tms_cutime = 0; 4918 tmbuf->tms_cstime = 0; 4919 } 4920 return 0; 4921} 4922 4923#define yield_once() Sleep(0) 4924#define yield_until(condition) do yield_once(); while (!(condition)) 4925 4926/* License: Ruby's */ 4927static void 4928catch_interrupt(void) 4929{ 4930 yield_once(); 4931 RUBY_CRITICAL(rb_w32_wait_events(NULL, 0, 0)); 4932} 4933 4934#if defined __BORLANDC__ 4935#undef read 4936/* License: Ruby's */ 4937int 4938read(int fd, void *buf, size_t size) 4939{ 4940 int ret = _read(fd, buf, size); 4941 if ((ret < 0) && (errno == EPIPE)) { 4942 errno = 0; 4943 ret = 0; 4944 } 4945 catch_interrupt(); 4946 return ret; 4947} 4948#endif 4949 4950 4951#define FILE_COUNT _cnt 4952#define FILE_READPTR _ptr 4953 4954#undef fgetc 4955/* License: Ruby's */ 4956int 4957rb_w32_getc(FILE* stream) 4958{ 4959 int c; 4960 if (enough_to_get(stream->FILE_COUNT)) { 4961 c = (unsigned char)*stream->FILE_READPTR++; 4962 } 4963 else { 4964 c = _filbuf(stream); 4965#if defined __BORLANDC__ 4966 if ((c == EOF) && (errno == EPIPE)) { 4967 clearerr(stream); 4968 } 4969#endif 4970 catch_interrupt(); 4971 } 4972 return c; 4973} 4974 4975#undef fputc 4976/* License: Ruby's */ 4977int 4978rb_w32_putc(int c, FILE* stream) 4979{ 4980 if (enough_to_put(stream->FILE_COUNT)) { 4981 c = (unsigned char)(*stream->FILE_READPTR++ = (char)c); 4982 } 4983 else { 4984 c = _flsbuf(c, stream); 4985 catch_interrupt(); 4986 } 4987 return c; 4988} 4989 4990/* License: Ruby's */ 4991struct asynchronous_arg_t { 4992 /* output field */ 4993 void* stackaddr; 4994 int errnum; 4995 4996 /* input field */ 4997 uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv); 4998 uintptr_t self; 4999 int argc; 5000 uintptr_t* argv; 5001}; 5002 5003/* License: Ruby's */ 5004static DWORD WINAPI 5005call_asynchronous(PVOID argp) 5006{ 5007 DWORD ret; 5008 struct asynchronous_arg_t *arg = argp; 5009 arg->stackaddr = &argp; 5010 ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv); 5011 arg->errnum = errno; 5012 return ret; 5013} 5014 5015/* License: Ruby's */ 5016uintptr_t 5017rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self, 5018 int argc, uintptr_t* argv, uintptr_t intrval) 5019{ 5020 DWORD val; 5021 BOOL interrupted = FALSE; 5022 HANDLE thr; 5023 5024 RUBY_CRITICAL({ 5025 struct asynchronous_arg_t arg; 5026 5027 arg.stackaddr = NULL; 5028 arg.errnum = 0; 5029 arg.func = func; 5030 arg.self = self; 5031 arg.argc = argc; 5032 arg.argv = argv; 5033 5034 thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val); 5035 5036 if (thr) { 5037 yield_until(arg.stackaddr); 5038 5039 if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) { 5040 interrupted = TRUE; 5041 5042 if (TerminateThread(thr, intrval)) { 5043 yield_once(); 5044 } 5045 } 5046 5047 GetExitCodeThread(thr, &val); 5048 CloseHandle(thr); 5049 5050 if (interrupted) { 5051 /* must release stack of killed thread, why doesn't Windows? */ 5052 MEMORY_BASIC_INFORMATION m; 5053 5054 memset(&m, 0, sizeof(m)); 5055 if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) { 5056 Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n", 5057 arg.stackaddr, GetLastError())); 5058 } 5059 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) { 5060 Debug(fprintf(stderr, "couldn't release stack:%p:%d\n", 5061 m.AllocationBase, GetLastError())); 5062 } 5063 errno = EINTR; 5064 } 5065 else { 5066 errno = arg.errnum; 5067 } 5068 } 5069 }); 5070 5071 if (!thr) { 5072 rb_fatal("failed to launch waiter thread:%ld", GetLastError()); 5073 } 5074 5075 return val; 5076} 5077 5078/* License: Ruby's */ 5079char ** 5080rb_w32_get_environ(void) 5081{ 5082 WCHAR *envtop, *env; 5083 char **myenvtop, **myenv; 5084 int num; 5085 5086 /* 5087 * We avoid values started with `='. If you want to deal those values, 5088 * change this function, and some functions in hash.c which recognize 5089 * `=' as delimiter or rb_w32_getenv() and ruby_setenv(). 5090 * CygWin deals these values by changing first `=' to '!'. But we don't 5091 * use such trick and follow cmd.exe's way that just doesn't show these 5092 * values. 5093 * 5094 * This function returns UTF-8 strings. 5095 */ 5096 envtop = GetEnvironmentStringsW(); 5097 for (env = envtop, num = 0; *env; env += lstrlenW(env) + 1) 5098 if (*env != '=') num++; 5099 5100 myenvtop = (char **)malloc(sizeof(char *) * (num + 1)); 5101 for (env = envtop, myenv = myenvtop; *env; env += lstrlenW(env) + 1) { 5102 if (*env != '=') { 5103 if (!(*myenv = wstr_to_utf8(env, NULL))) { 5104 break; 5105 } 5106 myenv++; 5107 } 5108 } 5109 *myenv = NULL; 5110 FreeEnvironmentStringsW(envtop); 5111 5112 return myenvtop; 5113} 5114 5115/* License: Ruby's */ 5116void 5117rb_w32_free_environ(char **env) 5118{ 5119 char **t = env; 5120 5121 while (*t) free(*t++); 5122 free(env); 5123} 5124 5125/* License: Ruby's */ 5126rb_pid_t 5127rb_w32_getpid(void) 5128{ 5129 return GetCurrentProcessId(); 5130} 5131 5132 5133/* License: Ruby's */ 5134rb_pid_t 5135rb_w32_getppid(void) 5136{ 5137 typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *); 5138 static query_func *pNtQueryInformationProcess = NULL; 5139 rb_pid_t ppid = 0; 5140 5141 if (rb_w32_osver() >= 5) { 5142 if (!pNtQueryInformationProcess) 5143 pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL); 5144 if (pNtQueryInformationProcess) { 5145 struct { 5146 long ExitStatus; 5147 void* PebBaseAddress; 5148 uintptr_t AffinityMask; 5149 uintptr_t BasePriority; 5150 uintptr_t UniqueProcessId; 5151 uintptr_t ParentProcessId; 5152 } pbi; 5153 ULONG len; 5154 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len); 5155 if (!ret) { 5156 ppid = pbi.ParentProcessId; 5157 } 5158 } 5159 } 5160 5161 return ppid; 5162} 5163 5164/* License: Ruby's */ 5165int 5166rb_w32_uopen(const char *file, int oflag, ...) 5167{ 5168 WCHAR *wfile; 5169 int ret; 5170 int pmode; 5171 5172 va_list arg; 5173 va_start(arg, oflag); 5174 pmode = va_arg(arg, int); 5175 va_end(arg); 5176 5177 if (!(wfile = utf8_to_wstr(file, NULL))) 5178 return -1; 5179 ret = rb_w32_wopen(wfile, oflag, pmode); 5180 free(wfile); 5181 return ret; 5182} 5183 5184/* License: Ruby's */ 5185static int 5186check_if_wdir(const WCHAR *wfile) 5187{ 5188 DWORD attr = GetFileAttributesW(wfile); 5189 if (attr == (DWORD)-1L || 5190 !(attr & FILE_ATTRIBUTE_DIRECTORY) || 5191 check_valid_dir(wfile)) { 5192 return FALSE; 5193 } 5194 errno = EISDIR; 5195 return TRUE; 5196} 5197 5198/* License: Ruby's */ 5199static int 5200check_if_dir(const char *file) 5201{ 5202 WCHAR *wfile; 5203 int ret; 5204 5205 if (!(wfile = filecp_to_wstr(file, NULL))) 5206 return FALSE; 5207 ret = check_if_wdir(wfile); 5208 free(wfile); 5209 return ret; 5210} 5211 5212/* License: Ruby's */ 5213int 5214rb_w32_open(const char *file, int oflag, ...) 5215{ 5216 WCHAR *wfile; 5217 int ret; 5218 int pmode; 5219 5220 va_list arg; 5221 va_start(arg, oflag); 5222 pmode = va_arg(arg, int); 5223 va_end(arg); 5224 5225 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) { 5226 ret = _open(file, oflag, pmode); 5227 if (ret == -1 && errno == EACCES) check_if_dir(file); 5228 return ret; 5229 } 5230 5231 if (!(wfile = filecp_to_wstr(file, NULL))) 5232 return -1; 5233 ret = rb_w32_wopen(wfile, oflag, pmode); 5234 free(wfile); 5235 return ret; 5236} 5237 5238int 5239rb_w32_wopen(const WCHAR *file, int oflag, ...) 5240{ 5241 char flags = 0; 5242 int fd; 5243 DWORD access; 5244 DWORD create; 5245 DWORD attr = FILE_ATTRIBUTE_NORMAL; 5246 SECURITY_ATTRIBUTES sec; 5247 HANDLE h; 5248 5249 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) { 5250 va_list arg; 5251 int pmode; 5252 va_start(arg, oflag); 5253 pmode = va_arg(arg, int); 5254 va_end(arg); 5255 fd = _wopen(file, oflag, pmode); 5256 if (fd == -1 && errno == EACCES) check_if_wdir(file); 5257 return fd; 5258 } 5259 5260 sec.nLength = sizeof(sec); 5261 sec.lpSecurityDescriptor = NULL; 5262 if (oflag & O_NOINHERIT) { 5263 sec.bInheritHandle = FALSE; 5264 flags |= FNOINHERIT; 5265 } 5266 else { 5267 sec.bInheritHandle = TRUE; 5268 } 5269 oflag &= ~O_NOINHERIT; 5270 5271 /* always open with binary mode */ 5272 oflag &= ~(O_BINARY | O_TEXT); 5273 5274 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) { 5275 case O_RDWR: 5276 access = GENERIC_READ | GENERIC_WRITE; 5277 break; 5278 case O_RDONLY: 5279 access = GENERIC_READ; 5280 break; 5281 case O_WRONLY: 5282 access = GENERIC_WRITE; 5283 break; 5284 default: 5285 errno = EINVAL; 5286 return -1; 5287 } 5288 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY); 5289 5290 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) { 5291 case O_CREAT: 5292 create = OPEN_ALWAYS; 5293 break; 5294 case 0: 5295 case O_EXCL: 5296 create = OPEN_EXISTING; 5297 break; 5298 case O_CREAT | O_EXCL: 5299 case O_CREAT | O_EXCL | O_TRUNC: 5300 create = CREATE_NEW; 5301 break; 5302 case O_TRUNC: 5303 case O_TRUNC | O_EXCL: 5304 create = TRUNCATE_EXISTING; 5305 break; 5306 case O_CREAT | O_TRUNC: 5307 create = CREATE_ALWAYS; 5308 break; 5309 default: 5310 errno = EINVAL; 5311 return -1; 5312 } 5313 if (oflag & O_CREAT) { 5314 va_list arg; 5315 int pmode; 5316 va_start(arg, oflag); 5317 pmode = va_arg(arg, int); 5318 va_end(arg); 5319 /* TODO: we need to check umask here, but it's not exported... */ 5320 if (!(pmode & S_IWRITE)) 5321 attr = FILE_ATTRIBUTE_READONLY; 5322 } 5323 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC); 5324 5325 if (oflag & O_TEMPORARY) { 5326 attr |= FILE_FLAG_DELETE_ON_CLOSE; 5327 access |= DELETE; 5328 } 5329 oflag &= ~O_TEMPORARY; 5330 5331 if (oflag & _O_SHORT_LIVED) 5332 attr |= FILE_ATTRIBUTE_TEMPORARY; 5333 oflag &= ~_O_SHORT_LIVED; 5334 5335 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) { 5336 case 0: 5337 break; 5338 case O_SEQUENTIAL: 5339 attr |= FILE_FLAG_SEQUENTIAL_SCAN; 5340 break; 5341 case O_RANDOM: 5342 attr |= FILE_FLAG_RANDOM_ACCESS; 5343 break; 5344 default: 5345 errno = EINVAL; 5346 return -1; 5347 } 5348 oflag &= ~(O_SEQUENTIAL | O_RANDOM); 5349 5350 if (oflag & ~O_APPEND) { 5351 errno = EINVAL; 5352 return -1; 5353 } 5354 5355 /* allocate a C Runtime file handle */ 5356 RUBY_CRITICAL({ 5357 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 5358 fd = _open_osfhandle((intptr_t)h, 0); 5359 CloseHandle(h); 5360 }); 5361 if (fd == -1) { 5362 errno = EMFILE; 5363 return -1; 5364 } 5365 RUBY_CRITICAL({ 5366 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 5367 _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE); 5368 _set_osflags(fd, 0); 5369 5370 h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec, 5371 create, attr, NULL); 5372 if (h == INVALID_HANDLE_VALUE) { 5373 DWORD e = GetLastError(); 5374 if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file)) 5375 errno = map_errno(e); 5376 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 5377 fd = -1; 5378 goto quit; 5379 } 5380 5381 switch (GetFileType(h)) { 5382 case FILE_TYPE_CHAR: 5383 flags |= FDEV; 5384 break; 5385 case FILE_TYPE_PIPE: 5386 flags |= FPIPE; 5387 break; 5388 case FILE_TYPE_UNKNOWN: 5389 errno = map_errno(GetLastError()); 5390 CloseHandle(h); 5391 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 5392 fd = -1; 5393 goto quit; 5394 } 5395 if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND)) 5396 flags |= FAPPEND; 5397 5398 _set_osfhnd(fd, (intptr_t)h); 5399 _osfile(fd) = flags | FOPEN; 5400 5401 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 5402 quit: 5403 ; 5404 }); 5405 5406 return fd; 5407} 5408 5409/* License: Ruby's */ 5410int 5411rb_w32_fclose(FILE *fp) 5412{ 5413 int fd = fileno(fp); 5414 SOCKET sock = TO_SOCKET(fd); 5415 int save_errno = errno; 5416 5417 if (fflush(fp)) return -1; 5418 if (!is_socket(sock)) { 5419 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); 5420 return fclose(fp); 5421 } 5422 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); 5423 fclose(fp); 5424 errno = save_errno; 5425 if (closesocket(sock) == SOCKET_ERROR) { 5426 errno = map_errno(WSAGetLastError()); 5427 return -1; 5428 } 5429 return 0; 5430} 5431 5432/* License: Ruby's */ 5433int 5434rb_w32_pipe(int fds[2]) 5435{ 5436 static DWORD serial = 0; 5437 char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000"; 5438 char *p; 5439 SECURITY_ATTRIBUTES sec; 5440 HANDLE hRead, hWrite, h; 5441 int fdRead, fdWrite; 5442 int ret; 5443 5444 /* if doesn't have CancelIo, use default pipe function */ 5445 if (!cancel_io) 5446 return _pipe(fds, 65536L, _O_NOINHERIT); 5447 5448 p = strchr(name, '0'); 5449 snprintf(p, strlen(p) + 1, "%"PRI_PIDT_PREFIX"x-%lx", rb_w32_getpid(), serial++); 5450 5451 sec.nLength = sizeof(sec); 5452 sec.lpSecurityDescriptor = NULL; 5453 sec.bInheritHandle = FALSE; 5454 5455 RUBY_CRITICAL({ 5456 hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 5457 0, 2, 65536, 65536, 0, &sec); 5458 }); 5459 if (hRead == INVALID_HANDLE_VALUE) { 5460 DWORD err = GetLastError(); 5461 if (err == ERROR_PIPE_BUSY) 5462 errno = EMFILE; 5463 else 5464 errno = map_errno(GetLastError()); 5465 return -1; 5466 } 5467 5468 RUBY_CRITICAL({ 5469 hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec, 5470 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 5471 }); 5472 if (hWrite == INVALID_HANDLE_VALUE) { 5473 errno = map_errno(GetLastError()); 5474 CloseHandle(hRead); 5475 return -1; 5476 } 5477 5478 RUBY_CRITICAL(do { 5479 ret = 0; 5480 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 5481 fdRead = _open_osfhandle((intptr_t)h, 0); 5482 CloseHandle(h); 5483 if (fdRead == -1) { 5484 errno = EMFILE; 5485 CloseHandle(hWrite); 5486 CloseHandle(hRead); 5487 ret = -1; 5488 break; 5489 } 5490 5491 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock))); 5492 _set_osfhnd(fdRead, (intptr_t)hRead); 5493 _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT); 5494 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock))); 5495 } while (0)); 5496 if (ret) 5497 return ret; 5498 5499 RUBY_CRITICAL(do { 5500 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 5501 fdWrite = _open_osfhandle((intptr_t)h, 0); 5502 CloseHandle(h); 5503 if (fdWrite == -1) { 5504 errno = EMFILE; 5505 CloseHandle(hWrite); 5506 ret = -1; 5507 break; 5508 } 5509 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock))); 5510 _set_osfhnd(fdWrite, (intptr_t)hWrite); 5511 _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT); 5512 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock))); 5513 } while (0)); 5514 if (ret) { 5515 rb_w32_close(fdRead); 5516 return ret; 5517 } 5518 5519 fds[0] = fdRead; 5520 fds[1] = fdWrite; 5521 5522 return 0; 5523} 5524 5525/* License: Ruby's */ 5526static struct constat * 5527constat_handle(HANDLE h) 5528{ 5529 st_data_t data; 5530 struct constat *p; 5531 if (!conlist) { 5532 conlist = st_init_numtable(); 5533 } 5534 if (st_lookup(conlist, (st_data_t)h, &data)) { 5535 p = (struct constat *)data; 5536 } 5537 else { 5538 CONSOLE_SCREEN_BUFFER_INFO csbi; 5539 p = ALLOC(struct constat); 5540 p->vt100.state = constat_init; 5541 p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; 5542 p->vt100.saved.X = p->vt100.saved.Y = 0; 5543 if (GetConsoleScreenBufferInfo(h, &csbi)) { 5544 p->vt100.attr = csbi.wAttributes; 5545 } 5546 st_insert(conlist, (st_data_t)h, (st_data_t)p); 5547 } 5548 return p; 5549} 5550 5551/* License: Ruby's */ 5552static void 5553constat_reset(HANDLE h) 5554{ 5555 st_data_t data; 5556 struct constat *p; 5557 if (!conlist) return; 5558 if (!st_lookup(conlist, (st_data_t)h, &data)) return; 5559 p = (struct constat *)data; 5560 p->vt100.state = constat_init; 5561} 5562 5563/* License: Ruby's */ 5564static DWORD 5565constat_attr(int count, const int *seq, DWORD attr, DWORD default_attr) 5566{ 5567#define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED) 5568#define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED) 5569 DWORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY); 5570 int rev = 0; 5571 5572 if (!count) return attr; 5573 while (count-- > 0) { 5574 switch (*seq++) { 5575 case 0: 5576 attr = default_attr; 5577 rev = 0; 5578 bold = 0; 5579 break; 5580 case 1: 5581 bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; 5582 break; 5583 case 4: 5584#ifndef COMMON_LVB_UNDERSCORE 5585#define COMMON_LVB_UNDERSCORE 0x8000 5586#endif 5587 attr |= COMMON_LVB_UNDERSCORE; 5588 break; 5589 case 7: 5590 rev = 1; 5591 break; 5592 5593 case 30: 5594 attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED); 5595 break; 5596 case 17: 5597 case 31: 5598 attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED; 5599 break; 5600 case 18: 5601 case 32: 5602 attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN; 5603 break; 5604 case 19: 5605 case 33: 5606 attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; 5607 break; 5608 case 20: 5609 case 34: 5610 attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE; 5611 break; 5612 case 21: 5613 case 35: 5614 attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED; 5615 break; 5616 case 22: 5617 case 36: 5618 attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN; 5619 break; 5620 case 23: 5621 case 37: 5622 attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; 5623 break; 5624 5625 case 40: 5626 attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED); 5627 break; 5628 case 41: 5629 attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED; 5630 break; 5631 case 42: 5632 attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN; 5633 break; 5634 case 43: 5635 attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; 5636 break; 5637 case 44: 5638 attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE; 5639 break; 5640 case 45: 5641 attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED; 5642 break; 5643 case 46: 5644 attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN; 5645 break; 5646 case 47: 5647 attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; 5648 break; 5649 } 5650 } 5651 if (rev) { 5652 attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) | 5653 ((attr & FOREGROUND_MASK) << 4) | 5654 ((attr & BACKGROUND_MASK) >> 4); 5655 } 5656 return attr | bold; 5657} 5658 5659/* License: Ruby's */ 5660static void 5661constat_apply(HANDLE handle, struct constat *s, WCHAR w) 5662{ 5663 CONSOLE_SCREEN_BUFFER_INFO csbi; 5664 const int *seq = s->vt100.seq; 5665 int count = s->vt100.state; 5666 int arg1 = 1; 5667 COORD pos; 5668 DWORD written; 5669 5670 if (!GetConsoleScreenBufferInfo(handle, &csbi)) return; 5671 if (count > 0 && seq[0] > 0) arg1 = seq[0]; 5672 switch (w) { 5673 case L'm': 5674 SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr)); 5675 break; 5676 case L'F': 5677 csbi.dwCursorPosition.X = 0; 5678 case L'A': 5679 csbi.dwCursorPosition.Y -= arg1; 5680 if (csbi.dwCursorPosition.Y < 0) 5681 csbi.dwCursorPosition.Y = 0; 5682 SetConsoleCursorPosition(handle, csbi.dwCursorPosition); 5683 break; 5684 case L'E': 5685 csbi.dwCursorPosition.X = 0; 5686 case L'B': 5687 case L'e': 5688 csbi.dwCursorPosition.Y += arg1; 5689 if (csbi.dwCursorPosition.Y >= csbi.dwSize.Y) 5690 csbi.dwCursorPosition.Y = csbi.dwSize.Y; 5691 SetConsoleCursorPosition(handle, csbi.dwCursorPosition); 5692 break; 5693 case L'C': 5694 csbi.dwCursorPosition.X += arg1; 5695 if (csbi.dwCursorPosition.X >= csbi.dwSize.X) 5696 csbi.dwCursorPosition.X = csbi.dwSize.X; 5697 SetConsoleCursorPosition(handle, csbi.dwCursorPosition); 5698 break; 5699 case L'D': 5700 csbi.dwCursorPosition.X -= arg1; 5701 if (csbi.dwCursorPosition.X < 0) 5702 csbi.dwCursorPosition.X = 0; 5703 SetConsoleCursorPosition(handle, csbi.dwCursorPosition); 5704 break; 5705 case L'G': 5706 case L'`': 5707 csbi.dwCursorPosition.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1; 5708 SetConsoleCursorPosition(handle, csbi.dwCursorPosition); 5709 break; 5710 case L'd': 5711 csbi.dwCursorPosition.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1; 5712 SetConsoleCursorPosition(handle, csbi.dwCursorPosition); 5713 break; 5714 case L'H': 5715 case L'f': 5716 pos.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1; 5717 if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1; 5718 pos.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1; 5719 SetConsoleCursorPosition(handle, pos); 5720 break; 5721 case L'J': 5722 switch (arg1) { 5723 case 0: /* erase after cursor */ 5724 FillConsoleOutputCharacterW(handle, L' ', 5725 csbi.dwSize.X * (csbi.dwSize.Y - csbi.dwCursorPosition.Y) - csbi.dwCursorPosition.X, 5726 csbi.dwCursorPosition, &written); 5727 break; 5728 case 1: /* erase before cursor */ 5729 pos.X = 0; 5730 pos.Y = csbi.dwCursorPosition.Y; 5731 FillConsoleOutputCharacterW(handle, L' ', 5732 csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X, 5733 pos, &written); 5734 break; 5735 case 2: /* erase entire line */ 5736 pos.X = 0; 5737 pos.Y = 0; 5738 FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X * csbi.dwSize.Y, pos, &written); 5739 break; 5740 } 5741 break; 5742 case L'K': 5743 switch (arg1) { 5744 case 0: /* erase after cursor */ 5745 FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written); 5746 break; 5747 case 1: /* erase before cursor */ 5748 pos.X = 0; 5749 pos.Y = csbi.dwCursorPosition.Y; 5750 FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written); 5751 break; 5752 case 2: /* erase entire line */ 5753 pos.X = 0; 5754 pos.Y = csbi.dwCursorPosition.Y; 5755 FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written); 5756 break; 5757 } 5758 break; 5759 case L's': 5760 s->vt100.saved = csbi.dwCursorPosition; 5761 break; 5762 case L'u': 5763 SetConsoleCursorPosition(handle, s->vt100.saved); 5764 break; 5765 case L'h': 5766 if (count >= 2 && seq[0] == -1 && seq[1] == 25) { 5767 CONSOLE_CURSOR_INFO cci; 5768 GetConsoleCursorInfo(handle, &cci); 5769 cci.bVisible = TRUE; 5770 SetConsoleCursorInfo(handle, &cci); 5771 } 5772 break; 5773 case L'l': 5774 if (count >= 2 && seq[0] == -1 && seq[1] == 25) { 5775 CONSOLE_CURSOR_INFO cci; 5776 GetConsoleCursorInfo(handle, &cci); 5777 cci.bVisible = FALSE; 5778 SetConsoleCursorInfo(handle, &cci); 5779 } 5780 break; 5781 } 5782} 5783 5784/* License: Ruby's */ 5785static long 5786constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp) 5787{ 5788 const WCHAR *ptr = *ptrp; 5789 long rest, len = *lenp; 5790 while (len-- > 0) { 5791 WCHAR wc = *ptr++; 5792 if (wc == 0x1b) { 5793 rest = *lenp - len - 1; 5794 s->vt100.state = constat_esc; 5795 } 5796 else if (s->vt100.state == constat_esc && wc == L'[') { 5797 rest = *lenp - len - 1; 5798 if (rest > 0) --rest; 5799 s->vt100.state = constat_seq; 5800 s->vt100.seq[0] = 0; 5801 } 5802 else if (s->vt100.state >= constat_seq) { 5803 if (wc >= L'0' && wc <= L'9') { 5804 if (s->vt100.state < (int)numberof(s->vt100.seq)) { 5805 int *seq = &s->vt100.seq[s->vt100.state]; 5806 *seq = (*seq * 10) + (wc - L'0'); 5807 } 5808 } 5809 else if (s->vt100.state == constat_seq && s->vt100.seq[0] == 0 && wc == L'?') { 5810 s->vt100.seq[s->vt100.state++] = -1; 5811 } 5812 else { 5813 do { 5814 if (++s->vt100.state < (int)numberof(s->vt100.seq)) { 5815 s->vt100.seq[s->vt100.state] = 0; 5816 } 5817 else { 5818 s->vt100.state = (int)numberof(s->vt100.seq); 5819 } 5820 } while (0); 5821 if (wc != L';') { 5822 constat_apply(h, s, wc); 5823 s->vt100.state = constat_init; 5824 } 5825 } 5826 rest = 0; 5827 } 5828 else { 5829 continue; 5830 } 5831 *ptrp = ptr; 5832 *lenp = len; 5833 return rest; 5834 } 5835 len = *lenp; 5836 *ptrp = ptr; 5837 *lenp = 0; 5838 return len; 5839} 5840 5841 5842/* License: Ruby's */ 5843int 5844rb_w32_close(int fd) 5845{ 5846 SOCKET sock = TO_SOCKET(fd); 5847 int save_errno = errno; 5848 5849 if (!is_socket(sock)) { 5850 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); 5851 constat_delete((HANDLE)sock); 5852 return _close(fd); 5853 } 5854 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); 5855 socklist_delete(&sock, NULL); 5856 _close(fd); 5857 errno = save_errno; 5858 if (closesocket(sock) == SOCKET_ERROR) { 5859 errno = map_errno(WSAGetLastError()); 5860 return -1; 5861 } 5862 return 0; 5863} 5864 5865static int 5866setup_overlapped(OVERLAPPED *ol, int fd) 5867{ 5868 memset(ol, 0, sizeof(*ol)); 5869 if (!(_osfile(fd) & (FDEV | FPIPE))) { 5870 LONG high = 0; 5871 DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT; 5872 DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method); 5873#ifndef INVALID_SET_FILE_POINTER 5874#define INVALID_SET_FILE_POINTER ((DWORD)-1) 5875#endif 5876 if (low == INVALID_SET_FILE_POINTER) { 5877 DWORD err = GetLastError(); 5878 if (err != NO_ERROR) { 5879 errno = map_errno(err); 5880 return -1; 5881 } 5882 } 5883 ol->Offset = low; 5884 ol->OffsetHigh = high; 5885 } 5886 ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 5887 if (!ol->hEvent) { 5888 errno = map_errno(GetLastError()); 5889 return -1; 5890 } 5891 return 0; 5892} 5893 5894static void 5895finish_overlapped(OVERLAPPED *ol, int fd, DWORD size) 5896{ 5897 CloseHandle(ol->hEvent); 5898 5899 if (!(_osfile(fd) & (FDEV | FPIPE))) { 5900 LONG high = ol->OffsetHigh; 5901 DWORD low = ol->Offset + size; 5902 if (low < ol->Offset) 5903 ++high; 5904 SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN); 5905 } 5906} 5907 5908#undef read 5909/* License: Ruby's */ 5910ssize_t 5911rb_w32_read(int fd, void *buf, size_t size) 5912{ 5913 SOCKET sock = TO_SOCKET(fd); 5914 DWORD read; 5915 DWORD wait; 5916 DWORD err; 5917 size_t len; 5918 size_t ret; 5919 OVERLAPPED ol, *pol = NULL; 5920 BOOL isconsole; 5921 BOOL islineinput = FALSE; 5922 int start = 0; 5923 5924 if (is_socket(sock)) 5925 return rb_w32_recv(fd, buf, size, 0); 5926 5927 // validate fd by using _get_osfhandle() because we cannot access _nhandle 5928 if (_get_osfhandle(fd) == -1) { 5929 return -1; 5930 } 5931 5932 if (_osfile(fd) & FTEXT) { 5933 return _read(fd, buf, size); 5934 } 5935 5936 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 5937 5938 if (!size || _osfile(fd) & FEOFLAG) { 5939 _set_osflags(fd, _osfile(fd) & ~FEOFLAG); 5940 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 5941 return 0; 5942 } 5943 5944 ret = 0; 5945 isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2)); 5946 if (isconsole) { 5947 DWORD mode; 5948 GetConsoleMode((HANDLE)_osfhnd(fd),&mode); 5949 islineinput = (mode & ENABLE_LINE_INPUT) != 0; 5950 } 5951 retry: 5952 /* get rid of console reading bug */ 5953 if (isconsole) { 5954 constat_reset((HANDLE)_osfhnd(fd)); 5955 if (start) 5956 len = 1; 5957 else { 5958 len = 0; 5959 start = 1; 5960 } 5961 } 5962 else 5963 len = size; 5964 size -= len; 5965 5966 /* if have cancel_io, use Overlapped I/O */ 5967 if (cancel_io) { 5968 if (setup_overlapped(&ol, fd)) { 5969 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 5970 return -1; 5971 } 5972 5973 pol = &ol; 5974 } 5975 5976 if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) { 5977 err = GetLastError(); 5978 if (err != ERROR_IO_PENDING) { 5979 if (pol) CloseHandle(ol.hEvent); 5980 if (err == ERROR_ACCESS_DENIED) 5981 errno = EBADF; 5982 else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) { 5983 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 5984 return 0; 5985 } 5986 else 5987 errno = map_errno(err); 5988 5989 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 5990 return -1; 5991 } 5992 5993 if (pol) { 5994 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE); 5995 if (wait != WAIT_OBJECT_0) { 5996 if (wait == WAIT_OBJECT_0 + 1) 5997 errno = EINTR; 5998 else 5999 errno = map_errno(GetLastError()); 6000 CloseHandle(ol.hEvent); 6001 cancel_io((HANDLE)_osfhnd(fd)); 6002 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6003 return -1; 6004 } 6005 6006 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) && 6007 (err = GetLastError()) != ERROR_HANDLE_EOF) { 6008 int ret = 0; 6009 if (err != ERROR_BROKEN_PIPE) { 6010 errno = map_errno(err); 6011 ret = -1; 6012 } 6013 CloseHandle(ol.hEvent); 6014 cancel_io((HANDLE)_osfhnd(fd)); 6015 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6016 return ret; 6017 } 6018 } 6019 } 6020 else { 6021 err = GetLastError(); 6022 errno = map_errno(err); 6023 } 6024 6025 if (pol) { 6026 finish_overlapped(&ol, fd, read); 6027 } 6028 6029 ret += read; 6030 if (read >= len) { 6031 buf = (char *)buf + read; 6032 if (err != ERROR_OPERATION_ABORTED && 6033 !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0) 6034 goto retry; 6035 } 6036 if (read == 0) 6037 _set_osflags(fd, _osfile(fd) | FEOFLAG); 6038 6039 6040 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6041 6042 return ret; 6043} 6044 6045#undef write 6046/* License: Ruby's */ 6047ssize_t 6048rb_w32_write(int fd, const void *buf, size_t size) 6049{ 6050 SOCKET sock = TO_SOCKET(fd); 6051 DWORD written; 6052 DWORD wait; 6053 DWORD err; 6054 size_t len; 6055 size_t ret; 6056 OVERLAPPED ol, *pol = NULL; 6057 6058 if (is_socket(sock)) 6059 return rb_w32_send(fd, buf, size, 0); 6060 6061 // validate fd by using _get_osfhandle() because we cannot access _nhandle 6062 if (_get_osfhandle(fd) == -1) { 6063 return -1; 6064 } 6065 6066 if ((_osfile(fd) & FTEXT) && 6067 (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) { 6068 return _write(fd, buf, size); 6069 } 6070 6071 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 6072 6073 if (!size || _osfile(fd) & FEOFLAG) { 6074 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6075 return 0; 6076 } 6077 6078 ret = 0; 6079 retry: 6080 /* get rid of console writing bug */ 6081 len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size; 6082 size -= len; 6083 6084 /* if have cancel_io, use Overlapped I/O */ 6085 if (cancel_io) { 6086 if (setup_overlapped(&ol, fd)) { 6087 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6088 return -1; 6089 } 6090 6091 pol = &ol; 6092 } 6093 6094 if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) { 6095 err = GetLastError(); 6096 if (err != ERROR_IO_PENDING) { 6097 if (pol) CloseHandle(ol.hEvent); 6098 if (err == ERROR_ACCESS_DENIED) 6099 errno = EBADF; 6100 else 6101 errno = map_errno(err); 6102 6103 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6104 return -1; 6105 } 6106 6107 if (pol) { 6108 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE); 6109 if (wait != WAIT_OBJECT_0) { 6110 if (wait == WAIT_OBJECT_0 + 1) 6111 errno = EINTR; 6112 else 6113 errno = map_errno(GetLastError()); 6114 CloseHandle(ol.hEvent); 6115 cancel_io((HANDLE)_osfhnd(fd)); 6116 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6117 return -1; 6118 } 6119 6120 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written, 6121 TRUE)) { 6122 errno = map_errno(err); 6123 CloseHandle(ol.hEvent); 6124 cancel_io((HANDLE)_osfhnd(fd)); 6125 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6126 return -1; 6127 } 6128 } 6129 } 6130 6131 if (pol) { 6132 finish_overlapped(&ol, fd, written); 6133 } 6134 6135 ret += written; 6136 if (written == len) { 6137 buf = (const char *)buf + len; 6138 if (size > 0) 6139 goto retry; 6140 } 6141 6142 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 6143 6144 return ret; 6145} 6146 6147/* License: Ruby's */ 6148long 6149rb_w32_write_console(uintptr_t strarg, int fd) 6150{ 6151 static int disable; 6152 HANDLE handle; 6153 DWORD dwMode, reslen; 6154 VALUE str = strarg; 6155 rb_encoding *utf16 = rb_enc_find("UTF-16LE"); 6156 const WCHAR *ptr, *next; 6157 struct constat *s; 6158 long len; 6159 6160 if (disable) return -1L; 6161 handle = (HANDLE)_osfhnd(fd); 6162 if (!GetConsoleMode(handle, &dwMode) || 6163 !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE")) 6164 return -1L; 6165 6166 str = rb_str_encode(str, rb_enc_from_encoding(utf16), 6167 ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil); 6168 ptr = (const WCHAR *)RSTRING_PTR(str); 6169 len = RSTRING_LEN(str) / sizeof(WCHAR); 6170 s = constat_handle(handle); 6171 while (len > 0) { 6172 long curlen = constat_parse(handle, s, (next = ptr, &next), &len); 6173 if (curlen > 0) { 6174 if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) { 6175 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 6176 disable = TRUE; 6177 return -1L; 6178 } 6179 } 6180 ptr = next; 6181 } 6182 RB_GC_GUARD(str); 6183 return (long)reslen; 6184} 6185 6186/* License: Ruby's */ 6187static int 6188unixtime_to_filetime(time_t time, FILETIME *ft) 6189{ 6190 ULARGE_INTEGER tmp; 6191 6192 tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000; 6193 ft->dwLowDateTime = tmp.LowPart; 6194 ft->dwHighDateTime = tmp.HighPart; 6195 return 0; 6196} 6197 6198/* License: Ruby's */ 6199static int 6200wutime(const WCHAR *path, const struct utimbuf *times) 6201{ 6202 HANDLE hFile; 6203 FILETIME atime, mtime; 6204 struct stati64 stat; 6205 int ret = 0; 6206 6207 if (wstati64(path, &stat)) { 6208 return -1; 6209 } 6210 6211 if (times) { 6212 if (unixtime_to_filetime(times->actime, &atime)) { 6213 return -1; 6214 } 6215 if (unixtime_to_filetime(times->modtime, &mtime)) { 6216 return -1; 6217 } 6218 } 6219 else { 6220 GetSystemTimeAsFileTime(&atime); 6221 mtime = atime; 6222 } 6223 6224 RUBY_CRITICAL({ 6225 const DWORD attr = GetFileAttributesW(path); 6226 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) 6227 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY); 6228 hFile = CreateFileW(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 6229 FILE_FLAG_BACKUP_SEMANTICS, 0); 6230 if (hFile == INVALID_HANDLE_VALUE) { 6231 errno = map_errno(GetLastError()); 6232 ret = -1; 6233 } 6234 else { 6235 if (!SetFileTime(hFile, NULL, &atime, &mtime)) { 6236 errno = map_errno(GetLastError()); 6237 ret = -1; 6238 } 6239 CloseHandle(hFile); 6240 } 6241 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) 6242 SetFileAttributesW(path, attr); 6243 }); 6244 6245 return ret; 6246} 6247 6248/* License: Ruby's */ 6249int 6250rb_w32_uutime(const char *path, const struct utimbuf *times) 6251{ 6252 WCHAR *wpath; 6253 int ret; 6254 6255 if (!(wpath = utf8_to_wstr(path, NULL))) 6256 return -1; 6257 ret = wutime(wpath, times); 6258 free(wpath); 6259 return ret; 6260} 6261 6262/* License: Ruby's */ 6263int 6264rb_w32_utime(const char *path, const struct utimbuf *times) 6265{ 6266 WCHAR *wpath; 6267 int ret; 6268 6269 if (!(wpath = filecp_to_wstr(path, NULL))) 6270 return -1; 6271 ret = wutime(wpath, times); 6272 free(wpath); 6273 return ret; 6274} 6275 6276/* License: Ruby's */ 6277int 6278rb_w32_uchdir(const char *path) 6279{ 6280 WCHAR *wpath; 6281 int ret; 6282 6283 if (!(wpath = utf8_to_wstr(path, NULL))) 6284 return -1; 6285 ret = _wchdir(wpath); 6286 free(wpath); 6287 return ret; 6288} 6289 6290/* License: Ruby's */ 6291static int 6292wmkdir(const WCHAR *wpath, int mode) 6293{ 6294 int ret = -1; 6295 6296 RUBY_CRITICAL(do { 6297 if (CreateDirectoryW(wpath, NULL) == FALSE) { 6298 errno = map_errno(GetLastError()); 6299 break; 6300 } 6301 if (_wchmod(wpath, mode) == -1) { 6302 RemoveDirectoryW(wpath); 6303 break; 6304 } 6305 ret = 0; 6306 } while (0)); 6307 return ret; 6308} 6309 6310/* License: Ruby's */ 6311int 6312rb_w32_umkdir(const char *path, int mode) 6313{ 6314 WCHAR *wpath; 6315 int ret; 6316 6317 if (!(wpath = utf8_to_wstr(path, NULL))) 6318 return -1; 6319 ret = wmkdir(wpath, mode); 6320 free(wpath); 6321 return ret; 6322} 6323 6324/* License: Ruby's */ 6325int 6326rb_w32_mkdir(const char *path, int mode) 6327{ 6328 WCHAR *wpath; 6329 int ret; 6330 6331 if (!(wpath = filecp_to_wstr(path, NULL))) 6332 return -1; 6333 ret = wmkdir(wpath, mode); 6334 free(wpath); 6335 return ret; 6336} 6337 6338/* License: Ruby's */ 6339static int 6340wrmdir(const WCHAR *wpath) 6341{ 6342 int ret = 0; 6343 RUBY_CRITICAL({ 6344 const DWORD attr = GetFileAttributesW(wpath); 6345 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 6346 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY); 6347 } 6348 if (RemoveDirectoryW(wpath) == FALSE) { 6349 errno = map_errno(GetLastError()); 6350 ret = -1; 6351 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 6352 SetFileAttributesW(wpath, attr); 6353 } 6354 } 6355 }); 6356 return ret; 6357} 6358 6359/* License: Ruby's */ 6360int 6361rb_w32_rmdir(const char *path) 6362{ 6363 WCHAR *wpath; 6364 int ret; 6365 6366 if (!(wpath = filecp_to_wstr(path, NULL))) 6367 return -1; 6368 ret = wrmdir(wpath); 6369 free(wpath); 6370 return ret; 6371} 6372 6373/* License: Ruby's */ 6374int 6375rb_w32_urmdir(const char *path) 6376{ 6377 WCHAR *wpath; 6378 int ret; 6379 6380 if (!(wpath = utf8_to_wstr(path, NULL))) 6381 return -1; 6382 ret = wrmdir(wpath); 6383 free(wpath); 6384 return ret; 6385} 6386 6387/* License: Ruby's */ 6388static int 6389wunlink(const WCHAR *path) 6390{ 6391 int ret = 0; 6392 RUBY_CRITICAL({ 6393 const DWORD attr = GetFileAttributesW(path); 6394 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 6395 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY); 6396 } 6397 if (!DeleteFileW(path)) { 6398 errno = map_errno(GetLastError()); 6399 ret = -1; 6400 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 6401 SetFileAttributesW(path, attr); 6402 } 6403 } 6404 }); 6405 return ret; 6406} 6407 6408/* License: Ruby's */ 6409int 6410rb_w32_uunlink(const char *path) 6411{ 6412 WCHAR *wpath; 6413 int ret; 6414 6415 if (!(wpath = utf8_to_wstr(path, NULL))) 6416 return -1; 6417 ret = wunlink(wpath); 6418 free(wpath); 6419 return ret; 6420} 6421 6422/* License: Ruby's */ 6423int 6424rb_w32_unlink(const char *path) 6425{ 6426 WCHAR *wpath; 6427 int ret; 6428 6429 if (!(wpath = filecp_to_wstr(path, NULL))) 6430 return -1; 6431 ret = wunlink(wpath); 6432 free(wpath); 6433 return ret; 6434} 6435 6436/* License: Ruby's */ 6437int 6438rb_w32_uchmod(const char *path, int mode) 6439{ 6440 WCHAR *wpath; 6441 int ret; 6442 6443 if (!(wpath = utf8_to_wstr(path, NULL))) 6444 return -1; 6445 ret = _wchmod(wpath, mode); 6446 free(wpath); 6447 return ret; 6448} 6449 6450#if !defined(__BORLANDC__) 6451/* License: Ruby's */ 6452int 6453rb_w32_isatty(int fd) 6454{ 6455 DWORD mode; 6456 6457 // validate fd by using _get_osfhandle() because we cannot access _nhandle 6458 if (_get_osfhandle(fd) == -1) { 6459 return 0; 6460 } 6461 if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) { 6462 errno = ENOTTY; 6463 return 0; 6464 } 6465 return 1; 6466} 6467#endif 6468 6469// 6470// Fix bcc32's stdio bug 6471// 6472 6473#ifdef __BORLANDC__ 6474/* License: Ruby's */ 6475static int 6476too_many_files(void) 6477{ 6478 FILE *f; 6479 for (f = _streams; f < _streams + _nfile; f++) { 6480 if (f->fd < 0) return 0; 6481 } 6482 return 1; 6483} 6484 6485#undef fopen 6486/* License: Ruby's */ 6487FILE * 6488rb_w32_fopen(const char *path, const char *mode) 6489{ 6490 FILE *f = (errno = 0, fopen(path, mode)); 6491 if (f == NULL && errno == 0) { 6492 if (too_many_files()) 6493 errno = EMFILE; 6494 } 6495 return f; 6496} 6497 6498/* License: Ruby's */ 6499FILE * 6500rb_w32_fdopen(int handle, const char *type) 6501{ 6502 FILE *f = (errno = 0, _fdopen(handle, (char *)type)); 6503 if (f == NULL && errno == 0) { 6504 if (handle < 0) 6505 errno = EBADF; 6506 else if (too_many_files()) 6507 errno = EMFILE; 6508 } 6509 return f; 6510} 6511 6512/* License: Ruby's */ 6513FILE * 6514rb_w32_fsopen(const char *path, const char *mode, int shflags) 6515{ 6516 FILE *f = (errno = 0, _fsopen(path, mode, shflags)); 6517 if (f == NULL && errno == 0) { 6518 if (too_many_files()) 6519 errno = EMFILE; 6520 } 6521 return f; 6522} 6523#endif 6524 6525#if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60 6526extern long _ftol(double); 6527/* License: Ruby's */ 6528long 6529_ftol2(double d) 6530{ 6531 return _ftol(d); 6532} 6533 6534/* License: Ruby's */ 6535long 6536_ftol2_sse(double d) 6537{ 6538 return _ftol(d); 6539} 6540#endif 6541 6542#ifndef signbit 6543/* License: Ruby's */ 6544int 6545signbit(double x) 6546{ 6547 int *ip = (int *)(&x + 1) - 1; 6548 return *ip < 0; 6549} 6550#endif 6551 6552/* License: Ruby's */ 6553const char * WSAAPI 6554rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len) 6555{ 6556 typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t); 6557 inet_ntop_t *pInetNtop; 6558 pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL); 6559 if (pInetNtop) { 6560 return pInetNtop(af, (void *)addr, numaddr, numaddr_len); 6561 } 6562 else { 6563 struct in_addr in; 6564 memcpy(&in.s_addr, addr, sizeof(in.s_addr)); 6565 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in)); 6566 } 6567 return numaddr; 6568} 6569 6570/* License: Ruby's */ 6571char 6572rb_w32_fd_is_text(int fd) 6573{ 6574 return _osfile(fd) & FTEXT; 6575} 6576 6577#if RUBY_MSVCRT_VERSION < 80 && !defined(__MINGW64__) 6578/* License: Ruby's */ 6579static int 6580unixtime_to_systemtime(const time_t t, SYSTEMTIME *st) 6581{ 6582 FILETIME ft; 6583 if (unixtime_to_filetime(t, &ft)) return -1; 6584 if (!FileTimeToSystemTime(&ft, st)) return -1; 6585 return 0; 6586} 6587 6588/* License: Ruby's */ 6589static void 6590systemtime_to_tm(const SYSTEMTIME *st, struct tm *t) 6591{ 6592 int y = st->wYear, m = st->wMonth, d = st->wDay; 6593 t->tm_sec = st->wSecond; 6594 t->tm_min = st->wMinute; 6595 t->tm_hour = st->wHour; 6596 t->tm_mday = st->wDay; 6597 t->tm_mon = st->wMonth - 1; 6598 t->tm_year = y - 1900; 6599 t->tm_wday = st->wDayOfWeek; 6600 switch (m) { 6601 case 1: 6602 break; 6603 case 2: 6604 d += 31; 6605 break; 6606 default: 6607 d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400))); 6608 d += ((m - 3) * 153 + 2) / 5; 6609 break; 6610 } 6611 t->tm_yday = d - 1; 6612} 6613 6614/* License: Ruby's */ 6615static int 6616systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst) 6617{ 6618 TIME_ZONE_INFORMATION stdtz; 6619 SYSTEMTIME sst; 6620 6621 if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1; 6622 if (!tz) { 6623 GetTimeZoneInformation(&stdtz); 6624 tz = &stdtz; 6625 } 6626 if (tz->StandardBias == tz->DaylightBias) return 0; 6627 if (!tz->StandardDate.wMonth) return 0; 6628 if (!tz->DaylightDate.wMonth) return 0; 6629 if (tz != &stdtz) stdtz = *tz; 6630 6631 stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0; 6632 if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0; 6633 if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour) 6634 return 0; 6635 return 1; 6636} 6637#endif 6638 6639#ifdef __MINGW64__ 6640# ifndef MINGW_HAS_SECURE_API 6641 _CRTIMP errno_t __cdecl _gmtime64_s(struct tm* tm, const __time64_t *time); 6642 _CRTIMP errno_t __cdecl _localtime64_s(struct tm* tm, const __time64_t *time); 6643# endif 6644# define gmtime_s _gmtime64_s 6645# define localtime_s _localtime64_s 6646#endif 6647 6648/* License: Ruby's */ 6649struct tm * 6650gmtime_r(const time_t *tp, struct tm *rp) 6651{ 6652 int e = EINVAL; 6653 if (!tp || !rp) { 6654 error: 6655 errno = e; 6656 return NULL; 6657 } 6658#if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__) 6659 e = gmtime_s(rp, tp); 6660 if (e != 0) goto error; 6661#else 6662 { 6663 SYSTEMTIME st; 6664 if (unixtime_to_systemtime(*tp, &st)) goto error; 6665 rp->tm_isdst = 0; 6666 systemtime_to_tm(&st, rp); 6667 } 6668#endif 6669 return rp; 6670} 6671 6672/* License: Ruby's */ 6673struct tm * 6674localtime_r(const time_t *tp, struct tm *rp) 6675{ 6676 int e = EINVAL; 6677 if (!tp || !rp) { 6678 error: 6679 errno = e; 6680 return NULL; 6681 } 6682#if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__) 6683 e = localtime_s(rp, tp); 6684 if (e) goto error; 6685#else 6686 { 6687 SYSTEMTIME gst, lst; 6688 if (unixtime_to_systemtime(*tp, &gst)) goto error; 6689 rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst); 6690 systemtime_to_tm(&lst, rp); 6691 } 6692#endif 6693 return rp; 6694} 6695 6696/* License: Ruby's */ 6697int 6698rb_w32_wrap_io_handle(HANDLE h, int flags) 6699{ 6700 BOOL tmp; 6701 int len = sizeof(tmp); 6702 int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (char *)&tmp, &len); 6703 if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) { 6704 int f = 0; 6705 if (flags & O_NONBLOCK) { 6706 flags &= ~O_NONBLOCK; 6707 f = O_NONBLOCK; 6708 } 6709 socklist_insert((SOCKET)h, f); 6710 } 6711 else if (flags & O_NONBLOCK) { 6712 errno = EINVAL; 6713 return -1; 6714 } 6715 return rb_w32_open_osfhandle((intptr_t)h, flags); 6716} 6717 6718/* License: Ruby's */ 6719int 6720rb_w32_unwrap_io_handle(int fd) 6721{ 6722 SOCKET sock = TO_SOCKET(fd); 6723 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); 6724 if (!is_socket(sock)) { 6725 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); 6726 constat_delete((HANDLE)sock); 6727 } 6728 else { 6729 socklist_delete(&sock, NULL); 6730 } 6731 return _close(fd); 6732} 6733