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