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