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