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