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