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 RUBY_CRITICAL({
01044 fRet = CreateProcess(prog, (char *)cmd, psa, psa,
01045 psa->bInheritHandle, dwCreationFlags, NULL, NULL,
01046 &aStartupInfo, &aProcessInformation);
01047 errno = map_errno(GetLastError());
01048 });
01049
01050 if (!fRet) {
01051 child->pid = 0;
01052 return NULL;
01053 }
01054
01055 CloseHandle(aProcessInformation.hThread);
01056
01057 child->hProcess = aProcessInformation.hProcess;
01058 child->pid = (rb_pid_t)aProcessInformation.dwProcessId;
01059
01060 if (!IsWinNT()) {
01061
01062 child->pid = -child->pid;
01063 }
01064
01065 return child;
01066 }
01067
01068 static int
01069 is_batch(const char *cmd)
01070 {
01071 int len = strlen(cmd);
01072 if (len <= 4) return 0;
01073 cmd += len - 4;
01074 if (*cmd++ != '.') return 0;
01075 if (strcasecmp(cmd, "bat") == 0) return 1;
01076 if (strcasecmp(cmd, "cmd") == 0) return 1;
01077 return 0;
01078 }
01079
01080 rb_pid_t
01081 rb_w32_spawn(int mode, const char *cmd, const char *prog)
01082 {
01083 char fbuf[MAXPATHLEN];
01084 char *p = NULL;
01085 const char *shell = NULL;
01086
01087 if (check_spawn_mode(mode)) return -1;
01088
01089 if (prog) {
01090 if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
01091 shell = prog;
01092 }
01093 else {
01094 shell = p;
01095 translate_char(p, '/', '\\');
01096 }
01097 }
01098 else {
01099 int redir = -1;
01100 int nt;
01101 while (ISSPACE(*cmd)) cmd++;
01102 if ((shell = getenv("RUBYSHELL")) && (redir = has_redirection(cmd))) {
01103 char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) + sizeof(" -c ") + 2);
01104 sprintf(tmp, "%s -c \"%s\"", shell, cmd);
01105 cmd = tmp;
01106 }
01107 else if ((shell = getenv("COMSPEC")) &&
01108 (nt = !is_command_com(shell),
01109 (redir < 0 ? has_redirection(cmd) : redir) ||
01110 is_internal_cmd(cmd, nt))) {
01111 char *tmp = ALLOCA_N(char, strlen(shell) + strlen(cmd) + sizeof(" /c ")
01112 + (nt ? 2 : 0));
01113 sprintf(tmp, nt ? "%s /c \"%s\"" : "%s /c %s", shell, cmd);
01114 cmd = tmp;
01115 }
01116 else {
01117 int len = 0, quote = (*cmd == '"') ? '"' : (*cmd == '\'') ? '\'' : 0;
01118 for (prog = cmd + !!quote;; prog = CharNext(prog)) {
01119 if (!*prog) {
01120 len = prog - cmd;
01121 shell = cmd;
01122 break;
01123 }
01124 if ((unsigned char)*prog == quote) {
01125 len = prog++ - cmd - 1;
01126 STRNDUPA(p, cmd + 1, len);
01127 shell = p;
01128 break;
01129 }
01130 if (quote) continue;
01131 if (ISSPACE(*prog) || strchr("<>|*?\"", *prog)) {
01132 len = prog - cmd;
01133 STRNDUPA(p, cmd, len);
01134 shell = p;
01135 break;
01136 }
01137 }
01138 shell = dln_find_exe_r(shell, NULL, fbuf, sizeof(fbuf));
01139 if (!shell) {
01140 shell = p ? p : cmd;
01141 }
01142 else {
01143 len = strlen(shell);
01144 if (strchr(shell, ' ')) quote = -1;
01145 if (shell == fbuf) {
01146 p = fbuf;
01147 }
01148 else if (shell != p && strchr(shell, '/')) {
01149 STRNDUPA(p, shell, len);
01150 shell = p;
01151 }
01152 if (p) translate_char(p, '/', '\\');
01153 if (is_batch(shell)) {
01154 int alen = strlen(prog);
01155 cmd = p = ALLOCA_N(char, len + alen + (quote ? 2 : 0) + 1);
01156 if (quote) *p++ = '"';
01157 memcpy(p, shell, len);
01158 p += len;
01159 if (quote) *p++ = '"';
01160 memcpy(p, prog, alen + 1);
01161 shell = 0;
01162 }
01163 }
01164 }
01165 }
01166
01167 return child_result(CreateChild(cmd, shell, NULL, NULL, NULL, NULL), mode);
01168 }
01169
01170 rb_pid_t
01171 rb_w32_aspawn(int mode, const char *prog, char *const *argv)
01172 {
01173 int c_switch = 0;
01174 size_t len;
01175 BOOL ntcmd = FALSE, tmpnt;
01176 const char *shell;
01177 char *cmd, fbuf[MAXPATHLEN];
01178
01179 if (check_spawn_mode(mode)) return -1;
01180
01181 if (!prog) prog = argv[0];
01182 if ((shell = getenv("COMSPEC")) &&
01183 internal_cmd_match(prog, tmpnt = !is_command_com(shell))) {
01184 ntcmd = tmpnt;
01185 prog = shell;
01186 c_switch = 1;
01187 }
01188 else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) {
01189 if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf));
01190 translate_char(cmd, '/', '\\');
01191 prog = cmd;
01192 }
01193 else if (strchr(prog, '/')) {
01194 len = strlen(prog);
01195 if (len < sizeof(fbuf))
01196 strlcpy(cmd = fbuf, prog, sizeof(fbuf));
01197 else
01198 STRNDUPA(cmd, prog, len);
01199 translate_char(cmd, '/', '\\');
01200 prog = cmd;
01201 }
01202 if (c_switch || is_batch(prog)) {
01203 char *progs[2];
01204 progs[0] = (char *)prog;
01205 progs[1] = NULL;
01206 len = join_argv(NULL, progs, ntcmd);
01207 if (c_switch) len += 3;
01208 else ++argv;
01209 if (argv[0]) len += join_argv(NULL, argv, ntcmd);
01210 cmd = ALLOCA_N(char, len);
01211 join_argv(cmd, progs, ntcmd);
01212 if (c_switch) strlcat(cmd, " /c", len);
01213 if (argv[0]) join_argv(cmd + strlcat(cmd, " ", len), argv, ntcmd);
01214 prog = c_switch ? shell : 0;
01215 }
01216 else {
01217 len = join_argv(NULL, argv, FALSE);
01218 cmd = ALLOCA_N(char, len);
01219 join_argv(cmd, argv, FALSE);
01220 }
01221
01222 return child_result(CreateChild(cmd, prog, NULL, NULL, NULL, NULL), mode);
01223 }
01224
01225 typedef struct _NtCmdLineElement {
01226 struct _NtCmdLineElement *next;
01227 char *str;
01228 int len;
01229 int flags;
01230 } NtCmdLineElement;
01231
01232
01233
01234
01235
01236 #define NTGLOB 0x1 // element contains a wildcard
01237 #define NTMALLOC 0x2 // string in element was malloc'ed
01238 #define NTSTRING 0x4 // element contains a quoted string
01239
01240 static int
01241 insert(const char *path, VALUE vinfo, void *enc)
01242 {
01243 NtCmdLineElement *tmpcurr;
01244 NtCmdLineElement ***tail = (NtCmdLineElement ***)vinfo;
01245
01246 tmpcurr = (NtCmdLineElement *)malloc(sizeof(NtCmdLineElement));
01247 if (!tmpcurr) return -1;
01248 MEMZERO(tmpcurr, NtCmdLineElement, 1);
01249 tmpcurr->len = strlen(path);
01250 tmpcurr->str = strdup(path);
01251 if (!tmpcurr->str) return -1;
01252 tmpcurr->flags |= NTMALLOC;
01253 **tail = tmpcurr;
01254 *tail = &tmpcurr->next;
01255
01256 return 0;
01257 }
01258
01259
01260 static NtCmdLineElement **
01261 cmdglob(NtCmdLineElement *patt, NtCmdLineElement **tail)
01262 {
01263 char buffer[MAXPATHLEN], *buf = buffer;
01264 char *p;
01265 NtCmdLineElement **last = tail;
01266 int status;
01267
01268 if (patt->len >= MAXPATHLEN)
01269 if (!(buf = malloc(patt->len + 1))) return 0;
01270
01271 strlcpy(buf, patt->str, patt->len + 1);
01272 buf[patt->len] = '\0';
01273 for (p = buf; *p; p = CharNext(p))
01274 if (*p == '\\')
01275 *p = '/';
01276 status = ruby_brace_glob(buf, 0, insert, (VALUE)&tail);
01277 if (buf != buffer)
01278 free(buf);
01279
01280 if (status || last == tail) return 0;
01281 if (patt->flags & NTMALLOC)
01282 free(patt->str);
01283 free(patt);
01284 return tail;
01285 }
01286
01287
01288
01289
01290
01291
01292 static int
01293 has_redirection(const char *cmd)
01294 {
01295 char quote = '\0';
01296 const char *ptr;
01297
01298
01299
01300
01301
01302
01303 for (ptr = cmd; *ptr;) {
01304 switch (*ptr) {
01305 case '\'':
01306 case '\"':
01307 if (!quote)
01308 quote = *ptr;
01309 else if (quote == *ptr)
01310 quote = '\0';
01311 ptr++;
01312 break;
01313
01314 case '>':
01315 case '<':
01316 case '|':
01317 case '\n':
01318 if (!quote)
01319 return TRUE;
01320 ptr++;
01321 break;
01322
01323 case '%':
01324 if (*++ptr != '_' && !ISALPHA(*ptr)) break;
01325 while (*++ptr == '_' || ISALNUM(*ptr));
01326 if (*ptr++ == '%') return TRUE;
01327 break;
01328
01329 case '\\':
01330 ptr++;
01331 default:
01332 ptr = CharNext(ptr);
01333 break;
01334 }
01335 }
01336 return FALSE;
01337 }
01338
01339 static inline char *
01340 skipspace(char *ptr)
01341 {
01342 while (ISSPACE(*ptr))
01343 ptr++;
01344 return ptr;
01345 }
01346
01347 int
01348 rb_w32_cmdvector(const char *cmd, char ***vec)
01349 {
01350 int globbing, len;
01351 int elements, strsz, done;
01352 int slashes, escape;
01353 char *ptr, *base, *buffer, *cmdline;
01354 char **vptr;
01355 char quote;
01356 NtCmdLineElement *curr, **tail;
01357 NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead;
01358
01359
01360
01361
01362
01363 while (ISSPACE(*cmd))
01364 cmd++;
01365 if (!*cmd) {
01366 *vec = NULL;
01367 return 0;
01368 }
01369
01370 ptr = cmdline = strdup(cmd);
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381 while (*(ptr = skipspace(ptr))) {
01382 base = ptr;
01383 quote = slashes = globbing = escape = 0;
01384 for (done = 0; !done && *ptr; ) {
01385
01386
01387
01388
01389
01390
01391 switch (*ptr) {
01392 case '\\':
01393 if (quote != '\'') slashes++;
01394 break;
01395
01396 case ' ':
01397 case '\t':
01398 case '\n':
01399
01400
01401
01402
01403
01404 if (!quote) {
01405 *ptr = 0;
01406 done = 1;
01407 }
01408 break;
01409
01410 case '*':
01411 case '?':
01412 case '[':
01413 case '{':
01414
01415
01416
01417
01418
01419 if (quote != '\'')
01420 globbing++;
01421 slashes = 0;
01422 break;
01423
01424 case '\'':
01425 case '\"':
01426
01427
01428
01429
01430
01431
01432
01433 if (!(slashes & 1)) {
01434 if (!quote)
01435 quote = *ptr;
01436 else if (quote == *ptr) {
01437 if (quote == '"' && quote == ptr[1])
01438 ptr++;
01439 quote = '\0';
01440 }
01441 }
01442 escape++;
01443 slashes = 0;
01444 break;
01445
01446 default:
01447 ptr = CharNext(ptr);
01448 slashes = 0;
01449 continue;
01450 }
01451 ptr++;
01452 }
01453
01454
01455
01456
01457
01458
01459
01460 len = ptr - base;
01461 if (done) --len;
01462
01463
01464
01465
01466
01467
01468 if (escape) {
01469 char *p = base, c;
01470 slashes = quote = 0;
01471 while (p < base + len) {
01472 switch (c = *p) {
01473 case '\\':
01474 p++;
01475 if (quote != '\'') slashes++;
01476 break;
01477
01478 case '\'':
01479 case '"':
01480 if (!(slashes & 1) && quote && quote != c) {
01481 p++;
01482 slashes = 0;
01483 break;
01484 }
01485 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1),
01486 base + len - p);
01487 len -= ((slashes + 1) >> 1) + (~slashes & 1);
01488 p -= (slashes + 1) >> 1;
01489 if (!(slashes & 1)) {
01490 if (quote) {
01491 if (quote == '"' && quote == *p)
01492 p++;
01493 quote = '\0';
01494 }
01495 else
01496 quote = c;
01497 }
01498 else
01499 p++;
01500 slashes = 0;
01501 break;
01502
01503 default:
01504 p = CharNext(p);
01505 slashes = 0;
01506 break;
01507 }
01508 }
01509 }
01510
01511 curr = (NtCmdLineElement *)calloc(sizeof(NtCmdLineElement), 1);
01512 if (!curr) goto do_nothing;
01513 curr->str = base;
01514 curr->len = len;
01515
01516 if (globbing && (tail = cmdglob(curr, cmdtail))) {
01517 cmdtail = tail;
01518 }
01519 else {
01520 *cmdtail = curr;
01521 cmdtail = &curr->next;
01522 }
01523 }
01524
01525
01526
01527
01528
01529
01530
01531 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) {
01532 elements++;
01533 strsz += (curr->len + 1);
01534 }
01535
01536 len = (elements+1)*sizeof(char *) + strsz;
01537 buffer = (char *)malloc(len);
01538 if (!buffer) {
01539 do_nothing:
01540 while (curr = cmdhead) {
01541 cmdhead = curr->next;
01542 if (curr->flags & NTMALLOC) free(curr->str);
01543 free(curr);
01544 }
01545 free(cmdline);
01546 for (vptr = *vec; *vptr; ++vptr);
01547 return vptr - *vec;
01548 }
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562 vptr = (char **) buffer;
01563
01564 ptr = buffer + (elements+1) * sizeof(char *);
01565
01566 while (curr = cmdhead) {
01567 strlcpy(ptr, curr->str, curr->len + 1);
01568 *vptr++ = ptr;
01569 ptr += curr->len + 1;
01570 cmdhead = curr->next;
01571 if (curr->flags & NTMALLOC) free(curr->str);
01572 free(curr);
01573 }
01574 *vptr = 0;
01575
01576 *vec = (char **) buffer;
01577 free(cmdline);
01578 return elements;
01579 }
01580
01581
01582
01583
01584
01585 #define PATHLEN 1024
01586
01587
01588
01589
01590
01591
01592
01593 #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT))
01594 #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT))
01595
01596 #define BitOfIsDir(n) ((n) * 2)
01597 #define BitOfIsRep(n) ((n) * 2 + 1)
01598 #define DIRENT_PER_CHAR (CHAR_BIT / 2)
01599
01600 static HANDLE
01601 open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd)
01602 {
01603 HANDLE fh;
01604 static const WCHAR wildcard[] = L"\\*";
01605 WCHAR *scanname;
01606 WCHAR *p;
01607 int len;
01608
01609
01610
01611
01612 len = lstrlenW(filename);
01613 scanname = ALLOCA_N(WCHAR, len + sizeof(wildcard) / sizeof(WCHAR));
01614 lstrcpyW(scanname, filename);
01615 p = CharPrevW(scanname, scanname + len);
01616 if (*p == L'/' || *p == L'\\' || *p == L':')
01617 lstrcatW(scanname, wildcard + 1);
01618 else
01619 lstrcatW(scanname, wildcard);
01620
01621
01622
01623
01624 fh = FindFirstFileW(scanname, fd);
01625 if (fh == INVALID_HANDLE_VALUE) {
01626 errno = map_errno(GetLastError());
01627 }
01628 return fh;
01629 }
01630
01631 static DIR *
01632 opendir_internal(HANDLE fh, WIN32_FIND_DATAW *fd)
01633 {
01634 DIR *p;
01635 long len;
01636 long idx;
01637 WCHAR *tmpW;
01638 char *tmp;
01639
01640 if (fh == INVALID_HANDLE_VALUE) {
01641 return NULL;
01642 }
01643
01644
01645
01646
01647 p = calloc(sizeof(DIR), 1);
01648 if (p == NULL)
01649 return NULL;
01650
01651 idx = 0;
01652
01653
01654
01655
01656
01657
01658
01659 do {
01660 len = lstrlenW(fd->cFileName) + 1;
01661
01662
01663
01664
01665
01666 tmpW = realloc(p->start, (idx + len) * sizeof(WCHAR));
01667 if (!tmpW) {
01668 error:
01669 rb_w32_closedir(p);
01670 FindClose(fh);
01671 errno = ENOMEM;
01672 return NULL;
01673 }
01674
01675 p->start = tmpW;
01676 memcpy(&p->start[idx], fd->cFileName, len * sizeof(WCHAR));
01677
01678 if (p->nfiles % DIRENT_PER_CHAR == 0) {
01679 tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1);
01680 if (!tmp)
01681 goto error;
01682 p->bits = tmp;
01683 p->bits[p->nfiles / DIRENT_PER_CHAR] = 0;
01684 }
01685 if (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01686 SetBit(p->bits, BitOfIsDir(p->nfiles));
01687 if (fd->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
01688 SetBit(p->bits, BitOfIsRep(p->nfiles));
01689
01690 p->nfiles++;
01691 idx += len;
01692 } while (FindNextFileW(fh, fd));
01693 FindClose(fh);
01694 p->size = idx;
01695 p->curr = p->start;
01696 return p;
01697 }
01698
01699 static char *
01700 wstr_to_filecp(const WCHAR *wstr, long *plen)
01701 {
01702 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
01703 char *ptr;
01704 int len = WideCharToMultiByte(cp, 0, wstr, -1, NULL, 0, NULL, NULL) - 1;
01705 if (!(ptr = malloc(len + 1))) return 0;
01706 WideCharToMultiByte(cp, 0, wstr, -1, ptr, len + 1, NULL, NULL);
01707 if (plen) *plen = len;
01708 return ptr;
01709 }
01710
01711 static WCHAR *
01712 filecp_to_wstr(const char *str, long *plen)
01713 {
01714 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
01715 WCHAR *ptr;
01716 int len = MultiByteToWideChar(cp, 0, str, -1, NULL, 0) - 1;
01717 if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0;
01718 MultiByteToWideChar(cp, 0, str, -1, ptr, len + 1);
01719 if (plen) *plen = len;
01720 return ptr;
01721 }
01722
01723 static char *
01724 wstr_to_utf8(const WCHAR *wstr, long *plen)
01725 {
01726 char *ptr;
01727 int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL) - 1;
01728 if (!(ptr = malloc(len + 1))) return 0;
01729 WideCharToMultiByte(CP_UTF8, 0, wstr, -1, ptr, len + 1, NULL, NULL);
01730 if (plen) *plen = len;
01731 return ptr;
01732 }
01733
01734 static WCHAR *
01735 utf8_to_wstr(const char *str, long *plen)
01736 {
01737 WCHAR *ptr;
01738 int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0) - 1;
01739 if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0;
01740 MultiByteToWideChar(CP_UTF8, 0, str, -1, ptr, len + 1);
01741 if (plen) *plen = len;
01742 return ptr;
01743 }
01744
01745 DIR *
01746 rb_w32_opendir(const char *filename)
01747 {
01748 struct stati64 sbuf;
01749 WIN32_FIND_DATAW fd;
01750 HANDLE fh;
01751 WCHAR *wpath;
01752
01753 if (!(wpath = filecp_to_wstr(filename, NULL)))
01754 return NULL;
01755
01756
01757
01758
01759 if (wstati64(wpath, &sbuf) < 0) {
01760 free(wpath);
01761 return NULL;
01762 }
01763 if (!(sbuf.st_mode & S_IFDIR) &&
01764 (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' ||
01765 ((1 << ((filename[0] & 0x5f) - 'A')) & GetLogicalDrives()) == 0)) {
01766 free(wpath);
01767 errno = ENOTDIR;
01768 return NULL;
01769 }
01770
01771 fh = open_dir_handle(wpath, &fd);
01772 free(wpath);
01773 return opendir_internal(fh, &fd);
01774 }
01775
01776
01777
01778
01779
01780 static void
01781 move_to_next_entry(DIR *dirp)
01782 {
01783 if (dirp->curr) {
01784 dirp->loc++;
01785 dirp->curr += lstrlenW(dirp->curr) + 1;
01786 if (dirp->curr >= (dirp->start + dirp->size)) {
01787 dirp->curr = NULL;
01788 }
01789 }
01790 }
01791
01792
01793
01794
01795
01796 static BOOL
01797 win32_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *dummy)
01798 {
01799 if (!(entry->d_name = wstr_to_filecp(file, &entry->d_namlen)))
01800 return FALSE;
01801 return TRUE;
01802 }
01803
01804 VALUE
01805 rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc)
01806 {
01807 static rb_encoding *utf16 = (rb_encoding *)-1;
01808 VALUE src;
01809 VALUE opthash;
01810 int ecflags;
01811 VALUE ecopts;
01812
01813 if (utf16 == (rb_encoding *)-1) {
01814 utf16 = rb_enc_find("UTF-16LE");
01815 if (utf16 == rb_ascii8bit_encoding())
01816 utf16 = NULL;
01817 }
01818 if (!utf16)
01819
01820 return Qnil;
01821
01822 src = rb_enc_str_new((char *)wstr, lstrlenW(wstr) * sizeof(WCHAR), utf16);
01823 opthash = rb_hash_new();
01824 rb_hash_aset(opthash, ID2SYM(rb_intern("undef")),
01825 ID2SYM(rb_intern("replace")));
01826 ecflags = rb_econv_prepare_opts(opthash, &ecopts);
01827 return rb_str_encode(src, rb_enc_from_encoding(enc), ecflags, ecopts);
01828 }
01829
01830 char *
01831 rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc)
01832 {
01833 VALUE str = rb_w32_conv_from_wchar(wstr, enc);
01834 long len;
01835 char *ptr;
01836
01837 if (NIL_P(str)) return wstr_to_filecp(wstr, lenp);
01838 *lenp = len = RSTRING_LEN(str);
01839 memcpy(ptr = malloc(len + 1), RSTRING_PTR(str), len);
01840 ptr[len] = '\0';
01841 return ptr;
01842 }
01843
01844 static BOOL
01845 ruby_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *enc)
01846 {
01847 if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc)))
01848 return FALSE;
01849 return TRUE;
01850 }
01851
01852 static struct direct *
01853 readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, struct direct *, rb_encoding *), rb_encoding *enc)
01854 {
01855 static int dummy = 0;
01856
01857 if (dirp->curr) {
01858
01859
01860
01861
01862 if (dirp->dirstr.d_name)
01863 free(dirp->dirstr.d_name);
01864 conv(dirp->curr, &dirp->dirstr, enc);
01865
01866
01867
01868
01869 dirp->dirstr.d_ino = dummy++;
01870
01871
01872
01873
01874 dirp->dirstr.d_isdir = GetBit(dirp->bits, BitOfIsDir(dirp->loc));
01875 dirp->dirstr.d_isrep = GetBit(dirp->bits, BitOfIsRep(dirp->loc));
01876
01877
01878
01879
01880
01881 move_to_next_entry(dirp);
01882
01883 return &(dirp->dirstr);
01884
01885 } else
01886 return NULL;
01887 }
01888
01889 struct direct *
01890 rb_w32_readdir(DIR *dirp)
01891 {
01892 return readdir_internal(dirp, win32_direct_conv, NULL);
01893 }
01894
01895 struct direct *
01896 rb_w32_readdir_with_enc(DIR *dirp, rb_encoding *enc)
01897 {
01898 if (enc == rb_ascii8bit_encoding())
01899 return readdir_internal(dirp, win32_direct_conv, NULL);
01900 else
01901 return readdir_internal(dirp, ruby_direct_conv, enc);
01902 }
01903
01904
01905
01906
01907
01908 long
01909 rb_w32_telldir(DIR *dirp)
01910 {
01911 return dirp->loc;
01912 }
01913
01914
01915
01916
01917
01918 void
01919 rb_w32_seekdir(DIR *dirp, long loc)
01920 {
01921 if (dirp->loc > loc) rb_w32_rewinddir(dirp);
01922
01923 while (dirp->curr && dirp->loc < loc) {
01924 move_to_next_entry(dirp);
01925 }
01926 }
01927
01928
01929
01930
01931
01932 void
01933 rb_w32_rewinddir(DIR *dirp)
01934 {
01935 dirp->curr = dirp->start;
01936 dirp->loc = 0;
01937 }
01938
01939
01940
01941
01942
01943 void
01944 rb_w32_closedir(DIR *dirp)
01945 {
01946 if (dirp) {
01947 if (dirp->dirstr.d_name)
01948 free(dirp->dirstr.d_name);
01949 if (dirp->start)
01950 free(dirp->start);
01951 if (dirp->bits)
01952 free(dirp->bits);
01953 free(dirp);
01954 }
01955 }
01956
01957 #if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__
01958 #define MSVCRT_THREADS
01959 #endif
01960 #ifdef MSVCRT_THREADS
01961 # define MTHREAD_ONLY(x) x
01962 # define STHREAD_ONLY(x)
01963 #elif defined(__BORLANDC__)
01964 # define MTHREAD_ONLY(x)
01965 # define STHREAD_ONLY(x)
01966 #else
01967 # define MTHREAD_ONLY(x)
01968 # define STHREAD_ONLY(x) x
01969 #endif
01970
01971 typedef struct {
01972 intptr_t osfhnd;
01973 char osfile;
01974 char pipech;
01975 #ifdef MSVCRT_THREADS
01976 int lockinitflag;
01977 CRITICAL_SECTION lock;
01978 #endif
01979 #if RT_VER >= 80
01980 char textmode;
01981 char pipech2[2];
01982 #endif
01983 } ioinfo;
01984
01985 #if !defined _CRTIMP || defined __MINGW32__
01986 #undef _CRTIMP
01987 #define _CRTIMP __declspec(dllimport)
01988 #endif
01989
01990 #if !defined(__BORLANDC__)
01991 EXTERN_C _CRTIMP ioinfo * __pioinfo[];
01992
01993 #define IOINFO_L2E 5
01994 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
01995 #define _pioinfo(i) ((ioinfo*)((char*)(__pioinfo[i >> IOINFO_L2E]) + (i & (IOINFO_ARRAY_ELTS - 1)) * (sizeof(ioinfo) + pioinfo_extra)))
01996 #define _osfhnd(i) (_pioinfo(i)->osfhnd)
01997 #define _osfile(i) (_pioinfo(i)->osfile)
01998 #define _pipech(i) (_pioinfo(i)->pipech)
01999
02000 #if RT_VER >= 80
02001 static size_t pioinfo_extra = 0;
02002
02003 static void
02004 set_pioinfo_extra(void)
02005 {
02006 int fd;
02007
02008 fd = _open("NUL", O_RDONLY);
02009 for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra += sizeof(void *)) {
02010 if (_osfhnd(fd) == _get_osfhandle(fd)) {
02011 break;
02012 }
02013 }
02014 _close(fd);
02015
02016 if (pioinfo_extra > 64) {
02017
02018 pioinfo_extra = 0;
02019 }
02020 }
02021 #else
02022 #define pioinfo_extra 0
02023 #endif
02024
02025 #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
02026 #define _set_osflags(fh, flags) (_osfile(fh) = (flags))
02027
02028 #define FOPEN 0x01
02029 #define FEOFLAG 0x02
02030 #define FPIPE 0x08
02031 #define FNOINHERIT 0x10
02032 #define FAPPEND 0x20
02033 #define FDEV 0x40
02034 #define FTEXT 0x80
02035
02036 static int
02037 rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
02038 {
02039 int fh;
02040 char fileflags;
02041 HANDLE hF;
02042
02043
02044 fileflags = FDEV;
02045
02046 if (flags & O_APPEND)
02047 fileflags |= FAPPEND;
02048
02049 if (flags & O_TEXT)
02050 fileflags |= FTEXT;
02051
02052 if (flags & O_NOINHERIT)
02053 fileflags |= FNOINHERIT;
02054
02055
02056 hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
02057 fh = _open_osfhandle((intptr_t)hF, 0);
02058 CloseHandle(hF);
02059 if (fh == -1) {
02060 errno = EMFILE;
02061 _doserrno = 0L;
02062 }
02063 else {
02064
02065 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock)));
02066
02067 _set_osfhnd(fh, osfhandle);
02068
02069 fileflags |= FOPEN;
02070
02071 _set_osflags(fh, fileflags);
02072 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock));
02073 }
02074 return fh;
02075 }
02076
02077 static void
02078 init_stdhandle(void)
02079 {
02080 int nullfd = -1;
02081 int keep = 0;
02082 #define open_null(fd) \
02083 (((nullfd < 0) ? \
02084 (nullfd = open("NUL", O_RDWR|O_BINARY)) : 0), \
02085 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \
02086 (fd))
02087
02088 if (fileno(stdin) < 0) {
02089 stdin->_file = open_null(0);
02090 }
02091 else {
02092 setmode(fileno(stdin), O_BINARY);
02093 }
02094 if (fileno(stdout) < 0) {
02095 stdout->_file = open_null(1);
02096 }
02097 else {
02098 setmode(fileno(stdout), O_BINARY);
02099 }
02100 if (fileno(stderr) < 0) {
02101 stderr->_file = open_null(2);
02102 }
02103 else {
02104 setmode(fileno(stderr), O_BINARY);
02105 }
02106 if (nullfd >= 0 && !keep) close(nullfd);
02107 setvbuf(stderr, NULL, _IONBF, 0);
02108 }
02109 #else
02110
02111 #define _set_osfhnd(fh, osfh) (void)((fh), (osfh))
02112 #define _set_osflags(fh, flags) (void)((fh), (flags))
02113
02114 static void
02115 init_stdhandle(void)
02116 {
02117 }
02118 #endif
02119
02120 #ifdef __BORLANDC__
02121 static int
02122 rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
02123 {
02124 int fd = _open_osfhandle(osfhandle, flags);
02125 if (fd == -1) {
02126 errno = EMFILE;
02127 _doserrno = 0L;
02128 }
02129 return fd;
02130 }
02131 #endif
02132
02133 #undef getsockopt
02134
02135 static int
02136 is_socket(SOCKET sock)
02137 {
02138 if (st_lookup(socklist, (st_data_t)sock, NULL))
02139 return TRUE;
02140 else
02141 return FALSE;
02142 }
02143
02144 int
02145 rb_w32_is_socket(int fd)
02146 {
02147 return is_socket(TO_SOCKET(fd));
02148 }
02149
02150
02151
02152
02153
02154
02155
02156 #undef strerror
02157
02158 char *
02159 rb_w32_strerror(int e)
02160 {
02161 static char buffer[512];
02162 DWORD source = 0;
02163 char *p;
02164
02165 #if defined __BORLANDC__ && defined ENOTEMPTY // _sys_errlist is broken
02166 switch (e) {
02167 case ENAMETOOLONG:
02168 return "Filename too long";
02169 case ENOTEMPTY:
02170 return "Directory not empty";
02171 }
02172 #endif
02173
02174 if (e < 0 || e > sys_nerr) {
02175 if (e < 0)
02176 e = GetLastError();
02177 #if WSAEWOULDBLOCK != EWOULDBLOCK
02178 else if (e >= EADDRINUSE && e <= EWOULDBLOCK) {
02179 static int s = -1;
02180 int i;
02181 if (s < 0)
02182 for (s = 0; s < (int)(sizeof(errmap)/sizeof(*errmap)); s++)
02183 if (errmap[s].winerr == WSAEWOULDBLOCK)
02184 break;
02185 for (i = s; i < (int)(sizeof(errmap)/sizeof(*errmap)); i++)
02186 if (errmap[i].err == e) {
02187 e = errmap[i].winerr;
02188 break;
02189 }
02190 }
02191 #endif
02192 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
02193 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0,
02194 buffer, sizeof(buffer), NULL) == 0)
02195 strlcpy(buffer, "Unknown Error", sizeof(buffer));
02196 }
02197 else
02198 strlcpy(buffer, strerror(e), sizeof(buffer));
02199
02200 p = buffer;
02201 while ((p = strpbrk(p, "\r\n")) != NULL) {
02202 memmove(p, p + 1, strlen(p));
02203 }
02204 return buffer;
02205 }
02206
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217
02218 #define ROOT_UID 0
02219 #define ROOT_GID 0
02220
02221 rb_uid_t
02222 getuid(void)
02223 {
02224 return ROOT_UID;
02225 }
02226
02227 rb_uid_t
02228 geteuid(void)
02229 {
02230 return ROOT_UID;
02231 }
02232
02233 rb_gid_t
02234 getgid(void)
02235 {
02236 return ROOT_GID;
02237 }
02238
02239 rb_gid_t
02240 getegid(void)
02241 {
02242 return ROOT_GID;
02243 }
02244
02245 int
02246 setuid(rb_uid_t uid)
02247 {
02248 return (uid == ROOT_UID ? 0 : -1);
02249 }
02250
02251 int
02252 setgid(rb_gid_t gid)
02253 {
02254 return (gid == ROOT_GID ? 0 : -1);
02255 }
02256
02257
02258
02259
02260
02261 int
02262 ioctl(int i, int u, ...)
02263 {
02264 errno = EINVAL;
02265 return -1;
02266 }
02267
02268 #undef FD_SET
02269
02270 void
02271 rb_w32_fdset(int fd, fd_set *set)
02272 {
02273 unsigned int i;
02274 SOCKET s = TO_SOCKET(fd);
02275
02276 for (i = 0; i < set->fd_count; i++) {
02277 if (set->fd_array[i] == s) {
02278 return;
02279 }
02280 }
02281 if (i == set->fd_count) {
02282 if (set->fd_count < FD_SETSIZE) {
02283 set->fd_array[i] = s;
02284 set->fd_count++;
02285 }
02286 }
02287 }
02288
02289 #undef FD_CLR
02290
02291 void
02292 rb_w32_fdclr(int fd, fd_set *set)
02293 {
02294 unsigned int i;
02295 SOCKET s = TO_SOCKET(fd);
02296
02297 for (i = 0; i < set->fd_count; i++) {
02298 if (set->fd_array[i] == s) {
02299 memmove(&set->fd_array[i], &set->fd_array[i+1],
02300 sizeof(set->fd_array[0]) * (--set->fd_count - i));
02301 break;
02302 }
02303 }
02304 }
02305
02306 #undef FD_ISSET
02307
02308 int
02309 rb_w32_fdisset(int fd, fd_set *set)
02310 {
02311 int ret;
02312 SOCKET s = TO_SOCKET(fd);
02313 if (s == (SOCKET)INVALID_HANDLE_VALUE)
02314 return 0;
02315 RUBY_CRITICAL(ret = __WSAFDIsSet(s, set));
02316 return ret;
02317 }
02318
02319
02320
02321
02322
02323
02324
02325 #undef select
02326
02327 static int
02328 extract_fd(rb_fdset_t *dst, fd_set *src, int (*func)(SOCKET))
02329 {
02330 unsigned int s = 0;
02331 if (!src || !dst) return 0;
02332
02333 while (s < src->fd_count) {
02334 SOCKET fd = src->fd_array[s];
02335
02336 if (!func || (*func)(fd)) {
02337 unsigned int d;
02338
02339 for (d = 0; d < dst->fdset->fd_count; d++) {
02340 if (dst->fdset->fd_array[d] == fd)
02341 break;
02342 }
02343 if (d == dst->fdset->fd_count) {
02344 if ((int)dst->fdset->fd_count >= dst->capa) {
02345 dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE;
02346 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa);
02347 }
02348 dst->fdset->fd_array[dst->fdset->fd_count++] = fd;
02349 }
02350 memmove(
02351 &src->fd_array[s],
02352 &src->fd_array[s+1],
02353 sizeof(src->fd_array[0]) * (--src->fd_count - s));
02354 }
02355 else s++;
02356 }
02357
02358 return dst->fdset->fd_count;
02359 }
02360
02361 static int
02362 copy_fd(fd_set *dst, fd_set *src)
02363 {
02364 unsigned int s;
02365 if (!src || !dst) return 0;
02366
02367 for (s = 0; s < src->fd_count; ++s) {
02368 SOCKET fd = src->fd_array[s];
02369 unsigned int d;
02370 for (d = 0; d < dst->fd_count; ++d) {
02371 if (dst->fd_array[d] == fd)
02372 break;
02373 }
02374 if (d == dst->fd_count && d < FD_SETSIZE) {
02375 dst->fd_array[dst->fd_count++] = fd;
02376 }
02377 }
02378
02379 return dst->fd_count;
02380 }
02381
02382 static int
02383 is_not_socket(SOCKET sock)
02384 {
02385 return !is_socket(sock);
02386 }
02387
02388 static int
02389 is_pipe(SOCKET sock)
02390 {
02391 int ret;
02392
02393 RUBY_CRITICAL({
02394 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE);
02395 });
02396
02397 return ret;
02398 }
02399
02400 static int
02401 is_readable_pipe(SOCKET sock)
02402 {
02403 int ret;
02404 DWORD n = 0;
02405
02406 RUBY_CRITICAL(
02407 if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) {
02408 ret = (n > 0);
02409 }
02410 else {
02411 ret = (GetLastError() == ERROR_BROKEN_PIPE);
02412 }
02413 );
02414
02415 return ret;
02416 }
02417
02418 static int
02419 is_console(SOCKET sock)
02420 {
02421 int ret;
02422 DWORD n = 0;
02423 INPUT_RECORD ir;
02424
02425 RUBY_CRITICAL(
02426 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n))
02427 );
02428
02429 return ret;
02430 }
02431
02432 static int
02433 is_readable_console(SOCKET sock)
02434 {
02435 int ret = 0;
02436 DWORD n = 0;
02437 INPUT_RECORD ir;
02438
02439 RUBY_CRITICAL(
02440 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) {
02441 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
02442 ir.Event.KeyEvent.uChar.AsciiChar) {
02443 ret = 1;
02444 }
02445 else {
02446 ReadConsoleInput((HANDLE)sock, &ir, 1, &n);
02447 }
02448 }
02449 );
02450
02451 return ret;
02452 }
02453
02454 static int
02455 do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
02456 struct timeval *timeout)
02457 {
02458 int r = 0;
02459
02460 if (nfds == 0) {
02461 if (timeout)
02462 rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
02463 else
02464 rb_w32_sleep(INFINITE);
02465 }
02466 else {
02467 RUBY_CRITICAL(
02468 EnterCriticalSection(&select_mutex);
02469 r = select(nfds, rd, wr, ex, timeout);
02470 LeaveCriticalSection(&select_mutex);
02471 if (r == SOCKET_ERROR) {
02472 errno = map_errno(WSAGetLastError());
02473 r = -1;
02474 }
02475 );
02476 }
02477
02478 return r;
02479 }
02480
02481 static inline int
02482 subtract(struct timeval *rest, const struct timeval *wait)
02483 {
02484 if (rest->tv_sec < wait->tv_sec) {
02485 return 0;
02486 }
02487 while (rest->tv_usec < wait->tv_usec) {
02488 if (rest->tv_sec <= wait->tv_sec) {
02489 return 0;
02490 }
02491 rest->tv_sec -= 1;
02492 rest->tv_usec += 1000 * 1000;
02493 }
02494 rest->tv_sec -= wait->tv_sec;
02495 rest->tv_usec -= wait->tv_usec;
02496 return rest->tv_sec != 0 || rest->tv_usec != 0;
02497 }
02498
02499 static inline int
02500 compare(const struct timeval *t1, const struct timeval *t2)
02501 {
02502 if (t1->tv_sec < t2->tv_sec)
02503 return -1;
02504 if (t1->tv_sec > t2->tv_sec)
02505 return 1;
02506 if (t1->tv_usec < t2->tv_usec)
02507 return -1;
02508 if (t1->tv_usec > t2->tv_usec)
02509 return 1;
02510 return 0;
02511 }
02512
02513 #undef Sleep
02514 int WSAAPI
02515 rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
02516 struct timeval *timeout)
02517 {
02518 int r;
02519 rb_fdset_t pipe_rd;
02520 rb_fdset_t cons_rd;
02521 rb_fdset_t else_rd;
02522 rb_fdset_t else_wr;
02523 rb_fdset_t except;
02524 int nonsock = 0;
02525 struct timeval limit = {0, 0};
02526
02527 if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) {
02528 errno = EINVAL;
02529 return -1;
02530 }
02531
02532 if (timeout) {
02533 if (timeout->tv_sec < 0 ||
02534 timeout->tv_usec < 0 ||
02535 timeout->tv_usec >= 1000000) {
02536 errno = EINVAL;
02537 return -1;
02538 }
02539 gettimeofday(&limit, NULL);
02540 limit.tv_sec += timeout->tv_sec;
02541 limit.tv_usec += timeout->tv_usec;
02542 if (limit.tv_usec >= 1000000) {
02543 limit.tv_usec -= 1000000;
02544 limit.tv_sec++;
02545 }
02546 }
02547
02548 if (!NtSocketsInitialized) {
02549 StartSockets();
02550 }
02551
02552
02553
02554
02555
02556
02557
02558 rb_fd_init(&else_rd);
02559 nonsock += extract_fd(&else_rd, rd, is_not_socket);
02560
02561 rb_fd_init(&pipe_rd);
02562 extract_fd(&pipe_rd, else_rd.fdset, is_pipe);
02563
02564 rb_fd_init(&cons_rd);
02565 extract_fd(&cons_rd, else_rd.fdset, is_console);
02566
02567 rb_fd_init(&else_wr);
02568 nonsock += extract_fd(&else_wr, wr, is_not_socket);
02569
02570 rb_fd_init(&except);
02571 extract_fd(&except, ex, is_not_socket);
02572
02573 r = 0;
02574 if (rd && (int)rd->fd_count > r) r = (int)rd->fd_count;
02575 if (wr && (int)wr->fd_count > r) r = (int)wr->fd_count;
02576 if (ex && (int)ex->fd_count > r) r = (int)ex->fd_count;
02577 if (nfds > r) nfds = r;
02578
02579 {
02580 struct timeval rest;
02581 struct timeval wait;
02582 struct timeval zero;
02583 wait.tv_sec = 0; wait.tv_usec = 10 * 1000;
02584 zero.tv_sec = 0; zero.tv_usec = 0;
02585 for (;;) {
02586 if (nonsock) {
02587
02588
02589 extract_fd(&else_rd, pipe_rd.fdset, is_readable_pipe);
02590 extract_fd(&else_rd, cons_rd.fdset, is_readable_console);
02591 }
02592
02593 if (else_rd.fdset->fd_count || else_wr.fdset->fd_count) {
02594 r = do_select(nfds, rd, wr, ex, &zero);
02595 if (r < 0) break;
02596 r = copy_fd(rd, else_rd.fdset);
02597 r += copy_fd(wr, else_wr.fdset);
02598 if (ex)
02599 r += ex->fd_count;
02600 break;
02601 }
02602 else {
02603 struct timeval *dowait = &wait;
02604
02605 fd_set orig_rd;
02606 fd_set orig_wr;
02607 fd_set orig_ex;
02608 if (rd) orig_rd = *rd;
02609 if (wr) orig_wr = *wr;
02610 if (ex) orig_ex = *ex;
02611 r = do_select(nfds, rd, wr, ex, &zero);
02612 if (r != 0) break;
02613 if (rd) *rd = orig_rd;
02614 if (wr) *wr = orig_wr;
02615 if (ex) *ex = orig_ex;
02616
02617 if (timeout) {
02618 struct timeval now;
02619 gettimeofday(&now, NULL);
02620 rest = limit;
02621 if (!subtract(&rest, &now)) break;
02622 if (compare(&rest, &wait) < 0) dowait = &rest;
02623 }
02624 Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000);
02625 }
02626 }
02627 }
02628
02629 rb_fd_term(&except);
02630 rb_fd_term(&else_wr);
02631 rb_fd_term(&cons_rd);
02632 rb_fd_term(&pipe_rd);
02633 rb_fd_term(&else_rd);
02634
02635 return r;
02636 }
02637
02638 #undef accept
02639
02640 int WSAAPI
02641 rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
02642 {
02643 SOCKET r;
02644 int fd;
02645
02646 if (!NtSocketsInitialized) {
02647 StartSockets();
02648 }
02649 RUBY_CRITICAL({
02650 HANDLE h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
02651 fd = rb_w32_open_osfhandle((intptr_t)h, O_RDWR|O_BINARY|O_NOINHERIT);
02652 if (fd != -1) {
02653 r = accept(TO_SOCKET(s), addr, addrlen);
02654 if (r != INVALID_SOCKET) {
02655 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
02656 _set_osfhnd(fd, r);
02657 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
02658 CloseHandle(h);
02659 st_insert(socklist, (st_data_t)r, (st_data_t)0);
02660 }
02661 else {
02662 errno = map_errno(WSAGetLastError());
02663 close(fd);
02664 fd = -1;
02665 }
02666 }
02667 else
02668 CloseHandle(h);
02669 });
02670 return fd;
02671 }
02672
02673 #undef bind
02674
02675 int WSAAPI
02676 rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
02677 {
02678 int r;
02679
02680 if (!NtSocketsInitialized) {
02681 StartSockets();
02682 }
02683 RUBY_CRITICAL({
02684 r = bind(TO_SOCKET(s), addr, addrlen);
02685 if (r == SOCKET_ERROR)
02686 errno = map_errno(WSAGetLastError());
02687 });
02688 return r;
02689 }
02690
02691 #undef connect
02692
02693 int WSAAPI
02694 rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
02695 {
02696 int r;
02697 if (!NtSocketsInitialized) {
02698 StartSockets();
02699 }
02700 RUBY_CRITICAL({
02701 r = connect(TO_SOCKET(s), addr, addrlen);
02702 if (r == SOCKET_ERROR) {
02703 int err = WSAGetLastError();
02704 if (err != WSAEWOULDBLOCK)
02705 errno = map_errno(err);
02706 else
02707 errno = EINPROGRESS;
02708 }
02709 });
02710 return r;
02711 }
02712
02713
02714 #undef getpeername
02715
02716 int WSAAPI
02717 rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
02718 {
02719 int r;
02720 if (!NtSocketsInitialized) {
02721 StartSockets();
02722 }
02723 RUBY_CRITICAL({
02724 r = getpeername(TO_SOCKET(s), addr, addrlen);
02725 if (r == SOCKET_ERROR)
02726 errno = map_errno(WSAGetLastError());
02727 });
02728 return r;
02729 }
02730
02731 #undef getsockname
02732
02733 int WSAAPI
02734 rb_w32_getsockname(int s, struct sockaddr *addr, int *addrlen)
02735 {
02736 int r;
02737 if (!NtSocketsInitialized) {
02738 StartSockets();
02739 }
02740 RUBY_CRITICAL({
02741 r = getsockname(TO_SOCKET(s), addr, addrlen);
02742 if (r == SOCKET_ERROR)
02743 errno = map_errno(WSAGetLastError());
02744 });
02745 return r;
02746 }
02747
02748 int WSAAPI
02749 rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
02750 {
02751 int r;
02752 if (!NtSocketsInitialized) {
02753 StartSockets();
02754 }
02755 RUBY_CRITICAL({
02756 r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
02757 if (r == SOCKET_ERROR)
02758 errno = map_errno(WSAGetLastError());
02759 });
02760 return r;
02761 }
02762
02763 #undef ioctlsocket
02764
02765 int WSAAPI
02766 rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
02767 {
02768 int r;
02769 if (!NtSocketsInitialized) {
02770 StartSockets();
02771 }
02772 RUBY_CRITICAL({
02773 r = ioctlsocket(TO_SOCKET(s), cmd, argp);
02774 if (r == SOCKET_ERROR)
02775 errno = map_errno(WSAGetLastError());
02776 });
02777 return r;
02778 }
02779
02780 #undef listen
02781
02782 int WSAAPI
02783 rb_w32_listen(int s, int backlog)
02784 {
02785 int r;
02786 if (!NtSocketsInitialized) {
02787 StartSockets();
02788 }
02789 RUBY_CRITICAL({
02790 r = listen(TO_SOCKET(s), backlog);
02791 if (r == SOCKET_ERROR)
02792 errno = map_errno(WSAGetLastError());
02793 });
02794 return r;
02795 }
02796
02797 #undef recv
02798 #undef recvfrom
02799 #undef send
02800 #undef sendto
02801
02802 static int
02803 overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
02804 struct sockaddr *addr, int *addrlen)
02805 {
02806 int r;
02807 int ret;
02808 int mode;
02809 st_data_t data;
02810 DWORD flg;
02811 WSAOVERLAPPED wol;
02812 WSABUF wbuf;
02813 int err;
02814 SOCKET s;
02815
02816 if (!NtSocketsInitialized)
02817 StartSockets();
02818
02819 s = TO_SOCKET(fd);
02820 st_lookup(socklist, (st_data_t)s, &data);
02821 mode = (int)data;
02822 if (!cancel_io || (mode & O_NONBLOCK)) {
02823 RUBY_CRITICAL({
02824 if (input) {
02825 if (addr && addrlen)
02826 r = recvfrom(s, buf, len, flags, addr, addrlen);
02827 else
02828 r = recv(s, buf, len, flags);
02829 }
02830 else {
02831 if (addr && addrlen)
02832 r = sendto(s, buf, len, flags, addr, *addrlen);
02833 else
02834 r = send(s, buf, len, flags);
02835 }
02836 if (r == SOCKET_ERROR)
02837 errno = map_errno(WSAGetLastError());
02838 });
02839 }
02840 else {
02841 DWORD size;
02842 wbuf.len = len;
02843 wbuf.buf = buf;
02844 memset(&wol, 0, sizeof(wol));
02845 RUBY_CRITICAL({
02846 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
02847 if (input) {
02848 flg = flags;
02849 if (addr && addrlen)
02850 ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
02851 &wol, NULL);
02852 else
02853 ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL);
02854 }
02855 else {
02856 if (addr && addrlen)
02857 ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
02858 &wol, NULL);
02859 else
02860 ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL);
02861 }
02862 });
02863
02864 if (ret != SOCKET_ERROR) {
02865 r = size;
02866 }
02867 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
02868 switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
02869 case WAIT_OBJECT_0:
02870 RUBY_CRITICAL(
02871 ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
02872 );
02873 if (ret) {
02874 r = size;
02875 break;
02876 }
02877
02878 default:
02879 errno = map_errno(WSAGetLastError());
02880
02881 case WAIT_OBJECT_0 + 1:
02882
02883 r = -1;
02884 cancel_io((HANDLE)s);
02885 break;
02886 }
02887 }
02888 else {
02889 errno = map_errno(err);
02890 r = -1;
02891 }
02892 CloseHandle(wol.hEvent);
02893 }
02894
02895 return r;
02896 }
02897
02898 int WSAAPI
02899 rb_w32_recv(int fd, char *buf, int len, int flags)
02900 {
02901 return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
02902 }
02903
02904 int WSAAPI
02905 rb_w32_recvfrom(int fd, char *buf, int len, int flags,
02906 struct sockaddr *from, int *fromlen)
02907 {
02908 return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
02909 }
02910
02911 int WSAAPI
02912 rb_w32_send(int fd, const char *buf, int len, int flags)
02913 {
02914 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL);
02915 }
02916
02917 int WSAAPI
02918 rb_w32_sendto(int fd, const char *buf, int len, int flags,
02919 const struct sockaddr *to, int tolen)
02920 {
02921 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
02922 (struct sockaddr *)to, &tolen);
02923 }
02924
02925 #if !defined(MSG_TRUNC) && !defined(__MINGW32__)
02926 typedef struct {
02927 SOCKADDR *name;
02928 int namelen;
02929 WSABUF *lpBuffers;
02930 DWORD dwBufferCount;
02931 WSABUF Control;
02932 DWORD dwFlags;
02933 } WSAMSG;
02934 #endif
02935 #ifndef WSAID_WSARECVMSG
02936 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
02937 #endif
02938 #ifndef WSAID_WSASENDMSG
02939 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
02940 #endif
02941
02942 #define msghdr_to_wsamsg(msg, wsamsg) \
02943 do { \
02944 int i; \
02945 (wsamsg)->name = (msg)->msg_name; \
02946 (wsamsg)->namelen = (msg)->msg_namelen; \
02947 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
02948 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
02949 for (i = 0; i < (msg)->msg_iovlen; ++i) { \
02950 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
02951 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
02952 } \
02953 (wsamsg)->Control.buf = (msg)->msg_control; \
02954 (wsamsg)->Control.len = (msg)->msg_controllen; \
02955 (wsamsg)->dwFlags = (msg)->msg_flags; \
02956 } while (0)
02957
02958 int
02959 recvmsg(int fd, struct msghdr *msg, int flags)
02960 {
02961 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
02962 static WSARecvMsg_t pWSARecvMsg = NULL;
02963 WSAMSG wsamsg;
02964 SOCKET s;
02965 st_data_t data;
02966 int mode;
02967 DWORD len;
02968 int ret;
02969
02970 if (!NtSocketsInitialized)
02971 StartSockets();
02972
02973 s = TO_SOCKET(fd);
02974
02975 if (!pWSARecvMsg) {
02976 static GUID guid = WSAID_WSARECVMSG;
02977 DWORD dmy;
02978 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
02979 &pWSARecvMsg, sizeof(pWSARecvMsg), &dmy, NULL, NULL);
02980 if (!pWSARecvMsg) {
02981 errno = ENOSYS;
02982 return -1;
02983 }
02984 }
02985
02986 msghdr_to_wsamsg(msg, &wsamsg);
02987 wsamsg.dwFlags |= flags;
02988
02989 st_lookup(socklist, (st_data_t)s, &data);
02990 mode = (int)data;
02991 if (!cancel_io || (mode & O_NONBLOCK)) {
02992 RUBY_CRITICAL({
02993 if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
02994 errno = map_errno(WSAGetLastError());
02995 len = -1;
02996 }
02997 });
02998 }
02999 else {
03000 DWORD size;
03001 int err;
03002 WSAOVERLAPPED wol;
03003 memset(&wol, 0, sizeof(wol));
03004 RUBY_CRITICAL({
03005 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03006 ret = pWSARecvMsg(s, &wsamsg, &len, &wol, NULL);
03007 });
03008
03009 if (ret != SOCKET_ERROR) {
03010
03011 }
03012 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
03013 DWORD flg;
03014 switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
03015 case WAIT_OBJECT_0:
03016 RUBY_CRITICAL(
03017 ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
03018 );
03019 if (ret) {
03020 len = size;
03021 break;
03022 }
03023
03024 default:
03025 errno = map_errno(WSAGetLastError());
03026
03027 case WAIT_OBJECT_0 + 1:
03028
03029 len = -1;
03030 cancel_io((HANDLE)s);
03031 break;
03032 }
03033 }
03034 else {
03035 errno = map_errno(err);
03036 len = -1;
03037 }
03038 CloseHandle(wol.hEvent);
03039 }
03040 if (ret == SOCKET_ERROR)
03041 return -1;
03042
03043
03044 msg->msg_name = wsamsg.name;
03045 msg->msg_namelen = wsamsg.namelen;
03046 msg->msg_flags = wsamsg.dwFlags;
03047
03048 return len;
03049 }
03050
03051 int
03052 sendmsg(int fd, const struct msghdr *msg, int flags)
03053 {
03054 typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
03055 static WSASendMsg_t pWSASendMsg = NULL;
03056 WSAMSG wsamsg;
03057 SOCKET s;
03058 st_data_t data;
03059 int mode;
03060 DWORD len;
03061 int ret;
03062
03063 if (!NtSocketsInitialized)
03064 StartSockets();
03065
03066 s = TO_SOCKET(fd);
03067
03068 if (!pWSASendMsg) {
03069 static GUID guid = WSAID_WSASENDMSG;
03070 DWORD dmy;
03071 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
03072 &pWSASendMsg, sizeof(pWSASendMsg), &dmy, NULL, NULL);
03073 if (!pWSASendMsg) {
03074 errno = ENOSYS;
03075 return -1;
03076 }
03077 }
03078
03079 msghdr_to_wsamsg(msg, &wsamsg);
03080
03081 st_lookup(socklist, (st_data_t)s, &data);
03082 mode = (int)data;
03083 if (!cancel_io || (mode & O_NONBLOCK)) {
03084 RUBY_CRITICAL({
03085 if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
03086 errno = map_errno(WSAGetLastError());
03087 len = -1;
03088 }
03089 });
03090 }
03091 else {
03092 DWORD size;
03093 int err;
03094 WSAOVERLAPPED wol;
03095 memset(&wol, 0, sizeof(wol));
03096 RUBY_CRITICAL({
03097 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03098 ret = pWSASendMsg(s, &wsamsg, flags, &len, &wol, NULL);
03099 });
03100
03101 if (ret != SOCKET_ERROR) {
03102
03103 }
03104 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
03105 DWORD flg;
03106 switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
03107 case WAIT_OBJECT_0:
03108 RUBY_CRITICAL(
03109 ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
03110 );
03111 if (ret) {
03112 len = size;
03113 break;
03114 }
03115
03116 default:
03117 errno = map_errno(WSAGetLastError());
03118
03119 case WAIT_OBJECT_0 + 1:
03120
03121 len = -1;
03122 cancel_io((HANDLE)s);
03123 break;
03124 }
03125 }
03126 else {
03127 errno = map_errno(err);
03128 len = -1;
03129 }
03130 CloseHandle(wol.hEvent);
03131 }
03132
03133 return len;
03134 }
03135
03136 #undef setsockopt
03137
03138 int WSAAPI
03139 rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
03140 {
03141 int r;
03142 if (!NtSocketsInitialized) {
03143 StartSockets();
03144 }
03145 RUBY_CRITICAL({
03146 r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
03147 if (r == SOCKET_ERROR)
03148 errno = map_errno(WSAGetLastError());
03149 });
03150 return r;
03151 }
03152
03153 #undef shutdown
03154
03155 int WSAAPI
03156 rb_w32_shutdown(int s, int how)
03157 {
03158 int r;
03159 if (!NtSocketsInitialized) {
03160 StartSockets();
03161 }
03162 RUBY_CRITICAL({
03163 r = shutdown(TO_SOCKET(s), how);
03164 if (r == SOCKET_ERROR)
03165 errno = map_errno(WSAGetLastError());
03166 });
03167 return r;
03168 }
03169
03170 static SOCKET
03171 open_ifs_socket(int af, int type, int protocol)
03172 {
03173 unsigned long proto_buffers_len = 0;
03174 int error_code;
03175 SOCKET out = INVALID_SOCKET;
03176
03177 if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) {
03178 error_code = WSAGetLastError();
03179 if (error_code == WSAENOBUFS) {
03180 WSAPROTOCOL_INFO *proto_buffers;
03181 int protocols_available = 0;
03182
03183 proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len);
03184 if (!proto_buffers) {
03185 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
03186 return INVALID_SOCKET;
03187 }
03188
03189 protocols_available =
03190 WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len);
03191 if (protocols_available != SOCKET_ERROR) {
03192 int i;
03193 for (i = 0; i < protocols_available; i++) {
03194 if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
03195 (type != proto_buffers[i].iSocketType) ||
03196 (protocol != 0 && protocol != proto_buffers[i].iProtocol))
03197 continue;
03198
03199 if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
03200 continue;
03201
03202 out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
03203 WSA_FLAG_OVERLAPPED);
03204 break;
03205 }
03206 if (out == INVALID_SOCKET)
03207 out = WSASocket(af, type, protocol, NULL, 0, 0);
03208 }
03209
03210 free(proto_buffers);
03211 }
03212 }
03213
03214 return out;
03215 }
03216
03217 #undef socket
03218
03219 int WSAAPI
03220 rb_w32_socket(int af, int type, int protocol)
03221 {
03222 SOCKET s;
03223 int fd;
03224
03225 if (!NtSocketsInitialized) {
03226 StartSockets();
03227 }
03228 RUBY_CRITICAL({
03229 s = open_ifs_socket(af, type, protocol);
03230 if (s == INVALID_SOCKET) {
03231 errno = map_errno(WSAGetLastError());
03232 fd = -1;
03233 }
03234 else {
03235 fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
03236 if (fd != -1)
03237 st_insert(socklist, (st_data_t)s, (st_data_t)0);
03238 else
03239 closesocket(s);
03240 }
03241 });
03242 return fd;
03243 }
03244
03245 #undef gethostbyaddr
03246
03247 struct hostent * WSAAPI
03248 rb_w32_gethostbyaddr(const char *addr, int len, int type)
03249 {
03250 struct hostent *r;
03251 if (!NtSocketsInitialized) {
03252 StartSockets();
03253 }
03254 RUBY_CRITICAL({
03255 r = gethostbyaddr(addr, len, type);
03256 if (r == NULL)
03257 errno = map_errno(WSAGetLastError());
03258 });
03259 return r;
03260 }
03261
03262 #undef gethostbyname
03263
03264 struct hostent * WSAAPI
03265 rb_w32_gethostbyname(const char *name)
03266 {
03267 struct hostent *r;
03268 if (!NtSocketsInitialized) {
03269 StartSockets();
03270 }
03271 RUBY_CRITICAL({
03272 r = gethostbyname(name);
03273 if (r == NULL)
03274 errno = map_errno(WSAGetLastError());
03275 });
03276 return r;
03277 }
03278
03279 #undef gethostname
03280
03281 int WSAAPI
03282 rb_w32_gethostname(char *name, int len)
03283 {
03284 int r;
03285 if (!NtSocketsInitialized) {
03286 StartSockets();
03287 }
03288 RUBY_CRITICAL({
03289 r = gethostname(name, len);
03290 if (r == SOCKET_ERROR)
03291 errno = map_errno(WSAGetLastError());
03292 });
03293 return r;
03294 }
03295
03296 #undef getprotobyname
03297
03298 struct protoent * WSAAPI
03299 rb_w32_getprotobyname(const char *name)
03300 {
03301 struct protoent *r;
03302 if (!NtSocketsInitialized) {
03303 StartSockets();
03304 }
03305 RUBY_CRITICAL({
03306 r = getprotobyname(name);
03307 if (r == NULL)
03308 errno = map_errno(WSAGetLastError());
03309 });
03310 return r;
03311 }
03312
03313 #undef getprotobynumber
03314
03315 struct protoent * WSAAPI
03316 rb_w32_getprotobynumber(int num)
03317 {
03318 struct protoent *r;
03319 if (!NtSocketsInitialized) {
03320 StartSockets();
03321 }
03322 RUBY_CRITICAL({
03323 r = getprotobynumber(num);
03324 if (r == NULL)
03325 errno = map_errno(WSAGetLastError());
03326 });
03327 return r;
03328 }
03329
03330 #undef getservbyname
03331
03332 struct servent * WSAAPI
03333 rb_w32_getservbyname(const char *name, const char *proto)
03334 {
03335 struct servent *r;
03336 if (!NtSocketsInitialized) {
03337 StartSockets();
03338 }
03339 RUBY_CRITICAL({
03340 r = getservbyname(name, proto);
03341 if (r == NULL)
03342 errno = map_errno(WSAGetLastError());
03343 });
03344 return r;
03345 }
03346
03347 #undef getservbyport
03348
03349 struct servent * WSAAPI
03350 rb_w32_getservbyport(int port, const char *proto)
03351 {
03352 struct servent *r;
03353 if (!NtSocketsInitialized) {
03354 StartSockets();
03355 }
03356 RUBY_CRITICAL({
03357 r = getservbyport(port, proto);
03358 if (r == NULL)
03359 errno = map_errno(WSAGetLastError());
03360 });
03361 return r;
03362 }
03363
03364 static int
03365 socketpair_internal(int af, int type, int protocol, SOCKET *sv)
03366 {
03367 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
03368 struct sockaddr_in sock_in4;
03369 #ifdef INET6
03370 struct sockaddr_in6 sock_in6;
03371 #endif
03372 struct sockaddr *addr;
03373 int ret = -1;
03374 int len;
03375
03376 if (!NtSocketsInitialized) {
03377 StartSockets();
03378 }
03379
03380 switch (af) {
03381 case AF_INET:
03382 #if defined PF_INET && PF_INET != AF_INET
03383 case PF_INET:
03384 #endif
03385 sock_in4.sin_family = AF_INET;
03386 sock_in4.sin_port = 0;
03387 sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
03388 addr = (struct sockaddr *)&sock_in4;
03389 len = sizeof(sock_in4);
03390 break;
03391 #ifdef INET6
03392 case AF_INET6:
03393 memset(&sock_in6, 0, sizeof(sock_in6));
03394 sock_in6.sin6_family = AF_INET6;
03395 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
03396 addr = (struct sockaddr *)&sock_in6;
03397 len = sizeof(sock_in6);
03398 break;
03399 #endif
03400 default:
03401 errno = EAFNOSUPPORT;
03402 return -1;
03403 }
03404 if (type != SOCK_STREAM) {
03405 errno = EPROTOTYPE;
03406 return -1;
03407 }
03408
03409 sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
03410 sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
03411 RUBY_CRITICAL({
03412 do {
03413 svr = open_ifs_socket(af, type, protocol);
03414 if (svr == INVALID_SOCKET)
03415 break;
03416 if (bind(svr, addr, len) < 0)
03417 break;
03418 if (getsockname(svr, addr, &len) < 0)
03419 break;
03420 if (type == SOCK_STREAM)
03421 listen(svr, 5);
03422
03423 w = open_ifs_socket(af, type, protocol);
03424 if (w == INVALID_SOCKET)
03425 break;
03426 if (connect(w, addr, len) < 0)
03427 break;
03428
03429 r = accept(svr, addr, &len);
03430 if (r == INVALID_SOCKET)
03431 break;
03432
03433 ret = 0;
03434 } while (0);
03435
03436 if (ret < 0) {
03437 errno = map_errno(WSAGetLastError());
03438 if (r != INVALID_SOCKET)
03439 closesocket(r);
03440 if (w != INVALID_SOCKET)
03441 closesocket(w);
03442 }
03443 else {
03444 sv[0] = r;
03445 sv[1] = w;
03446 }
03447 if (svr != INVALID_SOCKET)
03448 closesocket(svr);
03449 });
03450
03451 return ret;
03452 }
03453
03454 int
03455 rb_w32_socketpair(int af, int type, int protocol, int *sv)
03456 {
03457 SOCKET pair[2];
03458
03459 if (socketpair_internal(af, type, protocol, pair) < 0)
03460 return -1;
03461 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
03462 if (sv[0] == -1) {
03463 closesocket(pair[0]);
03464 closesocket(pair[1]);
03465 return -1;
03466 }
03467 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
03468 if (sv[1] == -1) {
03469 rb_w32_close(sv[0]);
03470 closesocket(pair[1]);
03471 return -1;
03472 }
03473 st_insert(socklist, (st_data_t)pair[0], (st_data_t)0);
03474 st_insert(socklist, (st_data_t)pair[1], (st_data_t)0);
03475
03476 return 0;
03477 }
03478
03479
03480
03481
03482
03483 void endhostent(void) {}
03484 void endnetent(void) {}
03485 void endprotoent(void) {}
03486 void endservent(void) {}
03487
03488 struct netent *getnetent (void) {return (struct netent *) NULL;}
03489
03490 struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;}
03491
03492 struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;}
03493
03494 struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
03495
03496 struct servent *getservent (void) {return (struct servent *) NULL;}
03497
03498 void sethostent (int stayopen) {}
03499
03500 void setnetent (int stayopen) {}
03501
03502 void setprotoent (int stayopen) {}
03503
03504 void setservent (int stayopen) {}
03505
03506 int
03507 fcntl(int fd, int cmd, ...)
03508 {
03509 SOCKET sock = TO_SOCKET(fd);
03510 va_list va;
03511 int arg;
03512 int ret;
03513 int flag = 0;
03514 st_data_t data;
03515 u_long ioctlArg;
03516
03517 if (!is_socket(sock)) {
03518 errno = EBADF;
03519 return -1;
03520 }
03521 if (cmd != F_SETFL) {
03522 errno = EINVAL;
03523 return -1;
03524 }
03525
03526 va_start(va, cmd);
03527 arg = va_arg(va, int);
03528 va_end(va);
03529 st_lookup(socklist, (st_data_t)sock, &data);
03530 flag = (int)data;
03531 if (arg & O_NONBLOCK) {
03532 flag |= O_NONBLOCK;
03533 ioctlArg = 1;
03534 }
03535 else {
03536 flag &= ~O_NONBLOCK;
03537 ioctlArg = 0;
03538 }
03539 RUBY_CRITICAL({
03540 ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
03541 if (ret == 0)
03542 st_insert(socklist, (st_data_t)sock, (st_data_t)flag);
03543 else
03544 errno = map_errno(WSAGetLastError());
03545 });
03546
03547 return ret;
03548 }
03549
03550 #ifndef WNOHANG
03551 #define WNOHANG -1
03552 #endif
03553
03554 static rb_pid_t
03555 poll_child_status(struct ChildRecord *child, int *stat_loc)
03556 {
03557 DWORD exitcode;
03558 DWORD err;
03559
03560 if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
03561
03562 err = GetLastError();
03563 if (err == ERROR_INVALID_PARAMETER)
03564 errno = ECHILD;
03565 else {
03566 if (GetLastError() == ERROR_INVALID_HANDLE)
03567 errno = EINVAL;
03568 else
03569 errno = map_errno(GetLastError());
03570 }
03571 CloseChildHandle(child);
03572 return -1;
03573 }
03574 if (exitcode != STILL_ACTIVE) {
03575
03576 rb_pid_t pid = child->pid;
03577 CloseChildHandle(child);
03578 if (stat_loc) *stat_loc = exitcode << 8;
03579 return pid;
03580 }
03581 return 0;
03582 }
03583
03584 rb_pid_t
03585 waitpid(rb_pid_t pid, int *stat_loc, int options)
03586 {
03587 DWORD timeout;
03588
03589 if (options == WNOHANG) {
03590 timeout = 0;
03591 } else {
03592 timeout = INFINITE;
03593 }
03594
03595 if (pid == -1) {
03596 int count = 0;
03597 int ret;
03598 HANDLE events[MAXCHILDNUM];
03599
03600 FOREACH_CHILD(child) {
03601 if (!child->pid || child->pid < 0) continue;
03602 if ((pid = poll_child_status(child, stat_loc))) return pid;
03603 events[count++] = child->hProcess;
03604 } END_FOREACH_CHILD;
03605 if (!count) {
03606 errno = ECHILD;
03607 return -1;
03608 }
03609
03610 ret = rb_w32_wait_events_blocking(events, count, timeout);
03611 if (ret == WAIT_TIMEOUT) return 0;
03612 if ((ret -= WAIT_OBJECT_0) == count) {
03613 return -1;
03614 }
03615 if (ret > count) {
03616 errno = map_errno(GetLastError());
03617 return -1;
03618 }
03619
03620 return poll_child_status(FindChildSlotByHandle(events[ret]), stat_loc);
03621 }
03622 else {
03623 struct ChildRecord* child = FindChildSlot(pid);
03624 if (!child) {
03625 errno = ECHILD;
03626 return -1;
03627 }
03628
03629 while (!(pid = poll_child_status(child, stat_loc))) {
03630
03631 if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) {
03632
03633 pid = 0;
03634 break;
03635 }
03636 }
03637 }
03638
03639 return pid;
03640 }
03641
03642 #include <sys/timeb.h>
03643
03644 static int
03645 filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
03646 {
03647 ULARGE_INTEGER tmp;
03648 unsigned LONG_LONG lt;
03649
03650 tmp.LowPart = ft->dwLowDateTime;
03651 tmp.HighPart = ft->dwHighDateTime;
03652 lt = tmp.QuadPart;
03653
03654
03655
03656
03657
03658 lt /= 10;
03659 lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000;
03660
03661 tv->tv_sec = (long)(lt / (1000 * 1000));
03662 tv->tv_usec = (long)(lt % (1000 * 1000));
03663
03664 return tv->tv_sec > 0 ? 0 : -1;
03665 }
03666
03667 int _cdecl
03668 gettimeofday(struct timeval *tv, struct timezone *tz)
03669 {
03670 FILETIME ft;
03671
03672 GetSystemTimeAsFileTime(&ft);
03673 filetime_to_timeval(&ft, tv);
03674
03675 return 0;
03676 }
03677
03678 char *
03679 rb_w32_getcwd(char *buffer, int size)
03680 {
03681 char *p = buffer;
03682 int len;
03683
03684 len = GetCurrentDirectory(0, NULL);
03685 if (!len) {
03686 errno = map_errno(GetLastError());
03687 return NULL;
03688 }
03689
03690 if (p) {
03691 if (size < len) {
03692 errno = ERANGE;
03693 return NULL;
03694 }
03695 }
03696 else {
03697 p = malloc(len);
03698 size = len;
03699 if (!p) {
03700 errno = ENOMEM;
03701 return NULL;
03702 }
03703 }
03704
03705 if (!GetCurrentDirectory(size, p)) {
03706 errno = map_errno(GetLastError());
03707 if (!buffer)
03708 free(p);
03709 return NULL;
03710 }
03711
03712 translate_char(p, '\\', '/');
03713
03714 return p;
03715 }
03716
03717 int
03718 chown(const char *path, int owner, int group)
03719 {
03720 return 0;
03721 }
03722
03723 int
03724 rb_w32_uchown(const char *path, int owner, int group)
03725 {
03726 return 0;
03727 }
03728
03729 int
03730 kill(int pid, int sig)
03731 {
03732 int ret = 0;
03733 DWORD err;
03734
03735 if (pid <= 0) {
03736 errno = EINVAL;
03737 return -1;
03738 }
03739
03740 (void)IfWin95(pid = -pid, 0);
03741 if ((unsigned int)pid == GetCurrentProcessId() &&
03742 (sig != 0 && sig != SIGKILL)) {
03743 if ((ret = raise(sig)) != 0) {
03744
03745 errno = EINVAL;
03746 }
03747 return ret;
03748 }
03749
03750 switch (sig) {
03751 case 0:
03752 RUBY_CRITICAL({
03753 HANDLE hProc =
03754 OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
03755 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
03756 if (GetLastError() == ERROR_INVALID_PARAMETER) {
03757 errno = ESRCH;
03758 }
03759 else {
03760 errno = EPERM;
03761 }
03762 ret = -1;
03763 }
03764 else {
03765 CloseHandle(hProc);
03766 }
03767 });
03768 break;
03769
03770 case SIGINT:
03771 RUBY_CRITICAL({
03772 if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) {
03773 if ((err = GetLastError()) == 0)
03774 errno = EPERM;
03775 else
03776 errno = map_errno(GetLastError());
03777 ret = -1;
03778 }
03779 });
03780 break;
03781
03782 case SIGKILL:
03783 RUBY_CRITICAL({
03784 HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD)pid);
03785 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
03786 if (GetLastError() == ERROR_INVALID_PARAMETER) {
03787 errno = ESRCH;
03788 }
03789 else {
03790 errno = EPERM;
03791 }
03792 ret = -1;
03793 }
03794 else {
03795 if (!TerminateProcess(hProc, 0)) {
03796 errno = EPERM;
03797 ret = -1;
03798 }
03799 CloseHandle(hProc);
03800 }
03801 });
03802 break;
03803
03804 default:
03805 errno = EINVAL;
03806 ret = -1;
03807 break;
03808 }
03809
03810 return ret;
03811 }
03812
03813 static int
03814 wlink(const WCHAR *from, const WCHAR *to)
03815 {
03816 static BOOL (WINAPI *pCreateHardLinkW)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES) = NULL;
03817 static int myerrno = 0;
03818
03819 if (!pCreateHardLinkW && !myerrno) {
03820 HANDLE hKernel;
03821
03822 hKernel = GetModuleHandle("kernel32.dll");
03823 if (hKernel) {
03824 pCreateHardLinkW = (BOOL (WINAPI *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))GetProcAddress(hKernel, "CreateHardLinkW");
03825 if (!pCreateHardLinkW) {
03826 myerrno = ENOSYS;
03827 }
03828 }
03829 else {
03830 myerrno = map_errno(GetLastError());
03831 }
03832 }
03833 if (!pCreateHardLinkW) {
03834 errno = myerrno;
03835 return -1;
03836 }
03837
03838 if (!pCreateHardLinkW(to, from, NULL)) {
03839 errno = map_errno(GetLastError());
03840 return -1;
03841 }
03842
03843 return 0;
03844 }
03845
03846 int
03847 rb_w32_ulink(const char *from, const char *to)
03848 {
03849 WCHAR *wfrom;
03850 WCHAR *wto;
03851 int ret;
03852
03853 if (!(wfrom = utf8_to_wstr(from, NULL)))
03854 return -1;
03855 if (!(wto = utf8_to_wstr(to, NULL))) {
03856 free(wfrom);
03857 return -1;
03858 }
03859 ret = wlink(wfrom, wto);
03860 free(wto);
03861 free(wfrom);
03862 return ret;
03863 }
03864
03865 int
03866 link(const char *from, const char *to)
03867 {
03868 WCHAR *wfrom;
03869 WCHAR *wto;
03870 int ret;
03871
03872 if (!(wfrom = filecp_to_wstr(from, NULL)))
03873 return -1;
03874 if (!(wto = filecp_to_wstr(to, NULL))) {
03875 free(wfrom);
03876 return -1;
03877 }
03878 ret = wlink(wfrom, wto);
03879 free(wto);
03880 free(wfrom);
03881 return ret;
03882 }
03883
03884 int
03885 wait(int *status)
03886 {
03887 return waitpid(-1, status, 0);
03888 }
03889
03890 char *
03891 rb_w32_getenv(const char *name)
03892 {
03893 int len = strlen(name);
03894 char *env;
03895
03896 if (len == 0) return NULL;
03897 if (envarea) FreeEnvironmentStrings(envarea);
03898 envarea = GetEnvironmentStrings();
03899 if (!envarea) {
03900 map_errno(GetLastError());
03901 return NULL;
03902 }
03903
03904 for (env = envarea; *env; env += strlen(env) + 1)
03905 if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
03906 return env + len + 1;
03907
03908 return NULL;
03909 }
03910
03911 static int
03912 wrename(const WCHAR *oldpath, const WCHAR *newpath)
03913 {
03914 int res = 0;
03915 int oldatts;
03916 int newatts;
03917
03918 oldatts = GetFileAttributesW(oldpath);
03919 newatts = GetFileAttributesW(newpath);
03920
03921 if (oldatts == -1) {
03922 errno = map_errno(GetLastError());
03923 return -1;
03924 }
03925
03926 RUBY_CRITICAL({
03927 if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
03928 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
03929
03930 if (!MoveFileW(oldpath, newpath))
03931 res = -1;
03932
03933 if (res) {
03934 switch (GetLastError()) {
03935 case ERROR_ALREADY_EXISTS:
03936 case ERROR_FILE_EXISTS:
03937 if (IsWinNT()) {
03938 if (MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
03939 res = 0;
03940 } else {
03941 for (;;) {
03942 if (!DeleteFileW(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND)
03943 break;
03944 else if (MoveFileW(oldpath, newpath)) {
03945 res = 0;
03946 break;
03947 }
03948 }
03949 }
03950 }
03951 }
03952
03953 if (res)
03954 errno = map_errno(GetLastError());
03955 else
03956 SetFileAttributesW(newpath, oldatts);
03957 });
03958
03959 return res;
03960 }
03961
03962 int rb_w32_urename(const char *from, const char *to)
03963 {
03964 WCHAR *wfrom;
03965 WCHAR *wto;
03966 int ret = -1;
03967
03968 if (!(wfrom = utf8_to_wstr(from, NULL)))
03969 return -1;
03970 if (!(wto = utf8_to_wstr(to, NULL))) {
03971 free(wfrom);
03972 return -1;
03973 }
03974 ret = wrename(wfrom, wto);
03975 free(wto);
03976 free(wfrom);
03977 return ret;
03978 }
03979
03980 int rb_w32_rename(const char *from, const char *to)
03981 {
03982 WCHAR *wfrom;
03983 WCHAR *wto;
03984 int ret = -1;
03985
03986 if (!(wfrom = filecp_to_wstr(from, NULL)))
03987 return -1;
03988 if (!(wto = filecp_to_wstr(to, NULL))) {
03989 free(wfrom);
03990 return -1;
03991 }
03992 ret = wrename(wfrom, wto);
03993 free(wto);
03994 free(wfrom);
03995 return ret;
03996 }
03997
03998 static int
03999 isUNCRoot(const WCHAR *path)
04000 {
04001 if (path[0] == L'\\' && path[1] == L'\\') {
04002 const WCHAR *p;
04003 for (p = path + 2; *p; p++) {
04004 if (*p == L'\\')
04005 break;
04006 }
04007 if (p[0] && p[1]) {
04008 for (p++; *p; p++) {
04009 if (*p == L'\\')
04010 break;
04011 }
04012 if (!p[0] || !p[1] || (p[1] == L'.' && !p[2]))
04013 return 1;
04014 }
04015 }
04016 return 0;
04017 }
04018
04019 #define COPY_STAT(src, dest, size_cast) do { \
04020 (dest).st_dev = (src).st_dev; \
04021 (dest).st_ino = (src).st_ino; \
04022 (dest).st_mode = (src).st_mode; \
04023 (dest).st_nlink = (src).st_nlink; \
04024 (dest).st_uid = (src).st_uid; \
04025 (dest).st_gid = (src).st_gid; \
04026 (dest).st_rdev = (src).st_rdev; \
04027 (dest).st_size = size_cast(src).st_size; \
04028 (dest).st_atime = (src).st_atime; \
04029 (dest).st_mtime = (src).st_mtime; \
04030 (dest).st_ctime = (src).st_ctime; \
04031 } while (0)
04032
04033 #ifdef __BORLANDC__
04034 #undef fstat
04035 int
04036 rb_w32_fstat(int fd, struct stat *st)
04037 {
04038 BY_HANDLE_FILE_INFORMATION info;
04039 int ret = fstat(fd, st);
04040
04041 if (ret) return ret;
04042 st->st_mode &= ~(S_IWGRP | S_IWOTH);
04043 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info) &&
04044 !(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04045 st->st_mode |= S_IWUSR;
04046 }
04047 return ret;
04048 }
04049
04050 int
04051 rb_w32_fstati64(int fd, struct stati64 *st)
04052 {
04053 BY_HANDLE_FILE_INFORMATION info;
04054 struct stat tmp;
04055 int ret = fstat(fd, &tmp);
04056
04057 if (ret) return ret;
04058 tmp.st_mode &= ~(S_IWGRP | S_IWOTH);
04059 COPY_STAT(tmp, *st, +);
04060 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
04061 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04062 st->st_mode |= S_IWUSR;
04063 }
04064 st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
04065 }
04066 return ret;
04067 }
04068 #endif
04069
04070 static time_t
04071 filetime_to_unixtime(const FILETIME *ft)
04072 {
04073 struct timeval tv;
04074
04075 if (filetime_to_timeval(ft, &tv) == (time_t)-1)
04076 return 0;
04077 else
04078 return tv.tv_sec;
04079 }
04080
04081 static unsigned
04082 fileattr_to_unixmode(DWORD attr, const WCHAR *path)
04083 {
04084 unsigned mode = 0;
04085
04086 if (attr & FILE_ATTRIBUTE_READONLY) {
04087 mode |= S_IREAD;
04088 }
04089 else {
04090 mode |= S_IREAD | S_IWRITE | S_IWUSR;
04091 }
04092
04093 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
04094 mode |= S_IFDIR | S_IEXEC;
04095 }
04096 else {
04097 mode |= S_IFREG;
04098 }
04099
04100 if (path && (mode & S_IFREG)) {
04101 const WCHAR *end = path + lstrlenW(path);
04102 while (path < end) {
04103 end = CharPrevW(path, end);
04104 if (*end == L'.') {
04105 if ((_wcsicmp(end, L".bat") == 0) ||
04106 (_wcsicmp(end, L".cmd") == 0) ||
04107 (_wcsicmp(end, L".com") == 0) ||
04108 (_wcsicmp(end, L".exe") == 0)) {
04109 mode |= S_IEXEC;
04110 }
04111 break;
04112 }
04113 }
04114 }
04115
04116 mode |= (mode & 0700) >> 3;
04117 mode |= (mode & 0700) >> 6;
04118
04119 return mode;
04120 }
04121
04122 static int
04123 check_valid_dir(const WCHAR *path)
04124 {
04125 WIN32_FIND_DATAW fd;
04126 HANDLE fh = open_dir_handle(path, &fd);
04127 if (fh == INVALID_HANDLE_VALUE)
04128 return -1;
04129 FindClose(fh);
04130 return 0;
04131 }
04132
04133 static int
04134 winnt_stat(const WCHAR *path, struct stati64 *st)
04135 {
04136 HANDLE h;
04137 WIN32_FIND_DATAW wfd;
04138
04139 memset(st, 0, sizeof(*st));
04140 st->st_nlink = 1;
04141
04142 if (wcspbrk(path, L"?*")) {
04143 errno = ENOENT;
04144 return -1;
04145 }
04146 h = FindFirstFileW(path, &wfd);
04147 if (h != INVALID_HANDLE_VALUE) {
04148 FindClose(h);
04149 st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path);
04150 st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
04151 st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
04152 st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
04153 st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
04154 }
04155 else {
04156
04157
04158 DWORD attr = GetFileAttributesW(path);
04159 if (attr == (DWORD)-1L) {
04160 errno = map_errno(GetLastError());
04161 return -1;
04162 }
04163 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
04164 if (check_valid_dir(path)) return -1;
04165 }
04166 st->st_mode = fileattr_to_unixmode(attr, path);
04167 }
04168
04169 st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?
04170 towupper(path[0]) - L'A' : _getdrive() - 1;
04171
04172 return 0;
04173 }
04174
04175 #ifdef WIN95
04176 static int
04177 win95_stat(const WCHAR *path, struct stati64 *st)
04178 {
04179 int ret = _wstati64(path, st);
04180 if (ret) return ret;
04181 if (st->st_mode & S_IFDIR) {
04182 return check_valid_dir(path);
04183 }
04184 return 0;
04185 }
04186 #else
04187 #define win95_stat(path, st) -1
04188 #endif
04189
04190 int
04191 rb_w32_stat(const char *path, struct stat *st)
04192 {
04193 struct stati64 tmp;
04194
04195 if (rb_w32_stati64(path, &tmp)) return -1;
04196 COPY_STAT(tmp, *st, (_off_t));
04197 return 0;
04198 }
04199
04200 static int
04201 wstati64(const WCHAR *path, struct stati64 *st)
04202 {
04203 const WCHAR *p;
04204 WCHAR *buf1, *s, *end;
04205 int len, size;
04206 int ret;
04207
04208 if (!path || !st) {
04209 errno = EFAULT;
04210 return -1;
04211 }
04212 size = lstrlenW(path) + 2;
04213 buf1 = ALLOCA_N(WCHAR, size);
04214 for (p = path, s = buf1; *p; p++, s++) {
04215 if (*p == L'/')
04216 *s = L'\\';
04217 else
04218 *s = *p;
04219 }
04220 *s = '\0';
04221 len = s - buf1;
04222 if (!len || L'\"' == *(--s)) {
04223 errno = ENOENT;
04224 return -1;
04225 }
04226 end = buf1 + len - 1;
04227
04228 if (isUNCRoot(buf1)) {
04229 if (*end == L'.')
04230 *end = L'\0';
04231 else if (*end != L'\\')
04232 lstrcatW(buf1, L"\\");
04233 }
04234 else if (*end == L'\\' || (buf1 + 1 == end && *end == L':'))
04235 lstrcatW(buf1, L".");
04236
04237 ret = IsWinNT() ? winnt_stat(buf1, st) : win95_stat(buf1, st);
04238 if (ret == 0) {
04239 st->st_mode &= ~(S_IWGRP | S_IWOTH);
04240 }
04241 return ret;
04242 }
04243
04244 int
04245 rb_w32_ustati64(const char *path, struct stati64 *st)
04246 {
04247 WCHAR *wpath;
04248 int ret;
04249
04250 if (!(wpath = utf8_to_wstr(path, NULL)))
04251 return -1;
04252 ret = wstati64(wpath, st);
04253 free(wpath);
04254 return ret;
04255 }
04256
04257 int
04258 rb_w32_stati64(const char *path, struct stati64 *st)
04259 {
04260 WCHAR *wpath;
04261 int ret;
04262
04263 if (!(wpath = filecp_to_wstr(path, NULL)))
04264 return -1;
04265 ret = wstati64(wpath, st);
04266 free(wpath);
04267 return ret;
04268 }
04269
04270 int
04271 rb_w32_access(const char *path, int mode)
04272 {
04273 struct stati64 stat;
04274 if (rb_w32_stati64(path, &stat) != 0)
04275 return -1;
04276 mode <<= 6;
04277 if ((stat.st_mode & mode) != mode) {
04278 errno = EACCES;
04279 return -1;
04280 }
04281 return 0;
04282 }
04283
04284 int
04285 rb_w32_uaccess(const char *path, int mode)
04286 {
04287 struct stati64 stat;
04288 if (rb_w32_ustati64(path, &stat) != 0)
04289 return -1;
04290 mode <<= 6;
04291 if ((stat.st_mode & mode) != mode) {
04292 errno = EACCES;
04293 return -1;
04294 }
04295 return 0;
04296 }
04297
04298 static int
04299 rb_chsize(HANDLE h, off_t size)
04300 {
04301 long upos, lpos, usize, lsize, uend, lend;
04302 off_t end;
04303 int ret = -1;
04304 DWORD e;
04305
04306 if (((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
04307 (e = GetLastError())) ||
04308 ((lend = GetFileSize(h, (DWORD *)&uend)) == -1L && (e = GetLastError()))) {
04309 errno = map_errno(e);
04310 return -1;
04311 }
04312 end = ((off_t)uend << 32) | (unsigned long)lend;
04313 usize = (long)(size >> 32);
04314 lsize = (long)size;
04315 if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L &&
04316 (e = GetLastError())) {
04317 errno = map_errno(e);
04318 }
04319 else if (!SetEndOfFile(h)) {
04320 errno = map_errno(GetLastError());
04321 }
04322 else {
04323 ret = 0;
04324 }
04325 SetFilePointer(h, lpos, &upos, SEEK_SET);
04326 return ret;
04327 }
04328
04329 int
04330 truncate(const char *path, off_t length)
04331 {
04332 HANDLE h;
04333 int ret;
04334 #ifdef WIN95
04335 if (IsWin95()) {
04336 int fd = open(path, O_WRONLY), e = 0;
04337 if (fd == -1) return -1;
04338 ret = chsize(fd, (unsigned long)length);
04339 if (ret == -1) e = errno;
04340 close(fd);
04341 if (ret == -1) errno = e;
04342 return ret;
04343 }
04344 #endif
04345 h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
04346 if (h == INVALID_HANDLE_VALUE) {
04347 errno = map_errno(GetLastError());
04348 return -1;
04349 }
04350 ret = rb_chsize(h, length);
04351 CloseHandle(h);
04352 return ret;
04353 }
04354
04355 int
04356 ftruncate(int fd, off_t length)
04357 {
04358 HANDLE h;
04359
04360 #ifdef WIN95
04361 if (IsWin95()) {
04362 return chsize(fd, (unsigned long)length);
04363 }
04364 #endif
04365 h = (HANDLE)_get_osfhandle(fd);
04366 if (h == (HANDLE)-1) return -1;
04367 return rb_chsize(h, length);
04368 }
04369
04370 #ifdef __BORLANDC__
04371 off_t
04372 _filelengthi64(int fd)
04373 {
04374 DWORD u, l;
04375 int e;
04376
04377 l = GetFileSize((HANDLE)_get_osfhandle(fd), &u);
04378 if (l == (DWORD)-1L && (e = GetLastError())) {
04379 errno = map_errno(e);
04380 return (off_t)-1;
04381 }
04382 return ((off_t)u << 32) | l;
04383 }
04384
04385 off_t
04386 _lseeki64(int fd, off_t offset, int whence)
04387 {
04388 long u, l;
04389 int e;
04390 HANDLE h = (HANDLE)_get_osfhandle(fd);
04391
04392 if (!h) {
04393 errno = EBADF;
04394 return -1;
04395 }
04396 u = (long)(offset >> 32);
04397 if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L &&
04398 (e = GetLastError())) {
04399 errno = map_errno(e);
04400 return -1;
04401 }
04402 return ((off_t)u << 32) | l;
04403 }
04404 #endif
04405
04406 int
04407 fseeko(FILE *stream, off_t offset, int whence)
04408 {
04409 off_t pos;
04410 switch (whence) {
04411 case SEEK_CUR:
04412 if (fgetpos(stream, (fpos_t *)&pos))
04413 return -1;
04414 pos += offset;
04415 break;
04416 case SEEK_END:
04417 if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1)
04418 return -1;
04419 pos += offset;
04420 break;
04421 default:
04422 pos = offset;
04423 break;
04424 }
04425 return fsetpos(stream, (fpos_t *)&pos);
04426 }
04427
04428 off_t
04429 ftello(FILE *stream)
04430 {
04431 off_t pos;
04432 if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1;
04433 return pos;
04434 }
04435
04436 static long
04437 filetime_to_clock(FILETIME *ft)
04438 {
04439 __int64 qw = ft->dwHighDateTime;
04440 qw <<= 32;
04441 qw |= ft->dwLowDateTime;
04442 qw /= 10000;
04443 return (long) qw;
04444 }
04445
04446 int
04447 rb_w32_times(struct tms *tmbuf)
04448 {
04449 FILETIME create, exit, kernel, user;
04450
04451 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
04452 tmbuf->tms_utime = filetime_to_clock(&user);
04453 tmbuf->tms_stime = filetime_to_clock(&kernel);
04454 tmbuf->tms_cutime = 0;
04455 tmbuf->tms_cstime = 0;
04456 }
04457 else {
04458 tmbuf->tms_utime = clock();
04459 tmbuf->tms_stime = 0;
04460 tmbuf->tms_cutime = 0;
04461 tmbuf->tms_cstime = 0;
04462 }
04463 return 0;
04464 }
04465
04466 #define yield_once() Sleep(0)
04467 #define yield_until(condition) do yield_once(); while (!(condition))
04468
04469 static void
04470 catch_interrupt(void)
04471 {
04472 yield_once();
04473 RUBY_CRITICAL(rb_w32_wait_events(NULL, 0, 0));
04474 }
04475
04476 #if defined __BORLANDC__
04477 #undef read
04478 int
04479 read(int fd, void *buf, size_t size)
04480 {
04481 int ret = _read(fd, buf, size);
04482 if ((ret < 0) && (errno == EPIPE)) {
04483 errno = 0;
04484 ret = 0;
04485 }
04486 catch_interrupt();
04487 return ret;
04488 }
04489 #endif
04490
04491 #undef fgetc
04492 int
04493 rb_w32_getc(FILE* stream)
04494 {
04495 int c;
04496 if (enough_to_get(stream->FILE_COUNT)) {
04497 c = (unsigned char)*stream->FILE_READPTR++;
04498 }
04499 else
04500 {
04501 c = _filbuf(stream);
04502 #if defined __BORLANDC__
04503 if ((c == EOF) && (errno == EPIPE)) {
04504 clearerr(stream);
04505 }
04506 #endif
04507 catch_interrupt();
04508 }
04509 return c;
04510 }
04511
04512 #undef fputc
04513 int
04514 rb_w32_putc(int c, FILE* stream)
04515 {
04516 if (enough_to_put(stream->FILE_COUNT)) {
04517 c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
04518 }
04519 else
04520 {
04521 c = _flsbuf(c, stream);
04522 catch_interrupt();
04523 }
04524 return c;
04525 }
04526
04527 struct asynchronous_arg_t {
04528
04529 void* stackaddr;
04530 int errnum;
04531
04532
04533 uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv);
04534 uintptr_t self;
04535 int argc;
04536 uintptr_t* argv;
04537 };
04538
04539 static DWORD WINAPI
04540 call_asynchronous(PVOID argp)
04541 {
04542 DWORD ret;
04543 struct asynchronous_arg_t *arg = argp;
04544 arg->stackaddr = &argp;
04545 ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
04546 arg->errnum = errno;
04547 return ret;
04548 }
04549
04550 uintptr_t
04551 rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self,
04552 int argc, uintptr_t* argv, uintptr_t intrval)
04553 {
04554 DWORD val;
04555 BOOL interrupted = FALSE;
04556 HANDLE thr;
04557
04558 RUBY_CRITICAL({
04559 struct asynchronous_arg_t arg;
04560
04561 arg.stackaddr = NULL;
04562 arg.errnum = 0;
04563 arg.func = func;
04564 arg.self = self;
04565 arg.argc = argc;
04566 arg.argv = argv;
04567
04568 thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
04569
04570 if (thr) {
04571 yield_until(arg.stackaddr);
04572
04573 if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
04574 interrupted = TRUE;
04575
04576 if (TerminateThread(thr, intrval)) {
04577 yield_once();
04578 }
04579 }
04580
04581 GetExitCodeThread(thr, &val);
04582 CloseHandle(thr);
04583
04584 if (interrupted) {
04585
04586 MEMORY_BASIC_INFORMATION m;
04587
04588 memset(&m, 0, sizeof(m));
04589 if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
04590 Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
04591 arg.stackaddr, GetLastError()));
04592 }
04593 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
04594 Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
04595 m.AllocationBase, GetLastError()));
04596 }
04597 errno = EINTR;
04598 }
04599 else {
04600 errno = arg.errnum;
04601 }
04602 }
04603 });
04604
04605 if (!thr) {
04606 rb_fatal("failed to launch waiter thread:%ld", GetLastError());
04607 }
04608
04609 return val;
04610 }
04611
04612 char **
04613 rb_w32_get_environ(void)
04614 {
04615 char *envtop, *env;
04616 char **myenvtop, **myenv;
04617 int num;
04618
04619
04620
04621
04622
04623
04624
04625
04626
04627
04628 envtop = GetEnvironmentStrings();
04629 for (env = envtop, num = 0; *env; env += strlen(env) + 1)
04630 if (*env != '=') num++;
04631
04632 myenvtop = (char **)malloc(sizeof(char *) * (num + 1));
04633 for (env = envtop, myenv = myenvtop; *env; env += strlen(env) + 1) {
04634 if (*env != '=') {
04635 if (!(*myenv = strdup(env))) {
04636 break;
04637 }
04638 myenv++;
04639 }
04640 }
04641 *myenv = NULL;
04642 FreeEnvironmentStrings(envtop);
04643
04644 return myenvtop;
04645 }
04646
04647 void
04648 rb_w32_free_environ(char **env)
04649 {
04650 char **t = env;
04651
04652 while (*t) free(*t++);
04653 free(env);
04654 }
04655
04656 rb_pid_t
04657 rb_w32_getpid(void)
04658 {
04659 rb_pid_t pid;
04660
04661 pid = GetCurrentProcessId();
04662
04663 (void)IfWin95(pid = -pid, 0);
04664
04665 return pid;
04666 }
04667
04668
04669 rb_pid_t
04670 rb_w32_getppid(void)
04671 {
04672 static long (WINAPI *pNtQueryInformationProcess)(HANDLE, int, void *, ULONG, ULONG *) = NULL;
04673 rb_pid_t ppid = 0;
04674
04675 if (!IsWin95() && rb_w32_osver() >= 5) {
04676 if (!pNtQueryInformationProcess) {
04677 HANDLE hNtDll = GetModuleHandle("ntdll.dll");
04678 if (hNtDll) {
04679 pNtQueryInformationProcess = (long (WINAPI *)(HANDLE, int, void *, ULONG, ULONG *))GetProcAddress(hNtDll, "NtQueryInformationProcess");
04680 }
04681 }
04682 if (pNtQueryInformationProcess) {
04683 struct {
04684 long ExitStatus;
04685 void* PebBaseAddress;
04686 ULONG AffinityMask;
04687 ULONG BasePriority;
04688 ULONG UniqueProcessId;
04689 ULONG ParentProcessId;
04690 } pbi;
04691 ULONG len;
04692 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
04693 if (!ret) {
04694 ppid = pbi.ParentProcessId;
04695 }
04696 }
04697 }
04698
04699 return ppid;
04700 }
04701
04702 int
04703 rb_w32_uopen(const char *file, int oflag, ...)
04704 {
04705 WCHAR *wfile;
04706 int ret;
04707 int pmode;
04708
04709 va_list arg;
04710 va_start(arg, oflag);
04711 pmode = va_arg(arg, int);
04712 va_end(arg);
04713
04714 if (!(wfile = utf8_to_wstr(file, NULL)))
04715 return -1;
04716 ret = rb_w32_wopen(wfile, oflag, pmode);
04717 free(wfile);
04718 return ret;
04719 }
04720
04721 int
04722 rb_w32_open(const char *file, int oflag, ...)
04723 {
04724 WCHAR *wfile;
04725 int ret;
04726 int pmode;
04727
04728 va_list arg;
04729 va_start(arg, oflag);
04730 pmode = va_arg(arg, int);
04731 va_end(arg);
04732
04733 if ((oflag & O_TEXT) || !(oflag & O_BINARY))
04734 return _open(file, oflag, pmode);
04735
04736 if (!(wfile = filecp_to_wstr(file, NULL)))
04737 return -1;
04738 ret = rb_w32_wopen(wfile, oflag, pmode);
04739 free(wfile);
04740 return ret;
04741 }
04742
04743 int
04744 rb_w32_wopen(const WCHAR *file, int oflag, ...)
04745 {
04746 char flags = 0;
04747 int fd;
04748 DWORD access;
04749 DWORD create;
04750 DWORD attr = FILE_ATTRIBUTE_NORMAL;
04751 SECURITY_ATTRIBUTES sec;
04752 HANDLE h;
04753
04754 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
04755 va_list arg;
04756 int pmode;
04757 va_start(arg, oflag);
04758 pmode = va_arg(arg, int);
04759 va_end(arg);
04760 return _wopen(file, oflag, pmode);
04761 }
04762
04763 sec.nLength = sizeof(sec);
04764 sec.lpSecurityDescriptor = NULL;
04765 if (oflag & O_NOINHERIT) {
04766 sec.bInheritHandle = FALSE;
04767 flags |= FNOINHERIT;
04768 }
04769 else {
04770 sec.bInheritHandle = TRUE;
04771 }
04772 oflag &= ~O_NOINHERIT;
04773
04774
04775 oflag &= ~(O_BINARY | O_TEXT);
04776
04777 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
04778 case O_RDWR:
04779 access = GENERIC_READ | GENERIC_WRITE;
04780 break;
04781 case O_RDONLY:
04782 access = GENERIC_READ;
04783 break;
04784 case O_WRONLY:
04785 access = GENERIC_WRITE;
04786 break;
04787 default:
04788 errno = EINVAL;
04789 return -1;
04790 }
04791 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
04792
04793 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
04794 case O_CREAT:
04795 create = OPEN_ALWAYS;
04796 break;
04797 case 0:
04798 case O_EXCL:
04799 create = OPEN_EXISTING;
04800 break;
04801 case O_CREAT | O_EXCL:
04802 case O_CREAT | O_EXCL | O_TRUNC:
04803 create = CREATE_NEW;
04804 break;
04805 case O_TRUNC:
04806 case O_TRUNC | O_EXCL:
04807 create = TRUNCATE_EXISTING;
04808 break;
04809 case O_CREAT | O_TRUNC:
04810 create = CREATE_ALWAYS;
04811 break;
04812 default:
04813 errno = EINVAL;
04814 return -1;
04815 }
04816 if (oflag & O_CREAT) {
04817 va_list arg;
04818 int pmode;
04819 va_start(arg, oflag);
04820 pmode = va_arg(arg, int);
04821 va_end(arg);
04822
04823 if (!(pmode & S_IWRITE))
04824 attr = FILE_ATTRIBUTE_READONLY;
04825 }
04826 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
04827
04828 if (oflag & O_TEMPORARY) {
04829 attr |= FILE_FLAG_DELETE_ON_CLOSE;
04830 access |= DELETE;
04831 }
04832 oflag &= ~O_TEMPORARY;
04833
04834 if (oflag & _O_SHORT_LIVED)
04835 attr |= FILE_ATTRIBUTE_TEMPORARY;
04836 oflag &= ~_O_SHORT_LIVED;
04837
04838 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
04839 case 0:
04840 break;
04841 case O_SEQUENTIAL:
04842 attr |= FILE_FLAG_SEQUENTIAL_SCAN;
04843 break;
04844 case O_RANDOM:
04845 attr |= FILE_FLAG_RANDOM_ACCESS;
04846 break;
04847 default:
04848 errno = EINVAL;
04849 return -1;
04850 }
04851 oflag &= ~(O_SEQUENTIAL | O_RANDOM);
04852
04853 if (oflag & ~O_APPEND) {
04854 errno = EINVAL;
04855 return -1;
04856 }
04857
04858
04859 RUBY_CRITICAL({
04860 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
04861 fd = _open_osfhandle((intptr_t)h, 0);
04862 CloseHandle(h);
04863 });
04864 if (fd == -1) {
04865 errno = EMFILE;
04866 return -1;
04867 }
04868 RUBY_CRITICAL({
04869 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
04870 _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
04871 _set_osflags(fd, 0);
04872
04873 h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec,
04874 create, attr, NULL);
04875 if (h == INVALID_HANDLE_VALUE) {
04876 errno = map_errno(GetLastError());
04877 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
04878 fd = -1;
04879 goto quit;
04880 }
04881
04882 switch (GetFileType(h)) {
04883 case FILE_TYPE_CHAR:
04884 flags |= FDEV;
04885 break;
04886 case FILE_TYPE_PIPE:
04887 flags |= FPIPE;
04888 break;
04889 case FILE_TYPE_UNKNOWN:
04890 errno = map_errno(GetLastError());
04891 CloseHandle(h);
04892 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
04893 fd = -1;
04894 goto quit;
04895 }
04896 if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
04897 flags |= FAPPEND;
04898
04899 _set_osfhnd(fd, (intptr_t)h);
04900 _osfile(fd) = flags | FOPEN;
04901
04902 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
04903 quit:
04904 ;
04905 });
04906
04907 return fd;
04908 }
04909
04910 int
04911 rb_w32_fclose(FILE *fp)
04912 {
04913 int fd = fileno(fp);
04914 SOCKET sock = TO_SOCKET(fd);
04915 int save_errno = errno;
04916
04917 if (fflush(fp)) return -1;
04918 if (!is_socket(sock)) {
04919 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
04920 return fclose(fp);
04921 }
04922 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
04923 fclose(fp);
04924 errno = save_errno;
04925 if (closesocket(sock) == SOCKET_ERROR) {
04926 errno = map_errno(WSAGetLastError());
04927 return -1;
04928 }
04929 return 0;
04930 }
04931
04932 int
04933 rb_w32_pipe(int fds[2])
04934 {
04935 static DWORD serial = 0;
04936 char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
04937 char *p;
04938 SECURITY_ATTRIBUTES sec;
04939 HANDLE hRead, hWrite, h;
04940 int fdRead, fdWrite;
04941 int ret;
04942
04943
04944 if (!cancel_io)
04945 return _pipe(fds, 65536L, _O_NOINHERIT);
04946
04947 p = strchr(name, '0');
04948 snprintf(p, strlen(p) + 1, "%x-%lx", rb_w32_getpid(), serial++);
04949
04950 sec.nLength = sizeof(sec);
04951 sec.lpSecurityDescriptor = NULL;
04952 sec.bInheritHandle = FALSE;
04953
04954 RUBY_CRITICAL({
04955 hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
04956 0, 2, 65536, 65536, 0, &sec);
04957 });
04958 if (hRead == INVALID_HANDLE_VALUE) {
04959 DWORD err = GetLastError();
04960 if (err == ERROR_PIPE_BUSY)
04961 errno = EMFILE;
04962 else
04963 errno = map_errno(GetLastError());
04964 return -1;
04965 }
04966
04967 RUBY_CRITICAL({
04968 hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
04969 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
04970 });
04971 if (hWrite == INVALID_HANDLE_VALUE) {
04972 errno = map_errno(GetLastError());
04973 CloseHandle(hRead);
04974 return -1;
04975 }
04976
04977 RUBY_CRITICAL(do {
04978 ret = 0;
04979 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
04980 fdRead = _open_osfhandle((intptr_t)h, 0);
04981 CloseHandle(h);
04982 if (fdRead == -1) {
04983 errno = EMFILE;
04984 CloseHandle(hWrite);
04985 CloseHandle(hRead);
04986 ret = -1;
04987 break;
04988 }
04989
04990 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock)));
04991 _set_osfhnd(fdRead, (intptr_t)hRead);
04992 _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
04993 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock)));
04994 } while (0));
04995 if (ret)
04996 return ret;
04997
04998 RUBY_CRITICAL(do {
04999 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05000 fdWrite = _open_osfhandle((intptr_t)h, 0);
05001 CloseHandle(h);
05002 if (fdWrite == -1) {
05003 errno = EMFILE;
05004 CloseHandle(hWrite);
05005 ret = -1;
05006 break;
05007 }
05008 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock)));
05009 _set_osfhnd(fdWrite, (intptr_t)hWrite);
05010 _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
05011 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock)));
05012 } while (0));
05013 if (ret) {
05014 rb_w32_close(fdRead);
05015 return ret;
05016 }
05017
05018 fds[0] = fdRead;
05019 fds[1] = fdWrite;
05020
05021 return 0;
05022 }
05023
05024 int
05025 rb_w32_close(int fd)
05026 {
05027 SOCKET sock = TO_SOCKET(fd);
05028 int save_errno = errno;
05029 st_data_t key;
05030
05031 if (!is_socket(sock)) {
05032 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
05033 return _close(fd);
05034 }
05035 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
05036 key = (st_data_t)sock;
05037 st_delete(socklist, &key, NULL);
05038 sock = (SOCKET)key;
05039 _close(fd);
05040 errno = save_errno;
05041 if (closesocket(sock) == SOCKET_ERROR) {
05042 errno = map_errno(WSAGetLastError());
05043 return -1;
05044 }
05045 return 0;
05046 }
05047
05048 #undef read
05049 size_t
05050 rb_w32_read(int fd, void *buf, size_t size)
05051 {
05052 SOCKET sock = TO_SOCKET(fd);
05053 DWORD read;
05054 DWORD wait;
05055 DWORD err;
05056 size_t len;
05057 size_t ret;
05058 OVERLAPPED ol, *pol = NULL;
05059 BOOL isconsole;
05060 BOOL islineinput;
05061 int start = 0;
05062
05063 if (is_socket(sock))
05064 return rb_w32_recv(fd, buf, size, 0);
05065
05066
05067 if (_get_osfhandle(fd) == -1) {
05068 return -1;
05069 }
05070
05071 if (_osfile(fd) & FTEXT) {
05072 return _read(fd, buf, size);
05073 }
05074
05075 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05076
05077 if (!size || _osfile(fd) & FEOFLAG) {
05078 _set_osflags(fd, _osfile(fd) & ~FEOFLAG);
05079 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05080 return 0;
05081 }
05082
05083 ret = 0;
05084 isconsole = is_console(_osfhnd(fd));
05085 if(isconsole){
05086 DWORD mode;
05087 GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
05088 islineinput = (mode & ENABLE_LINE_INPUT) != 0;
05089 }
05090 retry:
05091
05092 if (isconsole) {
05093 if (start)
05094 len = 1;
05095 else {
05096 len = 0;
05097 start = 1;
05098 }
05099 }
05100 else
05101 len = size;
05102 size -= len;
05103
05104
05105 if (cancel_io) {
05106 memset(&ol, 0, sizeof(ol));
05107 if (!(_osfile(fd) & (FDEV | FPIPE))) {
05108 LONG high = 0;
05109 DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high,
05110 FILE_CURRENT);
05111 #ifndef INVALID_SET_FILE_POINTER
05112 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
05113 #endif
05114 if (low == INVALID_SET_FILE_POINTER) {
05115 errno = map_errno(GetLastError());
05116 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05117 return -1;
05118 }
05119 ol.Offset = low;
05120 ol.OffsetHigh = high;
05121 }
05122 ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
05123 if (!ol.hEvent) {
05124 errno = map_errno(GetLastError());
05125 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05126 return -1;
05127 }
05128
05129 pol = &ol;
05130 }
05131
05132 if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
05133 err = GetLastError();
05134 if (err != ERROR_IO_PENDING) {
05135 if (pol) CloseHandle(ol.hEvent);
05136 if (err == ERROR_ACCESS_DENIED)
05137 errno = EBADF;
05138 else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
05139 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05140 return 0;
05141 }
05142 else
05143 errno = map_errno(err);
05144
05145 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05146 return -1;
05147 }
05148
05149 if (pol) {
05150 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
05151 if (wait != WAIT_OBJECT_0) {
05152 if (wait == WAIT_OBJECT_0 + 1)
05153 errno = EINTR;
05154 else
05155 errno = map_errno(GetLastError());
05156 CloseHandle(ol.hEvent);
05157 cancel_io((HANDLE)_osfhnd(fd));
05158 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05159 return -1;
05160 }
05161
05162 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
05163 (err = GetLastError()) != ERROR_HANDLE_EOF) {
05164 int ret = 0;
05165 if (err != ERROR_BROKEN_PIPE) {
05166 errno = map_errno(err);
05167 ret = -1;
05168 }
05169 CloseHandle(ol.hEvent);
05170 cancel_io((HANDLE)_osfhnd(fd));
05171 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05172 return ret;
05173 }
05174 }
05175 }
05176
05177 if (pol) {
05178 CloseHandle(ol.hEvent);
05179
05180 if (!(_osfile(fd) & (FDEV | FPIPE))) {
05181 LONG high = ol.OffsetHigh;
05182 DWORD low = ol.Offset + read;
05183 if (low < ol.Offset)
05184 ++high;
05185 SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
05186 }
05187 }
05188
05189 ret += read;
05190 if (read >= len) {
05191 buf = (char *)buf + read;
05192 if (!(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0)
05193 goto retry;
05194 }
05195 if (read == 0)
05196 _set_osflags(fd, _osfile(fd) | FEOFLAG);
05197
05198
05199 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05200
05201 return ret;
05202 }
05203
05204 #undef write
05205 size_t
05206 rb_w32_write(int fd, const void *buf, size_t size)
05207 {
05208 SOCKET sock = TO_SOCKET(fd);
05209 DWORD written;
05210 DWORD wait;
05211 DWORD err;
05212 size_t len;
05213 size_t ret;
05214 OVERLAPPED ol, *pol = NULL;
05215
05216 if (is_socket(sock))
05217 return rb_w32_send(fd, buf, size, 0);
05218
05219
05220 if (_get_osfhandle(fd) == -1) {
05221 return -1;
05222 }
05223
05224 if (_osfile(fd) & FTEXT) {
05225 return _write(fd, buf, size);
05226 }
05227
05228 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05229
05230 if (!size || _osfile(fd) & FEOFLAG) {
05231 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05232 return 0;
05233 }
05234
05235 ret = 0;
05236 retry:
05237
05238 len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size;
05239 size -= len;
05240
05241
05242 if (cancel_io) {
05243 memset(&ol, 0, sizeof(ol));
05244 if (!(_osfile(fd) & (FDEV | FPIPE))) {
05245 LONG high = 0;
05246 DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
05247 DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
05248 #ifndef INVALID_SET_FILE_POINTER
05249 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
05250 #endif
05251 if (low == INVALID_SET_FILE_POINTER) {
05252 errno = map_errno(GetLastError());
05253 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05254 return -1;
05255 }
05256 ol.Offset = low;
05257 ol.OffsetHigh = high;
05258 }
05259 ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
05260 if (!ol.hEvent) {
05261 errno = map_errno(GetLastError());
05262 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05263 return -1;
05264 }
05265
05266 pol = &ol;
05267 }
05268
05269 if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) {
05270 err = GetLastError();
05271 if (err != ERROR_IO_PENDING) {
05272 if (pol) CloseHandle(ol.hEvent);
05273 if (err == ERROR_ACCESS_DENIED)
05274 errno = EBADF;
05275 else
05276 errno = map_errno(err);
05277
05278 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05279 return -1;
05280 }
05281
05282 if (pol) {
05283 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
05284 if (wait != WAIT_OBJECT_0) {
05285 if (wait == WAIT_OBJECT_0 + 1)
05286 errno = EINTR;
05287 else
05288 errno = map_errno(GetLastError());
05289 CloseHandle(ol.hEvent);
05290 cancel_io((HANDLE)_osfhnd(fd));
05291 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05292 return -1;
05293 }
05294
05295 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written,
05296 TRUE)) {
05297 errno = map_errno(err);
05298 CloseHandle(ol.hEvent);
05299 cancel_io((HANDLE)_osfhnd(fd));
05300 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05301 return -1;
05302 }
05303 }
05304 }
05305
05306 if (pol) {
05307 CloseHandle(ol.hEvent);
05308
05309 if (!(_osfile(fd) & (FDEV | FPIPE))) {
05310 LONG high = ol.OffsetHigh;
05311 DWORD low = ol.Offset + written;
05312 if (low < ol.Offset)
05313 ++high;
05314 SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
05315 }
05316 }
05317
05318 ret += written;
05319 if (written == len) {
05320 buf = (const char *)buf + len;
05321 if (size > 0)
05322 goto retry;
05323 }
05324
05325 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05326
05327 return ret;
05328 }
05329
05330 static int
05331 unixtime_to_filetime(time_t time, FILETIME *ft)
05332 {
05333 struct tm *tm;
05334 SYSTEMTIME st;
05335 FILETIME lt;
05336
05337 tm = localtime(&time);
05338 st.wYear = tm->tm_year + 1900;
05339 st.wMonth = tm->tm_mon + 1;
05340 st.wDayOfWeek = tm->tm_wday;
05341 st.wDay = tm->tm_mday;
05342 st.wHour = tm->tm_hour;
05343 st.wMinute = tm->tm_min;
05344 st.wSecond = tm->tm_sec;
05345 st.wMilliseconds = 0;
05346 if (!SystemTimeToFileTime(&st, <) ||
05347 !LocalFileTimeToFileTime(<, ft)) {
05348 errno = map_errno(GetLastError());
05349 return -1;
05350 }
05351 return 0;
05352 }
05353
05354 static int
05355 wutime(const WCHAR *path, const struct utimbuf *times)
05356 {
05357 HANDLE hFile;
05358 FILETIME atime, mtime;
05359 struct stati64 stat;
05360 int ret = 0;
05361
05362 if (wstati64(path, &stat)) {
05363 return -1;
05364 }
05365
05366 if (times) {
05367 if (unixtime_to_filetime(times->actime, &atime)) {
05368 return -1;
05369 }
05370 if (unixtime_to_filetime(times->modtime, &mtime)) {
05371 return -1;
05372 }
05373 }
05374 else {
05375 GetSystemTimeAsFileTime(&atime);
05376 mtime = atime;
05377 }
05378
05379 RUBY_CRITICAL({
05380 const DWORD attr = GetFileAttributesW(path);
05381 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
05382 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
05383 hFile = CreateFileW(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
05384 IsWin95() ? 0 : FILE_FLAG_BACKUP_SEMANTICS, 0);
05385 if (hFile == INVALID_HANDLE_VALUE) {
05386 errno = map_errno(GetLastError());
05387 ret = -1;
05388 }
05389 else {
05390 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
05391 errno = map_errno(GetLastError());
05392 ret = -1;
05393 }
05394 CloseHandle(hFile);
05395 }
05396 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
05397 SetFileAttributesW(path, attr);
05398 });
05399
05400 return ret;
05401 }
05402
05403 int
05404 rb_w32_uutime(const char *path, const struct utimbuf *times)
05405 {
05406 WCHAR *wpath;
05407 int ret;
05408
05409 if (!(wpath = utf8_to_wstr(path, NULL)))
05410 return -1;
05411 ret = wutime(wpath, times);
05412 free(wpath);
05413 return ret;
05414 }
05415
05416 int
05417 rb_w32_utime(const char *path, const struct utimbuf *times)
05418 {
05419 WCHAR *wpath;
05420 int ret;
05421
05422 if (!(wpath = filecp_to_wstr(path, NULL)))
05423 return -1;
05424 ret = wutime(wpath, times);
05425 free(wpath);
05426 return ret;
05427 }
05428
05429 int
05430 rb_w32_uchdir(const char *path)
05431 {
05432 WCHAR *wpath;
05433 int ret;
05434
05435 if (!(wpath = utf8_to_wstr(path, NULL)))
05436 return -1;
05437 ret = _wchdir(wpath);
05438 free(wpath);
05439 return ret;
05440 }
05441
05442 static int
05443 wmkdir(const WCHAR *wpath, int mode)
05444 {
05445 int ret = -1;
05446
05447 RUBY_CRITICAL(do {
05448 if (CreateDirectoryW(wpath, NULL) == FALSE) {
05449 errno = map_errno(GetLastError());
05450 break;
05451 }
05452 if (_wchmod(wpath, mode) == -1) {
05453 RemoveDirectoryW(wpath);
05454 break;
05455 }
05456 ret = 0;
05457 } while (0));
05458 return ret;
05459 }
05460
05461 int
05462 rb_w32_umkdir(const char *path, int mode)
05463 {
05464 WCHAR *wpath;
05465 int ret;
05466
05467 if (!(wpath = utf8_to_wstr(path, NULL)))
05468 return -1;
05469 ret = wmkdir(wpath, mode);
05470 free(wpath);
05471 return ret;
05472 }
05473
05474 int
05475 rb_w32_mkdir(const char *path, int mode)
05476 {
05477 WCHAR *wpath;
05478 int ret;
05479
05480 if (!(wpath = filecp_to_wstr(path, NULL)))
05481 return -1;
05482 ret = wmkdir(wpath, mode);
05483 free(wpath);
05484 return ret;
05485 }
05486
05487 static int
05488 wrmdir(const WCHAR *wpath)
05489 {
05490 int ret = 0;
05491 RUBY_CRITICAL({
05492 const DWORD attr = GetFileAttributesW(wpath);
05493 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
05494 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
05495 }
05496 if (RemoveDirectoryW(wpath) == FALSE) {
05497 errno = map_errno(GetLastError());
05498 ret = -1;
05499 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
05500 SetFileAttributesW(wpath, attr);
05501 }
05502 }
05503 });
05504 return ret;
05505 }
05506
05507 int
05508 rb_w32_rmdir(const char *path)
05509 {
05510 WCHAR *wpath;
05511 int ret;
05512
05513 if (!(wpath = filecp_to_wstr(path, NULL)))
05514 return -1;
05515 ret = wrmdir(wpath);
05516 free(wpath);
05517 return ret;
05518 }
05519
05520 int
05521 rb_w32_urmdir(const char *path)
05522 {
05523 WCHAR *wpath;
05524 int ret;
05525
05526 if (!(wpath = utf8_to_wstr(path, NULL)))
05527 return -1;
05528 ret = wrmdir(wpath);
05529 free(wpath);
05530 return ret;
05531 }
05532
05533 static int
05534 wunlink(const WCHAR *path)
05535 {
05536 int ret = 0;
05537 RUBY_CRITICAL({
05538 const DWORD attr = GetFileAttributesW(path);
05539 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
05540 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
05541 }
05542 if (DeleteFileW(path) == FALSE) {
05543 errno = map_errno(GetLastError());
05544 ret = -1;
05545 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
05546 SetFileAttributesW(path, attr);
05547 }
05548 }
05549 });
05550 return ret;
05551 }
05552
05553 int
05554 rb_w32_uunlink(const char *path)
05555 {
05556 WCHAR *wpath;
05557 int ret;
05558
05559 if (!(wpath = utf8_to_wstr(path, NULL)))
05560 return -1;
05561 ret = wunlink(wpath);
05562 free(wpath);
05563 return ret;
05564 }
05565
05566 int
05567 rb_w32_unlink(const char *path)
05568 {
05569 WCHAR *wpath;
05570 int ret;
05571
05572 if (!(wpath = filecp_to_wstr(path, NULL)))
05573 return -1;
05574 ret = wunlink(wpath);
05575 free(wpath);
05576 return ret;
05577 }
05578
05579 int
05580 rb_w32_uchmod(const char *path, int mode)
05581 {
05582 WCHAR *wpath;
05583 int ret;
05584
05585 if (!(wpath = filecp_to_wstr(path, NULL)))
05586 return -1;
05587 ret = _wchmod(wpath, mode);
05588 free(wpath);
05589 return ret;
05590 }
05591
05592 #if !defined(__BORLANDC__)
05593 int
05594 rb_w32_isatty(int fd)
05595 {
05596
05597 if (_get_osfhandle(fd) == -1) {
05598 return 0;
05599 }
05600 if (!(_osfile(fd) & FDEV)) {
05601 errno = ENOTTY;
05602 return 0;
05603 }
05604 return 1;
05605 }
05606 #endif
05607
05608
05609
05610
05611
05612 #ifdef __BORLANDC__
05613 static int
05614 too_many_files(void)
05615 {
05616 FILE *f;
05617 for (f = _streams; f < _streams + _nfile; f++) {
05618 if (f->fd < 0) return 0;
05619 }
05620 return 1;
05621 }
05622
05623 #undef fopen
05624 FILE *
05625 rb_w32_fopen(const char *path, const char *mode)
05626 {
05627 FILE *f = (errno = 0, fopen(path, mode));
05628 if (f == NULL && errno == 0) {
05629 if (too_many_files())
05630 errno = EMFILE;
05631 }
05632 return f;
05633 }
05634
05635 FILE *
05636 rb_w32_fdopen(int handle, const char *type)
05637 {
05638 FILE *f = (errno = 0, _fdopen(handle, (char *)type));
05639 if (f == NULL && errno == 0) {
05640 if (handle < 0)
05641 errno = EBADF;
05642 else if (too_many_files())
05643 errno = EMFILE;
05644 }
05645 return f;
05646 }
05647
05648 FILE *
05649 rb_w32_fsopen(const char *path, const char *mode, int shflags)
05650 {
05651 FILE *f = (errno = 0, _fsopen(path, mode, shflags));
05652 if (f == NULL && errno == 0) {
05653 if (too_many_files())
05654 errno = EMFILE;
05655 }
05656 return f;
05657 }
05658 #endif
05659
05660 #if defined(_MSC_VER) && RT_VER <= 60
05661 extern long _ftol(double);
05662 long
05663 _ftol2(double d)
05664 {
05665 return _ftol(d);
05666 }
05667 long
05668 _ftol2_sse(double d)
05669 {
05670 return _ftol(d);
05671 }
05672 #endif
05673
05674 #ifndef signbit
05675 int
05676 signbit(double x)
05677 {
05678 int *ip = (int *)(&x + 1) - 1;
05679 return *ip < 0;
05680 }
05681 #endif
05682