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