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