00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "ruby/ruby.h"
00023 #include "ruby/encoding.h"
00024 #include "dln.h"
00025 #include <fcntl.h>
00026 #include <process.h>
00027 #include <sys/stat.h>
00028
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <errno.h>
00032 #include <assert.h>
00033 #include <ctype.h>
00034
00035 #include <windows.h>
00036 #include <winbase.h>
00037 #include <wincon.h>
00038 #include <share.h>
00039 #include <shlobj.h>
00040 #include <mbstring.h>
00041 #if _MSC_VER >= 1400
00042 #include <crtdbg.h>
00043 #include <rtcapi.h>
00044 #endif
00045 #ifdef __MINGW32__
00046 #include <mswsock.h>
00047 #endif
00048 #include "ruby/win32.h"
00049 #include "win32/dir.h"
00050 #define isdirsep(x) ((x) == '/' || (x) == '\\')
00051
00052 #undef stat
00053 #undef fclose
00054 #undef close
00055 #undef setsockopt
00056
00057 #if defined __BORLANDC__
00058 # define _filbuf _fgetc
00059 # define _flsbuf _fputc
00060 # define enough_to_get(n) (--(n) >= 0)
00061 # define enough_to_put(n) (++(n) < 0)
00062 #else
00063 # define enough_to_get(n) (--(n) >= 0)
00064 # define enough_to_put(n) (--(n) >= 0)
00065 #endif
00066
00067 #ifdef WIN32_DEBUG
00068 #define Debug(something) something
00069 #else
00070 #define Debug(something)
00071 #endif
00072
00073 #define TO_SOCKET(x) _get_osfhandle(x)
00074
00075 static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE, DWORD);
00076 static int has_redirection(const char *);
00077 int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
00078 static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
00079 static int wstati64(const WCHAR *path, struct stati64 *st);
00080 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
00081
00082 #define RUBY_CRITICAL(expr) do { expr; } while (0)
00083
00084
00085 static struct {
00086 DWORD winerr;
00087 int err;
00088 } errmap[] = {
00089 { ERROR_INVALID_FUNCTION, EINVAL },
00090 { ERROR_FILE_NOT_FOUND, ENOENT },
00091 { ERROR_PATH_NOT_FOUND, ENOENT },
00092 { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
00093 { ERROR_ACCESS_DENIED, EACCES },
00094 { ERROR_INVALID_HANDLE, EBADF },
00095 { ERROR_ARENA_TRASHED, ENOMEM },
00096 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM },
00097 { ERROR_INVALID_BLOCK, ENOMEM },
00098 { ERROR_BAD_ENVIRONMENT, E2BIG },
00099 { ERROR_BAD_FORMAT, ENOEXEC },
00100 { ERROR_INVALID_ACCESS, EINVAL },
00101 { ERROR_INVALID_DATA, EINVAL },
00102 { ERROR_INVALID_DRIVE, ENOENT },
00103 { ERROR_CURRENT_DIRECTORY, EACCES },
00104 { ERROR_NOT_SAME_DEVICE, EXDEV },
00105 { ERROR_NO_MORE_FILES, ENOENT },
00106 { ERROR_WRITE_PROTECT, EROFS },
00107 { ERROR_BAD_UNIT, ENODEV },
00108 { ERROR_NOT_READY, ENXIO },
00109 { ERROR_BAD_COMMAND, EACCES },
00110 { ERROR_CRC, EACCES },
00111 { ERROR_BAD_LENGTH, EACCES },
00112 { ERROR_SEEK, EIO },
00113 { ERROR_NOT_DOS_DISK, EACCES },
00114 { ERROR_SECTOR_NOT_FOUND, EACCES },
00115 { ERROR_OUT_OF_PAPER, EACCES },
00116 { ERROR_WRITE_FAULT, EIO },
00117 { ERROR_READ_FAULT, EIO },
00118 { ERROR_GEN_FAILURE, EACCES },
00119 { ERROR_LOCK_VIOLATION, EACCES },
00120 { ERROR_SHARING_VIOLATION, EACCES },
00121 { ERROR_WRONG_DISK, EACCES },
00122 { ERROR_SHARING_BUFFER_EXCEEDED, EACCES },
00123 { ERROR_BAD_NETPATH, ENOENT },
00124 { ERROR_NETWORK_ACCESS_DENIED, EACCES },
00125 { ERROR_BAD_NET_NAME, ENOENT },
00126 { ERROR_FILE_EXISTS, EEXIST },
00127 { ERROR_CANNOT_MAKE, EACCES },
00128 { ERROR_FAIL_I24, EACCES },
00129 { ERROR_INVALID_PARAMETER, EINVAL },
00130 { ERROR_NO_PROC_SLOTS, EAGAIN },
00131 { ERROR_DRIVE_LOCKED, EACCES },
00132 { ERROR_BROKEN_PIPE, EPIPE },
00133 { ERROR_DISK_FULL, ENOSPC },
00134 { ERROR_INVALID_TARGET_HANDLE, EBADF },
00135 { ERROR_INVALID_HANDLE, EINVAL },
00136 { ERROR_WAIT_NO_CHILDREN, ECHILD },
00137 { ERROR_CHILD_NOT_COMPLETE, ECHILD },
00138 { ERROR_DIRECT_ACCESS_HANDLE, EBADF },
00139 { ERROR_NEGATIVE_SEEK, EINVAL },
00140 { ERROR_SEEK_ON_DEVICE, EACCES },
00141 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY },
00142 { ERROR_DIRECTORY, ENOTDIR },
00143 { ERROR_NOT_LOCKED, EACCES },
00144 { ERROR_BAD_PATHNAME, ENOENT },
00145 { ERROR_MAX_THRDS_REACHED, EAGAIN },
00146 { ERROR_LOCK_FAILED, EACCES },
00147 { ERROR_ALREADY_EXISTS, EEXIST },
00148 { ERROR_INVALID_STARTING_CODESEG, ENOEXEC },
00149 { ERROR_INVALID_STACKSEG, ENOEXEC },
00150 { ERROR_INVALID_MODULETYPE, ENOEXEC },
00151 { ERROR_INVALID_EXE_SIGNATURE, ENOEXEC },
00152 { ERROR_EXE_MARKED_INVALID, ENOEXEC },
00153 { ERROR_BAD_EXE_FORMAT, ENOEXEC },
00154 { ERROR_ITERATED_DATA_EXCEEDS_64k,ENOEXEC },
00155 { ERROR_INVALID_MINALLOCSIZE, ENOEXEC },
00156 { ERROR_DYNLINK_FROM_INVALID_RING,ENOEXEC },
00157 { ERROR_IOPL_NOT_ENABLED, ENOEXEC },
00158 { ERROR_INVALID_SEGDPL, ENOEXEC },
00159 { ERROR_AUTODATASEG_EXCEEDS_64k, ENOEXEC },
00160 { ERROR_RING2SEG_MUST_BE_MOVABLE, ENOEXEC },
00161 { ERROR_RELOC_CHAIN_XEEDS_SEGLIM, ENOEXEC },
00162 { ERROR_INFLOOP_IN_RELOC_CHAIN, ENOEXEC },
00163 { ERROR_FILENAME_EXCED_RANGE, ENOENT },
00164 { ERROR_NESTING_NOT_ALLOWED, EAGAIN },
00165 #ifndef ERROR_PIPE_LOCAL
00166 #define ERROR_PIPE_LOCAL 229L
00167 #endif
00168 { ERROR_PIPE_LOCAL, EPIPE },
00169 { ERROR_BAD_PIPE, EPIPE },
00170 { ERROR_PIPE_BUSY, EAGAIN },
00171 { ERROR_NO_DATA, EPIPE },
00172 { ERROR_PIPE_NOT_CONNECTED, EPIPE },
00173 { ERROR_OPERATION_ABORTED, EINTR },
00174 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM },
00175 { ERROR_MOD_NOT_FOUND, ENOENT },
00176 { WSAEINTR, EINTR },
00177 { WSAEBADF, EBADF },
00178 { WSAEACCES, EACCES },
00179 { WSAEFAULT, EFAULT },
00180 { WSAEINVAL, EINVAL },
00181 { WSAEMFILE, EMFILE },
00182 { WSAEWOULDBLOCK, EWOULDBLOCK },
00183 { WSAEINPROGRESS, EINPROGRESS },
00184 { WSAEALREADY, EALREADY },
00185 { WSAENOTSOCK, ENOTSOCK },
00186 { WSAEDESTADDRREQ, EDESTADDRREQ },
00187 { WSAEMSGSIZE, EMSGSIZE },
00188 { WSAEPROTOTYPE, EPROTOTYPE },
00189 { WSAENOPROTOOPT, ENOPROTOOPT },
00190 { WSAEPROTONOSUPPORT, EPROTONOSUPPORT },
00191 { WSAESOCKTNOSUPPORT, ESOCKTNOSUPPORT },
00192 { WSAEOPNOTSUPP, EOPNOTSUPP },
00193 { WSAEPFNOSUPPORT, EPFNOSUPPORT },
00194 { WSAEAFNOSUPPORT, EAFNOSUPPORT },
00195 { WSAEADDRINUSE, EADDRINUSE },
00196 { WSAEADDRNOTAVAIL, EADDRNOTAVAIL },
00197 { WSAENETDOWN, ENETDOWN },
00198 { WSAENETUNREACH, ENETUNREACH },
00199 { WSAENETRESET, ENETRESET },
00200 { WSAECONNABORTED, ECONNABORTED },
00201 { WSAECONNRESET, ECONNRESET },
00202 { WSAENOBUFS, ENOBUFS },
00203 { WSAEISCONN, EISCONN },
00204 { WSAENOTCONN, ENOTCONN },
00205 { WSAESHUTDOWN, ESHUTDOWN },
00206 { WSAETOOMANYREFS, ETOOMANYREFS },
00207 { WSAETIMEDOUT, ETIMEDOUT },
00208 { WSAECONNREFUSED, ECONNREFUSED },
00209 { WSAELOOP, ELOOP },
00210 { WSAENAMETOOLONG, ENAMETOOLONG },
00211 { WSAEHOSTDOWN, EHOSTDOWN },
00212 { WSAEHOSTUNREACH, EHOSTUNREACH },
00213 { WSAEPROCLIM, EPROCLIM },
00214 { WSAENOTEMPTY, ENOTEMPTY },
00215 { WSAEUSERS, EUSERS },
00216 { WSAEDQUOT, EDQUOT },
00217 { WSAESTALE, ESTALE },
00218 { WSAEREMOTE, EREMOTE },
00219 };
00220
00221
00222 int
00223 rb_w32_map_errno(DWORD winerr)
00224 {
00225 int i;
00226
00227 if (winerr == 0) {
00228 return 0;
00229 }
00230
00231 for (i = 0; i < (int)(sizeof(errmap) / sizeof(*errmap)); i++) {
00232 if (errmap[i].winerr == winerr) {
00233 return errmap[i].err;
00234 }
00235 }
00236
00237 if (winerr >= WSABASEERR) {
00238 return winerr;
00239 }
00240 return EINVAL;
00241 }
00242
00243 #define map_errno rb_w32_map_errno
00244
00245 static const char *NTLoginName;
00246
00247 static OSVERSIONINFO osver;
00248
00249
00250 static void
00251 get_version(void)
00252 {
00253 memset(&osver, 0, sizeof(OSVERSIONINFO));
00254 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
00255 GetVersionEx(&osver);
00256 }
00257
00258 #ifdef _M_IX86
00259
00260 DWORD
00261 rb_w32_osid(void)
00262 {
00263 return osver.dwPlatformId;
00264 }
00265 #endif
00266
00267
00268 DWORD
00269 rb_w32_osver(void)
00270 {
00271 return osver.dwMajorVersion;
00272 }
00273
00274
00275
00276
00277 #define LK_ERR(f,i) \
00278 do { \
00279 if (f) \
00280 i = 0; \
00281 else { \
00282 DWORD err = GetLastError(); \
00283 if (err == ERROR_LOCK_VIOLATION || err == ERROR_IO_PENDING) \
00284 errno = EWOULDBLOCK; \
00285 else if (err == ERROR_NOT_LOCKED) \
00286 i = 0; \
00287 else \
00288 errno = map_errno(err); \
00289 } \
00290 } while (0)
00291 #define LK_LEN ULONG_MAX
00292
00293
00294 static uintptr_t
00295 flock_winnt(uintptr_t self, int argc, uintptr_t* argv)
00296 {
00297 OVERLAPPED o;
00298 int i = -1;
00299 const HANDLE fh = (HANDLE)self;
00300 const int oper = argc;
00301
00302 memset(&o, 0, sizeof(o));
00303
00304 switch(oper) {
00305 case LOCK_SH:
00306 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, LK_LEN, &o), i);
00307 break;
00308 case LOCK_EX:
00309 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, LK_LEN, &o), i);
00310 break;
00311 case LOCK_SH|LOCK_NB:
00312 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, LK_LEN, &o), i);
00313 break;
00314 case LOCK_EX|LOCK_NB:
00315 LK_ERR(LockFileEx(fh,
00316 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
00317 0, LK_LEN, LK_LEN, &o), i);
00318 break;
00319 case LOCK_UN:
00320 case LOCK_UN|LOCK_NB:
00321 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, LK_LEN, &o), i);
00322 break;
00323 default:
00324 errno = EINVAL;
00325 break;
00326 }
00327 return i;
00328 }
00329
00330 #undef LK_ERR
00331
00332
00333 int
00334 flock(int fd, int oper)
00335 {
00336 const asynchronous_func_t locker = flock_winnt;
00337
00338 return rb_w32_asynchronize(locker,
00339 (VALUE)_get_osfhandle(fd), oper, NULL,
00340 (DWORD)-1);
00341 }
00342
00343
00344 static inline WCHAR *
00345 translate_wchar(WCHAR *p, int from, int to)
00346 {
00347 for (; *p; p++) {
00348 if (*p == from)
00349 *p = to;
00350 }
00351 return p;
00352 }
00353
00354
00355 static inline char *
00356 translate_char(char *p, int from, int to)
00357 {
00358 while (*p) {
00359 if ((unsigned char)*p == from)
00360 *p = to;
00361 p = CharNext(p);
00362 }
00363 return p;
00364 }
00365
00366 #ifndef CSIDL_LOCAL_APPDATA
00367 #define CSIDL_LOCAL_APPDATA 28
00368 #endif
00369 #ifndef CSIDL_COMMON_APPDATA
00370 #define CSIDL_COMMON_APPDATA 35
00371 #endif
00372 #ifndef CSIDL_WINDOWS
00373 #define CSIDL_WINDOWS 36
00374 #endif
00375 #ifndef CSIDL_SYSTEM
00376 #define CSIDL_SYSTEM 37
00377 #endif
00378 #ifndef CSIDL_PROFILE
00379 #define CSIDL_PROFILE 40
00380 #endif
00381
00382
00383 static BOOL
00384 get_special_folder(int n, WCHAR *env)
00385 {
00386 LPITEMIDLIST pidl;
00387 LPMALLOC alloc;
00388 BOOL f = FALSE;
00389 if (SHGetSpecialFolderLocation(NULL, n, &pidl) == 0) {
00390 f = SHGetPathFromIDListW(pidl, env);
00391 SHGetMalloc(&alloc);
00392 alloc->lpVtbl->Free(alloc, pidl);
00393 alloc->lpVtbl->Release(alloc);
00394 }
00395 return f;
00396 }
00397
00398
00399 static void
00400 regulate_path(WCHAR *path)
00401 {
00402 WCHAR *p = translate_wchar(path, L'\\', L'/');
00403 if (p - path == 2 && path[1] == L':') {
00404 *p++ = L'/';
00405 *p = L'\0';
00406 }
00407 }
00408
00409
00410 static FARPROC
00411 get_proc_address(const char *module, const char *func, HANDLE *mh)
00412 {
00413 HANDLE h;
00414 FARPROC ptr;
00415
00416 if (mh)
00417 h = LoadLibrary(module);
00418 else
00419 h = GetModuleHandle(module);
00420 if (!h)
00421 return NULL;
00422
00423 ptr = GetProcAddress(h, func);
00424 if (mh) {
00425 if (ptr)
00426 *mh = h;
00427 else
00428 FreeLibrary(h);
00429 }
00430 return ptr;
00431 }
00432
00433
00434 static UINT
00435 get_system_directory(WCHAR *path, UINT len)
00436 {
00437 typedef UINT WINAPI wgetdir_func(WCHAR*, UINT);
00438 FARPROC ptr =
00439 get_proc_address("kernel32", "GetSystemWindowsDirectoryW", NULL);
00440 if (ptr)
00441 return (*(wgetdir_func *)ptr)(path, len);
00442 return GetWindowsDirectoryW(path, len);
00443 }
00444
00445 #define numberof(array) (sizeof(array) / sizeof(*array))
00446
00447
00448 VALUE
00449 rb_w32_special_folder(int type)
00450 {
00451 WCHAR path[_MAX_PATH];
00452
00453 if (!get_special_folder(type, path)) return Qnil;
00454 regulate_path(path);
00455 return rb_w32_conv_from_wchar(path, rb_filesystem_encoding());
00456 }
00457
00458
00459 UINT
00460 rb_w32_system_tmpdir(WCHAR *path, UINT len)
00461 {
00462 static const WCHAR temp[] = L"temp";
00463 WCHAR *p;
00464
00465 if (!get_special_folder(CSIDL_LOCAL_APPDATA, path)) {
00466 if (get_system_directory(path, len)) return 0;
00467 }
00468 p = translate_wchar(path, L'\\', L'/');
00469 if (*(p - 1) != L'/') *p++ = L'/';
00470 if (p - path + numberof(temp) >= len) return 0;
00471 memcpy(p, temp, sizeof(temp));
00472 return p - path + numberof(temp) - 1;
00473 }
00474
00475 static UINT filecp(void);
00476 static WCHAR *mbstr_to_wstr(UINT, const char *, int, long *);
00477 static char *wstr_to_mbstr(UINT, const WCHAR *, int, long *);
00478 #define acp_to_wstr(str, plen) mbstr_to_wstr(CP_ACP, str, -1, plen)
00479 #define wstr_to_acp(str, plen) wstr_to_mbstr(CP_ACP, str, -1, plen)
00480 #define filecp_to_wstr(str, plen) mbstr_to_wstr(filecp(), str, -1, plen)
00481 #define wstr_to_filecp(str, plen) wstr_to_mbstr(filecp(), str, -1, plen)
00482 #define utf8_to_wstr(str, plen) mbstr_to_wstr(CP_UTF8, str, -1, plen)
00483 #define wstr_to_utf8(str, plen) wstr_to_mbstr(CP_UTF8, str, -1, plen)
00484
00485
00486 static void
00487 init_env(void)
00488 {
00489 static const WCHAR TMPDIR[] = L"TMPDIR";
00490 struct {WCHAR name[6], eq, val[_MAX_PATH];} wk;
00491 DWORD len;
00492 BOOL f;
00493 #define env wk.val
00494 #define set_env_val(vname) do { \
00495 typedef char namesizecheck[numberof(wk.name) < numberof(vname) - 1 ? -1 : 1]; \
00496 WCHAR *const buf = wk.name + numberof(wk.name) - numberof(vname) + 1; \
00497 MEMCPY(buf, vname, WCHAR, numberof(vname) - 1); \
00498 _wputenv(buf); \
00499 } while (0)
00500
00501 wk.eq = L'=';
00502
00503 if (!GetEnvironmentVariableW(L"HOME", env, numberof(env))) {
00504 f = FALSE;
00505 if (GetEnvironmentVariableW(L"HOMEDRIVE", env, numberof(env)))
00506 len = lstrlenW(env);
00507 else
00508 len = 0;
00509 if (GetEnvironmentVariableW(L"HOMEPATH", env + len, numberof(env) - len) || len) {
00510 f = TRUE;
00511 }
00512 else if (GetEnvironmentVariableW(L"USERPROFILE", env, numberof(env))) {
00513 f = TRUE;
00514 }
00515 else if (get_special_folder(CSIDL_PROFILE, env)) {
00516 f = TRUE;
00517 }
00518 else if (get_special_folder(CSIDL_PERSONAL, env)) {
00519 f = TRUE;
00520 }
00521 if (f) {
00522 regulate_path(env);
00523 set_env_val(L"HOME");
00524 }
00525 }
00526
00527 if (!GetEnvironmentVariableW(L"USER", env, numberof(env))) {
00528 if (!GetEnvironmentVariableW(L"USERNAME", env, numberof(env)) &&
00529 !GetUserNameW(env, (len = numberof(env), &len))) {
00530 NTLoginName = "<Unknown>";
00531 }
00532 else {
00533 set_env_val(L"USER");
00534 NTLoginName = wstr_to_mbstr(CP_UTF8, env, -1, NULL);
00535 }
00536 }
00537 else {
00538 NTLoginName = wstr_to_mbstr(CP_UTF8, env, -1, NULL);
00539 }
00540
00541 if (!GetEnvironmentVariableW(TMPDIR, env, numberof(env)) &&
00542 !GetEnvironmentVariableW(L"TMP", env, numberof(env)) &&
00543 !GetEnvironmentVariableW(L"TEMP", env, numberof(env)) &&
00544 rb_w32_system_tmpdir(env, numberof(env))) {
00545 set_env_val(TMPDIR);
00546 }
00547
00548 #undef env
00549 #undef set_env_val
00550 }
00551
00552
00553 typedef BOOL (WINAPI *cancel_io_t)(HANDLE);
00554 static cancel_io_t cancel_io = NULL;
00555
00556
00557 static void
00558 init_func(void)
00559 {
00560 if (!cancel_io)
00561 cancel_io = (cancel_io_t)get_proc_address("kernel32", "CancelIo", NULL);
00562 }
00563
00564 static void init_stdhandle(void);
00565
00566 #if RUBY_MSVCRT_VERSION >= 80
00567
00568 static void
00569 invalid_parameter(const wchar_t *expr, const wchar_t *func, const wchar_t *file, unsigned int line, uintptr_t dummy)
00570 {
00571
00572 }
00573
00574 int ruby_w32_rtc_error;
00575
00576
00577 static int __cdecl
00578 rtc_error_handler(int e, const char *src, int line, const char *exe, const char *fmt, ...)
00579 {
00580 va_list ap;
00581 VALUE str;
00582
00583 if (!ruby_w32_rtc_error) return 0;
00584 str = rb_sprintf("%s:%d: ", src, line);
00585 va_start(ap, fmt);
00586 rb_str_vcatf(str, fmt, ap);
00587 va_end(ap);
00588 rb_str_cat(str, "\n", 1);
00589 rb_write_error2(RSTRING_PTR(str), RSTRING_LEN(str));
00590 return 0;
00591 }
00592 #endif
00593
00594 static CRITICAL_SECTION select_mutex;
00595 static int NtSocketsInitialized = 0;
00596 static st_table *socklist = NULL;
00597 static st_table *conlist = NULL;
00598 static char *envarea;
00599 static char *uenvarea;
00600
00601
00602 struct constat {
00603 struct {
00604 int state, seq[16];
00605 WORD attr;
00606 COORD saved;
00607 } vt100;
00608 };
00609 enum {constat_init = -2, constat_esc = -1, constat_seq = 0};
00610
00611
00612 static int
00613 free_conlist(st_data_t key, st_data_t val, st_data_t arg)
00614 {
00615 xfree((struct constat *)val);
00616 return ST_DELETE;
00617 }
00618
00619
00620 static void
00621 constat_delete(HANDLE h)
00622 {
00623 if (conlist) {
00624 st_data_t key = (st_data_t)h, val;
00625 st_delete(conlist, &key, &val);
00626 xfree((struct constat *)val);
00627 }
00628 }
00629
00630
00631 static void
00632 exit_handler(void)
00633 {
00634 if (NtSocketsInitialized) {
00635 WSACleanup();
00636 if (socklist) {
00637 st_free_table(socklist);
00638 socklist = NULL;
00639 }
00640 DeleteCriticalSection(&select_mutex);
00641 NtSocketsInitialized = 0;
00642 }
00643 if (conlist) {
00644 st_foreach(conlist, free_conlist, 0);
00645 st_free_table(conlist);
00646 conlist = NULL;
00647 }
00648 if (envarea) {
00649 FreeEnvironmentStrings(envarea);
00650 envarea = NULL;
00651 }
00652 if (uenvarea) {
00653 free(uenvarea);
00654 uenvarea = NULL;
00655 }
00656 }
00657
00658
00659 static void
00660 StartSockets(void)
00661 {
00662 WORD version;
00663 WSADATA retdata;
00664
00665
00666
00667
00668
00669 version = MAKEWORD(2, 0);
00670 if (WSAStartup(version, &retdata))
00671 rb_fatal ("Unable to locate winsock library!\n");
00672 if (LOBYTE(retdata.wVersion) != 2)
00673 rb_fatal("could not find version 2 of winsock dll\n");
00674
00675 InitializeCriticalSection(&select_mutex);
00676
00677 NtSocketsInitialized = 1;
00678 }
00679
00680 #define MAKE_SOCKDATA(af, fl) ((int)((((int)af)<<4)|((fl)&0xFFFF)))
00681 #define GET_FAMILY(v) ((int)(((v)>>4)&0xFFFF))
00682 #define GET_FLAGS(v) ((int)((v)&0xFFFF))
00683
00684
00685 static inline int
00686 socklist_insert(SOCKET sock, int flag)
00687 {
00688 if (!socklist)
00689 socklist = st_init_numtable();
00690 return st_insert(socklist, (st_data_t)sock, (st_data_t)flag);
00691 }
00692
00693
00694 static inline int
00695 socklist_lookup(SOCKET sock, int *flagp)
00696 {
00697 st_data_t data;
00698 int ret;
00699
00700 if (!socklist)
00701 return 0;
00702 ret = st_lookup(socklist, (st_data_t)sock, (st_data_t *)&data);
00703 if (ret && flagp)
00704 *flagp = (int)data;
00705
00706 return ret;
00707 }
00708
00709
00710 static inline int
00711 socklist_delete(SOCKET *sockp, int *flagp)
00712 {
00713 st_data_t key;
00714 st_data_t data;
00715 int ret;
00716
00717 if (!socklist)
00718 return 0;
00719 key = (st_data_t)*sockp;
00720 if (flagp)
00721 data = (st_data_t)*flagp;
00722 ret = st_delete(socklist, &key, &data);
00723 if (ret) {
00724 *sockp = (SOCKET)key;
00725 if (flagp)
00726 *flagp = (int)data;
00727 }
00728
00729 return ret;
00730 }
00731
00732
00733
00734
00735
00736 void
00737 rb_w32_sysinit(int *argc, char ***argv)
00738 {
00739 #if RUBY_MSVCRT_VERSION >= 80
00740 static void set_pioinfo_extra(void);
00741
00742 _CrtSetReportMode(_CRT_ASSERT, 0);
00743 _set_invalid_parameter_handler(invalid_parameter);
00744 _RTC_SetErrorFunc(rtc_error_handler);
00745 set_pioinfo_extra();
00746 #else
00747 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
00748 #endif
00749
00750 get_version();
00751
00752
00753
00754
00755 *argc = rb_w32_cmdvector(GetCommandLine(), argv);
00756
00757
00758
00759
00760
00761 tzset();
00762
00763 init_env();
00764
00765 init_func();
00766
00767 init_stdhandle();
00768
00769 atexit(exit_handler);
00770
00771
00772 StartSockets();
00773 }
00774
00775 char *
00776 getlogin(void)
00777 {
00778 return (char *)NTLoginName;
00779 }
00780
00781 #define MAXCHILDNUM 256
00782
00783
00784 static struct ChildRecord {
00785 HANDLE hProcess;
00786 rb_pid_t pid;
00787 } ChildRecord[MAXCHILDNUM];
00788
00789
00790 #define FOREACH_CHILD(v) do { \
00791 struct ChildRecord* v; \
00792 for (v = ChildRecord; v < ChildRecord + sizeof(ChildRecord) / sizeof(ChildRecord[0]); ++v)
00793 #define END_FOREACH_CHILD } while (0)
00794
00795
00796 static struct ChildRecord *
00797 FindChildSlot(rb_pid_t pid)
00798 {
00799
00800 FOREACH_CHILD(child) {
00801 if (child->pid == pid) {
00802 return child;
00803 }
00804 } END_FOREACH_CHILD;
00805 return NULL;
00806 }
00807
00808
00809 static struct ChildRecord *
00810 FindChildSlotByHandle(HANDLE h)
00811 {
00812
00813 FOREACH_CHILD(child) {
00814 if (child->hProcess == h) {
00815 return child;
00816 }
00817 } END_FOREACH_CHILD;
00818 return NULL;
00819 }
00820
00821
00822 static void
00823 CloseChildHandle(struct ChildRecord *child)
00824 {
00825 HANDLE h = child->hProcess;
00826 child->hProcess = NULL;
00827 child->pid = 0;
00828 CloseHandle(h);
00829 }
00830
00831
00832 static struct ChildRecord *
00833 FindFreeChildSlot(void)
00834 {
00835 FOREACH_CHILD(child) {
00836 if (!child->pid) {
00837 child->pid = -1;
00838 child->hProcess = NULL;
00839 return child;
00840 }
00841 } END_FOREACH_CHILD;
00842 return NULL;
00843 }
00844
00845
00846
00847
00848
00849
00850
00851
00852 static const char *const szInternalCmds[] = {
00853 "\2" "assoc",
00854 "\3" "break",
00855 "\3" "call",
00856 "\3" "cd",
00857 "\1" "chcp",
00858 "\3" "chdir",
00859 "\3" "cls",
00860 "\2" "color",
00861 "\3" "copy",
00862 "\1" "ctty",
00863 "\3" "date",
00864 "\3" "del",
00865 "\3" "dir",
00866 "\3" "echo",
00867 "\2" "endlocal",
00868 "\3" "erase",
00869 "\3" "exit",
00870 "\3" "for",
00871 "\2" "ftype",
00872 "\3" "goto",
00873 "\3" "if",
00874 "\1" "lfnfor",
00875 "\1" "lh",
00876 "\1" "lock",
00877 "\3" "md",
00878 "\3" "mkdir",
00879 "\2" "move",
00880 "\3" "path",
00881 "\3" "pause",
00882 "\2" "popd",
00883 "\3" "prompt",
00884 "\2" "pushd",
00885 "\3" "rd",
00886 "\3" "rem",
00887 "\3" "ren",
00888 "\3" "rename",
00889 "\3" "rmdir",
00890 "\3" "set",
00891 "\2" "setlocal",
00892 "\3" "shift",
00893 "\2" "start",
00894 "\3" "time",
00895 "\2" "title",
00896 "\1" "truename",
00897 "\3" "type",
00898 "\1" "unlock",
00899 "\3" "ver",
00900 "\3" "verify",
00901 "\3" "vol",
00902 };
00903
00904
00905 static int
00906 internal_match(const void *key, const void *elem)
00907 {
00908 return strcmp(key, (*(const char *const *)elem) + 1);
00909 }
00910
00911
00912 static int
00913 is_command_com(const char *interp)
00914 {
00915 int i = strlen(interp) - 11;
00916
00917 if ((i == 0 || i > 0 && isdirsep(interp[i-1])) &&
00918 strcasecmp(interp+i, "command.com") == 0) {
00919 return 1;
00920 }
00921 return 0;
00922 }
00923
00924 static int internal_cmd_match(const char *cmdname, int nt);
00925
00926
00927 static int
00928 is_internal_cmd(const char *cmd, int nt)
00929 {
00930 char cmdname[9], *b = cmdname, c;
00931
00932 do {
00933 if (!(c = *cmd++)) return 0;
00934 } while (isspace(c));
00935 if (c == '@')
00936 return 1;
00937 while (isalpha(c)) {
00938 *b++ = tolower(c);
00939 if (b == cmdname + sizeof(cmdname)) return 0;
00940 c = *cmd++;
00941 }
00942 if (c == '.') c = *cmd;
00943 switch (c) {
00944 case '<': case '>': case '|':
00945 return 1;
00946 case '\0': case ' ': case '\t': case '\n':
00947 break;
00948 default:
00949 return 0;
00950 }
00951 *b = 0;
00952 return internal_cmd_match(cmdname, nt);
00953 }
00954
00955
00956 static int
00957 internal_cmd_match(const char *cmdname, int nt)
00958 {
00959 char **nm;
00960
00961 nm = bsearch(cmdname, szInternalCmds,
00962 sizeof(szInternalCmds) / sizeof(*szInternalCmds),
00963 sizeof(*szInternalCmds),
00964 internal_match);
00965 if (!nm || !(nm[0][0] & (nt ? 2 : 1)))
00966 return 0;
00967 return 1;
00968 }
00969
00970
00971 SOCKET
00972 rb_w32_get_osfhandle(int fh)
00973 {
00974 return _get_osfhandle(fh);
00975 }
00976
00977
00978 static int
00979 join_argv(char *cmd, char *const *argv, BOOL escape)
00980 {
00981 const char *p, *s;
00982 char *q, *const *t;
00983 int len, n, bs, quote;
00984
00985 for (t = argv, q = cmd, len = 0; p = *t; t++) {
00986 quote = 0;
00987 s = p;
00988 if (!*p || strpbrk(p, " \t\"'")) {
00989 quote = 1;
00990 len++;
00991 if (q) *q++ = '"';
00992 }
00993 for (bs = 0; *p; ++p) {
00994 switch (*p) {
00995 case '\\':
00996 ++bs;
00997 break;
00998 case '"':
00999 len += n = p - s;
01000 if (q) {
01001 memcpy(q, s, n);
01002 q += n;
01003 }
01004 s = p;
01005 len += ++bs;
01006 if (q) {
01007 memset(q, '\\', bs);
01008 q += bs;
01009 }
01010 bs = 0;
01011 break;
01012 case '<': case '>': case '|': case '^':
01013 if (escape && !quote) {
01014 len += (n = p - s) + 1;
01015 if (q) {
01016 memcpy(q, s, n);
01017 q += n;
01018 *q++ = '^';
01019 }
01020 s = p;
01021 break;
01022 }
01023 default:
01024 bs = 0;
01025 p = CharNext(p) - 1;
01026 break;
01027 }
01028 }
01029 len += (n = p - s) + 1;
01030 if (quote) len++;
01031 if (q) {
01032 memcpy(q, s, n);
01033 q += n;
01034 if (quote) *q++ = '"';
01035 *q++ = ' ';
01036 }
01037 }
01038 if (q > cmd) --len;
01039 if (q) {
01040 if (q > cmd) --q;
01041 *q = '\0';
01042 }
01043 return len;
01044 }
01045
01046 #ifdef HAVE_SYS_PARAM_H
01047 # include <sys/param.h>
01048 #else
01049 # define MAXPATHLEN 512
01050 #endif
01051
01052
01053 #define STRNDUPV(ptr, v, src, len) \
01054 (((char *)memcpy(((ptr) = ALLOCV((v), (len) + 1)), (src), (len)))[len] = 0)
01055
01056
01057 static int
01058 check_spawn_mode(int mode)
01059 {
01060 switch (mode) {
01061 case P_NOWAIT:
01062 case P_OVERLAY:
01063 return 0;
01064 default:
01065 errno = EINVAL;
01066 return -1;
01067 }
01068 }
01069
01070
01071 static rb_pid_t
01072 child_result(struct ChildRecord *child, int mode)
01073 {
01074 DWORD exitcode;
01075
01076 if (!child) {
01077 return -1;
01078 }
01079
01080 if (mode == P_OVERLAY) {
01081 WaitForSingleObject(child->hProcess, INFINITE);
01082 GetExitCodeProcess(child->hProcess, &exitcode);
01083 CloseChildHandle(child);
01084 _exit(exitcode);
01085 }
01086 return child->pid;
01087 }
01088
01089
01090 static struct ChildRecord *
01091 CreateChild(const WCHAR *cmd, const WCHAR *prog, SECURITY_ATTRIBUTES *psa,
01092 HANDLE hInput, HANDLE hOutput, HANDLE hError, DWORD dwCreationFlags)
01093 {
01094 BOOL fRet;
01095 STARTUPINFOW aStartupInfo;
01096 PROCESS_INFORMATION aProcessInformation;
01097 SECURITY_ATTRIBUTES sa;
01098 struct ChildRecord *child;
01099
01100 if (!cmd && !prog) {
01101 errno = EFAULT;
01102 return NULL;
01103 }
01104
01105 child = FindFreeChildSlot();
01106 if (!child) {
01107 errno = EAGAIN;
01108 return NULL;
01109 }
01110
01111 if (!psa) {
01112 sa.nLength = sizeof (SECURITY_ATTRIBUTES);
01113 sa.lpSecurityDescriptor = NULL;
01114 sa.bInheritHandle = TRUE;
01115 psa = &sa;
01116 }
01117
01118 memset(&aStartupInfo, 0, sizeof(aStartupInfo));
01119 memset(&aProcessInformation, 0, sizeof(aProcessInformation));
01120 aStartupInfo.cb = sizeof(aStartupInfo);
01121 aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
01122 if (hInput) {
01123 aStartupInfo.hStdInput = hInput;
01124 }
01125 else {
01126 aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
01127 }
01128 if (hOutput) {
01129 aStartupInfo.hStdOutput = hOutput;
01130 }
01131 else {
01132 aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
01133 }
01134 if (hError) {
01135 aStartupInfo.hStdError = hError;
01136 }
01137 else {
01138 aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
01139 }
01140
01141 dwCreationFlags |= NORMAL_PRIORITY_CLASS;
01142
01143 if (lstrlenW(cmd) > 32767) {
01144 child->pid = 0;
01145 errno = E2BIG;
01146 return NULL;
01147 }
01148
01149 RUBY_CRITICAL({
01150 fRet = CreateProcessW(prog, (WCHAR *)cmd, psa, psa,
01151 psa->bInheritHandle, dwCreationFlags, NULL, NULL,
01152 &aStartupInfo, &aProcessInformation);
01153 errno = map_errno(GetLastError());
01154 });
01155
01156 if (!fRet) {
01157 child->pid = 0;
01158 return NULL;
01159 }
01160
01161 CloseHandle(aProcessInformation.hThread);
01162
01163 child->hProcess = aProcessInformation.hProcess;
01164 child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
01165
01166 return child;
01167 }
01168
01169
01170 static int
01171 is_batch(const char *cmd)
01172 {
01173 int len = strlen(cmd);
01174 if (len <= 4) return 0;
01175 cmd += len - 4;
01176 if (*cmd++ != '.') return 0;
01177 if (strcasecmp(cmd, "bat") == 0) return 1;
01178 if (strcasecmp(cmd, "cmd") == 0) return 1;
01179 return 0;
01180 }
01181
01182
01183 rb_pid_t
01184 rb_w32_spawn(int mode, const char *cmd, const char *prog)
01185 {
01186 char fbuf[MAXPATHLEN];
01187 char *p = NULL;
01188 const char *shell = NULL;
01189 WCHAR *wcmd = NULL, *wshell = NULL;
01190 int e = 0;
01191 rb_pid_t ret = -1;
01192 VALUE v = 0;
01193 VALUE v2 = 0;
01194
01195 if (check_spawn_mode(mode)) return -1;
01196
01197 if (prog) {
01198 if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
01199 shell = prog;
01200 }
01201 else {
01202 shell = p;
01203 translate_char(p, '/', '\\');
01204 }
01205 }
01206 else {
01207 int redir = -1;
01208 int nt;
01209 while (ISSPACE(*cmd)) cmd++;
01210 if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) {
01211 char *tmp = ALLOCV(v, strlen(shell) + strlen(cmd) + sizeof(" -c ") + 2);
01212 sprintf(tmp, "%s -c \"%s\"", shell, cmd);
01213 cmd = tmp;
01214 }
01215 else if ((shell = getenv("COMSPEC")) &&
01216 (nt = !is_command_com(shell),
01217 (redir < 0 ? has_redirection(cmd) : redir) ||
01218 is_internal_cmd(cmd, nt))) {
01219 char *tmp = ALLOCV(v, strlen(shell) + strlen(cmd) + sizeof(" /c ") + (nt ? 2 : 0));
01220 sprintf(tmp, nt ? "%s /c \"%s\"" : "%s /c %s", shell, cmd);
01221 cmd = tmp;
01222 }
01223 else {
01224 int len = 0, quote = (*cmd == '"') ? '"' : (*cmd == '\'') ? '\'' : 0;
01225 for (prog = cmd + !!quote;; prog = CharNext(prog)) {
01226 if (!*prog) {
01227 len = prog - cmd;
01228 shell = cmd;
01229 break;
01230 }
01231 if ((unsigned char)*prog == quote) {
01232 len = prog++ - cmd - 1;
01233 STRNDUPV(p, v2, cmd + 1, len);
01234 shell = p;
01235 break;
01236 }
01237 if (quote) continue;
01238 if (ISSPACE(*prog) || strchr("<>|*?\"", *prog)) {
01239 len = prog - cmd;
01240 STRNDUPV(p, v2, cmd, len);
01241 shell = p;
01242 break;
01243 }
01244 }
01245 shell = dln_find_exe_r(shell, NULL, fbuf, sizeof(fbuf));
01246 if (!shell) {
01247 shell = p ? p : cmd;
01248 }
01249 else {
01250 len = strlen(shell);
01251 if (strchr(shell, ' ')) quote = -1;
01252 if (shell == fbuf) {
01253 p = fbuf;
01254 }
01255 else if (shell != p && strchr(shell, '/')) {
01256 STRNDUPV(p, v2, shell, len);
01257 shell = p;
01258 }
01259 if (p) translate_char(p, '/', '\\');
01260 if (is_batch(shell)) {
01261 int alen = strlen(prog);
01262 cmd = p = ALLOCV(v, len + alen + (quote ? 2 : 0) + 1);
01263 if (quote) *p++ = '"';
01264 memcpy(p, shell, len);
01265 p += len;
01266 if (quote) *p++ = '"';
01267 memcpy(p, prog, alen + 1);
01268 shell = 0;
01269 }
01270 }
01271 }
01272 }
01273
01274
01275 if (!e && cmd && !(wcmd = acp_to_wstr(cmd, NULL))) e = E2BIG;
01276 if (v) ALLOCV_END(v);
01277 if (!e && shell && !(wshell = acp_to_wstr(shell, NULL))) e = E2BIG;
01278 if (v2) ALLOCV_END(v2);
01279
01280 if (!e) {
01281 ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL, 0), mode);
01282 }
01283 free(wshell);
01284 free(wcmd);
01285 if (e) errno = e;
01286 return ret;
01287 }
01288
01289
01290 rb_pid_t
01291 rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
01292 {
01293 int c_switch = 0;
01294 size_t len;
01295 BOOL ntcmd = FALSE, tmpnt;
01296 const char *shell;
01297 char *cmd, fbuf[MAXPATHLEN];
01298 WCHAR *wcmd = NULL, *wprog = NULL;
01299 int e = 0;
01300 rb_pid_t ret = -1;
01301 VALUE v = 0;
01302
01303 if (check_spawn_mode(mode)) return -1;
01304
01305 if (!prog) prog = argv[0];
01306 if ((shell = getenv("COMSPEC")) &&
01307 internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
01308 ntcmd = tmpnt;
01309 prog = shell;
01310 c_switch = 1;
01311 }
01312 else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
01313 if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf));
01314 translate_char(cmd, '/', '\\');
01315 prog = cmd;
01316 }
01317 else if (strchr(prog, '/')) {
01318 len = strlen(prog);
01319 if (len < sizeof(fbuf))
01320 strlcpy(cmd = fbuf, prog, sizeof(fbuf));
01321 else
01322 STRNDUPV(cmd, v, prog, len);
01323 translate_char(cmd, '/', '\\');
01324 prog = cmd;
01325 }
01326 if (c_switch || is_batch(prog)) {
01327 char *progs[2];
01328 progs[0] = (char *)prog;
01329 progs[1] = NULL;
01330 len = join_argv(NULL, progs, ntcmd);
01331 if (c_switch) len += 3;
01332 else ++argv;
01333 if (argv[0]) len += join_argv(NULL, argv, ntcmd);
01334 cmd = ALLOCV(v, len);
01335 join_argv(cmd, progs, ntcmd);
01336 if (c_switch) strlcat(cmd, " /c", len);
01337 if (argv[0]) join_argv(cmd + strlcat(cmd, " ", len), argv, ntcmd);
01338 prog = c_switch ? shell : 0;
01339 }
01340 else {
01341 len = join_argv(NULL, argv, FALSE);
01342 cmd = ALLOCV(v, len);
01343 join_argv(cmd, argv, FALSE);
01344 }
01345
01346
01347 if (!e && cmd && !(wcmd = acp_to_wstr(cmd, NULL))) e = E2BIG;
01348 if (v) ALLOCV_END(v);
01349 if (!e && prog && !(wprog = acp_to_wstr(prog, NULL))) e = E2BIG;
01350
01351 if (!e) {
01352 ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL, flags), mode);
01353 }
01354 free(wprog);
01355 free(wcmd);
01356 if (e) errno = e;
01357 return ret;
01358 }
01359
01360 rb_pid_t
01361 rb_w32_aspawn(int mode, const char *prog, char *const *argv)
01362 {
01363 return rb_w32_aspawn_flags(mode, prog, argv, 0);
01364 }
01365
01366
01367 typedef struct _NtCmdLineElement {
01368 struct _NtCmdLineElement *next;
01369 char *str;
01370 int len;
01371 int flags;
01372 } NtCmdLineElement;
01373
01374
01375
01376
01377
01378 #define NTGLOB 0x1 // element contains a wildcard
01379 #define NTMALLOC 0x2 // string in element was malloc'ed
01380 #define NTSTRING 0x4 // element contains a quoted string
01381
01382
01383 static int
01384 insert(const char *path, VALUE vinfo, void *enc)
01385 {
01386 NtCmdLineElement *tmpcurr;
01387 NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo;
01388
01389 tmpcurr = (NtCmdLineElement *)malloc(sizeof(NtCmdLineElement));
01390 if (!tmpcurr) return -1;
01391 MEMZERO(tmpcurr, NtCmdLineElement, 1);
01392 tmpcurr->len = strlen(path);
01393 tmpcurr->str = strdup(path);
01394 if (!tmpcurr->str) return -1;
01395 tmpcurr->flags |= NTMALLOC;
01396 **tail = tmpcurr;
01397 *tail = &tmpcurr->next;
01398
01399 return 0;
01400 }
01401
01402
01403
01404
01405 static NtCmdLineElement **
01406 cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail)
01407 {
01408 char buffer[MAXPATHLEN], *buf = buffer;
01409 char *p;
01410 NtCmdLineElement **last = tail;
01411 int status;
01412
01413 if (patt->len >= MAXPATHLEN)
01414 if (!(buf = malloc(patt->len + 1))) return 0;
01415
01416 strlcpy(buf, patt->str, patt->len + 1);
01417 buf[patt->len] = '\0';
01418 for (p = buf; *p; p = CharNext(p))
01419 if (*p == '\\')
01420 *p = '/';
01421 status = ruby_brace_glob(buf, 0, insert, (VALUE)&tail);
01422 if (buf != buffer)
01423 free(buf);
01424
01425 if (status || last == tail) return 0;
01426 if (patt->flags & NTMALLOC)
01427 free(patt->str);
01428 free(patt);
01429 return tail;
01430 }
01431
01432
01433
01434
01435
01436
01437
01438 static int
01439 has_redirection(const char *cmd)
01440 {
01441 char quote = '\0';
01442 const char *ptr;
01443
01444
01445
01446
01447
01448
01449 for (ptr = cmd; *ptr;) {
01450 switch (*ptr) {
01451 case '\'':
01452 case '\"':
01453 if (!quote)
01454 quote = *ptr;
01455 else if (quote == *ptr)
01456 quote = '\0';
01457 ptr++;
01458 break;
01459
01460 case '>':
01461 case '<':
01462 case '|':
01463 case '&':
01464 case '\n':
01465 if (!quote)
01466 return TRUE;
01467 ptr++;
01468 break;
01469
01470 case '%':
01471 if (*++ptr != '_' && !ISALPHA(*ptr)) break;
01472 while (*++ptr == '_' || ISALNUM(*ptr));
01473 if (*ptr++ == '%') return TRUE;
01474 break;
01475
01476 case '\\':
01477 ptr++;
01478 default:
01479 ptr = CharNext(ptr);
01480 break;
01481 }
01482 }
01483 return FALSE;
01484 }
01485
01486
01487 static inline char *
01488 skipspace(char *ptr)
01489 {
01490 while (ISSPACE(*ptr))
01491 ptr++;
01492 return ptr;
01493 }
01494
01495
01496 int
01497 rb_w32_cmdvector(const char *cmd, char ***vec)
01498 {
01499 int globbing, len;
01500 int elements, strsz, done;
01501 int slashes, escape;
01502 char *ptr, *base, *buffer, *cmdline;
01503 char **vptr;
01504 char quote;
01505 NtCmdLineElement *curr, **tail;
01506 NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead;
01507
01508
01509
01510
01511
01512 while (ISSPACE(*cmd))
01513 cmd++;
01514 if (!*cmd) {
01515 *vec = NULL;
01516 return 0;
01517 }
01518
01519 ptr = cmdline = strdup(cmd);
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530 while (*(ptr = skipspace(ptr))) {
01531 base = ptr;
01532 quote = slashes = globbing = escape = 0;
01533 for (done = 0; !done && *ptr; ) {
01534
01535
01536
01537
01538
01539
01540 switch (*ptr) {
01541 case '\\':
01542 if (quote != '\'') slashes++;
01543 break;
01544
01545 case ' ':
01546 case '\t':
01547 case '\n':
01548
01549
01550
01551
01552
01553 if (!quote) {
01554 *ptr = 0;
01555 done = 1;
01556 }
01557 break;
01558
01559 case '*':
01560 case '?':
01561 case '[':
01562 case '{':
01563
01564
01565
01566
01567
01568 if (quote != '\'')
01569 globbing++;
01570 slashes = 0;
01571 break;
01572
01573 case '\'':
01574 case '\"':
01575
01576
01577
01578
01579
01580
01581
01582 if (!(slashes & 1)) {
01583 if (!quote)
01584 quote = *ptr;
01585 else if (quote == *ptr) {
01586 if (quote == '"' && quote == ptr[1])
01587 ptr++;
01588 quote = '\0';
01589 }
01590 }
01591 escape++;
01592 slashes = 0;
01593 break;
01594
01595 default:
01596 ptr = CharNext(ptr);
01597 slashes = 0;
01598 continue;
01599 }
01600 ptr++;
01601 }
01602
01603
01604
01605
01606
01607
01608
01609 len = ptr - base;
01610 if (done) --len;
01611
01612
01613
01614
01615
01616
01617 if (escape) {
01618 char *p = base, c;
01619 slashes = quote = 0;
01620 while (p < base + len) {
01621 switch (c = *p) {
01622 case '\\':
01623 p++;
01624 if (quote != '\'') slashes++;
01625 break;
01626
01627 case '\'':
01628 case '"':
01629 if (!(slashes & 1) && quote && quote != c) {
01630 p++;
01631 slashes = 0;
01632 break;
01633 }
01634 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
01635 base + len - p);
01636 len -= ((slashes + 1) >> 1) + (~slashes & 1);
01637 p -= (slashes + 1) >> 1;
01638 if (!(slashes & 1)) {
01639 if (quote) {
01640 if (quote == '"' && quote == *p)
01641 p++;
01642 quote = '\0';
01643 }
01644 else
01645 quote = c;
01646 }
01647 else
01648 p++;
01649 slashes = 0;
01650 break;
01651
01652 default:
01653 p = CharNext(p);
01654 slashes = 0;
01655 break;
01656 }
01657 }
01658 }
01659
01660 curr = (NtCmdLineElement *)calloc(sizeof(NtCmdLineElement), 1);
01661 if (!curr) goto do_nothing;
01662 curr->str = base;
01663 curr->len = len;
01664
01665 if (globbing && (tail = cmdglob(curr, cmdtail))) {
01666 cmdtail = tail;
01667 }
01668 else {
01669 *cmdtail = curr;
01670 cmdtail = &curr->next;
01671 }
01672 }
01673
01674
01675
01676
01677
01678
01679
01680 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) {
01681 elements++;
01682 strsz += (curr->len + 1);
01683 }
01684
01685 len = (elements+1)*sizeof(char *) + strsz;
01686 buffer = (char *)malloc(len);
01687 if (!buffer) {
01688 do_nothing:
01689 while (curr = cmdhead) {
01690 cmdhead = curr->next;
01691 if (curr->flags & NTMALLOC) free(curr->str);
01692 free(curr);
01693 }
01694 free(cmdline);
01695 for (vptr = *vec; *vptr; ++vptr);
01696 return vptr - *vec;
01697 }
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711 vptr = (char **) buffer;
01712
01713 ptr = buffer + (elements+1) * sizeof(char *);
01714
01715 while (curr = cmdhead) {
01716 strlcpy(ptr, curr->str, curr->len + 1);
01717 *vptr++ = ptr;
01718 ptr += curr->len + 1;
01719 cmdhead = curr->next;
01720 if (curr->flags & NTMALLOC) free(curr->str);
01721 free(curr);
01722 }
01723 *vptr = 0;
01724
01725 *vec = (char **) buffer;
01726 free(cmdline);
01727 return elements;
01728 }
01729
01730
01731
01732
01733
01734 #define PATHLEN 1024
01735
01736
01737
01738
01739
01740
01741
01742
01743 #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT))
01744 #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT))
01745
01746 #define BitOfIsDir(n) ((n) * 2)
01747 #define BitOfIsRep(n) ((n) * 2 + 1)
01748 #define DIRENT_PER_CHAR (CHAR_BIT / 2)
01749
01750
01751 static HANDLE
01752 open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
01753 {
01754 HANDLE fh;
01755 static const WCHAR wildcard[] = L"\\*";
01756 WCHAR *scanname;
01757 WCHAR *p;
01758 int len;
01759 VALUE v;
01760
01761
01762
01763
01764 len = lstrlenW(filename);
01765 scanname = ALLOCV_N(WCHAR, v, len + sizeof(wildcard) / sizeof(WCHAR));
01766 lstrcpyW(scanname, filename);
01767 p = CharPrevW(scanname, scanname + len);
01768 if (*p == L'/' || *p == L'\\' || *p == L':')
01769 lstrcatW(scanname, wildcard + 1);
01770 else
01771 lstrcatW(scanname, wildcard);
01772
01773
01774
01775
01776 fh = FindFirstFileW(scanname, fd);
01777 ALLOCV_END(v);
01778 if (fh == INVALID_HANDLE_VALUE) {
01779 errno = map_errno(GetLastError());
01780 }
01781 return fh;
01782 }
01783
01784
01785 static DIR *
01786 opendir_internal(WCHAR *wpath, const char *filename)
01787 {
01788 struct stati64 sbuf;
01789 WIN32_FIND_DATAW fd;
01790 HANDLE fh;
01791 DIR *p;
01792 long len;
01793 long idx;
01794 WCHAR *tmpW;
01795 char *tmp;
01796
01797
01798
01799
01800 if (wstati64(wpath, &sbuf) < 0) {
01801 return NULL;
01802 }
01803 if (!(sbuf.st_mode & S_IFDIR) &&
01804 (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' ||
01805 ((1 << ((filename[0] & 0x5f) - 'A')) & GetLogicalDrives()) == 0)) {
01806 errno = ENOTDIR;
01807 return NULL;
01808 }
01809 fh = open_dir_handle(wpath, &fd);
01810 if (fh == INVALID_HANDLE_VALUE) {
01811 return NULL;
01812 }
01813
01814
01815
01816
01817 p = calloc(sizeof(DIR), 1);
01818 if (p == NULL)
01819 return NULL;
01820
01821 idx = 0;
01822
01823
01824
01825
01826
01827
01828
01829 do {
01830 len = lstrlenW(fd.cFileName) + 1;
01831
01832
01833
01834
01835
01836 tmpW = realloc(p->start, (idx + len) * sizeof(WCHAR));
01837 if (!tmpW) {
01838 error:
01839 rb_w32_closedir(p);
01840 FindClose(fh);
01841 errno = ENOMEM;
01842 return NULL;
01843 }
01844
01845 p->start = tmpW;
01846 memcpy(&p->start[idx], fd.cFileName, len * sizeof(WCHAR));
01847
01848 if (p->nfiles % DIRENT_PER_CHAR == 0) {
01849 tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1);
01850 if (!tmp)
01851 goto error;
01852 p->bits = tmp;
01853 p->bits[p->nfiles / DIRENT_PER_CHAR] = 0;
01854 }
01855 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01856 SetBit(p->bits, BitOfIsDir(p->nfiles));
01857 if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
01858 SetBit(p->bits, BitOfIsRep(p->nfiles));
01859
01860 p->nfiles++;
01861 idx += len;
01862 } while (FindNextFileW(fh, &fd));
01863 FindClose(fh);
01864 p->size = idx;
01865 p->curr = p->start;
01866 return p;
01867 }
01868
01869
01870 static inline UINT
01871 filecp(void)
01872 {
01873 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
01874 return cp;
01875 }
01876
01877
01878 static char *
01879 wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen)
01880 {
01881 char *ptr;
01882 int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL) - 1;
01883 if (!(ptr = malloc(len + 1))) return 0;
01884 WideCharToMultiByte(cp, 0, wstr, clen, ptr, len + 1, NULL, NULL);
01885 if (plen) *plen = len;
01886 return ptr;
01887 }
01888
01889
01890 static WCHAR *
01891 mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen)
01892 {
01893 WCHAR *ptr;
01894 int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0) - 1;
01895 if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0;
01896 MultiByteToWideChar(cp, 0, str, clen, ptr, len + 1);
01897 if (plen) *plen = len;
01898 return ptr;
01899 }
01900
01901
01902 DIR *
01903 rb_w32_opendir(const char *filename)
01904 {
01905 DIR *ret;
01906 WCHAR *wpath = filecp_to_wstr(filename, NULL);
01907 if (!wpath)
01908 return NULL;
01909 ret = opendir_internal(wpath, filename);
01910 free(wpath);
01911 return ret;
01912 }
01913
01914
01915 DIR *
01916 rb_w32_uopendir(const char *filename)
01917 {
01918 DIR *ret;
01919 WCHAR *wpath = utf8_to_wstr(filename, NULL);
01920 if (!wpath)
01921 return NULL;
01922 ret = opendir_internal(wpath, filename);
01923 free(wpath);
01924 return ret;
01925 }
01926
01927
01928
01929
01930
01931
01932 static void
01933 move_to_next_entry(DIR *dirp)
01934 {
01935 if (dirp->curr) {
01936 dirp->loc++;
01937 dirp->curr += lstrlenW(dirp->curr) + 1;
01938 if (dirp->curr >= (dirp->start + dirp->size)) {
01939 dirp->curr = NULL;
01940 }
01941 }
01942 }
01943
01944
01945
01946
01947
01948
01949 static BOOL
01950 win32_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *dummy)
01951 {
01952 if (!(entry->d_name = wstr_to_filecp(file, &entry->d_namlen)))
01953 return FALSE;
01954 return TRUE;
01955 }
01956
01957
01958 VALUE
01959 rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
01960 {
01961 static rb_encoding *utf16 = (rb_encoding *)-1;
01962 VALUE src;
01963
01964 if (utf16 == (rb_encoding *)-1) {
01965 utf16 = rb_enc_find("UTF-16LE");
01966 if (utf16 == rb_ascii8bit_encoding())
01967 utf16 = NULL;
01968 }
01969 if (!utf16)
01970
01971 return Qnil;
01972
01973 src = rb_enc_str_new((char *)wstr, lstrlenW(wstr) * sizeof(WCHAR), utf16);
01974 return rb_str_encode(src, rb_enc_from_encoding(enc), ECONV_UNDEF_REPLACE, Qnil);
01975 }
01976
01977
01978 char *
01979 rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc)
01980 {
01981 VALUE str = rb_w32_conv_from_wchar(wstr, enc);
01982 long len;
01983 char *ptr;
01984
01985 if (NIL_P(str)) return wstr_to_filecp(wstr, lenp);
01986 *lenp = len = RSTRING_LEN(str);
01987 memcpy(ptr = malloc(len + 1), RSTRING_PTR(str), len);
01988 ptr[len] = '\0';
01989 return ptr;
01990 }
01991
01992
01993 static BOOL
01994 ruby_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *enc)
01995 {
01996 if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc)))
01997 return FALSE;
01998 return TRUE;
01999 }
02000
02001
02002 static struct direct *
02003 readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, struct direct *, rb_encoding *), rb_encoding *enc)
02004 {
02005 static int dummy = 0;
02006
02007 if (dirp->curr) {
02008
02009
02010
02011
02012 if (dirp->dirstr.d_name)
02013 free(dirp->dirstr.d_name);
02014 conv(dirp->curr, &dirp->dirstr, enc);
02015
02016
02017
02018
02019 dirp->dirstr.d_ino = dummy++;
02020
02021
02022
02023
02024 dirp->dirstr.d_isdir = GetBit(dirp->bits, BitOfIsDir(dirp->loc));
02025 dirp->dirstr.d_isrep = GetBit(dirp->bits, BitOfIsRep(dirp->loc));
02026
02027
02028
02029
02030
02031 move_to_next_entry(dirp);
02032
02033 return &(dirp->dirstr);
02034
02035 }
02036 else
02037 return NULL;
02038 }
02039
02040
02041 struct direct *
02042 rb_w32_readdir(DIR *dirp, rb_encoding *enc)
02043 {
02044 if (!enc || enc == rb_ascii8bit_encoding())
02045 return readdir_internal(dirp, win32_direct_conv, NULL);
02046 else
02047 return readdir_internal(dirp, ruby_direct_conv, enc);
02048 }
02049
02050
02051
02052
02053
02054
02055 long
02056 rb_w32_telldir(DIR *dirp)
02057 {
02058 return dirp->loc;
02059 }
02060
02061
02062
02063
02064
02065
02066 void
02067 rb_w32_seekdir(DIR *dirp, long loc)
02068 {
02069 if (dirp->loc > loc) rb_w32_rewinddir(dirp);
02070
02071 while (dirp->curr && dirp->loc < loc) {
02072 move_to_next_entry(dirp);
02073 }
02074 }
02075
02076
02077
02078
02079
02080
02081 void
02082 rb_w32_rewinddir(DIR *dirp)
02083 {
02084 dirp->curr = dirp->start;
02085 dirp->loc = 0;
02086 }
02087
02088
02089
02090
02091
02092
02093 void
02094 rb_w32_closedir(DIR *dirp)
02095 {
02096 if (dirp) {
02097 if (dirp->dirstr.d_name)
02098 free(dirp->dirstr.d_name);
02099 if (dirp->start)
02100 free(dirp->start);
02101 if (dirp->bits)
02102 free(dirp->bits);
02103 free(dirp);
02104 }
02105 }
02106
02107 #if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__
02108 #define MSVCRT_THREADS
02109 #endif
02110 #ifdef MSVCRT_THREADS
02111 # define MTHREAD_ONLY(x) x
02112 # define STHREAD_ONLY(x)
02113 #elif defined(__BORLANDC__)
02114 # define MTHREAD_ONLY(x)
02115 # define STHREAD_ONLY(x)
02116 #else
02117 # define MTHREAD_ONLY(x)
02118 # define STHREAD_ONLY(x) x
02119 #endif
02120
02121
02122 typedef struct {
02123 intptr_t osfhnd;
02124 char osfile;
02125 char pipech;
02126 #ifdef MSVCRT_THREADS
02127 int lockinitflag;
02128 CRITICAL_SECTION lock;
02129 #endif
02130 #if RUBY_MSVCRT_VERSION >= 80
02131 char textmode;
02132 char pipech2[2];
02133 #endif
02134 } ioinfo;
02135
02136 #if !defined _CRTIMP || defined __MINGW32__
02137 #undef _CRTIMP
02138 #define _CRTIMP __declspec(dllimport)
02139 #endif
02140
02141 #if !defined(__BORLANDC__)
02142 EXTERN_C _CRTIMP ioinfo * __pioinfo[];
02143 static inline ioinfo* _pioinfo(int);
02144
02145 #define IOINFO_L2E 5
02146 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
02147 #define _osfhnd(i) (_pioinfo(i)->osfhnd)
02148 #define _osfile(i) (_pioinfo(i)->osfile)
02149 #define _pipech(i) (_pioinfo(i)->pipech)
02150
02151 #if RUBY_MSVCRT_VERSION >= 80
02152 static size_t pioinfo_extra = 0;
02153
02154
02155 static void
02156 set_pioinfo_extra(void)
02157 {
02158 int fd;
02159
02160 fd = _open("NUL", O_RDONLY);
02161 for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra += sizeof(void *)) {
02162 if (_osfhnd(fd) == _get_osfhandle(fd)) {
02163 break;
02164 }
02165 }
02166 _close(fd);
02167
02168 if (pioinfo_extra > 64) {
02169
02170 pioinfo_extra = 0;
02171 }
02172 }
02173 #else
02174 #define pioinfo_extra 0
02175 #endif
02176
02177 static inline ioinfo*
02178 _pioinfo(int fd)
02179 {
02180 const size_t sizeof_ioinfo = sizeof(ioinfo) + pioinfo_extra;
02181 return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
02182 (fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
02183 }
02184
02185 #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
02186 #define _set_osflags(fh, flags) (_osfile(fh) = (flags))
02187
02188 #define FOPEN 0x01
02189 #define FEOFLAG 0x02
02190 #define FPIPE 0x08
02191 #define FNOINHERIT 0x10
02192 #define FAPPEND 0x20
02193 #define FDEV 0x40
02194 #define FTEXT 0x80
02195
02196 static int is_socket(SOCKET);
02197 static int is_console(SOCKET);
02198
02199
02200 int
02201 rb_w32_io_cancelable_p(int fd)
02202 {
02203 return cancel_io != NULL && (is_socket(TO_SOCKET(fd)) || !is_console(TO_SOCKET(fd)));
02204 }
02205
02206
02207 static int
02208 rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
02209 {
02210 int fh;
02211 char fileflags;
02212 HANDLE hF;
02213
02214
02215 fileflags = FDEV;
02216
02217 if (flags & O_APPEND)
02218 fileflags |= FAPPEND;
02219
02220 if (flags & O_TEXT)
02221 fileflags |= FTEXT;
02222
02223 if (flags & O_NOINHERIT)
02224 fileflags |= FNOINHERIT;
02225
02226
02227 hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
02228 fh = _open_osfhandle((intptr_t)hF, 0);
02229 CloseHandle(hF);
02230 if (fh == -1) {
02231 errno = EMFILE;
02232 _doserrno = 0L;
02233 }
02234 else {
02235
02236 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock)));
02237
02238 _set_osfhnd(fh, osfhandle);
02239
02240 fileflags |= FOPEN;
02241
02242 _set_osflags(fh, fileflags);
02243 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock));
02244 }
02245 return fh;
02246 }
02247
02248
02249 static void
02250 init_stdhandle(void)
02251 {
02252 int nullfd = -1;
02253 int keep = 0;
02254 #define open_null(fd) \
02255 (((nullfd < 0) ? \
02256 (nullfd = open("NUL", O_RDWR)) : 0), \
02257 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \
02258 (fd))
02259
02260 if (fileno(stdin) < 0) {
02261 stdin->_file = open_null(0);
02262 }
02263 else {
02264 setmode(fileno(stdin), O_BINARY);
02265 }
02266 if (fileno(stdout) < 0) {
02267 stdout->_file = open_null(1);
02268 }
02269 if (fileno(stderr) < 0) {
02270 stderr->_file = open_null(2);
02271 }
02272 if (nullfd >= 0 && !keep) close(nullfd);
02273 setvbuf(stderr, NULL, _IONBF, 0);
02274 }
02275 #else
02276
02277 #define _set_osfhnd(fh, osfh) (void)((fh), (osfh))
02278 #define _set_osflags(fh, flags) (void)((fh), (flags))
02279
02280
02281 static void
02282 init_stdhandle(void)
02283 {
02284 }
02285 #endif
02286
02287
02288 #ifdef __BORLANDC__
02289 static int
02290 rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
02291 {
02292 int fd = _open_osfhandle(osfhandle, flags);
02293 if (fd == -1) {
02294 errno = EMFILE;
02295 _doserrno = 0L;
02296 }
02297 return fd;
02298 }
02299 #endif
02300
02301 #undef getsockopt
02302
02303
02304 static int
02305 is_socket(SOCKET sock)
02306 {
02307 if (socklist_lookup(sock, NULL))
02308 return TRUE;
02309 else
02310 return FALSE;
02311 }
02312
02313
02314 int
02315 rb_w32_is_socket(int fd)
02316 {
02317 return is_socket(TO_SOCKET(fd));
02318 }
02319
02320
02321
02322
02323
02324
02325
02326 #undef strerror
02327
02328
02329 char *
02330 rb_w32_strerror(int e)
02331 {
02332 static char buffer[512];
02333 DWORD source = 0;
02334 char *p;
02335
02336 #if defined __BORLANDC__ && defined ENOTEMPTY // _sys_errlist is broken
02337 switch (e) {
02338 case ENAMETOOLONG:
02339 return "Filename too long";
02340 case ENOTEMPTY:
02341 return "Directory not empty";
02342 }
02343 #endif
02344
02345 if (e < 0 || e > sys_nerr) {
02346 if (e < 0)
02347 e = GetLastError();
02348 #if WSAEWOULDBLOCK != EWOULDBLOCK
02349 else if (e >= EADDRINUSE && e <= EWOULDBLOCK) {
02350 static int s = -1;
02351 int i;
02352 if (s < 0)
02353 for (s = 0; s < (int)(sizeof(errmap)/sizeof(*errmap)); s++)
02354 if (errmap[s].winerr == WSAEWOULDBLOCK)
02355 break;
02356 for (i = s; i < (int)(sizeof(errmap)/sizeof(*errmap)); i++)
02357 if (errmap[i].err == e) {
02358 e = errmap[i].winerr;
02359 break;
02360 }
02361 }
02362 #endif
02363 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
02364 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e,
02365 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
02366 buffer, sizeof(buffer), NULL) == 0 &&
02367 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
02368 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
02369 buffer, sizeof(buffer), NULL) == 0)
02370 strlcpy(buffer, "Unknown Error", sizeof(buffer));
02371 }
02372 else
02373 strlcpy(buffer, strerror(e), sizeof(buffer));
02374
02375 p = buffer;
02376 while ((p = strpbrk(p, "\r\n")) != NULL) {
02377 memmove(p, p + 1, strlen(p));
02378 }
02379 return buffer;
02380 }
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393 #define ROOT_UID 0
02394 #define ROOT_GID 0
02395
02396
02397 rb_uid_t
02398 getuid(void)
02399 {
02400 return ROOT_UID;
02401 }
02402
02403
02404 rb_uid_t
02405 geteuid(void)
02406 {
02407 return ROOT_UID;
02408 }
02409
02410
02411 rb_gid_t
02412 getgid(void)
02413 {
02414 return ROOT_GID;
02415 }
02416
02417
02418 rb_gid_t
02419 getegid(void)
02420 {
02421 return ROOT_GID;
02422 }
02423
02424
02425 int
02426 setuid(rb_uid_t uid)
02427 {
02428 return (uid == ROOT_UID ? 0 : -1);
02429 }
02430
02431
02432 int
02433 setgid(rb_gid_t gid)
02434 {
02435 return (gid == ROOT_GID ? 0 : -1);
02436 }
02437
02438
02439
02440
02441
02442
02443 int
02444 ioctl(int i, int u, ...)
02445 {
02446 errno = EINVAL;
02447 return -1;
02448 }
02449
02450 void
02451 rb_w32_fdset(int fd, fd_set *set)
02452 {
02453 FD_SET(fd, set);
02454 }
02455
02456 #undef FD_CLR
02457
02458
02459 void
02460 rb_w32_fdclr(int fd, fd_set *set)
02461 {
02462 unsigned int i;
02463 SOCKET s = TO_SOCKET(fd);
02464
02465 for (i = 0; i < set->fd_count; i++) {
02466 if (set->fd_array[i] == s) {
02467 memmove(&set->fd_array[i], &set->fd_array[i+1],
02468 sizeof(set->fd_array[0]) * (--set->fd_count - i));
02469 break;
02470 }
02471 }
02472 }
02473
02474 #undef FD_ISSET
02475
02476
02477 int
02478 rb_w32_fdisset(int fd, fd_set *set)
02479 {
02480 int ret;
02481 SOCKET s = TO_SOCKET(fd);
02482 if (s == (SOCKET)INVALID_HANDLE_VALUE)
02483 return 0;
02484 RUBY_CRITICAL(ret = __WSAFDIsSet(s, set));
02485 return ret;
02486 }
02487
02488
02489 void
02490 rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
02491 {
02492 max = min(src->fd_count, (UINT)max);
02493 if ((UINT)dst->capa < (UINT)max) {
02494 dst->capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
02495 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
02496 }
02497
02498 memcpy(dst->fdset->fd_array, src->fd_array,
02499 max * sizeof(src->fd_array[0]));
02500 dst->fdset->fd_count = src->fd_count;
02501 }
02502
02503
02504 void
02505 rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
02506 {
02507 if ((UINT)dst->capa < src->fdset->fd_count) {
02508 dst->capa = (src->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
02509 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
02510 }
02511
02512 memcpy(dst->fdset->fd_array, src->fdset->fd_array,
02513 src->fdset->fd_count * sizeof(src->fdset->fd_array[0]));
02514 dst->fdset->fd_count = src->fdset->fd_count;
02515 }
02516
02517
02518
02519
02520
02521
02522
02523 #undef select
02524
02525
02526 static int
02527 extract_fd(rb_fdset_t *dst, fd_set *src, int (*func)(SOCKET))
02528 {
02529 unsigned int s = 0;
02530 unsigned int m = 0;
02531 if (!src) return 0;
02532
02533 while (s < src->fd_count) {
02534 SOCKET fd = src->fd_array[s];
02535
02536 if (!func || (*func)(fd)) {
02537 if (dst) {
02538 unsigned int d;
02539
02540 for (d = 0; d < dst->fdset->fd_count; d++) {
02541 if (dst->fdset->fd_array[d] == fd)
02542 break;
02543 }
02544 if (d == dst->fdset->fd_count) {
02545 if ((int)dst->fdset->fd_count >= dst->capa) {
02546 dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
02547 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
02548 }
02549 dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
02550 }
02551 memmove(
02552 &src->fd_array[s],
02553 &src->fd_array[s+1],
02554 sizeof(src->fd_array[0]) * (--src->fd_count - s));
02555 }
02556 else {
02557 m++;
02558 s++;
02559 }
02560 }
02561 else s++;
02562 }
02563
02564 return dst ? dst->fdset->fd_count : m;
02565 }
02566
02567
02568 static int
02569 copy_fd(fd_set *dst, fd_set *src)
02570 {
02571 unsigned int s;
02572 if (!src || !dst) return 0;
02573
02574 for (s = 0; s < src->fd_count; ++s) {
02575 SOCKET fd = src->fd_array[s];
02576 unsigned int d;
02577 for (d = 0; d < dst->fd_count; ++d) {
02578 if (dst->fd_array[d] == fd)
02579 break;
02580 }
02581 if (d == dst->fd_count && d < FD_SETSIZE) {
02582 dst->fd_array[dst->fd_count++] = fd;
02583 }
02584 }
02585
02586 return dst->fd_count;
02587 }
02588
02589
02590 static int
02591 is_not_socket(SOCKET sock)
02592 {
02593 return !is_socket(sock);
02594 }
02595
02596
02597 static int
02598 is_pipe(SOCKET sock)
02599 {
02600 int ret;
02601
02602 RUBY_CRITICAL({
02603 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
02604 });
02605
02606 return ret;
02607 }
02608
02609
02610 static int
02611 is_readable_pipe(SOCKET sock)
02612 {
02613 int ret;
02614 DWORD n = 0;
02615
02616 RUBY_CRITICAL(
02617 if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
02618 ret = (n > 0);
02619 }
02620 else {
02621 ret = (GetLastError() == ERROR_BROKEN_PIPE);
02622 }
02623 );
02624
02625 return ret;
02626 }
02627
02628
02629 static int
02630 is_console(SOCKET sock)
02631 {
02632 int ret;
02633 DWORD n = 0;
02634 INPUT_RECORD ir;
02635
02636 RUBY_CRITICAL(
02637 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n))
02638 );
02639
02640 return ret;
02641 }
02642
02643
02644 static int
02645 is_readable_console(SOCKET sock)
02646 {
02647 int ret = 0;
02648 DWORD n = 0;
02649 INPUT_RECORD ir;
02650
02651 RUBY_CRITICAL(
02652 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
02653 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
02654 ir.Event.KeyEvent.uChar.AsciiChar) {
02655 ret = 1;
02656 }
02657 else {
02658 ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
02659 }
02660 }
02661 );
02662
02663 return ret;
02664 }
02665
02666
02667 static int
02668 is_invalid_handle(SOCKET sock)
02669 {
02670 return (HANDLE)sock == INVALID_HANDLE_VALUE;
02671 }
02672
02673
02674 static int
02675 do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
02676 struct timeval *timeout)
02677 {
02678 int r = 0;
02679
02680 if (nfds == 0) {
02681 if (timeout)
02682 rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
02683 else
02684 rb_w32_sleep(INFINITE);
02685 }
02686 else {
02687 if (!NtSocketsInitialized)
02688 StartSockets();
02689
02690 RUBY_CRITICAL(
02691 EnterCriticalSection(&select_mutex);
02692 r = select(nfds, rd, wr, ex, timeout);
02693 LeaveCriticalSection(&select_mutex);
02694 if (r == SOCKET_ERROR) {
02695 errno = map_errno(WSAGetLastError());
02696 r = -1;
02697 }
02698 );
02699 }
02700
02701 return r;
02702 }
02703
02704
02705
02706
02707
02708
02709 int
02710 rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait)
02711 {
02712 if (rest->tv_sec < wait->tv_sec) {
02713 return 0;
02714 }
02715 while (rest->tv_usec < wait->tv_usec) {
02716 if (rest->tv_sec <= wait->tv_sec) {
02717 return 0;
02718 }
02719 rest->tv_sec -= 1;
02720 rest->tv_usec += 1000 * 1000;
02721 }
02722 rest->tv_sec -= wait->tv_sec;
02723 rest->tv_usec -= wait->tv_usec;
02724 return rest->tv_sec != 0 || rest->tv_usec != 0;
02725 }
02726
02727
02728 static inline int
02729 compare(const struct timeval *t1, const struct timeval *t2)
02730 {
02731 if (t1->tv_sec < t2->tv_sec)
02732 return -1;
02733 if (t1->tv_sec > t2->tv_sec)
02734 return 1;
02735 if (t1->tv_usec < t2->tv_usec)
02736 return -1;
02737 if (t1->tv_usec > t2->tv_usec)
02738 return 1;
02739 return 0;
02740 }
02741
02742 #undef Sleep
02743
02744 int rb_w32_check_interrupt(void *);
02745
02746
02747
02748 int
02749 rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
02750 struct timeval *timeout, void *th)
02751 {
02752 int r;
02753 rb_fdset_t pipe_rd;
02754 rb_fdset_t cons_rd;
02755 rb_fdset_t else_rd;
02756 rb_fdset_t else_wr;
02757 rb_fdset_t except;
02758 int nonsock = 0;
02759 struct timeval limit = {0, 0};
02760
02761 if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
02762 errno = EINVAL;
02763 return -1;
02764 }
02765
02766 if (timeout) {
02767 if (timeout->tv_sec < 0 ||
02768 timeout->tv_usec < 0 ||
02769 timeout->tv_usec >= 1000000) {
02770 errno = EINVAL;
02771 return -1;
02772 }
02773 gettimeofday(&limit, NULL);
02774 limit.tv_sec += timeout->tv_sec;
02775 limit.tv_usec += timeout->tv_usec;
02776 if (limit.tv_usec >= 1000000) {
02777 limit.tv_usec -= 1000000;
02778 limit.tv_sec++;
02779 }
02780 }
02781
02782
02783
02784
02785
02786
02787
02788 rb_fd_init(&else_rd);
02789 nonsock += extract_fd(&else_rd, rd, is_not_socket);
02790
02791 rb_fd_init(&else_wr);
02792 nonsock += extract_fd(&else_wr, wr, is_not_socket);
02793
02794
02795 if (extract_fd(NULL, else_rd.fdset, is_invalid_handle) > 0 ||
02796 extract_fd(NULL, else_wr.fdset, is_invalid_handle) > 0) {
02797 rb_fd_term(&else_wr);
02798 rb_fd_term(&else_rd);
02799 errno = EBADF;
02800 return -1;
02801 }
02802
02803 rb_fd_init(&pipe_rd);
02804 extract_fd(&pipe_rd, else_rd.fdset, is_pipe);
02805
02806 rb_fd_init(&cons_rd);
02807 extract_fd(&cons_rd, else_rd.fdset, is_console);
02808
02809 rb_fd_init(&except);
02810 extract_fd(&except, ex, is_not_socket);
02811
02812 r = 0;
02813 if (rd && (int)rd->fd_count > r) r = (int)rd->fd_count;
02814 if (wr && (int)wr->fd_count > r) r = (int)wr->fd_count;
02815 if (ex && (int)ex->fd_count > r) r = (int)ex->fd_count;
02816 if (nfds > r) nfds = r;
02817
02818 {
02819 struct timeval rest;
02820 struct timeval wait;
02821 struct timeval zero;
02822 wait.tv_sec = 0; wait.tv_usec = 10 * 1000;
02823 zero.tv_sec = 0; zero.tv_usec = 0;
02824 for (;;) {
02825 if (th && rb_w32_check_interrupt(th) != WAIT_TIMEOUT) {
02826 r = -1;
02827 break;
02828 }
02829 if (nonsock) {
02830
02831
02832 extract_fd(&else_rd, pipe_rd.fdset, is_readable_pipe);
02833 extract_fd(&else_rd, cons_rd.fdset, is_readable_console);
02834 }
02835
02836 if (else_rd.fdset->fd_count || else_wr.fdset->fd_count) {
02837 r = do_select(nfds, rd, wr, ex, &zero);
02838 if (r < 0) break;
02839 r += copy_fd(rd, else_rd.fdset);
02840 r += copy_fd(wr, else_wr.fdset);
02841 if (ex)
02842 r += ex->fd_count;
02843 break;
02844 }
02845 else {
02846 struct timeval *dowait = &wait;
02847
02848 fd_set orig_rd;
02849 fd_set orig_wr;
02850 fd_set orig_ex;
02851
02852 FD_ZERO(&orig_rd);
02853 FD_ZERO(&orig_wr);
02854 FD_ZERO(&orig_ex);
02855
02856 if (rd) copy_fd(&orig_rd, rd);
02857 if (wr) copy_fd(&orig_wr, wr);
02858 if (ex) copy_fd(&orig_ex, ex);
02859 r = do_select(nfds, rd, wr, ex, &zero);
02860 if (r != 0) break;
02861 if (rd) copy_fd(rd, &orig_rd);
02862 if (wr) copy_fd(wr, &orig_wr);
02863 if (ex) copy_fd(ex, &orig_ex);
02864
02865 if (timeout) {
02866 struct timeval now;
02867 gettimeofday(&now, NULL);
02868 rest = limit;
02869 if (!rb_w32_time_subtract(&rest, &now)) break;
02870 if (compare(&rest, &wait) < 0) dowait = &rest;
02871 }
02872 Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000);
02873 }
02874 }
02875 }
02876
02877 rb_fd_term(&except);
02878 rb_fd_term(&cons_rd);
02879 rb_fd_term(&pipe_rd);
02880 rb_fd_term(&else_wr);
02881 rb_fd_term(&else_rd);
02882
02883 return r;
02884 }
02885
02886
02887 int WSAAPI
02888 rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
02889 struct timeval *timeout)
02890 {
02891 return rb_w32_select_with_thread(nfds, rd, wr, ex, timeout, 0);
02892 }
02893
02894
02895 static FARPROC
02896 get_wsa_extension_function(SOCKET s, GUID *guid)
02897 {
02898 DWORD dmy;
02899 FARPROC ptr = NULL;
02900
02901 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, guid, sizeof(*guid),
02902 &ptr, sizeof(ptr), &dmy, NULL, NULL);
02903 if (!ptr)
02904 errno = ENOSYS;
02905 return ptr;
02906 }
02907
02908 #undef accept
02909
02910
02911 int WSAAPI
02912 rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
02913 {
02914 SOCKET r;
02915 int fd;
02916
02917 if (!NtSocketsInitialized) {
02918 StartSockets();
02919 }
02920 RUBY_CRITICAL({
02921 HANDLE h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
02922 fd = rb_w32_open_osfhandle((intptr_t)h, O_RDWR|O_BINARY|O_NOINHERIT);
02923 if (fd != -1) {
02924 r = accept(TO_SOCKET(s), addr, addrlen);
02925 if (r != INVALID_SOCKET) {
02926 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
02927 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
02928 _set_osfhnd(fd, r);
02929 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
02930 CloseHandle(h);
02931 socklist_insert(r, 0);
02932 }
02933 else {
02934 errno = map_errno(WSAGetLastError());
02935 close(fd);
02936 fd = -1;
02937 }
02938 }
02939 else
02940 CloseHandle(h);
02941 });
02942 return fd;
02943 }
02944
02945 #undef bind
02946
02947
02948 int WSAAPI
02949 rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
02950 {
02951 int r;
02952
02953 if (!NtSocketsInitialized) {
02954 StartSockets();
02955 }
02956 RUBY_CRITICAL({
02957 r = bind(TO_SOCKET(s), addr, addrlen);
02958 if (r == SOCKET_ERROR)
02959 errno = map_errno(WSAGetLastError());
02960 });
02961 return r;
02962 }
02963
02964 #undef connect
02965
02966
02967 int WSAAPI
02968 rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
02969 {
02970 int r;
02971 if (!NtSocketsInitialized) {
02972 StartSockets();
02973 }
02974 RUBY_CRITICAL({
02975 r = connect(TO_SOCKET(s), addr, addrlen);
02976 if (r == SOCKET_ERROR) {
02977 int err = WSAGetLastError();
02978 if (err != WSAEWOULDBLOCK)
02979 errno = map_errno(err);
02980 else
02981 errno = EINPROGRESS;
02982 }
02983 });
02984 return r;
02985 }
02986
02987
02988 #undef getpeername
02989
02990
02991 int WSAAPI
02992 rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
02993 {
02994 int r;
02995 if (!NtSocketsInitialized) {
02996 StartSockets();
02997 }
02998 RUBY_CRITICAL({
02999 r = getpeername(TO_SOCKET(s), addr, addrlen);
03000 if (r == SOCKET_ERROR)
03001 errno = map_errno(WSAGetLastError());
03002 });
03003 return r;
03004 }
03005
03006 #undef getsockname
03007
03008
03009 int WSAAPI
03010 rb_w32_getsockname(int fd, struct sockaddr *addr, int *addrlen)
03011 {
03012 int sock;
03013 int r;
03014 if (!NtSocketsInitialized) {
03015 StartSockets();
03016 }
03017 RUBY_CRITICAL({
03018 sock = TO_SOCKET(fd);
03019 r = getsockname(sock, addr, addrlen);
03020 if (r == SOCKET_ERROR) {
03021 DWORD wsaerror = WSAGetLastError();
03022 if (wsaerror == WSAEINVAL) {
03023 int flags;
03024 if (socklist_lookup(sock, &flags)) {
03025 int af = GET_FAMILY(flags);
03026 if (af) {
03027 memset(addr, 0, *addrlen);
03028 addr->sa_family = af;
03029 return 0;
03030 }
03031 }
03032 }
03033 errno = map_errno(wsaerror);
03034 }
03035 });
03036 return r;
03037 }
03038
03039 #undef getsockopt
03040
03041
03042 int WSAAPI
03043 rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
03044 {
03045 int r;
03046 if (!NtSocketsInitialized) {
03047 StartSockets();
03048 }
03049 RUBY_CRITICAL({
03050 r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
03051 if (r == SOCKET_ERROR)
03052 errno = map_errno(WSAGetLastError());
03053 });
03054 return r;
03055 }
03056
03057 #undef ioctlsocket
03058
03059
03060 int WSAAPI
03061 rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
03062 {
03063 int r;
03064 if (!NtSocketsInitialized) {
03065 StartSockets();
03066 }
03067 RUBY_CRITICAL({
03068 r = ioctlsocket(TO_SOCKET(s), cmd, argp);
03069 if (r == SOCKET_ERROR)
03070 errno = map_errno(WSAGetLastError());
03071 });
03072 return r;
03073 }
03074
03075 #undef listen
03076
03077
03078 int WSAAPI
03079 rb_w32_listen(int s, int backlog)
03080 {
03081 int r;
03082 if (!NtSocketsInitialized) {
03083 StartSockets();
03084 }
03085 RUBY_CRITICAL({
03086 r = listen(TO_SOCKET(s), backlog);
03087 if (r == SOCKET_ERROR)
03088 errno = map_errno(WSAGetLastError());
03089 });
03090 return r;
03091 }
03092
03093 #undef recv
03094 #undef recvfrom
03095 #undef send
03096 #undef sendto
03097
03098
03099 static int
03100 finish_overlapped_socket(BOOL input, SOCKET s, WSAOVERLAPPED *wol, int result, DWORD *len, DWORD size)
03101 {
03102 DWORD flg;
03103 int err;
03104
03105 if (result != SOCKET_ERROR)
03106 *len = size;
03107 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
03108 switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) {
03109 case WAIT_OBJECT_0:
03110 RUBY_CRITICAL(
03111 result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg)
03112 );
03113 if (result) {
03114 *len = size;
03115 break;
03116 }
03117
03118 default:
03119 if ((err = WSAGetLastError()) == WSAECONNABORTED && !input)
03120 errno = EPIPE;
03121 else
03122 errno = map_errno(WSAGetLastError());
03123
03124 case WAIT_OBJECT_0 + 1:
03125
03126 *len = -1;
03127 cancel_io((HANDLE)s);
03128 break;
03129 }
03130 }
03131 else {
03132 if (err == WSAECONNABORTED && !input)
03133 errno = EPIPE;
03134 else
03135 errno = map_errno(err);
03136 *len = -1;
03137 }
03138 CloseHandle(wol->hEvent);
03139
03140 return result;
03141 }
03142
03143
03144 static int
03145 overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
03146 struct sockaddr *addr, int *addrlen)
03147 {
03148 int r;
03149 int ret;
03150 int mode = 0;
03151 DWORD flg;
03152 WSAOVERLAPPED wol;
03153 WSABUF wbuf;
03154 SOCKET s;
03155
03156 if (!NtSocketsInitialized)
03157 StartSockets();
03158
03159 s = TO_SOCKET(fd);
03160 socklist_lookup(s, &mode);
03161 if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
03162 RUBY_CRITICAL({
03163 if (input) {
03164 if (addr && addrlen)
03165 r = recvfrom(s, buf, len, flags, addr, addrlen);
03166 else
03167 r = recv(s, buf, len, flags);
03168 if (r == SOCKET_ERROR)
03169 errno = map_errno(WSAGetLastError());
03170 }
03171 else {
03172 if (addr && addrlen)
03173 r = sendto(s, buf, len, flags, addr, *addrlen);
03174 else
03175 r = send(s, buf, len, flags);
03176 if (r == SOCKET_ERROR) {
03177 DWORD err = WSAGetLastError();
03178 if (err == WSAECONNABORTED)
03179 errno = EPIPE;
03180 else
03181 errno = map_errno(err);
03182 }
03183 }
03184 });
03185 }
03186 else {
03187 DWORD size;
03188 DWORD rlen;
03189 wbuf.len = len;
03190 wbuf.buf = buf;
03191 memset(&wol, 0, sizeof(wol));
03192 RUBY_CRITICAL({
03193 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03194 if (input) {
03195 flg = flags;
03196 if (addr && addrlen)
03197 ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
03198 &wol, NULL);
03199 else
03200 ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL);
03201 }
03202 else {
03203 if (addr && addrlen)
03204 ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
03205 &wol, NULL);
03206 else
03207 ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL);
03208 }
03209 });
03210
03211 finish_overlapped_socket(input, s, &wol, ret, &rlen, size);
03212 r = (int)rlen;
03213 }
03214
03215 return r;
03216 }
03217
03218
03219 int WSAAPI
03220 rb_w32_recv(int fd, char *buf, int len, int flags)
03221 {
03222 return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
03223 }
03224
03225
03226 int WSAAPI
03227 rb_w32_recvfrom(int fd, char *buf, int len, int flags,
03228 struct sockaddr *from, int *fromlen)
03229 {
03230 return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
03231 }
03232
03233
03234 int WSAAPI
03235 rb_w32_send(int fd, const char *buf, int len, int flags)
03236 {
03237 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL);
03238 }
03239
03240
03241 int WSAAPI
03242 rb_w32_sendto(int fd, const char *buf, int len, int flags,
03243 const struct sockaddr *to, int tolen)
03244 {
03245 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
03246 (struct sockaddr *)to, &tolen);
03247 }
03248
03249 #if !defined(MSG_TRUNC) && !defined(__MINGW32__)
03250
03251 typedef struct {
03252 SOCKADDR *name;
03253 int namelen;
03254 WSABUF *lpBuffers;
03255 DWORD dwBufferCount;
03256 WSABUF Control;
03257 DWORD dwFlags;
03258 } WSAMSG;
03259 #endif
03260 #ifndef WSAID_WSARECVMSG
03261 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
03262 #endif
03263 #ifndef WSAID_WSASENDMSG
03264 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
03265 #endif
03266
03267
03268 #define msghdr_to_wsamsg(msg, wsamsg) \
03269 do { \
03270 int i; \
03271 (wsamsg)->name = (msg)->msg_name; \
03272 (wsamsg)->namelen = (msg)->msg_namelen; \
03273 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
03274 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
03275 for (i = 0; i < (msg)->msg_iovlen; ++i) { \
03276 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
03277 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
03278 } \
03279 (wsamsg)->Control.buf = (msg)->msg_control; \
03280 (wsamsg)->Control.len = (msg)->msg_controllen; \
03281 (wsamsg)->dwFlags = (msg)->msg_flags; \
03282 } while (0)
03283
03284
03285 int
03286 recvmsg(int fd, struct msghdr *msg, int flags)
03287 {
03288 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
03289 static WSARecvMsg_t pWSARecvMsg = NULL;
03290 WSAMSG wsamsg;
03291 SOCKET s;
03292 int mode = 0;
03293 DWORD len;
03294 int ret;
03295
03296 if (!NtSocketsInitialized)
03297 StartSockets();
03298
03299 s = TO_SOCKET(fd);
03300
03301 if (!pWSARecvMsg) {
03302 static GUID guid = WSAID_WSARECVMSG;
03303 pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid);
03304 if (!pWSARecvMsg)
03305 return -1;
03306 }
03307
03308 msghdr_to_wsamsg(msg, &wsamsg);
03309 wsamsg.dwFlags |= flags;
03310
03311 socklist_lookup(s, &mode);
03312 if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
03313 RUBY_CRITICAL({
03314 if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
03315 errno = map_errno(WSAGetLastError());
03316 len = -1;
03317 }
03318 });
03319 }
03320 else {
03321 DWORD size;
03322 WSAOVERLAPPED wol;
03323 memset(&wol, 0, sizeof(wol));
03324 RUBY_CRITICAL({
03325 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03326 ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL);
03327 });
03328
03329 ret = finish_overlapped_socket(TRUE, s, &wol, ret, &len, size);
03330 }
03331 if (ret == SOCKET_ERROR)
03332 return -1;
03333
03334
03335 msg->msg_name = wsamsg.name;
03336 msg->msg_namelen = wsamsg.namelen;
03337 msg->msg_flags = wsamsg.dwFlags;
03338
03339 return len;
03340 }
03341
03342
03343 int
03344 sendmsg(int fd, const struct msghdr *msg, int flags)
03345 {
03346 typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
03347 static WSASendMsg_t pWSASendMsg = NULL;
03348 WSAMSG wsamsg;
03349 SOCKET s;
03350 int mode = 0;
03351 DWORD len;
03352 int ret;
03353
03354 if (!NtSocketsInitialized)
03355 StartSockets();
03356
03357 s = TO_SOCKET(fd);
03358
03359 if (!pWSASendMsg) {
03360 static GUID guid = WSAID_WSASENDMSG;
03361 pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid);
03362 if (!pWSASendMsg)
03363 return -1;
03364 }
03365
03366 msghdr_to_wsamsg(msg, &wsamsg);
03367
03368 socklist_lookup(s, &mode);
03369 if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
03370 RUBY_CRITICAL({
03371 if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
03372 errno = map_errno(WSAGetLastError());
03373 len = -1;
03374 }
03375 });
03376 }
03377 else {
03378 DWORD size;
03379 WSAOVERLAPPED wol;
03380 memset(&wol, 0, sizeof(wol));
03381 RUBY_CRITICAL({
03382 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03383 ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL);
03384 });
03385
03386 finish_overlapped_socket(FALSE, s, &wol, ret, &len, size);
03387 }
03388
03389 return len;
03390 }
03391
03392 #undef setsockopt
03393
03394
03395 int WSAAPI
03396 rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
03397 {
03398 int r;
03399 if (!NtSocketsInitialized) {
03400 StartSockets();
03401 }
03402 RUBY_CRITICAL({
03403 r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
03404 if (r == SOCKET_ERROR)
03405 errno = map_errno(WSAGetLastError());
03406 });
03407 return r;
03408 }
03409
03410 #undef shutdown
03411
03412
03413 int WSAAPI
03414 rb_w32_shutdown(int s, int how)
03415 {
03416 int r;
03417 if (!NtSocketsInitialized) {
03418 StartSockets();
03419 }
03420 RUBY_CRITICAL({
03421 r = shutdown(TO_SOCKET(s), how);
03422 if (r == SOCKET_ERROR)
03423 errno = map_errno(WSAGetLastError());
03424 });
03425 return r;
03426 }
03427
03428
03429 static SOCKET
03430 open_ifs_socket(int af, int type, int protocol)
03431 {
03432 unsigned long proto_buffers_len = 0;
03433 int error_code;
03434 SOCKET out = INVALID_SOCKET;
03435
03436 if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) {
03437 error_code = WSAGetLastError();
03438 if (error_code == WSAENOBUFS) {
03439 WSAPROTOCOL_INFO *proto_buffers;
03440 int protocols_available = 0;
03441
03442 proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len);
03443 if (!proto_buffers) {
03444 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
03445 return INVALID_SOCKET;
03446 }
03447
03448 protocols_available =
03449 WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len);
03450 if (protocols_available != SOCKET_ERROR) {
03451 int i;
03452 for (i = 0; i < protocols_available; i++) {
03453 if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
03454 (type != proto_buffers[i].iSocketType) ||
03455 (protocol != 0 && protocol != proto_buffers[i].iProtocol))
03456 continue;
03457
03458 if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
03459 continue;
03460
03461 out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
03462 WSA_FLAG_OVERLAPPED);
03463 break;
03464 }
03465 if (out == INVALID_SOCKET)
03466 out = WSASocket(af, type, protocol, NULL, 0, 0);
03467 if (out != INVALID_SOCKET)
03468 SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0);
03469 }
03470
03471 free(proto_buffers);
03472 }
03473 }
03474
03475 return out;
03476 }
03477
03478 #undef socket
03479
03480
03481 int WSAAPI
03482 rb_w32_socket(int af, int type, int protocol)
03483 {
03484 SOCKET s;
03485 int fd;
03486
03487 if (!NtSocketsInitialized) {
03488 StartSockets();
03489 }
03490 RUBY_CRITICAL({
03491 s = open_ifs_socket(af, type, protocol);
03492 if (s == INVALID_SOCKET) {
03493 errno = map_errno(WSAGetLastError());
03494 fd = -1;
03495 }
03496 else {
03497 fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
03498 if (fd != -1)
03499 socklist_insert(s, MAKE_SOCKDATA(af, 0));
03500 else
03501 closesocket(s);
03502 }
03503 });
03504 return fd;
03505 }
03506
03507 #undef gethostbyaddr
03508
03509
03510 struct hostent * WSAAPI
03511 rb_w32_gethostbyaddr(const char *addr, int len, int type)
03512 {
03513 struct hostent *r;
03514 if (!NtSocketsInitialized) {
03515 StartSockets();
03516 }
03517 RUBY_CRITICAL({
03518 r = gethostbyaddr(addr, len, type);
03519 if (r == NULL)
03520 errno = map_errno(WSAGetLastError());
03521 });
03522 return r;
03523 }
03524
03525 #undef gethostbyname
03526
03527
03528 struct hostent * WSAAPI
03529 rb_w32_gethostbyname(const char *name)
03530 {
03531 struct hostent *r;
03532 if (!NtSocketsInitialized) {
03533 StartSockets();
03534 }
03535 RUBY_CRITICAL({
03536 r = gethostbyname(name);
03537 if (r == NULL)
03538 errno = map_errno(WSAGetLastError());
03539 });
03540 return r;
03541 }
03542
03543 #undef gethostname
03544
03545
03546 int WSAAPI
03547 rb_w32_gethostname(char *name, int len)
03548 {
03549 int r;
03550 if (!NtSocketsInitialized) {
03551 StartSockets();
03552 }
03553 RUBY_CRITICAL({
03554 r = gethostname(name, len);
03555 if (r == SOCKET_ERROR)
03556 errno = map_errno(WSAGetLastError());
03557 });
03558 return r;
03559 }
03560
03561 #undef getprotobyname
03562
03563
03564 struct protoent * WSAAPI
03565 rb_w32_getprotobyname(const char *name)
03566 {
03567 struct protoent *r;
03568 if (!NtSocketsInitialized) {
03569 StartSockets();
03570 }
03571 RUBY_CRITICAL({
03572 r = getprotobyname(name);
03573 if (r == NULL)
03574 errno = map_errno(WSAGetLastError());
03575 });
03576 return r;
03577 }
03578
03579 #undef getprotobynumber
03580
03581
03582 struct protoent * WSAAPI
03583 rb_w32_getprotobynumber(int num)
03584 {
03585 struct protoent *r;
03586 if (!NtSocketsInitialized) {
03587 StartSockets();
03588 }
03589 RUBY_CRITICAL({
03590 r = getprotobynumber(num);
03591 if (r == NULL)
03592 errno = map_errno(WSAGetLastError());
03593 });
03594 return r;
03595 }
03596
03597 #undef getservbyname
03598
03599
03600 struct servent * WSAAPI
03601 rb_w32_getservbyname(const char *name, const char *proto)
03602 {
03603 struct servent *r;
03604 if (!NtSocketsInitialized) {
03605 StartSockets();
03606 }
03607 RUBY_CRITICAL({
03608 r = getservbyname(name, proto);
03609 if (r == NULL)
03610 errno = map_errno(WSAGetLastError());
03611 });
03612 return r;
03613 }
03614
03615 #undef getservbyport
03616
03617
03618 struct servent * WSAAPI
03619 rb_w32_getservbyport(int port, const char *proto)
03620 {
03621 struct servent *r;
03622 if (!NtSocketsInitialized) {
03623 StartSockets();
03624 }
03625 RUBY_CRITICAL({
03626 r = getservbyport(port, proto);
03627 if (r == NULL)
03628 errno = map_errno(WSAGetLastError());
03629 });
03630 return r;
03631 }
03632
03633
03634 static int
03635 socketpair_internal(int af, int type, int protocol, SOCKET *sv)
03636 {
03637 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
03638 struct sockaddr_in sock_in4;
03639 #ifdef INET6
03640 struct sockaddr_in6 sock_in6;
03641 #endif
03642 struct sockaddr *addr;
03643 int ret = -1;
03644 int len;
03645
03646 if (!NtSocketsInitialized) {
03647 StartSockets();
03648 }
03649
03650 switch (af) {
03651 case AF_INET:
03652 #if defined PF_INET && PF_INET != AF_INET
03653 case PF_INET:
03654 #endif
03655 sock_in4.sin_family = AF_INET;
03656 sock_in4.sin_port = 0;
03657 sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
03658 addr = (struct sockaddr *)&sock_in4;
03659 len = sizeof(sock_in4);
03660 break;
03661 #ifdef INET6
03662 case AF_INET6:
03663 memset(&sock_in6, 0, sizeof(sock_in6));
03664 sock_in6.sin6_family = AF_INET6;
03665 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
03666 addr = (struct sockaddr *)&sock_in6;
03667 len = sizeof(sock_in6);
03668 break;
03669 #endif
03670 default:
03671 errno = EAFNOSUPPORT;
03672 return -1;
03673 }
03674 if (type != SOCK_STREAM) {
03675 errno = EPROTOTYPE;
03676 return -1;
03677 }
03678
03679 sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
03680 sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
03681 RUBY_CRITICAL({
03682 do {
03683 svr = open_ifs_socket(af, type, protocol);
03684 if (svr == INVALID_SOCKET)
03685 break;
03686 if (bind(svr, addr, len) < 0)
03687 break;
03688 if (getsockname(svr, addr, &len) < 0)
03689 break;
03690 if (type == SOCK_STREAM)
03691 listen(svr, 5);
03692
03693 w = open_ifs_socket(af, type, protocol);
03694 if (w == INVALID_SOCKET)
03695 break;
03696 if (connect(w, addr, len) < 0)
03697 break;
03698
03699 r = accept(svr, addr, &len);
03700 if (r == INVALID_SOCKET)
03701 break;
03702 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
03703
03704 ret = 0;
03705 } while (0);
03706
03707 if (ret < 0) {
03708 errno = map_errno(WSAGetLastError());
03709 if (r != INVALID_SOCKET)
03710 closesocket(r);
03711 if (w != INVALID_SOCKET)
03712 closesocket(w);
03713 }
03714 else {
03715 sv[0] = r;
03716 sv[1] = w;
03717 }
03718 if (svr != INVALID_SOCKET)
03719 closesocket(svr);
03720 });
03721
03722 return ret;
03723 }
03724
03725
03726 int
03727 rb_w32_socketpair(int af, int type, int protocol, int *sv)
03728 {
03729 SOCKET pair[2];
03730
03731 if (socketpair_internal(af, type, protocol, pair) < 0)
03732 return -1;
03733 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
03734 if (sv[0] == -1) {
03735 closesocket(pair[0]);
03736 closesocket(pair[1]);
03737 return -1;
03738 }
03739 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
03740 if (sv[1] == -1) {
03741 rb_w32_close(sv[0]);
03742 closesocket(pair[1]);
03743 return -1;
03744 }
03745 socklist_insert(pair[0], MAKE_SOCKDATA(af, 0));
03746 socklist_insert(pair[1], MAKE_SOCKDATA(af, 0));
03747
03748 return 0;
03749 }
03750
03751
03752
03753
03754
03755 void endhostent(void) {}
03756 void endnetent(void) {}
03757 void endprotoent(void) {}
03758 void endservent(void) {}
03759
03760 struct netent *getnetent (void) {return (struct netent *) NULL;}
03761
03762 struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;}
03763
03764 struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;}
03765
03766 struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
03767
03768 struct servent *getservent (void) {return (struct servent *) NULL;}
03769
03770 void sethostent (int stayopen) {}
03771
03772 void setnetent (int stayopen) {}
03773
03774 void setprotoent (int stayopen) {}
03775
03776 void setservent (int stayopen) {}
03777
03778
03779 static int
03780 setfl(SOCKET sock, int arg)
03781 {
03782 int ret;
03783 int af = 0;
03784 int flag = 0;
03785 u_long ioctlArg;
03786
03787 socklist_lookup(sock, &flag);
03788 af = GET_FAMILY(flag);
03789 flag = GET_FLAGS(flag);
03790 if (arg & O_NONBLOCK) {
03791 flag |= O_NONBLOCK;
03792 ioctlArg = 1;
03793 }
03794 else {
03795 flag &= ~O_NONBLOCK;
03796 ioctlArg = 0;
03797 }
03798 RUBY_CRITICAL({
03799 ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
03800 if (ret == 0)
03801 socklist_insert(sock, MAKE_SOCKDATA(af, flag));
03802 else
03803 errno = map_errno(WSAGetLastError());
03804 });
03805
03806 return ret;
03807 }
03808
03809
03810 static int
03811 dupfd(HANDLE hDup, char flags, int minfd)
03812 {
03813 int save_errno;
03814 int ret;
03815 int fds[32];
03816 int filled = 0;
03817
03818 do {
03819 ret = _open_osfhandle((intptr_t)hDup, flags | FOPEN);
03820 if (ret == -1) {
03821 goto close_fds_and_return;
03822 }
03823 if (ret >= minfd) {
03824 goto close_fds_and_return;
03825 }
03826 fds[filled++] = ret;
03827 } while (filled < (int)numberof(fds));
03828
03829 ret = dupfd(hDup, flags, minfd);
03830
03831 close_fds_and_return:
03832 save_errno = errno;
03833 while (filled > 0) {
03834 int fd = fds[--filled];
03835 _osfhnd(fd) = (intptr_t)INVALID_HANDLE_VALUE;
03836 close(fd);
03837 }
03838 errno = save_errno;
03839
03840 return ret;
03841 }
03842
03843
03844 int
03845 fcntl(int fd, int cmd, ...)
03846 {
03847 va_list va;
03848 int arg;
03849
03850 if (cmd == F_SETFL) {
03851 SOCKET sock = TO_SOCKET(fd);
03852 if (!is_socket(sock)) {
03853 errno = EBADF;
03854 return -1;
03855 }
03856
03857 va_start(va, cmd);
03858 arg = va_arg(va, int);
03859 va_end(va);
03860 return setfl(sock, arg);
03861 }
03862 else if (cmd == F_DUPFD) {
03863 int ret;
03864 HANDLE hDup;
03865 if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
03866 GetCurrentProcess(), &hDup, 0L,
03867 !(_osfile(fd) & FNOINHERIT),
03868 DUPLICATE_SAME_ACCESS))) {
03869 errno = map_errno(GetLastError());
03870 return -1;
03871 }
03872
03873 va_start(va, cmd);
03874 arg = va_arg(va, int);
03875 va_end(va);
03876
03877 if ((ret = dupfd(hDup, _osfile(fd), arg)) == -1)
03878 CloseHandle(hDup);
03879 return ret;
03880 }
03881 else {
03882 errno = EINVAL;
03883 return -1;
03884 }
03885 }
03886
03887 #ifndef WNOHANG
03888 #define WNOHANG -1
03889 #endif
03890
03891
03892 static rb_pid_t
03893 poll_child_status(struct ChildRecord *child, int *stat_loc)
03894 {
03895 DWORD exitcode;
03896 DWORD err;
03897
03898 if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
03899
03900 error_exit:
03901 err = GetLastError();
03902 if (err == ERROR_INVALID_PARAMETER)
03903 errno = ECHILD;
03904 else {
03905 if (GetLastError() == ERROR_INVALID_HANDLE)
03906 errno = EINVAL;
03907 else
03908 errno = map_errno(GetLastError());
03909 }
03910 CloseChildHandle(child);
03911 return -1;
03912 }
03913 if (exitcode != STILL_ACTIVE) {
03914 rb_pid_t pid;
03915
03916 if (rb_w32_wait_events_blocking(&child->hProcess, 1, INFINITE) != WAIT_OBJECT_0) {
03917 goto error_exit;
03918 }
03919 pid = child->pid;
03920 CloseChildHandle(child);
03921 if (stat_loc) *stat_loc = exitcode << 8;
03922 return pid;
03923 }
03924 return 0;
03925 }
03926
03927
03928 rb_pid_t
03929 waitpid(rb_pid_t pid, int *stat_loc, int options)
03930 {
03931 DWORD timeout;
03932
03933
03934 if (options == WNOHANG) {
03935 timeout = 0;
03936 }
03937 else {
03938 timeout = INFINITE;
03939 }
03940
03941
03942 if (pid == -1) {
03943 int count = 0;
03944 int ret;
03945 HANDLE events[MAXCHILDNUM];
03946 struct ChildRecord* cause;
03947
03948 FOREACH_CHILD(child) {
03949 if (!child->pid || child->pid < 0) continue;
03950 if ((pid = poll_child_status(child, stat_loc))) return pid;
03951 events[count++] = child->hProcess;
03952 } END_FOREACH_CHILD;
03953 if (!count) {
03954 errno = ECHILD;
03955 return -1;
03956 }
03957
03958 ret = rb_w32_wait_events_blocking(events, count, timeout);
03959 if (ret == WAIT_TIMEOUT) return 0;
03960 if ((ret -= WAIT_OBJECT_0) == count) {
03961 return -1;
03962 }
03963 if (ret > count) {
03964 errno = map_errno(GetLastError());
03965 return -1;
03966 }
03967
03968 cause = FindChildSlotByHandle(events[ret]);
03969 if (!cause) {
03970 errno = ECHILD;
03971 return -1;
03972 }
03973 return poll_child_status(cause, stat_loc);
03974 }
03975 else {
03976 struct ChildRecord* child = FindChildSlot(pid);
03977 if (!child) {
03978 errno = ECHILD;
03979 return -1;
03980 }
03981
03982 while (!(pid = poll_child_status(child, stat_loc))) {
03983
03984 if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) {
03985
03986 pid = 0;
03987 break;
03988 }
03989 }
03990 }
03991
03992 return pid;
03993 }
03994
03995 #include <sys/timeb.h>
03996
03997
03998 static int
03999 filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
04000 {
04001 ULARGE_INTEGER tmp;
04002 unsigned LONG_LONG lt;
04003
04004 tmp.LowPart = ft->dwLowDateTime;
04005 tmp.HighPart = ft->dwHighDateTime;
04006 lt = tmp.QuadPart;
04007
04008
04009
04010
04011
04012 lt /= 10;
04013 lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000;
04014
04015 tv->tv_sec = (long)(lt / (1000 * 1000));
04016 tv->tv_usec = (long)(lt % (1000 * 1000));
04017
04018 return tv->tv_sec > 0 ? 0 : -1;
04019 }
04020
04021
04022 int _cdecl
04023 gettimeofday(struct timeval *tv, struct timezone *tz)
04024 {
04025 FILETIME ft;
04026
04027 GetSystemTimeAsFileTime(&ft);
04028 filetime_to_timeval(&ft, tv);
04029
04030 return 0;
04031 }
04032
04033
04034 char *
04035 rb_w32_getcwd(char *buffer, int size)
04036 {
04037 char *p = buffer;
04038 int len;
04039
04040 len = GetCurrentDirectory(0, NULL);
04041 if (!len) {
04042 errno = map_errno(GetLastError());
04043 return NULL;
04044 }
04045
04046 if (p) {
04047 if (size < len) {
04048 errno = ERANGE;
04049 return NULL;
04050 }
04051 }
04052 else {
04053 p = malloc(len);
04054 size = len;
04055 if (!p) {
04056 errno = ENOMEM;
04057 return NULL;
04058 }
04059 }
04060
04061 if (!GetCurrentDirectory(size, p)) {
04062 errno = map_errno(GetLastError());
04063 if (!buffer)
04064 free(p);
04065 return NULL;
04066 }
04067
04068 translate_char(p, '\\', '/');
04069
04070 return p;
04071 }
04072
04073
04074 int
04075 chown(const char *path, int owner, int group)
04076 {
04077 return 0;
04078 }
04079
04080
04081 int
04082 rb_w32_uchown(const char *path, int owner, int group)
04083 {
04084 return 0;
04085 }
04086
04087
04088 int
04089 kill(int pid, int sig)
04090 {
04091 int ret = 0;
04092 DWORD err;
04093
04094 if (pid < 0 || pid == 0 && sig != SIGINT) {
04095 errno = EINVAL;
04096 return -1;
04097 }
04098
04099 if ((unsigned int)pid == GetCurrentProcessId() &&
04100 (sig != 0 && sig != SIGKILL)) {
04101 if ((ret = raise(sig)) != 0) {
04102
04103 errno = EINVAL;
04104 }
04105 return ret;
04106 }
04107
04108 switch (sig) {
04109 case 0:
04110 RUBY_CRITICAL({
04111 HANDLE hProc =
04112 OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
04113 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
04114 if (GetLastError() == ERROR_INVALID_PARAMETER) {
04115 errno = ESRCH;
04116 }
04117 else {
04118 errno = EPERM;
04119 }
04120 ret = -1;
04121 }
04122 else {
04123 CloseHandle(hProc);
04124 }
04125 });
04126 break;
04127
04128 case SIGINT:
04129 RUBY_CRITICAL({
04130 DWORD ctrlEvent = CTRL_C_EVENT;
04131 if (pid != 0) {
04132
04133
04134 ctrlEvent = CTRL_BREAK_EVENT;
04135 }
04136 if (!GenerateConsoleCtrlEvent(ctrlEvent, (DWORD)pid)) {
04137 if ((err = GetLastError()) == 0)
04138 errno = EPERM;
04139 else
04140 errno = map_errno(GetLastError());
04141 ret = -1;
04142 }
04143 });
04144 break;
04145
04146 case SIGKILL:
04147 RUBY_CRITICAL({
04148 HANDLE hProc;
04149 struct ChildRecord* child = FindChildSlot(pid);
04150 if (child) {
04151 hProc = child->hProcess;
04152 }
04153 else {
04154 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
04155 }
04156 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
04157 if (GetLastError() == ERROR_INVALID_PARAMETER) {
04158 errno = ESRCH;
04159 }
04160 else {
04161 errno = EPERM;
04162 }
04163 ret = -1;
04164 }
04165 else {
04166 DWORD status;
04167 if (!GetExitCodeProcess(hProc, &status)) {
04168 errno = map_errno(GetLastError());
04169 ret = -1;
04170 }
04171 else if (status == STILL_ACTIVE) {
04172 if (!TerminateProcess(hProc, 0)) {
04173 errno = EPERM;
04174 ret = -1;
04175 }
04176 }
04177 else {
04178 errno = ESRCH;
04179 ret = -1;
04180 }
04181 if (!child) {
04182 CloseHandle(hProc);
04183 }
04184 }
04185 });
04186 break;
04187
04188 default:
04189 errno = EINVAL;
04190 ret = -1;
04191 break;
04192 }
04193
04194 return ret;
04195 }
04196
04197
04198 static int
04199 wlink(const WCHAR *from, const WCHAR *to)
04200 {
04201 typedef BOOL (WINAPI link_func)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
04202 static link_func *pCreateHardLinkW = NULL;
04203 static int myerrno = 0;
04204
04205 if (!pCreateHardLinkW && !myerrno) {
04206 pCreateHardLinkW = (link_func *)get_proc_address("kernel32", "CreateHardLinkW", NULL);
04207 if (!pCreateHardLinkW)
04208 myerrno = ENOSYS;
04209 }
04210 if (!pCreateHardLinkW) {
04211 errno = myerrno;
04212 return -1;
04213 }
04214
04215 if (!pCreateHardLinkW(to, from, NULL)) {
04216 errno = map_errno(GetLastError());
04217 return -1;
04218 }
04219
04220 return 0;
04221 }
04222
04223
04224 int
04225 rb_w32_ulink(const char *from, const char *to)
04226 {
04227 WCHAR *wfrom;
04228 WCHAR *wto;
04229 int ret;
04230
04231 if (!(wfrom = utf8_to_wstr(from, NULL)))
04232 return -1;
04233 if (!(wto = utf8_to_wstr(to, NULL))) {
04234 free(wfrom);
04235 return -1;
04236 }
04237 ret = wlink(wfrom, wto);
04238 free(wto);
04239 free(wfrom);
04240 return ret;
04241 }
04242
04243
04244 int
04245 link(const char *from, const char *to)
04246 {
04247 WCHAR *wfrom;
04248 WCHAR *wto;
04249 int ret;
04250
04251 if (!(wfrom = filecp_to_wstr(from, NULL)))
04252 return -1;
04253 if (!(wto = filecp_to_wstr(to, NULL))) {
04254 free(wfrom);
04255 return -1;
04256 }
04257 ret = wlink(wfrom, wto);
04258 free(wto);
04259 free(wfrom);
04260 return ret;
04261 }
04262
04263
04264 int
04265 wait(int *status)
04266 {
04267 return waitpid(-1, status, 0);
04268 }
04269
04270
04271 char *
04272 rb_w32_ugetenv(const char *name)
04273 {
04274 WCHAR *wenvarea, *wenv;
04275 int len = strlen(name);
04276 char *env;
04277 int wlen;
04278
04279 if (len == 0) return NULL;
04280
04281 if (uenvarea) {
04282 free(uenvarea);
04283 uenvarea = NULL;
04284 }
04285 if (envarea) {
04286 FreeEnvironmentStrings(envarea);
04287 envarea = NULL;
04288 }
04289 wenvarea = GetEnvironmentStringsW();
04290 if (!wenvarea) {
04291 map_errno(GetLastError());
04292 return NULL;
04293 }
04294 for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
04295 wlen += lstrlenW(wenv) + 1;
04296 uenvarea = wstr_to_mbstr(CP_UTF8, wenvarea, wlen, NULL);
04297 FreeEnvironmentStringsW(wenvarea);
04298 if (!uenvarea)
04299 return NULL;
04300
04301 for (env = uenvarea; *env; env += strlen(env) + 1)
04302 if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
04303 return env + len + 1;
04304
04305 return NULL;
04306 }
04307
04308
04309 char *
04310 rb_w32_getenv(const char *name)
04311 {
04312 int len = strlen(name);
04313 char *env;
04314
04315 if (len == 0) return NULL;
04316 if (uenvarea) {
04317 free(uenvarea);
04318 uenvarea = NULL;
04319 }
04320 if (envarea) {
04321 FreeEnvironmentStrings(envarea);
04322 envarea = NULL;
04323 }
04324 envarea = GetEnvironmentStrings();
04325 if (!envarea) {
04326 map_errno(GetLastError());
04327 return NULL;
04328 }
04329
04330 for (env = envarea; *env; env += strlen(env) + 1)
04331 if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
04332 return env + len + 1;
04333
04334 return NULL;
04335 }
04336
04337
04338 static int
04339 wrename(const WCHAR *oldpath, const WCHAR *newpath)
04340 {
04341 int res = 0;
04342 int oldatts;
04343 int newatts;
04344
04345 oldatts = GetFileAttributesW(oldpath);
04346 newatts = GetFileAttributesW(newpath);
04347
04348 if (oldatts == -1) {
04349 errno = map_errno(GetLastError());
04350 return -1;
04351 }
04352
04353 RUBY_CRITICAL({
04354 if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
04355 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
04356
04357 if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
04358 res = -1;
04359
04360 if (res)
04361 errno = map_errno(GetLastError());
04362 else
04363 SetFileAttributesW(newpath, oldatts);
04364 });
04365
04366 return res;
04367 }
04368
04369
04370 int rb_w32_urename(const char *from, const char *to)
04371 {
04372 WCHAR *wfrom;
04373 WCHAR *wto;
04374 int ret = -1;
04375
04376 if (!(wfrom = utf8_to_wstr(from, NULL)))
04377 return -1;
04378 if (!(wto = utf8_to_wstr(to, NULL))) {
04379 free(wfrom);
04380 return -1;
04381 }
04382 ret = wrename(wfrom, wto);
04383 free(wto);
04384 free(wfrom);
04385 return ret;
04386 }
04387
04388
04389 int rb_w32_rename(const char *from, const char *to)
04390 {
04391 WCHAR *wfrom;
04392 WCHAR *wto;
04393 int ret = -1;
04394
04395 if (!(wfrom = filecp_to_wstr(from, NULL)))
04396 return -1;
04397 if (!(wto = filecp_to_wstr(to, NULL))) {
04398 free(wfrom);
04399 return -1;
04400 }
04401 ret = wrename(wfrom, wto);
04402 free(wto);
04403 free(wfrom);
04404 return ret;
04405 }
04406
04407
04408 static int
04409 isUNCRoot(const WCHAR *path)
04410 {
04411 if (path[0] == L'\\' && path[1] == L'\\') {
04412 const WCHAR *p = path + 2;
04413 if (p[0] == L'?' && p[1] == L'\\') {
04414 p += 2;
04415 }
04416 for (; *p; p++) {
04417 if (*p == L'\\')
04418 break;
04419 }
04420 if (p[0] && p[1]) {
04421 for (p++; *p; p++) {
04422 if (*p == L'\\')
04423 break;
04424 }
04425 if (!p[0] || !p[1] || (p[1] == L'.' && !p[2]))
04426 return 1;
04427 }
04428 }
04429 return 0;
04430 }
04431
04432 #define COPY_STAT(src, dest, size_cast) do { \
04433 (dest).st_dev = (src).st_dev; \
04434 (dest).st_ino = (src).st_ino; \
04435 (dest).st_mode = (src).st_mode; \
04436 (dest).st_nlink = (src).st_nlink; \
04437 (dest).st_uid = (src).st_uid; \
04438 (dest).st_gid = (src).st_gid; \
04439 (dest).st_rdev = (src).st_rdev; \
04440 (dest).st_size = size_cast(src).st_size; \
04441 (dest).st_atime = (src).st_atime; \
04442 (dest).st_mtime = (src).st_mtime; \
04443 (dest).st_ctime = (src).st_ctime; \
04444 } while (0)
04445
04446 static time_t filetime_to_unixtime(const FILETIME *ft);
04447
04448 #undef fstat
04449
04450 int
04451 rb_w32_fstat(int fd, struct stat *st)
04452 {
04453 BY_HANDLE_FILE_INFORMATION info;
04454 int ret = fstat(fd, st);
04455
04456 if (ret) return ret;
04457 #ifdef __BORLANDC__
04458 st->st_mode &= ~(S_IWGRP | S_IWOTH);
04459 #endif
04460 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
04461 #ifdef __BORLANDC__
04462 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04463 st->st_mode |= S_IWUSR;
04464 }
04465 #endif
04466 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
04467 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
04468 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
04469 }
04470 return ret;
04471 }
04472
04473
04474 int
04475 rb_w32_fstati64(int fd, struct stati64 *st)
04476 {
04477 BY_HANDLE_FILE_INFORMATION info;
04478 struct stat tmp;
04479 int ret = fstat(fd, &tmp);
04480
04481 if (ret) return ret;
04482 #ifdef __BORLANDC__
04483 tmp.st_mode &= ~(S_IWGRP | S_IWOTH);
04484 #endif
04485 COPY_STAT(tmp, *st, +);
04486 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
04487 #ifdef __BORLANDC__
04488 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04489 st->st_mode |= S_IWUSR;
04490 }
04491 #endif
04492 st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
04493 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
04494 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
04495 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
04496 }
04497 return ret;
04498 }
04499
04500
04501 static time_t
04502 filetime_to_unixtime(const FILETIME *ft)
04503 {
04504 struct timeval tv;
04505
04506 if (filetime_to_timeval(ft, &tv) == (time_t)-1)
04507 return 0;
04508 else
04509 return tv.tv_sec;
04510 }
04511
04512
04513 static unsigned
04514 fileattr_to_unixmode(DWORD attr, const WCHAR *path)
04515 {
04516 unsigned mode = 0;
04517
04518 if (attr & FILE_ATTRIBUTE_READONLY) {
04519 mode |= S_IREAD;
04520 }
04521 else {
04522 mode |= S_IREAD | S_IWRITE | S_IWUSR;
04523 }
04524
04525 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
04526 mode |= S_IFDIR | S_IEXEC;
04527 }
04528 else {
04529 mode |= S_IFREG;
04530 }
04531
04532 if (path && (mode & S_IFREG)) {
04533 const WCHAR *end = path + lstrlenW(path);
04534 while (path < end) {
04535 end = CharPrevW(path, end);
04536 if (*end == L'.') {
04537 if ((_wcsicmp(end, L".bat") == 0) ||
04538 (_wcsicmp(end, L".cmd") == 0) ||
04539 (_wcsicmp(end, L".com") == 0) ||
04540 (_wcsicmp(end, L".exe") == 0)) {
04541 mode |= S_IEXEC;
04542 }
04543 break;
04544 }
04545 }
04546 }
04547
04548 mode |= (mode & 0700) >> 3;
04549 mode |= (mode & 0700) >> 6;
04550
04551 return mode;
04552 }
04553
04554
04555 static int
04556 check_valid_dir(const WCHAR *path)
04557 {
04558 WIN32_FIND_DATAW fd;
04559 HANDLE fh;
04560 WCHAR full[MAX_PATH];
04561 WCHAR *dmy;
04562 WCHAR *p, *q;
04563
04564
04565
04566 if (!(p = wcsstr(path, L"...")))
04567 return 0;
04568 q = p + wcsspn(p, L".");
04569 if ((p == path || wcschr(L":/\\", *(p - 1))) &&
04570 (!*q || wcschr(L":/\\", *q))) {
04571 errno = ENOENT;
04572 return -1;
04573 }
04574
04575
04576
04577 if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) {
04578 errno = map_errno(GetLastError());
04579 return -1;
04580 }
04581 if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
04582 return 0;
04583
04584 fh = open_dir_handle(path, &fd);
04585 if (fh == INVALID_HANDLE_VALUE)
04586 return -1;
04587 FindClose(fh);
04588 return 0;
04589 }
04590
04591
04592 static int
04593 winnt_stat(const WCHAR *path, struct stati64 *st)
04594 {
04595 HANDLE h;
04596 WIN32_FIND_DATAW wfd;
04597 WIN32_FILE_ATTRIBUTE_DATA wfa;
04598 const WCHAR *p = path;
04599
04600 memset(st, 0, sizeof(*st));
04601 st->st_nlink = 1;
04602
04603 if (wcsncmp(p, L"\\\\?\\", 4) == 0) p += 4;
04604 if (wcspbrk(p, L"?*")) {
04605 errno = ENOENT;
04606 return -1;
04607 }
04608 if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) {
04609 if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
04610 if (check_valid_dir(path)) return -1;
04611 st->st_size = 0;
04612 }
04613 else {
04614 st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow;
04615 }
04616 st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path);
04617 st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
04618 st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
04619 st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
04620 }
04621 else {
04622
04623 int e = GetLastError();
04624
04625 if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
04626 || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
04627 errno = map_errno(e);
04628 return -1;
04629 }
04630
04631
04632 h = FindFirstFileW(path, &wfd);
04633 if (h != INVALID_HANDLE_VALUE) {
04634 FindClose(h);
04635 st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
04636 st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
04637 st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
04638 st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
04639 st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
04640 }
04641 else {
04642 errno = map_errno(GetLastError());
04643 return -1;
04644 }
04645 }
04646
04647 st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?
04648 towupper(path[0]) - L'A' : _getdrive() - 1;
04649
04650 return 0;
04651 }
04652
04653
04654 int
04655 rb_w32_stat(const char *path, struct stat *st)
04656 {
04657 struct stati64 tmp;
04658
04659 if (rb_w32_stati64(path, &tmp)) return -1;
04660 COPY_STAT(tmp, *st, (_off_t));
04661 return 0;
04662 }
04663
04664
04665 static int
04666 wstati64(const WCHAR *path, struct stati64 *st)
04667 {
04668 const WCHAR *p;
04669 WCHAR *buf1, *s, *end;
04670 int len, size;
04671 int ret;
04672 VALUE v;
04673
04674 if (!path || !st) {
04675 errno = EFAULT;
04676 return -1;
04677 }
04678 size = lstrlenW(path) + 2;
04679 buf1 = ALLOCV_N(WCHAR, v, size);
04680 for (p = path, s = buf1; *p; p++, s++) {
04681 if (*p == L'/')
04682 *s = L'\\';
04683 else
04684 *s = *p;
04685 }
04686 *s = '\0';
04687 len = s - buf1;
04688 if (!len || L'\"' == *(--s)) {
04689 errno = ENOENT;
04690 return -1;
04691 }
04692 end = buf1 + len - 1;
04693
04694 if (isUNCRoot(buf1)) {
04695 if (*end == L'.')
04696 *end = L'\0';
04697 else if (*end != L'\\')
04698 lstrcatW(buf1, L"\\");
04699 }
04700 else if (*end == L'\\' || (buf1 + 1 == end && *end == L':'))
04701 lstrcatW(buf1, L".");
04702
04703 ret = winnt_stat(buf1, st);
04704 if (ret == 0) {
04705 st->st_mode &= ~(S_IWGRP | S_IWOTH);
04706 }
04707 if (v)
04708 ALLOCV_END(v);
04709
04710 return ret;
04711 }
04712
04713
04714 int
04715 rb_w32_ustati64(const char *path, struct stati64 *st)
04716 {
04717 WCHAR *wpath;
04718 int ret;
04719
04720 if (!(wpath = utf8_to_wstr(path, NULL)))
04721 return -1;
04722 ret = wstati64(wpath, st);
04723 free(wpath);
04724 return ret;
04725 }
04726
04727
04728 int
04729 rb_w32_stati64(const char *path, struct stati64 *st)
04730 {
04731 WCHAR *wpath;
04732 int ret;
04733
04734 if (!(wpath = filecp_to_wstr(path, NULL)))
04735 return -1;
04736 ret = wstati64(wpath, st);
04737 free(wpath);
04738 return ret;
04739 }
04740
04741
04742 int
04743 rb_w32_access(const char *path, int mode)
04744 {
04745 struct stati64 stat;
04746 if (rb_w32_stati64(path, &stat) != 0)
04747 return -1;
04748 mode <<= 6;
04749 if ((stat.st_mode & mode) != mode) {
04750 errno = EACCES;
04751 return -1;
04752 }
04753 return 0;
04754 }
04755
04756
04757 int
04758 rb_w32_uaccess(const char *path, int mode)
04759 {
04760 struct stati64 stat;
04761 if (rb_w32_ustati64(path, &stat) != 0)
04762 return -1;
04763 mode <<= 6;
04764 if ((stat.st_mode & mode) != mode) {
04765 errno = EACCES;
04766 return -1;
04767 }
04768 return 0;
04769 }
04770
04771
04772 static int
04773 rb_chsize(HANDLE h, off_t size)
04774 {
04775 long upos, lpos, usize, lsize;
04776 int ret = -1;
04777 DWORD e;
04778
04779 if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
04780 (e = GetLastError())) {
04781 errno = map_errno(e);
04782 return -1;
04783 }
04784 usize = (long)(size >> 32);
04785 lsize = (long)size;
04786 if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L &&
04787 (e = GetLastError())) {
04788 errno = map_errno(e);
04789 }
04790 else if (!SetEndOfFile(h)) {
04791 errno = map_errno(GetLastError());
04792 }
04793 else {
04794 ret = 0;
04795 }
04796 SetFilePointer(h, lpos, &upos, SEEK_SET);
04797 return ret;
04798 }
04799
04800
04801 int
04802 rb_w32_truncate(const char *path, off_t length)
04803 {
04804 HANDLE h;
04805 int ret;
04806 h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
04807 if (h == INVALID_HANDLE_VALUE) {
04808 errno = map_errno(GetLastError());
04809 return -1;
04810 }
04811 ret = rb_chsize(h, length);
04812 CloseHandle(h);
04813 return ret;
04814 }
04815
04816
04817 int
04818 rb_w32_ftruncate(int fd, off_t length)
04819 {
04820 HANDLE h;
04821
04822 h = (HANDLE)_get_osfhandle(fd);
04823 if (h == (HANDLE)-1) return -1;
04824 return rb_chsize(h, length);
04825 }
04826
04827 #ifdef __BORLANDC__
04828
04829 off_t
04830 _filelengthi64(int fd)
04831 {
04832 DWORD u, l;
04833 int e;
04834
04835 l = GetFileSize((HANDLE)_get_osfhandle(fd), &u);
04836 if (l == (DWORD)-1L && (e = GetLastError())) {
04837 errno = map_errno(e);
04838 return (off_t)-1;
04839 }
04840 return ((off_t)u << 32) | l;
04841 }
04842
04843
04844 off_t
04845 _lseeki64(int fd, off_t offset, int whence)
04846 {
04847 long u, l;
04848 int e;
04849 HANDLE h = (HANDLE)_get_osfhandle(fd);
04850
04851 if (!h) {
04852 errno = EBADF;
04853 return -1;
04854 }
04855 u = (long)(offset >> 32);
04856 if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L &&
04857 (e = GetLastError())) {
04858 errno = map_errno(e);
04859 return -1;
04860 }
04861 return ((off_t)u << 32) | l;
04862 }
04863 #endif
04864
04865
04866 int
04867 fseeko(FILE *stream, off_t offset, int whence)
04868 {
04869 off_t pos;
04870 switch (whence) {
04871 case SEEK_CUR:
04872 if (fgetpos(stream, (fpos_t *)&pos))
04873 return -1;
04874 pos += offset;
04875 break;
04876 case SEEK_END:
04877 if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1)
04878 return -1;
04879 pos += offset;
04880 break;
04881 default:
04882 pos = offset;
04883 break;
04884 }
04885 return fsetpos(stream, (fpos_t *)&pos);
04886 }
04887
04888
04889 off_t
04890 rb_w32_ftello(FILE *stream)
04891 {
04892 off_t pos;
04893 if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1;
04894 return pos;
04895 }
04896
04897
04898 static long
04899 filetime_to_clock(FILETIME *ft)
04900 {
04901 __int64 qw = ft->dwHighDateTime;
04902 qw <<= 32;
04903 qw |= ft->dwLowDateTime;
04904 qw /= 10000;
04905 return (long) qw;
04906 }
04907
04908
04909 int
04910 rb_w32_times(struct tms *tmbuf)
04911 {
04912 FILETIME create, exit, kernel, user;
04913
04914 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
04915 tmbuf->tms_utime = filetime_to_clock(&user);
04916 tmbuf->tms_stime = filetime_to_clock(&kernel);
04917 tmbuf->tms_cutime = 0;
04918 tmbuf->tms_cstime = 0;
04919 }
04920 else {
04921 tmbuf->tms_utime = clock();
04922 tmbuf->tms_stime = 0;
04923 tmbuf->tms_cutime = 0;
04924 tmbuf->tms_cstime = 0;
04925 }
04926 return 0;
04927 }
04928
04929 #define yield_once() Sleep(0)
04930 #define yield_until(condition) do yield_once(); while (!(condition))
04931
04932
04933 static void
04934 catch_interrupt(void)
04935 {
04936 yield_once();
04937 RUBY_CRITICAL(rb_w32_wait_events(NULL, 0, 0));
04938 }
04939
04940 #if defined __BORLANDC__
04941 #undef read
04942
04943 int
04944 read(int fd, void *buf, size_t size)
04945 {
04946 int ret = _read(fd, buf, size);
04947 if ((ret < 0) && (errno == EPIPE)) {
04948 errno = 0;
04949 ret = 0;
04950 }
04951 catch_interrupt();
04952 return ret;
04953 }
04954 #endif
04955
04956
04957 #define FILE_COUNT _cnt
04958 #define FILE_READPTR _ptr
04959
04960 #undef fgetc
04961
04962 int
04963 rb_w32_getc(FILE* stream)
04964 {
04965 int c;
04966 if (enough_to_get(stream->FILE_COUNT)) {
04967 c = (unsigned char)*stream->FILE_READPTR++;
04968 }
04969 else {
04970 c = _filbuf(stream);
04971 #if defined __BORLANDC__
04972 if ((c == EOF) && (errno == EPIPE)) {
04973 clearerr(stream);
04974 }
04975 #endif
04976 catch_interrupt();
04977 }
04978 return c;
04979 }
04980
04981 #undef fputc
04982
04983 int
04984 rb_w32_putc(int c, FILE* stream)
04985 {
04986 if (enough_to_put(stream->FILE_COUNT)) {
04987 c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
04988 }
04989 else {
04990 c = _flsbuf(c, stream);
04991 catch_interrupt();
04992 }
04993 return c;
04994 }
04995
04996
04997 struct asynchronous_arg_t {
04998
04999 void* stackaddr;
05000 int errnum;
05001
05002
05003 uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv);
05004 uintptr_t self;
05005 int argc;
05006 uintptr_t* argv;
05007 };
05008
05009
05010 static DWORD WINAPI
05011 call_asynchronous(PVOID argp)
05012 {
05013 DWORD ret;
05014 struct asynchronous_arg_t *arg = argp;
05015 arg->stackaddr = &argp;
05016 ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
05017 arg->errnum = errno;
05018 return ret;
05019 }
05020
05021
05022 uintptr_t
05023 rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self,
05024 int argc, uintptr_t* argv, uintptr_t intrval)
05025 {
05026 DWORD val;
05027 BOOL interrupted = FALSE;
05028 HANDLE thr;
05029
05030 RUBY_CRITICAL({
05031 struct asynchronous_arg_t arg;
05032
05033 arg.stackaddr = NULL;
05034 arg.errnum = 0;
05035 arg.func = func;
05036 arg.self = self;
05037 arg.argc = argc;
05038 arg.argv = argv;
05039
05040 thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
05041
05042 if (thr) {
05043 yield_until(arg.stackaddr);
05044
05045 if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
05046 interrupted = TRUE;
05047
05048 if (TerminateThread(thr, intrval)) {
05049 yield_once();
05050 }
05051 }
05052
05053 GetExitCodeThread(thr, &val);
05054 CloseHandle(thr);
05055
05056 if (interrupted) {
05057
05058 MEMORY_BASIC_INFORMATION m;
05059
05060 memset(&m, 0, sizeof(m));
05061 if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
05062 Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
05063 arg.stackaddr, GetLastError()));
05064 }
05065 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
05066 Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
05067 m.AllocationBase, GetLastError()));
05068 }
05069 errno = EINTR;
05070 }
05071 else {
05072 errno = arg.errnum;
05073 }
05074 }
05075 });
05076
05077 if (!thr) {
05078 rb_fatal("failed to launch waiter thread:%ld", GetLastError());
05079 }
05080
05081 return val;
05082 }
05083
05084
05085 char **
05086 rb_w32_get_environ(void)
05087 {
05088 WCHAR *envtop, *env;
05089 char **myenvtop, **myenv;
05090 int num;
05091
05092
05093
05094
05095
05096
05097
05098
05099
05100
05101
05102 envtop = GetEnvironmentStringsW();
05103 for (env = envtop, num = 0; *env; env += lstrlenW(env) + 1)
05104 if (*env != '=') num++;
05105
05106 myenvtop = (char **)malloc(sizeof(char *) * (num + 1));
05107 for (env = envtop, myenv = myenvtop; *env; env += lstrlenW(env) + 1) {
05108 if (*env != '=') {
05109 if (!(*myenv = wstr_to_utf8(env, NULL))) {
05110 break;
05111 }
05112 myenv++;
05113 }
05114 }
05115 *myenv = NULL;
05116 FreeEnvironmentStringsW(envtop);
05117
05118 return myenvtop;
05119 }
05120
05121
05122 void
05123 rb_w32_free_environ(char **env)
05124 {
05125 char **t = env;
05126
05127 while (*t) free(*t++);
05128 free(env);
05129 }
05130
05131
05132 rb_pid_t
05133 rb_w32_getpid(void)
05134 {
05135 return GetCurrentProcessId();
05136 }
05137
05138
05139
05140 rb_pid_t
05141 rb_w32_getppid(void)
05142 {
05143 typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *);
05144 static query_func *pNtQueryInformationProcess = NULL;
05145 rb_pid_t ppid = 0;
05146
05147 if (rb_w32_osver() >= 5) {
05148 if (!pNtQueryInformationProcess)
05149 pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL);
05150 if (pNtQueryInformationProcess) {
05151 struct {
05152 long ExitStatus;
05153 void* PebBaseAddress;
05154 uintptr_t AffinityMask;
05155 uintptr_t BasePriority;
05156 uintptr_t UniqueProcessId;
05157 uintptr_t ParentProcessId;
05158 } pbi;
05159 ULONG len;
05160 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
05161 if (!ret) {
05162 ppid = pbi.ParentProcessId;
05163 }
05164 }
05165 }
05166
05167 return ppid;
05168 }
05169
05170
05171 int
05172 rb_w32_uopen(const char *file, int oflag, ...)
05173 {
05174 WCHAR *wfile;
05175 int ret;
05176 int pmode;
05177
05178 va_list arg;
05179 va_start(arg, oflag);
05180 pmode = va_arg(arg, int);
05181 va_end(arg);
05182
05183 if (!(wfile = utf8_to_wstr(file, NULL)))
05184 return -1;
05185 ret = rb_w32_wopen(wfile, oflag, pmode);
05186 free(wfile);
05187 return ret;
05188 }
05189
05190
05191 static int
05192 check_if_wdir(const WCHAR *wfile)
05193 {
05194 DWORD attr = GetFileAttributesW(wfile);
05195 if (attr == (DWORD)-1L ||
05196 !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
05197 check_valid_dir(wfile)) {
05198 return FALSE;
05199 }
05200 errno = EISDIR;
05201 return TRUE;
05202 }
05203
05204
05205 static int
05206 check_if_dir(const char *file)
05207 {
05208 WCHAR *wfile;
05209 int ret;
05210
05211 if (!(wfile = filecp_to_wstr(file, NULL)))
05212 return FALSE;
05213 ret = check_if_wdir(wfile);
05214 free(wfile);
05215 return ret;
05216 }
05217
05218
05219 int
05220 rb_w32_open(const char *file, int oflag, ...)
05221 {
05222 WCHAR *wfile;
05223 int ret;
05224 int pmode;
05225
05226 va_list arg;
05227 va_start(arg, oflag);
05228 pmode = va_arg(arg, int);
05229 va_end(arg);
05230
05231 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
05232 ret = _open(file, oflag, pmode);
05233 if (ret == -1 && errno == EACCES) check_if_dir(file);
05234 return ret;
05235 }
05236
05237 if (!(wfile = filecp_to_wstr(file, NULL)))
05238 return -1;
05239 ret = rb_w32_wopen(wfile, oflag, pmode);
05240 free(wfile);
05241 return ret;
05242 }
05243
05244 int
05245 rb_w32_wopen(const WCHAR *file, int oflag, ...)
05246 {
05247 char flags = 0;
05248 int fd;
05249 DWORD access;
05250 DWORD create;
05251 DWORD attr = FILE_ATTRIBUTE_NORMAL;
05252 SECURITY_ATTRIBUTES sec;
05253 HANDLE h;
05254
05255 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
05256 va_list arg;
05257 int pmode;
05258 va_start(arg, oflag);
05259 pmode = va_arg(arg, int);
05260 va_end(arg);
05261 fd = _wopen(file, oflag, pmode);
05262 if (fd == -1 && errno == EACCES) check_if_wdir(file);
05263 return fd;
05264 }
05265
05266 sec.nLength = sizeof(sec);
05267 sec.lpSecurityDescriptor = NULL;
05268 if (oflag & O_NOINHERIT) {
05269 sec.bInheritHandle = FALSE;
05270 flags |= FNOINHERIT;
05271 }
05272 else {
05273 sec.bInheritHandle = TRUE;
05274 }
05275 oflag &= ~O_NOINHERIT;
05276
05277
05278 oflag &= ~(O_BINARY | O_TEXT);
05279
05280 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
05281 case O_RDWR:
05282 access = GENERIC_READ | GENERIC_WRITE;
05283 break;
05284 case O_RDONLY:
05285 access = GENERIC_READ;
05286 break;
05287 case O_WRONLY:
05288 access = GENERIC_WRITE;
05289 break;
05290 default:
05291 errno = EINVAL;
05292 return -1;
05293 }
05294 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
05295
05296 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
05297 case O_CREAT:
05298 create = OPEN_ALWAYS;
05299 break;
05300 case 0:
05301 case O_EXCL:
05302 create = OPEN_EXISTING;
05303 break;
05304 case O_CREAT | O_EXCL:
05305 case O_CREAT | O_EXCL | O_TRUNC:
05306 create = CREATE_NEW;
05307 break;
05308 case O_TRUNC:
05309 case O_TRUNC | O_EXCL:
05310 create = TRUNCATE_EXISTING;
05311 break;
05312 case O_CREAT | O_TRUNC:
05313 create = CREATE_ALWAYS;
05314 break;
05315 default:
05316 errno = EINVAL;
05317 return -1;
05318 }
05319 if (oflag & O_CREAT) {
05320 va_list arg;
05321 int pmode;
05322 va_start(arg, oflag);
05323 pmode = va_arg(arg, int);
05324 va_end(arg);
05325
05326 if (!(pmode & S_IWRITE))
05327 attr = FILE_ATTRIBUTE_READONLY;
05328 }
05329 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
05330
05331 if (oflag & O_TEMPORARY) {
05332 attr |= FILE_FLAG_DELETE_ON_CLOSE;
05333 access |= DELETE;
05334 }
05335 oflag &= ~O_TEMPORARY;
05336
05337 if (oflag & _O_SHORT_LIVED)
05338 attr |= FILE_ATTRIBUTE_TEMPORARY;
05339 oflag &= ~_O_SHORT_LIVED;
05340
05341 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
05342 case 0:
05343 break;
05344 case O_SEQUENTIAL:
05345 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
05346 break;
05347 case O_RANDOM:
05348 attr |= FILE_FLAG_RANDOM_ACCESS;
05349 break;
05350 default:
05351 errno = EINVAL;
05352 return -1;
05353 }
05354 oflag &= ~(O_SEQUENTIAL | O_RANDOM);
05355
05356 if (oflag & ~O_APPEND) {
05357 errno = EINVAL;
05358 return -1;
05359 }
05360
05361
05362 RUBY_CRITICAL({
05363 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05364 fd = _open_osfhandle((intptr_t)h, 0);
05365 CloseHandle(h);
05366 });
05367 if (fd == -1) {
05368 errno = EMFILE;
05369 return -1;
05370 }
05371 RUBY_CRITICAL({
05372 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05373 _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
05374 _set_osflags(fd, 0);
05375
05376 h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec,
05377 create, attr, NULL);
05378 if (h == INVALID_HANDLE_VALUE) {
05379 DWORD e = GetLastError();
05380 if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
05381 errno = map_errno(e);
05382 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05383 fd = -1;
05384 goto quit;
05385 }
05386
05387 switch (GetFileType(h)) {
05388 case FILE_TYPE_CHAR:
05389 flags |= FDEV;
05390 break;
05391 case FILE_TYPE_PIPE:
05392 flags |= FPIPE;
05393 break;
05394 case FILE_TYPE_UNKNOWN:
05395 errno = map_errno(GetLastError());
05396 CloseHandle(h);
05397 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05398 fd = -1;
05399 goto quit;
05400 }
05401 if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
05402 flags |= FAPPEND;
05403
05404 _set_osfhnd(fd, (intptr_t)h);
05405 _osfile(fd) = flags | FOPEN;
05406
05407 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05408 quit:
05409 ;
05410 });
05411
05412 return fd;
05413 }
05414
05415
05416 int
05417 rb_w32_fclose(FILE *fp)
05418 {
05419 int fd = fileno(fp);
05420 SOCKET sock = TO_SOCKET(fd);
05421 int save_errno = errno;
05422
05423 if (fflush(fp)) return -1;
05424 if (!is_socket(sock)) {
05425 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
05426 return fclose(fp);
05427 }
05428 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
05429 fclose(fp);
05430 errno = save_errno;
05431 if (closesocket(sock) == SOCKET_ERROR) {
05432 errno = map_errno(WSAGetLastError());
05433 return -1;
05434 }
05435 return 0;
05436 }
05437
05438
05439 int
05440 rb_w32_pipe(int fds[2])
05441 {
05442 static DWORD serial = 0;
05443 char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
05444 char *p;
05445 SECURITY_ATTRIBUTES sec;
05446 HANDLE hRead, hWrite, h;
05447 int fdRead, fdWrite;
05448 int ret;
05449
05450
05451 if (!cancel_io)
05452 return _pipe(fds, 65536L, _O_NOINHERIT);
05453
05454 p = strchr(name, '0');
05455 snprintf(p, strlen(p) + 1, "%"PRI_PIDT_PREFIX"x-%lx", rb_w32_getpid(), serial++);
05456
05457 sec.nLength = sizeof(sec);
05458 sec.lpSecurityDescriptor = NULL;
05459 sec.bInheritHandle = FALSE;
05460
05461 RUBY_CRITICAL({
05462 hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
05463 0, 2, 65536, 65536, 0, &sec);
05464 });
05465 if (hRead == INVALID_HANDLE_VALUE) {
05466 DWORD err = GetLastError();
05467 if (err == ERROR_PIPE_BUSY)
05468 errno = EMFILE;
05469 else
05470 errno = map_errno(GetLastError());
05471 return -1;
05472 }
05473
05474 RUBY_CRITICAL({
05475 hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
05476 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
05477 });
05478 if (hWrite == INVALID_HANDLE_VALUE) {
05479 errno = map_errno(GetLastError());
05480 CloseHandle(hRead);
05481 return -1;
05482 }
05483
05484 RUBY_CRITICAL(do {
05485 ret = 0;
05486 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05487 fdRead = _open_osfhandle((intptr_t)h, 0);
05488 CloseHandle(h);
05489 if (fdRead == -1) {
05490 errno = EMFILE;
05491 CloseHandle(hWrite);
05492 CloseHandle(hRead);
05493 ret = -1;
05494 break;
05495 }
05496
05497 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock)));
05498 _set_osfhnd(fdRead, (intptr_t)hRead);
05499 _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
05500 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock)));
05501 } while (0));
05502 if (ret)
05503 return ret;
05504
05505 RUBY_CRITICAL(do {
05506 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05507 fdWrite = _open_osfhandle((intptr_t)h, 0);
05508 CloseHandle(h);
05509 if (fdWrite == -1) {
05510 errno = EMFILE;
05511 CloseHandle(hWrite);
05512 ret = -1;
05513 break;
05514 }
05515 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock)));
05516 _set_osfhnd(fdWrite, (intptr_t)hWrite);
05517 _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
05518 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock)));
05519 } while (0));
05520 if (ret) {
05521 rb_w32_close(fdRead);
05522 return ret;
05523 }
05524
05525 fds[0] = fdRead;
05526 fds[1] = fdWrite;
05527
05528 return 0;
05529 }
05530
05531
05532 static struct constat *
05533 constat_handle(HANDLE h)
05534 {
05535 st_data_t data;
05536 struct constat *p;
05537 if (!conlist) {
05538 conlist = st_init_numtable();
05539 }
05540 if (st_lookup(conlist, (st_data_t)h, &data)) {
05541 p = (struct constat *)data;
05542 }
05543 else {
05544 CONSOLE_SCREEN_BUFFER_INFO csbi;
05545 p = ALLOC(struct constat);
05546 p->vt100.state = constat_init;
05547 p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05548 p->vt100.saved.X = p->vt100.saved.Y = 0;
05549 if (GetConsoleScreenBufferInfo(h, &csbi)) {
05550 p->vt100.attr = csbi.wAttributes;
05551 }
05552 st_insert(conlist, (st_data_t)h, (st_data_t)p);
05553 }
05554 return p;
05555 }
05556
05557
05558 static void
05559 constat_reset(HANDLE h)
05560 {
05561 st_data_t data;
05562 struct constat *p;
05563 if (!conlist) return;
05564 if (!st_lookup(conlist, (st_data_t)h, &data)) return;
05565 p = (struct constat *)data;
05566 p->vt100.state = constat_init;
05567 }
05568
05569
05570 static DWORD
05571 constat_attr(int count, const int *seq, DWORD attr, DWORD default_attr)
05572 {
05573 #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
05574 #define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
05575 DWORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
05576 int rev = 0;
05577
05578 if (!count) return attr;
05579 while (count-- > 0) {
05580 switch (*seq++) {
05581 case 0:
05582 attr = default_attr;
05583 rev = 0;
05584 bold = 0;
05585 break;
05586 case 1:
05587 bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
05588 break;
05589 case 4:
05590 #ifndef COMMON_LVB_UNDERSCORE
05591 #define COMMON_LVB_UNDERSCORE 0x8000
05592 #endif
05593 attr |= COMMON_LVB_UNDERSCORE;
05594 break;
05595 case 7:
05596 rev = 1;
05597 break;
05598
05599 case 30:
05600 attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
05601 break;
05602 case 17:
05603 case 31:
05604 attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED;
05605 break;
05606 case 18:
05607 case 32:
05608 attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN;
05609 break;
05610 case 19:
05611 case 33:
05612 attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05613 break;
05614 case 20:
05615 case 34:
05616 attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE;
05617 break;
05618 case 21:
05619 case 35:
05620 attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
05621 break;
05622 case 22:
05623 case 36:
05624 attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
05625 break;
05626 case 23:
05627 case 37:
05628 attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05629 break;
05630
05631 case 40:
05632 attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
05633 break;
05634 case 41:
05635 attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED;
05636 break;
05637 case 42:
05638 attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN;
05639 break;
05640 case 43:
05641 attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
05642 break;
05643 case 44:
05644 attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE;
05645 break;
05646 case 45:
05647 attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
05648 break;
05649 case 46:
05650 attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN;
05651 break;
05652 case 47:
05653 attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
05654 break;
05655 }
05656 }
05657 if (rev) {
05658 attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) |
05659 ((attr & FOREGROUND_MASK) << 4) |
05660 ((attr & BACKGROUND_MASK) >> 4);
05661 }
05662 return attr | bold;
05663 }
05664
05665
05666 static void
05667 constat_apply(HANDLE handle, struct constat *s, WCHAR w)
05668 {
05669 CONSOLE_SCREEN_BUFFER_INFO csbi;
05670 const int *seq = s->vt100.seq;
05671 int count = s->vt100.state;
05672 int arg1 = 1;
05673 COORD pos;
05674 DWORD written;
05675
05676 if (!GetConsoleScreenBufferInfo(handle, &csbi)) return;
05677 if (count > 0 && seq[0] > 0) arg1 = seq[0];
05678 switch (w) {
05679 case L'm':
05680 SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr));
05681 break;
05682 case L'F':
05683 csbi.dwCursorPosition.X = 0;
05684 case L'A':
05685 csbi.dwCursorPosition.Y -= arg1;
05686 if (csbi.dwCursorPosition.Y < 0)
05687 csbi.dwCursorPosition.Y = 0;
05688 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05689 break;
05690 case L'E':
05691 csbi.dwCursorPosition.X = 0;
05692 case L'B':
05693 case L'e':
05694 csbi.dwCursorPosition.Y += arg1;
05695 if (csbi.dwCursorPosition.Y >= csbi.dwSize.Y)
05696 csbi.dwCursorPosition.Y = csbi.dwSize.Y;
05697 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05698 break;
05699 case L'C':
05700 csbi.dwCursorPosition.X += arg1;
05701 if (csbi.dwCursorPosition.X >= csbi.dwSize.X)
05702 csbi.dwCursorPosition.X = csbi.dwSize.X;
05703 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05704 break;
05705 case L'D':
05706 csbi.dwCursorPosition.X -= arg1;
05707 if (csbi.dwCursorPosition.X < 0)
05708 csbi.dwCursorPosition.X = 0;
05709 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05710 break;
05711 case L'G':
05712 case L'`':
05713 csbi.dwCursorPosition.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
05714 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05715 break;
05716 case L'd':
05717 csbi.dwCursorPosition.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
05718 SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05719 break;
05720 case L'H':
05721 case L'f':
05722 pos.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
05723 if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1;
05724 pos.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
05725 SetConsoleCursorPosition(handle, pos);
05726 break;
05727 case L'J':
05728 switch (arg1) {
05729 case 0:
05730 FillConsoleOutputCharacterW(handle, L' ',
05731 csbi.dwSize.X * (csbi.dwSize.Y - csbi.dwCursorPosition.Y) - csbi.dwCursorPosition.X,
05732 csbi.dwCursorPosition, &written);
05733 break;
05734 case 1:
05735 pos.X = 0;
05736 pos.Y = csbi.dwCursorPosition.Y;
05737 FillConsoleOutputCharacterW(handle, L' ',
05738 csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X,
05739 pos, &written);
05740 break;
05741 case 2:
05742 pos.X = 0;
05743 pos.Y = 0;
05744 FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X * csbi.dwSize.Y, pos, &written);
05745 break;
05746 }
05747 break;
05748 case L'K':
05749 switch (arg1) {
05750 case 0:
05751 FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written);
05752 break;
05753 case 1:
05754 pos.X = 0;
05755 pos.Y = csbi.dwCursorPosition.Y;
05756 FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written);
05757 break;
05758 case 2:
05759 pos.X = 0;
05760 pos.Y = csbi.dwCursorPosition.Y;
05761 FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written);
05762 break;
05763 }
05764 break;
05765 case L's':
05766 s->vt100.saved = csbi.dwCursorPosition;
05767 break;
05768 case L'u':
05769 SetConsoleCursorPosition(handle, s->vt100.saved);
05770 break;
05771 case L'h':
05772 if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
05773 CONSOLE_CURSOR_INFO cci;
05774 GetConsoleCursorInfo(handle, &cci);
05775 cci.bVisible = TRUE;
05776 SetConsoleCursorInfo(handle, &cci);
05777 }
05778 break;
05779 case L'l':
05780 if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
05781 CONSOLE_CURSOR_INFO cci;
05782 GetConsoleCursorInfo(handle, &cci);
05783 cci.bVisible = FALSE;
05784 SetConsoleCursorInfo(handle, &cci);
05785 }
05786 break;
05787 }
05788 }
05789
05790
05791 static long
05792 constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
05793 {
05794 const WCHAR *ptr = *ptrp;
05795 long rest, len = *lenp;
05796 while (len-- > 0) {
05797 WCHAR wc = *ptr++;
05798 if (wc == 0x1b) {
05799 rest = *lenp - len - 1;
05800 s->vt100.state = constat_esc;
05801 }
05802 else if (s->vt100.state == constat_esc && wc == L'[') {
05803 rest = *lenp - len - 1;
05804 if (rest > 0) --rest;
05805 s->vt100.state = constat_seq;
05806 s->vt100.seq[0] = 0;
05807 }
05808 else if (s->vt100.state >= constat_seq) {
05809 if (wc >= L'0' && wc <= L'9') {
05810 if (s->vt100.state < (int)numberof(s->vt100.seq)) {
05811 int *seq = &s->vt100.seq[s->vt100.state];
05812 *seq = (*seq * 10) + (wc - L'0');
05813 }
05814 }
05815 else if (s->vt100.state == constat_seq && s->vt100.seq[0] == 0 && wc == L'?') {
05816 s->vt100.seq[s->vt100.state++] = -1;
05817 }
05818 else {
05819 do {
05820 if (++s->vt100.state < (int)numberof(s->vt100.seq)) {
05821 s->vt100.seq[s->vt100.state] = 0;
05822 }
05823 else {
05824 s->vt100.state = (int)numberof(s->vt100.seq);
05825 }
05826 } while (0);
05827 if (wc != L';') {
05828 constat_apply(h, s, wc);
05829 s->vt100.state = constat_init;
05830 }
05831 }
05832 rest = 0;
05833 }
05834 else {
05835 continue;
05836 }
05837 *ptrp = ptr;
05838 *lenp = len;
05839 return rest;
05840 }
05841 len = *lenp;
05842 *ptrp = ptr;
05843 *lenp = 0;
05844 return len;
05845 }
05846
05847
05848
05849 int
05850 rb_w32_close(int fd)
05851 {
05852 SOCKET sock = TO_SOCKET(fd);
05853 int save_errno = errno;
05854
05855 if (!is_socket(sock)) {
05856 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
05857 constat_delete((HANDLE)sock);
05858 return _close(fd);
05859 }
05860 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
05861 socklist_delete(&sock, NULL);
05862 _close(fd);
05863 errno = save_errno;
05864 if (closesocket(sock) == SOCKET_ERROR) {
05865 errno = map_errno(WSAGetLastError());
05866 return -1;
05867 }
05868 return 0;
05869 }
05870
05871 static int
05872 setup_overlapped(OVERLAPPED *ol, int fd)
05873 {
05874 memset(ol, 0, sizeof(*ol));
05875 if (!(_osfile(fd) & (FDEV | FPIPE))) {
05876 LONG high = 0;
05877 DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
05878 DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
05879 #ifndef INVALID_SET_FILE_POINTER
05880 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
05881 #endif
05882 if (low == INVALID_SET_FILE_POINTER) {
05883 DWORD err = GetLastError();
05884 if (err != NO_ERROR) {
05885 errno = map_errno(err);
05886 return -1;
05887 }
05888 }
05889 ol->Offset = low;
05890 ol->OffsetHigh = high;
05891 }
05892 ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
05893 if (!ol->hEvent) {
05894 errno = map_errno(GetLastError());
05895 return -1;
05896 }
05897 return 0;
05898 }
05899
05900 static void
05901 finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
05902 {
05903 CloseHandle(ol->hEvent);
05904
05905 if (!(_osfile(fd) & (FDEV | FPIPE))) {
05906 LONG high = ol->OffsetHigh;
05907 DWORD low = ol->Offset + size;
05908 if (low < ol->Offset)
05909 ++high;
05910 SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
05911 }
05912 }
05913
05914 #undef read
05915
05916 ssize_t
05917 rb_w32_read(int fd, void *buf, size_t size)
05918 {
05919 SOCKET sock = TO_SOCKET(fd);
05920 DWORD read;
05921 DWORD wait;
05922 DWORD err;
05923 size_t len;
05924 size_t ret;
05925 OVERLAPPED ol, *pol = NULL;
05926 BOOL isconsole;
05927 BOOL islineinput = FALSE;
05928 int start = 0;
05929
05930 if (is_socket(sock))
05931 return rb_w32_recv(fd, buf, size, 0);
05932
05933
05934 if (_get_osfhandle(fd) == -1) {
05935 return -1;
05936 }
05937
05938 if (_osfile(fd) & FTEXT) {
05939 return _read(fd, buf, size);
05940 }
05941
05942 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05943
05944 if (!size || _osfile(fd) & FEOFLAG) {
05945 _set_osflags(fd, _osfile(fd) & ~FEOFLAG);
05946 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05947 return 0;
05948 }
05949
05950 ret = 0;
05951 isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
05952 if (isconsole) {
05953 DWORD mode;
05954 GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
05955 islineinput = (mode & ENABLE_LINE_INPUT) != 0;
05956 }
05957 retry:
05958
05959 if (isconsole) {
05960 constat_reset((HANDLE)_osfhnd(fd));
05961 if (start)
05962 len = 1;
05963 else {
05964 len = 0;
05965 start = 1;
05966 }
05967 }
05968 else
05969 len = size;
05970 size -= len;
05971
05972
05973 if (cancel_io) {
05974 if (setup_overlapped(&ol, fd)) {
05975 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05976 return -1;
05977 }
05978
05979 pol = &ol;
05980 }
05981
05982 if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
05983 err = GetLastError();
05984 if (err != ERROR_IO_PENDING) {
05985 if (pol) CloseHandle(ol.hEvent);
05986 if (err == ERROR_ACCESS_DENIED)
05987 errno = EBADF;
05988 else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
05989 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05990 return 0;
05991 }
05992 else
05993 errno = map_errno(err);
05994
05995 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05996 return -1;
05997 }
05998
05999 if (pol) {
06000 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
06001 if (wait != WAIT_OBJECT_0) {
06002 if (wait == WAIT_OBJECT_0 + 1)
06003 errno = EINTR;
06004 else
06005 errno = map_errno(GetLastError());
06006 CloseHandle(ol.hEvent);
06007 cancel_io((HANDLE)_osfhnd(fd));
06008 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06009 return -1;
06010 }
06011
06012 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
06013 (err = GetLastError()) != ERROR_HANDLE_EOF) {
06014 int ret = 0;
06015 if (err != ERROR_BROKEN_PIPE) {
06016 errno = map_errno(err);
06017 ret = -1;
06018 }
06019 CloseHandle(ol.hEvent);
06020 cancel_io((HANDLE)_osfhnd(fd));
06021 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06022 return ret;
06023 }
06024 }
06025 }
06026 else {
06027 err = GetLastError();
06028 errno = map_errno(err);
06029 }
06030
06031 if (pol) {
06032 finish_overlapped(&ol, fd, read);
06033 }
06034
06035 ret += read;
06036 if (read >= len) {
06037 buf = (char *)buf + read;
06038 if (err != ERROR_OPERATION_ABORTED &&
06039 !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0)
06040 goto retry;
06041 }
06042 if (read == 0)
06043 _set_osflags(fd, _osfile(fd) | FEOFLAG);
06044
06045
06046 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06047
06048 return ret;
06049 }
06050
06051 #undef write
06052
06053 ssize_t
06054 rb_w32_write(int fd, const void *buf, size_t size)
06055 {
06056 SOCKET sock = TO_SOCKET(fd);
06057 DWORD written;
06058 DWORD wait;
06059 DWORD err;
06060 size_t len;
06061 size_t ret;
06062 OVERLAPPED ol, *pol = NULL;
06063
06064 if (is_socket(sock))
06065 return rb_w32_send(fd, buf, size, 0);
06066
06067
06068 if (_get_osfhandle(fd) == -1) {
06069 return -1;
06070 }
06071
06072 if ((_osfile(fd) & FTEXT) &&
06073 (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) {
06074 return _write(fd, buf, size);
06075 }
06076
06077 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
06078
06079 if (!size || _osfile(fd) & FEOFLAG) {
06080 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06081 return 0;
06082 }
06083
06084 ret = 0;
06085 retry:
06086
06087 len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size;
06088 size -= len;
06089
06090
06091 if (cancel_io) {
06092 if (setup_overlapped(&ol, fd)) {
06093 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06094 return -1;
06095 }
06096
06097 pol = &ol;
06098 }
06099
06100 if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) {
06101 err = GetLastError();
06102 if (err != ERROR_IO_PENDING) {
06103 if (pol) CloseHandle(ol.hEvent);
06104 if (err == ERROR_ACCESS_DENIED)
06105 errno = EBADF;
06106 else
06107 errno = map_errno(err);
06108
06109 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06110 return -1;
06111 }
06112
06113 if (pol) {
06114 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
06115 if (wait != WAIT_OBJECT_0) {
06116 if (wait == WAIT_OBJECT_0 + 1)
06117 errno = EINTR;
06118 else
06119 errno = map_errno(GetLastError());
06120 CloseHandle(ol.hEvent);
06121 cancel_io((HANDLE)_osfhnd(fd));
06122 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06123 return -1;
06124 }
06125
06126 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written,
06127 TRUE)) {
06128 errno = map_errno(err);
06129 CloseHandle(ol.hEvent);
06130 cancel_io((HANDLE)_osfhnd(fd));
06131 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06132 return -1;
06133 }
06134 }
06135 }
06136
06137 if (pol) {
06138 finish_overlapped(&ol, fd, written);
06139 }
06140
06141 ret += written;
06142 if (written == len) {
06143 buf = (const char *)buf + len;
06144 if (size > 0)
06145 goto retry;
06146 }
06147
06148 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06149
06150 return ret;
06151 }
06152
06153
06154 long
06155 rb_w32_write_console(uintptr_t strarg, int fd)
06156 {
06157 static int disable;
06158 HANDLE handle;
06159 DWORD dwMode, reslen;
06160 VALUE str = strarg;
06161 rb_encoding *utf16 = rb_enc_find("UTF-16LE");
06162 const WCHAR *ptr, *next;
06163 struct constat *s;
06164 long len;
06165
06166 if (disable) return -1L;
06167 handle = (HANDLE)_osfhnd(fd);
06168 if (!GetConsoleMode(handle, &dwMode) ||
06169 !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE"))
06170 return -1L;
06171
06172 str = rb_str_encode(str, rb_enc_from_encoding(utf16),
06173 ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
06174 ptr = (const WCHAR *)RSTRING_PTR(str);
06175 len = RSTRING_LEN(str) / sizeof(WCHAR);
06176 s = constat_handle(handle);
06177 while (len > 0) {
06178 long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
06179 if (curlen > 0) {
06180 if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) {
06181 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
06182 disable = TRUE;
06183 return -1L;
06184 }
06185 }
06186 ptr = next;
06187 }
06188 RB_GC_GUARD(str);
06189 return (long)reslen;
06190 }
06191
06192
06193 static int
06194 unixtime_to_filetime(time_t time, FILETIME *ft)
06195 {
06196 ULARGE_INTEGER tmp;
06197
06198 tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
06199 ft->dwLowDateTime = tmp.LowPart;
06200 ft->dwHighDateTime = tmp.HighPart;
06201 return 0;
06202 }
06203
06204
06205 static int
06206 wutime(const WCHAR *path, const struct utimbuf *times)
06207 {
06208 HANDLE hFile;
06209 FILETIME atime, mtime;
06210 struct stati64 stat;
06211 int ret = 0;
06212
06213 if (wstati64(path, &stat)) {
06214 return -1;
06215 }
06216
06217 if (times) {
06218 if (unixtime_to_filetime(times->actime, &atime)) {
06219 return -1;
06220 }
06221 if (unixtime_to_filetime(times->modtime, &mtime)) {
06222 return -1;
06223 }
06224 }
06225 else {
06226 GetSystemTimeAsFileTime(&atime);
06227 mtime = atime;
06228 }
06229
06230 RUBY_CRITICAL({
06231 const DWORD attr = GetFileAttributesW(path);
06232 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
06233 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
06234 hFile = CreateFileW(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
06235 FILE_FLAG_BACKUP_SEMANTICS, 0);
06236 if (hFile == INVALID_HANDLE_VALUE) {
06237 errno = map_errno(GetLastError());
06238 ret = -1;
06239 }
06240 else {
06241 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
06242 errno = map_errno(GetLastError());
06243 ret = -1;
06244 }
06245 CloseHandle(hFile);
06246 }
06247 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
06248 SetFileAttributesW(path, attr);
06249 });
06250
06251 return ret;
06252 }
06253
06254
06255 int
06256 rb_w32_uutime(const char *path, const struct utimbuf *times)
06257 {
06258 WCHAR *wpath;
06259 int ret;
06260
06261 if (!(wpath = utf8_to_wstr(path, NULL)))
06262 return -1;
06263 ret = wutime(wpath, times);
06264 free(wpath);
06265 return ret;
06266 }
06267
06268
06269 int
06270 rb_w32_utime(const char *path, const struct utimbuf *times)
06271 {
06272 WCHAR *wpath;
06273 int ret;
06274
06275 if (!(wpath = filecp_to_wstr(path, NULL)))
06276 return -1;
06277 ret = wutime(wpath, times);
06278 free(wpath);
06279 return ret;
06280 }
06281
06282
06283 int
06284 rb_w32_uchdir(const char *path)
06285 {
06286 WCHAR *wpath;
06287 int ret;
06288
06289 if (!(wpath = utf8_to_wstr(path, NULL)))
06290 return -1;
06291 ret = _wchdir(wpath);
06292 free(wpath);
06293 return ret;
06294 }
06295
06296
06297 static int
06298 wmkdir(const WCHAR *wpath, int mode)
06299 {
06300 int ret = -1;
06301
06302 RUBY_CRITICAL(do {
06303 if (CreateDirectoryW(wpath, NULL) == FALSE) {
06304 errno = map_errno(GetLastError());
06305 break;
06306 }
06307 if (_wchmod(wpath, mode) == -1) {
06308 RemoveDirectoryW(wpath);
06309 break;
06310 }
06311 ret = 0;
06312 } while (0));
06313 return ret;
06314 }
06315
06316
06317 int
06318 rb_w32_umkdir(const char *path, int mode)
06319 {
06320 WCHAR *wpath;
06321 int ret;
06322
06323 if (!(wpath = utf8_to_wstr(path, NULL)))
06324 return -1;
06325 ret = wmkdir(wpath, mode);
06326 free(wpath);
06327 return ret;
06328 }
06329
06330
06331 int
06332 rb_w32_mkdir(const char *path, int mode)
06333 {
06334 WCHAR *wpath;
06335 int ret;
06336
06337 if (!(wpath = filecp_to_wstr(path, NULL)))
06338 return -1;
06339 ret = wmkdir(wpath, mode);
06340 free(wpath);
06341 return ret;
06342 }
06343
06344
06345 static int
06346 wrmdir(const WCHAR *wpath)
06347 {
06348 int ret = 0;
06349 RUBY_CRITICAL({
06350 const DWORD attr = GetFileAttributesW(wpath);
06351 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06352 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
06353 }
06354 if (RemoveDirectoryW(wpath) == FALSE) {
06355 errno = map_errno(GetLastError());
06356 ret = -1;
06357 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06358 SetFileAttributesW(wpath, attr);
06359 }
06360 }
06361 });
06362 return ret;
06363 }
06364
06365
06366 int
06367 rb_w32_rmdir(const char *path)
06368 {
06369 WCHAR *wpath;
06370 int ret;
06371
06372 if (!(wpath = filecp_to_wstr(path, NULL)))
06373 return -1;
06374 ret = wrmdir(wpath);
06375 free(wpath);
06376 return ret;
06377 }
06378
06379
06380 int
06381 rb_w32_urmdir(const char *path)
06382 {
06383 WCHAR *wpath;
06384 int ret;
06385
06386 if (!(wpath = utf8_to_wstr(path, NULL)))
06387 return -1;
06388 ret = wrmdir(wpath);
06389 free(wpath);
06390 return ret;
06391 }
06392
06393
06394 static int
06395 wunlink(const WCHAR *path)
06396 {
06397 int ret = 0;
06398 RUBY_CRITICAL({
06399 const DWORD attr = GetFileAttributesW(path);
06400 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06401 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
06402 }
06403 if (!DeleteFileW(path)) {
06404 errno = map_errno(GetLastError());
06405 ret = -1;
06406 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06407 SetFileAttributesW(path, attr);
06408 }
06409 }
06410 });
06411 return ret;
06412 }
06413
06414
06415 int
06416 rb_w32_uunlink(const char *path)
06417 {
06418 WCHAR *wpath;
06419 int ret;
06420
06421 if (!(wpath = utf8_to_wstr(path, NULL)))
06422 return -1;
06423 ret = wunlink(wpath);
06424 free(wpath);
06425 return ret;
06426 }
06427
06428
06429 int
06430 rb_w32_unlink(const char *path)
06431 {
06432 WCHAR *wpath;
06433 int ret;
06434
06435 if (!(wpath = filecp_to_wstr(path, NULL)))
06436 return -1;
06437 ret = wunlink(wpath);
06438 free(wpath);
06439 return ret;
06440 }
06441
06442
06443 int
06444 rb_w32_uchmod(const char *path, int mode)
06445 {
06446 WCHAR *wpath;
06447 int ret;
06448
06449 if (!(wpath = utf8_to_wstr(path, NULL)))
06450 return -1;
06451 ret = _wchmod(wpath, mode);
06452 free(wpath);
06453 return ret;
06454 }
06455
06456 #if !defined(__BORLANDC__)
06457
06458 int
06459 rb_w32_isatty(int fd)
06460 {
06461 DWORD mode;
06462
06463
06464 if (_get_osfhandle(fd) == -1) {
06465 return 0;
06466 }
06467 if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) {
06468 errno = ENOTTY;
06469 return 0;
06470 }
06471 return 1;
06472 }
06473 #endif
06474
06475
06476
06477
06478
06479 #ifdef __BORLANDC__
06480
06481 static int
06482 too_many_files(void)
06483 {
06484 FILE *f;
06485 for (f = _streams; f < _streams + _nfile; f++) {
06486 if (f->fd < 0) return 0;
06487 }
06488 return 1;
06489 }
06490
06491 #undef fopen
06492
06493 FILE *
06494 rb_w32_fopen(const char *path, const char *mode)
06495 {
06496 FILE *f = (errno = 0, fopen(path, mode));
06497 if (f == NULL && errno == 0) {
06498 if (too_many_files())
06499 errno = EMFILE;
06500 }
06501 return f;
06502 }
06503
06504
06505 FILE *
06506 rb_w32_fdopen(int handle, const char *type)
06507 {
06508 FILE *f = (errno = 0, _fdopen(handle, (char *)type));
06509 if (f == NULL && errno == 0) {
06510 if (handle < 0)
06511 errno = EBADF;
06512 else if (too_many_files())
06513 errno = EMFILE;
06514 }
06515 return f;
06516 }
06517
06518
06519 FILE *
06520 rb_w32_fsopen(const char *path, const char *mode, int shflags)
06521 {
06522 FILE *f = (errno = 0, _fsopen(path, mode, shflags));
06523 if (f == NULL && errno == 0) {
06524 if (too_many_files())
06525 errno = EMFILE;
06526 }
06527 return f;
06528 }
06529 #endif
06530
06531 #if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
06532 extern long _ftol(double);
06533
06534 long
06535 _ftol2(double d)
06536 {
06537 return _ftol(d);
06538 }
06539
06540
06541 long
06542 _ftol2_sse(double d)
06543 {
06544 return _ftol(d);
06545 }
06546 #endif
06547
06548 #ifndef signbit
06549
06550 int
06551 signbit(double x)
06552 {
06553 int *ip = (int *)(&x + 1) - 1;
06554 return *ip < 0;
06555 }
06556 #endif
06557
06558
06559 const char * WSAAPI
06560 rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
06561 {
06562 typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t);
06563 inet_ntop_t *pInetNtop;
06564 pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL);
06565 if (pInetNtop) {
06566 return pInetNtop(af, (void *)addr, numaddr, numaddr_len);
06567 }
06568 else {
06569 struct in_addr in;
06570 memcpy(&in.s_addr, addr, sizeof(in.s_addr));
06571 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
06572 }
06573 return numaddr;
06574 }
06575
06576
06577 char
06578 rb_w32_fd_is_text(int fd)
06579 {
06580 return _osfile(fd) & FTEXT;
06581 }
06582
06583 #if RUBY_MSVCRT_VERSION < 80 && !defined(__MINGW64__)
06584
06585 static int
06586 unixtime_to_systemtime(const time_t t, SYSTEMTIME *st)
06587 {
06588 FILETIME ft;
06589 if (unixtime_to_filetime(t, &ft)) return -1;
06590 if (!FileTimeToSystemTime(&ft, st)) return -1;
06591 return 0;
06592 }
06593
06594
06595 static void
06596 systemtime_to_tm(const SYSTEMTIME *st, struct tm *t)
06597 {
06598 int y = st->wYear, m = st->wMonth, d = st->wDay;
06599 t->tm_sec = st->wSecond;
06600 t->tm_min = st->wMinute;
06601 t->tm_hour = st->wHour;
06602 t->tm_mday = st->wDay;
06603 t->tm_mon = st->wMonth - 1;
06604 t->tm_year = y - 1900;
06605 t->tm_wday = st->wDayOfWeek;
06606 switch (m) {
06607 case 1:
06608 break;
06609 case 2:
06610 d += 31;
06611 break;
06612 default:
06613 d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
06614 d += ((m - 3) * 153 + 2) / 5;
06615 break;
06616 }
06617 t->tm_yday = d - 1;
06618 }
06619
06620
06621 static int
06622 systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
06623 {
06624 TIME_ZONE_INFORMATION stdtz;
06625 SYSTEMTIME sst;
06626
06627 if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1;
06628 if (!tz) {
06629 GetTimeZoneInformation(&stdtz);
06630 tz = &stdtz;
06631 }
06632 if (tz->StandardBias == tz->DaylightBias) return 0;
06633 if (!tz->StandardDate.wMonth) return 0;
06634 if (!tz->DaylightDate.wMonth) return 0;
06635 if (tz != &stdtz) stdtz = *tz;
06636
06637 stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
06638 if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0;
06639 if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
06640 return 0;
06641 return 1;
06642 }
06643 #endif
06644
06645 #ifdef __MINGW64__
06646 # ifndef MINGW_HAS_SECURE_API
06647 _CRTIMP errno_t __cdecl _gmtime64_s(struct tm* tm, const __time64_t *time);
06648 _CRTIMP errno_t __cdecl _localtime64_s(struct tm* tm, const __time64_t *time);
06649 # endif
06650 # define gmtime_s _gmtime64_s
06651 # define localtime_s _localtime64_s
06652 #endif
06653
06654
06655 struct tm *
06656 gmtime_r(const time_t *tp, struct tm *rp)
06657 {
06658 int e = EINVAL;
06659 if (!tp || !rp) {
06660 error:
06661 errno = e;
06662 return NULL;
06663 }
06664 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
06665 e = gmtime_s(rp, tp);
06666 if (e != 0) goto error;
06667 #else
06668 {
06669 SYSTEMTIME st;
06670 if (unixtime_to_systemtime(*tp, &st)) goto error;
06671 rp->tm_isdst = 0;
06672 systemtime_to_tm(&st, rp);
06673 }
06674 #endif
06675 return rp;
06676 }
06677
06678
06679 struct tm *
06680 localtime_r(const time_t *tp, struct tm *rp)
06681 {
06682 int e = EINVAL;
06683 if (!tp || !rp) {
06684 error:
06685 errno = e;
06686 return NULL;
06687 }
06688 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
06689 e = localtime_s(rp, tp);
06690 if (e) goto error;
06691 #else
06692 {
06693 SYSTEMTIME gst, lst;
06694 if (unixtime_to_systemtime(*tp, &gst)) goto error;
06695 rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
06696 systemtime_to_tm(&lst, rp);
06697 }
06698 #endif
06699 return rp;
06700 }
06701
06702
06703 int
06704 rb_w32_wrap_io_handle(HANDLE h, int flags)
06705 {
06706 BOOL tmp;
06707 int len = sizeof(tmp);
06708 int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (char *)&tmp, &len);
06709 if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
06710 int f = 0;
06711 if (flags & O_NONBLOCK) {
06712 flags &= ~O_NONBLOCK;
06713 f = O_NONBLOCK;
06714 }
06715 socklist_insert((SOCKET)h, f);
06716 }
06717 else if (flags & O_NONBLOCK) {
06718 errno = EINVAL;
06719 return -1;
06720 }
06721 return rb_w32_open_osfhandle((intptr_t)h, flags);
06722 }
06723
06724
06725 int
06726 rb_w32_unwrap_io_handle(int fd)
06727 {
06728 SOCKET sock = TO_SOCKET(fd);
06729 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
06730 if (!is_socket(sock)) {
06731 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
06732 constat_delete((HANDLE)sock);
06733 }
06734 else {
06735 socklist_delete(&sock, NULL);
06736 }
06737 return _close(fd);
06738 }
06739