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