Ruby  2.0.0p353(2013-11-22revision43784)
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 (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
04348             res = -1;
04349 
04350         if (res)
04351             errno = map_errno(GetLastError());
04352         else
04353             SetFileAttributesW(newpath, oldatts);
04354     });
04355 
04356     return res;
04357 }
04358 
04359 /* License: Ruby's */
04360 int rb_w32_urename(const char *from, const char *to)
04361 {
04362     WCHAR *wfrom;
04363     WCHAR *wto;
04364     int ret = -1;
04365 
04366     if (!(wfrom = utf8_to_wstr(from, NULL)))
04367         return -1;
04368     if (!(wto = utf8_to_wstr(to, NULL))) {
04369         free(wfrom);
04370         return -1;
04371     }
04372     ret = wrename(wfrom, wto);
04373     free(wto);
04374     free(wfrom);
04375     return ret;
04376 }
04377 
04378 /* License: Ruby's */
04379 int rb_w32_rename(const char *from, const char *to)
04380 {
04381     WCHAR *wfrom;
04382     WCHAR *wto;
04383     int ret = -1;
04384 
04385     if (!(wfrom = filecp_to_wstr(from, NULL)))
04386         return -1;
04387     if (!(wto = filecp_to_wstr(to, NULL))) {
04388         free(wfrom);
04389         return -1;
04390     }
04391     ret = wrename(wfrom, wto);
04392     free(wto);
04393     free(wfrom);
04394     return ret;
04395 }
04396 
04397 /* License: Ruby's */
04398 static int
04399 isUNCRoot(const WCHAR *path)
04400 {
04401     if (path[0] == L'\\' && path[1] == L'\\') {
04402         const WCHAR *p = path + 2;
04403         if (p[0] == L'?' && p[1] == L'\\') {
04404             p += 2;
04405         }
04406         for (; *p; p++) {
04407             if (*p == L'\\')
04408                 break;
04409         }
04410         if (p[0] && p[1]) {
04411             for (p++; *p; p++) {
04412                 if (*p == L'\\')
04413                     break;
04414             }
04415             if (!p[0] || !p[1] || (p[1] == L'.' && !p[2]))
04416                 return 1;
04417         }
04418     }
04419     return 0;
04420 }
04421 
04422 #define COPY_STAT(src, dest, size_cast) do {    \
04423         (dest).st_dev   = (src).st_dev;         \
04424         (dest).st_ino   = (src).st_ino;         \
04425         (dest).st_mode  = (src).st_mode;        \
04426         (dest).st_nlink = (src).st_nlink;       \
04427         (dest).st_uid   = (src).st_uid;         \
04428         (dest).st_gid   = (src).st_gid;         \
04429         (dest).st_rdev  = (src).st_rdev;        \
04430         (dest).st_size  = size_cast(src).st_size; \
04431         (dest).st_atime = (src).st_atime;       \
04432         (dest).st_mtime = (src).st_mtime;       \
04433         (dest).st_ctime = (src).st_ctime;       \
04434     } while (0)
04435 
04436 static time_t filetime_to_unixtime(const FILETIME *ft);
04437 
04438 #undef fstat
04439 /* License: Ruby's */
04440 int
04441 rb_w32_fstat(int fd, struct stat *st)
04442 {
04443     BY_HANDLE_FILE_INFORMATION info;
04444     int ret = fstat(fd, st);
04445 
04446     if (ret) return ret;
04447 #ifdef __BORLANDC__
04448     st->st_mode &= ~(S_IWGRP | S_IWOTH);
04449 #endif
04450     if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
04451 #ifdef __BORLANDC__
04452         if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04453             st->st_mode |= S_IWUSR;
04454         }
04455 #endif
04456         st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
04457         st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
04458         st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
04459     }
04460     return ret;
04461 }
04462 
04463 /* License: Ruby's */
04464 int
04465 rb_w32_fstati64(int fd, struct stati64 *st)
04466 {
04467     BY_HANDLE_FILE_INFORMATION info;
04468     struct stat tmp;
04469     int ret = fstat(fd, &tmp);
04470 
04471     if (ret) return ret;
04472 #ifdef __BORLANDC__
04473     tmp.st_mode &= ~(S_IWGRP | S_IWOTH);
04474 #endif
04475     COPY_STAT(tmp, *st, +);
04476     if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
04477 #ifdef __BORLANDC__
04478         if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04479             st->st_mode |= S_IWUSR;
04480         }
04481 #endif
04482         st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
04483         st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
04484         st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
04485         st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
04486     }
04487     return ret;
04488 }
04489 
04490 /* License: Ruby's */
04491 static time_t
04492 filetime_to_unixtime(const FILETIME *ft)
04493 {
04494     struct timeval tv;
04495 
04496     if (filetime_to_timeval(ft, &tv) == (time_t)-1)
04497         return 0;
04498     else
04499         return tv.tv_sec;
04500 }
04501 
04502 /* License: Ruby's */
04503 static unsigned
04504 fileattr_to_unixmode(DWORD attr, const WCHAR *path)
04505 {
04506     unsigned mode = 0;
04507 
04508     if (attr & FILE_ATTRIBUTE_READONLY) {
04509         mode |= S_IREAD;
04510     }
04511     else {
04512         mode |= S_IREAD | S_IWRITE | S_IWUSR;
04513     }
04514 
04515     if (attr & FILE_ATTRIBUTE_DIRECTORY) {
04516         mode |= S_IFDIR | S_IEXEC;
04517     }
04518     else {
04519         mode |= S_IFREG;
04520     }
04521 
04522     if (path && (mode & S_IFREG)) {
04523         const WCHAR *end = path + lstrlenW(path);
04524         while (path < end) {
04525             end = CharPrevW(path, end);
04526             if (*end == L'.') {
04527                 if ((_wcsicmp(end, L".bat") == 0) ||
04528                     (_wcsicmp(end, L".cmd") == 0) ||
04529                     (_wcsicmp(end, L".com") == 0) ||
04530                     (_wcsicmp(end, L".exe") == 0)) {
04531                     mode |= S_IEXEC;
04532                 }
04533                 break;
04534             }
04535         }
04536     }
04537 
04538     mode |= (mode & 0700) >> 3;
04539     mode |= (mode & 0700) >> 6;
04540 
04541     return mode;
04542 }
04543 
04544 /* License: Ruby's */
04545 static int
04546 check_valid_dir(const WCHAR *path)
04547 {
04548     WIN32_FIND_DATAW fd;
04549     HANDLE fh;
04550     WCHAR full[MAX_PATH];
04551     WCHAR *dmy;
04552     WCHAR *p, *q;
04553 
04554     /* GetFileAttributes() determines "..." as directory. */
04555     /* We recheck it by FindFirstFile(). */
04556     if (!(p = wcsstr(path, L"...")))
04557         return 0;
04558     q = p + wcsspn(p, L".");
04559     if ((p == path || wcschr(L":/\\", *(p - 1))) &&
04560         (!*q || wcschr(L":/\\", *q))) {
04561         errno = ENOENT;
04562         return -1;
04563     }
04564 
04565     /* if the specified path is the root of a drive and the drive is empty, */
04566     /* FindFirstFile() returns INVALID_HANDLE_VALUE. */
04567     if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) {
04568         errno = map_errno(GetLastError());
04569         return -1;
04570     }
04571     if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
04572         return 0;
04573 
04574     fh = open_dir_handle(path, &fd);
04575     if (fh == INVALID_HANDLE_VALUE)
04576         return -1;
04577     FindClose(fh);
04578     return 0;
04579 }
04580 
04581 /* License: Ruby's */
04582 static int
04583 winnt_stat(const WCHAR *path, struct stati64 *st)
04584 {
04585     HANDLE h;
04586     WIN32_FIND_DATAW wfd;
04587     WIN32_FILE_ATTRIBUTE_DATA wfa;
04588     const WCHAR *p = path;
04589 
04590     memset(st, 0, sizeof(*st));
04591     st->st_nlink = 1;
04592 
04593     if (wcsncmp(p, L"\\\\?\\", 4) == 0) p += 4;
04594     if (wcspbrk(p, L"?*")) {
04595         errno = ENOENT;
04596         return -1;
04597     }
04598     if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) {
04599         if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
04600             if (check_valid_dir(path)) return -1;
04601             st->st_size = 0;
04602         }
04603         else {
04604             st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow;
04605         }
04606         st->st_mode  = fileattr_to_unixmode(wfa.dwFileAttributes, path);
04607         st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
04608         st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
04609         st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
04610     }
04611     else {
04612         /* GetFileAttributesEx failed; check why. */
04613         int e = GetLastError();
04614 
04615         if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
04616             || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
04617             errno = map_errno(e);
04618             return -1;
04619         }
04620 
04621         /* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
04622         h = FindFirstFileW(path, &wfd);
04623         if (h != INVALID_HANDLE_VALUE) {
04624             FindClose(h);
04625             st->st_mode  = fileattr_to_unixmode(wfd.dwFileAttributes, path);
04626             st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
04627             st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
04628             st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
04629             st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
04630         }
04631         else {
04632             errno = map_errno(GetLastError());
04633             return -1;
04634         }
04635     }
04636 
04637     st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?
04638         towupper(path[0]) - L'A' : _getdrive() - 1;
04639 
04640     return 0;
04641 }
04642 
04643 /* License: Ruby's */
04644 int
04645 rb_w32_stat(const char *path, struct stat *st)
04646 {
04647     struct stati64 tmp;
04648 
04649     if (rb_w32_stati64(path, &tmp)) return -1;
04650     COPY_STAT(tmp, *st, (_off_t));
04651     return 0;
04652 }
04653 
04654 /* License: Ruby's */
04655 static int
04656 wstati64(const WCHAR *path, struct stati64 *st)
04657 {
04658     const WCHAR *p;
04659     WCHAR *buf1, *s, *end;
04660     int len, size;
04661     int ret;
04662     VALUE v;
04663 
04664     if (!path || !st) {
04665         errno = EFAULT;
04666         return -1;
04667     }
04668     size = lstrlenW(path) + 2;
04669     buf1 = ALLOCV_N(WCHAR, v, size);
04670     for (p = path, s = buf1; *p; p++, s++) {
04671         if (*p == L'/')
04672             *s = L'\\';
04673         else
04674             *s = *p;
04675     }
04676     *s = '\0';
04677     len = s - buf1;
04678     if (!len || L'\"' == *(--s)) {
04679         errno = ENOENT;
04680         return -1;
04681     }
04682     end = buf1 + len - 1;
04683 
04684     if (isUNCRoot(buf1)) {
04685         if (*end == L'.')
04686             *end = L'\0';
04687         else if (*end != L'\\')
04688             lstrcatW(buf1, L"\\");
04689     }
04690     else if (*end == L'\\' || (buf1 + 1 == end && *end == L':'))
04691         lstrcatW(buf1, L".");
04692 
04693     ret = winnt_stat(buf1, st);
04694     if (ret == 0) {
04695         st->st_mode &= ~(S_IWGRP | S_IWOTH);
04696     }
04697     if (v)
04698         ALLOCV_END(v);
04699 
04700     return ret;
04701 }
04702 
04703 /* License: Ruby's */
04704 int
04705 rb_w32_ustati64(const char *path, struct stati64 *st)
04706 {
04707     WCHAR *wpath;
04708     int ret;
04709 
04710     if (!(wpath = utf8_to_wstr(path, NULL)))
04711         return -1;
04712     ret = wstati64(wpath, st);
04713     free(wpath);
04714     return ret;
04715 }
04716 
04717 /* License: Ruby's */
04718 int
04719 rb_w32_stati64(const char *path, struct stati64 *st)
04720 {
04721     WCHAR *wpath;
04722     int ret;
04723 
04724     if (!(wpath = filecp_to_wstr(path, NULL)))
04725         return -1;
04726     ret = wstati64(wpath, st);
04727     free(wpath);
04728     return ret;
04729 }
04730 
04731 /* License: Ruby's */
04732 int
04733 rb_w32_access(const char *path, int mode)
04734 {
04735     struct stati64 stat;
04736     if (rb_w32_stati64(path, &stat) != 0)
04737         return -1;
04738     mode <<= 6;
04739     if ((stat.st_mode & mode) != mode) {
04740         errno = EACCES;
04741         return -1;
04742     }
04743     return 0;
04744 }
04745 
04746 /* License: Ruby's */
04747 int
04748 rb_w32_uaccess(const char *path, int mode)
04749 {
04750     struct stati64 stat;
04751     if (rb_w32_ustati64(path, &stat) != 0)
04752         return -1;
04753     mode <<= 6;
04754     if ((stat.st_mode & mode) != mode) {
04755         errno = EACCES;
04756         return -1;
04757     }
04758     return 0;
04759 }
04760 
04761 /* License: Ruby's */
04762 static int
04763 rb_chsize(HANDLE h, off_t size)
04764 {
04765     long upos, lpos, usize, lsize;
04766     int ret = -1;
04767     DWORD e;
04768 
04769     if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
04770         (e = GetLastError())) {
04771         errno = map_errno(e);
04772         return -1;
04773     }
04774     usize = (long)(size >> 32);
04775     lsize = (long)size;
04776     if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L &&
04777         (e = GetLastError())) {
04778         errno = map_errno(e);
04779     }
04780     else if (!SetEndOfFile(h)) {
04781         errno = map_errno(GetLastError());
04782     }
04783     else {
04784         ret = 0;
04785     }
04786     SetFilePointer(h, lpos, &upos, SEEK_SET);
04787     return ret;
04788 }
04789 
04790 /* License: Ruby's */
04791 int
04792 rb_w32_truncate(const char *path, off_t length)
04793 {
04794     HANDLE h;
04795     int ret;
04796     h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
04797     if (h == INVALID_HANDLE_VALUE) {
04798         errno = map_errno(GetLastError());
04799         return -1;
04800     }
04801     ret = rb_chsize(h, length);
04802     CloseHandle(h);
04803     return ret;
04804 }
04805 
04806 /* License: Ruby's */
04807 int
04808 rb_w32_ftruncate(int fd, off_t length)
04809 {
04810     HANDLE h;
04811 
04812     h = (HANDLE)_get_osfhandle(fd);
04813     if (h == (HANDLE)-1) return -1;
04814     return rb_chsize(h, length);
04815 }
04816 
04817 #ifdef __BORLANDC__
04818 /* License: Ruby's */
04819 off_t
04820 _filelengthi64(int fd)
04821 {
04822     DWORD u, l;
04823     int e;
04824 
04825     l = GetFileSize((HANDLE)_get_osfhandle(fd), &u);
04826     if (l == (DWORD)-1L && (e = GetLastError())) {
04827         errno = map_errno(e);
04828         return (off_t)-1;
04829     }
04830     return ((off_t)u << 32) | l;
04831 }
04832 
04833 /* License: Ruby's */
04834 off_t
04835 _lseeki64(int fd, off_t offset, int whence)
04836 {
04837     long u, l;
04838     int e;
04839     HANDLE h = (HANDLE)_get_osfhandle(fd);
04840 
04841     if (!h) {
04842         errno = EBADF;
04843         return -1;
04844     }
04845     u = (long)(offset >> 32);
04846     if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L &&
04847         (e = GetLastError())) {
04848         errno = map_errno(e);
04849         return -1;
04850     }
04851     return ((off_t)u << 32) | l;
04852 }
04853 #endif
04854 
04855 /* License: Ruby's */
04856 int
04857 fseeko(FILE *stream, off_t offset, int whence)
04858 {
04859     off_t pos;
04860     switch (whence) {
04861       case SEEK_CUR:
04862         if (fgetpos(stream, (fpos_t *)&pos))
04863             return -1;
04864         pos += offset;
04865         break;
04866       case SEEK_END:
04867         if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1)
04868             return -1;
04869         pos += offset;
04870         break;
04871       default:
04872         pos = offset;
04873         break;
04874     }
04875     return fsetpos(stream, (fpos_t *)&pos);
04876 }
04877 
04878 /* License: Ruby's */
04879 off_t
04880 rb_w32_ftello(FILE *stream)
04881 {
04882     off_t pos;
04883     if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1;
04884     return pos;
04885 }
04886 
04887 /* License: Ruby's */
04888 static long
04889 filetime_to_clock(FILETIME *ft)
04890 {
04891     __int64 qw = ft->dwHighDateTime;
04892     qw <<= 32;
04893     qw |= ft->dwLowDateTime;
04894     qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
04895     return (long) qw;
04896 }
04897 
04898 /* License: Ruby's */
04899 int
04900 rb_w32_times(struct tms *tmbuf)
04901 {
04902     FILETIME create, exit, kernel, user;
04903 
04904     if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
04905         tmbuf->tms_utime = filetime_to_clock(&user);
04906         tmbuf->tms_stime = filetime_to_clock(&kernel);
04907         tmbuf->tms_cutime = 0;
04908         tmbuf->tms_cstime = 0;
04909     }
04910     else {
04911         tmbuf->tms_utime = clock();
04912         tmbuf->tms_stime = 0;
04913         tmbuf->tms_cutime = 0;
04914         tmbuf->tms_cstime = 0;
04915     }
04916     return 0;
04917 }
04918 
04919 #define yield_once() Sleep(0)
04920 #define yield_until(condition) do yield_once(); while (!(condition))
04921 
04922 /* License: Ruby's */
04923 static void
04924 catch_interrupt(void)
04925 {
04926     yield_once();
04927     RUBY_CRITICAL(rb_w32_wait_events(NULL, 0, 0));
04928 }
04929 
04930 #if defined __BORLANDC__
04931 #undef read
04932 /* License: Ruby's */
04933 int
04934 read(int fd, void *buf, size_t size)
04935 {
04936     int ret = _read(fd, buf, size);
04937     if ((ret < 0) && (errno == EPIPE)) {
04938         errno = 0;
04939         ret = 0;
04940     }
04941     catch_interrupt();
04942     return ret;
04943 }
04944 #endif
04945 
04946 
04947 #define FILE_COUNT _cnt
04948 #define FILE_READPTR _ptr
04949 
04950 #undef fgetc
04951 /* License: Ruby's */
04952 int
04953 rb_w32_getc(FILE* stream)
04954 {
04955     int c;
04956     if (enough_to_get(stream->FILE_COUNT)) {
04957         c = (unsigned char)*stream->FILE_READPTR++;
04958     }
04959     else {
04960         c = _filbuf(stream);
04961 #if defined __BORLANDC__
04962         if ((c == EOF) && (errno == EPIPE)) {
04963             clearerr(stream);
04964         }
04965 #endif
04966         catch_interrupt();
04967     }
04968     return c;
04969 }
04970 
04971 #undef fputc
04972 /* License: Ruby's */
04973 int
04974 rb_w32_putc(int c, FILE* stream)
04975 {
04976     if (enough_to_put(stream->FILE_COUNT)) {
04977         c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
04978     }
04979     else {
04980         c = _flsbuf(c, stream);
04981         catch_interrupt();
04982     }
04983     return c;
04984 }
04985 
04986 /* License: Ruby's */
04987 struct asynchronous_arg_t {
04988     /* output field */
04989     void* stackaddr;
04990     int errnum;
04991 
04992     /* input field */
04993     uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv);
04994     uintptr_t self;
04995     int argc;
04996     uintptr_t* argv;
04997 };
04998 
04999 /* License: Ruby's */
05000 static DWORD WINAPI
05001 call_asynchronous(PVOID argp)
05002 {
05003     DWORD ret;
05004     struct asynchronous_arg_t *arg = argp;
05005     arg->stackaddr = &argp;
05006     ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
05007     arg->errnum = errno;
05008     return ret;
05009 }
05010 
05011 /* License: Ruby's */
05012 uintptr_t
05013 rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self,
05014                     int argc, uintptr_t* argv, uintptr_t intrval)
05015 {
05016     DWORD val;
05017     BOOL interrupted = FALSE;
05018     HANDLE thr;
05019 
05020     RUBY_CRITICAL({
05021         struct asynchronous_arg_t arg;
05022 
05023         arg.stackaddr = NULL;
05024         arg.errnum = 0;
05025         arg.func = func;
05026         arg.self = self;
05027         arg.argc = argc;
05028         arg.argv = argv;
05029 
05030         thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
05031 
05032         if (thr) {
05033             yield_until(arg.stackaddr);
05034 
05035             if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
05036                 interrupted = TRUE;
05037 
05038                 if (TerminateThread(thr, intrval)) {
05039                     yield_once();
05040                 }
05041             }
05042 
05043             GetExitCodeThread(thr, &val);
05044             CloseHandle(thr);
05045 
05046             if (interrupted) {
05047                 /* must release stack of killed thread, why doesn't Windows? */
05048                 MEMORY_BASIC_INFORMATION m;
05049 
05050                 memset(&m, 0, sizeof(m));
05051                 if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
05052                     Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
05053                                   arg.stackaddr, GetLastError()));
05054                 }
05055                 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
05056                     Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
05057                                   m.AllocationBase, GetLastError()));
05058                 }
05059                 errno = EINTR;
05060             }
05061             else {
05062                 errno = arg.errnum;
05063             }
05064         }
05065     });
05066 
05067     if (!thr) {
05068         rb_fatal("failed to launch waiter thread:%ld", GetLastError());
05069     }
05070 
05071     return val;
05072 }
05073 
05074 /* License: Ruby's */
05075 char **
05076 rb_w32_get_environ(void)
05077 {
05078     WCHAR *envtop, *env;
05079     char **myenvtop, **myenv;
05080     int num;
05081 
05082     /*
05083      * We avoid values started with `='. If you want to deal those values,
05084      * change this function, and some functions in hash.c which recognize
05085      * `=' as delimiter or rb_w32_getenv() and ruby_setenv().
05086      * CygWin deals these values by changing first `=' to '!'. But we don't
05087      * use such trick and follow cmd.exe's way that just doesn't show these
05088      * values.
05089      *
05090      * This function returns UTF-8 strings.
05091      */
05092     envtop = GetEnvironmentStringsW();
05093     for (env = envtop, num = 0; *env; env += lstrlenW(env) + 1)
05094         if (*env != '=') num++;
05095 
05096     myenvtop = (char **)malloc(sizeof(char *) * (num + 1));
05097     for (env = envtop, myenv = myenvtop; *env; env += lstrlenW(env) + 1) {
05098         if (*env != '=') {
05099             if (!(*myenv = wstr_to_utf8(env, NULL))) {
05100                 break;
05101             }
05102             myenv++;
05103         }
05104     }
05105     *myenv = NULL;
05106     FreeEnvironmentStringsW(envtop);
05107 
05108     return myenvtop;
05109 }
05110 
05111 /* License: Ruby's */
05112 void
05113 rb_w32_free_environ(char **env)
05114 {
05115     char **t = env;
05116 
05117     while (*t) free(*t++);
05118     free(env);
05119 }
05120 
05121 /* License: Ruby's */
05122 rb_pid_t
05123 rb_w32_getpid(void)
05124 {
05125     return GetCurrentProcessId();
05126 }
05127 
05128 
05129 /* License: Ruby's */
05130 rb_pid_t
05131 rb_w32_getppid(void)
05132 {
05133     typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *);
05134     static query_func *pNtQueryInformationProcess = NULL;
05135     rb_pid_t ppid = 0;
05136 
05137     if (rb_w32_osver() >= 5) {
05138         if (!pNtQueryInformationProcess)
05139             pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL);
05140         if (pNtQueryInformationProcess) {
05141             struct {
05142                 long ExitStatus;
05143                 void* PebBaseAddress;
05144                 uintptr_t AffinityMask;
05145                 uintptr_t BasePriority;
05146                 uintptr_t UniqueProcessId;
05147                 uintptr_t ParentProcessId;
05148             } pbi;
05149             ULONG len;
05150             long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
05151             if (!ret) {
05152                 ppid = pbi.ParentProcessId;
05153             }
05154         }
05155     }
05156 
05157     return ppid;
05158 }
05159 
05160 /* License: Ruby's */
05161 int
05162 rb_w32_uopen(const char *file, int oflag, ...)
05163 {
05164     WCHAR *wfile;
05165     int ret;
05166     int pmode;
05167 
05168     va_list arg;
05169     va_start(arg, oflag);
05170     pmode = va_arg(arg, int);
05171     va_end(arg);
05172 
05173     if (!(wfile = utf8_to_wstr(file, NULL)))
05174         return -1;
05175     ret = rb_w32_wopen(wfile, oflag, pmode);
05176     free(wfile);
05177     return ret;
05178 }
05179 
05180 /* License: Ruby's */
05181 static int
05182 check_if_wdir(const WCHAR *wfile)
05183 {
05184     DWORD attr = GetFileAttributesW(wfile);
05185     if (attr == (DWORD)-1L ||
05186         !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
05187         check_valid_dir(wfile)) {
05188         return FALSE;
05189     }
05190     errno = EISDIR;
05191     return TRUE;
05192 }
05193 
05194 /* License: Ruby's */
05195 static int
05196 check_if_dir(const char *file)
05197 {
05198     WCHAR *wfile;
05199     int ret;
05200 
05201     if (!(wfile = filecp_to_wstr(file, NULL)))
05202         return FALSE;
05203     ret = check_if_wdir(wfile);
05204     free(wfile);
05205     return ret;
05206 }
05207 
05208 /* License: Ruby's */
05209 int
05210 rb_w32_open(const char *file, int oflag, ...)
05211 {
05212     WCHAR *wfile;
05213     int ret;
05214     int pmode;
05215 
05216     va_list arg;
05217     va_start(arg, oflag);
05218     pmode = va_arg(arg, int);
05219     va_end(arg);
05220 
05221     if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
05222         ret = _open(file, oflag, pmode);
05223         if (ret == -1 && errno == EACCES) check_if_dir(file);
05224         return ret;
05225     }
05226 
05227     if (!(wfile = filecp_to_wstr(file, NULL)))
05228         return -1;
05229     ret = rb_w32_wopen(wfile, oflag, pmode);
05230     free(wfile);
05231     return ret;
05232 }
05233 
05234 int
05235 rb_w32_wopen(const WCHAR *file, int oflag, ...)
05236 {
05237     char flags = 0;
05238     int fd;
05239     DWORD access;
05240     DWORD create;
05241     DWORD attr = FILE_ATTRIBUTE_NORMAL;
05242     SECURITY_ATTRIBUTES sec;
05243     HANDLE h;
05244 
05245     if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
05246         va_list arg;
05247         int pmode;
05248         va_start(arg, oflag);
05249         pmode = va_arg(arg, int);
05250         va_end(arg);
05251         fd = _wopen(file, oflag, pmode);
05252         if (fd == -1 && errno == EACCES) check_if_wdir(file);
05253         return fd;
05254     }
05255 
05256     sec.nLength = sizeof(sec);
05257     sec.lpSecurityDescriptor = NULL;
05258     if (oflag & O_NOINHERIT) {
05259         sec.bInheritHandle = FALSE;
05260         flags |= FNOINHERIT;
05261     }
05262     else {
05263         sec.bInheritHandle = TRUE;
05264     }
05265     oflag &= ~O_NOINHERIT;
05266 
05267     /* always open with binary mode */
05268     oflag &= ~(O_BINARY | O_TEXT);
05269 
05270     switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
05271       case O_RDWR:
05272         access = GENERIC_READ | GENERIC_WRITE;
05273         break;
05274       case O_RDONLY:
05275         access = GENERIC_READ;
05276         break;
05277       case O_WRONLY:
05278         access = GENERIC_WRITE;
05279         break;
05280       default:
05281         errno = EINVAL;
05282         return -1;
05283     }
05284     oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
05285 
05286     switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
05287       case O_CREAT:
05288         create = OPEN_ALWAYS;
05289         break;
05290       case 0:
05291       case O_EXCL:
05292         create = OPEN_EXISTING;
05293         break;
05294       case O_CREAT | O_EXCL:
05295       case O_CREAT | O_EXCL | O_TRUNC:
05296         create = CREATE_NEW;
05297         break;
05298       case O_TRUNC:
05299       case O_TRUNC | O_EXCL:
05300         create = TRUNCATE_EXISTING;
05301         break;
05302       case O_CREAT | O_TRUNC:
05303         create = CREATE_ALWAYS;
05304         break;
05305       default:
05306         errno = EINVAL;
05307         return -1;
05308     }
05309     if (oflag & O_CREAT) {
05310         va_list arg;
05311         int pmode;
05312         va_start(arg, oflag);
05313         pmode = va_arg(arg, int);
05314         va_end(arg);
05315         /* TODO: we need to check umask here, but it's not exported... */
05316         if (!(pmode & S_IWRITE))
05317             attr = FILE_ATTRIBUTE_READONLY;
05318     }
05319     oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
05320 
05321     if (oflag & O_TEMPORARY) {
05322         attr |= FILE_FLAG_DELETE_ON_CLOSE;
05323         access |= DELETE;
05324     }
05325     oflag &= ~O_TEMPORARY;
05326 
05327     if (oflag & _O_SHORT_LIVED)
05328         attr |= FILE_ATTRIBUTE_TEMPORARY;
05329     oflag &= ~_O_SHORT_LIVED;
05330 
05331     switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
05332       case 0:
05333         break;
05334       case O_SEQUENTIAL:
05335         attr |= FILE_FLAG_SEQUENTIAL_SCAN;
05336         break;
05337       case O_RANDOM:
05338         attr |= FILE_FLAG_RANDOM_ACCESS;
05339         break;
05340       default:
05341         errno = EINVAL;
05342         return -1;
05343     }
05344     oflag &= ~(O_SEQUENTIAL | O_RANDOM);
05345 
05346     if (oflag & ~O_APPEND) {
05347         errno = EINVAL;
05348         return -1;
05349     }
05350 
05351     /* allocate a C Runtime file handle */
05352     RUBY_CRITICAL({
05353         h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05354         fd = _open_osfhandle((intptr_t)h, 0);
05355         CloseHandle(h);
05356     });
05357     if (fd == -1) {
05358         errno = EMFILE;
05359         return -1;
05360     }
05361     RUBY_CRITICAL({
05362         MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05363         _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
05364         _set_osflags(fd, 0);
05365 
05366         h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec,
05367                         create, attr, NULL);
05368         if (h == INVALID_HANDLE_VALUE) {
05369             DWORD e = GetLastError();
05370             if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
05371                 errno = map_errno(e);
05372             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05373             fd = -1;
05374             goto quit;
05375         }
05376 
05377         switch (GetFileType(h)) {
05378           case FILE_TYPE_CHAR:
05379             flags |= FDEV;
05380             break;
05381           case FILE_TYPE_PIPE:
05382             flags |= FPIPE;
05383             break;
05384           case FILE_TYPE_UNKNOWN:
05385             errno = map_errno(GetLastError());
05386             CloseHandle(h);
05387             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05388             fd = -1;
05389             goto quit;
05390         }
05391         if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
05392             flags |= FAPPEND;
05393 
05394         _set_osfhnd(fd, (intptr_t)h);
05395         _osfile(fd) = flags | FOPEN;
05396 
05397         MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05398       quit:
05399         ;
05400     });
05401 
05402     return fd;
05403 }
05404 
05405 /* License: Ruby's */
05406 int
05407 rb_w32_fclose(FILE *fp)
05408 {
05409     int fd = fileno(fp);
05410     SOCKET sock = TO_SOCKET(fd);
05411     int save_errno = errno;
05412 
05413     if (fflush(fp)) return -1;
05414     if (!is_socket(sock)) {
05415         UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
05416         return fclose(fp);
05417     }
05418     _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
05419     fclose(fp);
05420     errno = save_errno;
05421     if (closesocket(sock) == SOCKET_ERROR) {
05422         errno = map_errno(WSAGetLastError());
05423         return -1;
05424     }
05425     return 0;
05426 }
05427 
05428 /* License: Ruby's */
05429 int
05430 rb_w32_pipe(int fds[2])
05431 {
05432     static DWORD serial = 0;
05433     char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
05434     char *p;
05435     SECURITY_ATTRIBUTES sec;
05436     HANDLE hRead, hWrite, h;
05437     int fdRead, fdWrite;
05438     int ret;
05439 
05440     /* if doesn't have CancelIo, use default pipe function */
05441     if (!cancel_io)
05442         return _pipe(fds, 65536L, _O_NOINHERIT);
05443 
05444     p = strchr(name, '0');
05445     snprintf(p, strlen(p) + 1, "%"PRI_PIDT_PREFIX"x-%lx", rb_w32_getpid(), serial++);
05446 
05447     sec.nLength = sizeof(sec);
05448     sec.lpSecurityDescriptor = NULL;
05449     sec.bInheritHandle = FALSE;
05450 
05451     RUBY_CRITICAL({
05452         hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
05453                                 0, 2, 65536, 65536, 0, &sec);
05454     });
05455     if (hRead == INVALID_HANDLE_VALUE) {
05456         DWORD err = GetLastError();
05457         if (err == ERROR_PIPE_BUSY)
05458             errno = EMFILE;
05459         else
05460             errno = map_errno(GetLastError());
05461         return -1;
05462     }
05463 
05464     RUBY_CRITICAL({
05465         hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
05466                             OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
05467     });
05468     if (hWrite == INVALID_HANDLE_VALUE) {
05469         errno = map_errno(GetLastError());
05470         CloseHandle(hRead);
05471         return -1;
05472     }
05473 
05474     RUBY_CRITICAL(do {
05475         ret = 0;
05476         h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05477         fdRead = _open_osfhandle((intptr_t)h, 0);
05478         CloseHandle(h);
05479         if (fdRead == -1) {
05480             errno = EMFILE;
05481             CloseHandle(hWrite);
05482             CloseHandle(hRead);
05483             ret = -1;
05484             break;
05485         }
05486 
05487         MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock)));
05488         _set_osfhnd(fdRead, (intptr_t)hRead);
05489         _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
05490         MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock)));
05491     } while (0));
05492     if (ret)
05493         return ret;
05494 
05495     RUBY_CRITICAL(do {
05496         h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05497         fdWrite = _open_osfhandle((intptr_t)h, 0);
05498         CloseHandle(h);
05499         if (fdWrite == -1) {
05500             errno = EMFILE;
05501             CloseHandle(hWrite);
05502             ret = -1;
05503             break;
05504         }
05505         MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock)));
05506         _set_osfhnd(fdWrite, (intptr_t)hWrite);
05507         _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
05508         MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock)));
05509     } while (0));
05510     if (ret) {
05511         rb_w32_close(fdRead);
05512         return ret;
05513     }
05514 
05515     fds[0] = fdRead;
05516     fds[1] = fdWrite;
05517 
05518     return 0;
05519 }
05520 
05521 /* License: Ruby's */
05522 static struct constat *
05523 constat_handle(HANDLE h)
05524 {
05525     st_data_t data;
05526     struct constat *p;
05527     if (!conlist) {
05528         conlist = st_init_numtable();
05529     }
05530     if (st_lookup(conlist, (st_data_t)h, &data)) {
05531         p = (struct constat *)data;
05532     }
05533     else {
05534         CONSOLE_SCREEN_BUFFER_INFO csbi;
05535         p = ALLOC(struct constat);
05536         p->vt100.state = constat_init;
05537         p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05538         p->vt100.saved.X = p->vt100.saved.Y = 0;
05539         if (GetConsoleScreenBufferInfo(h, &csbi)) {
05540             p->vt100.attr = csbi.wAttributes;
05541         }
05542         st_insert(conlist, (st_data_t)h, (st_data_t)p);
05543     }
05544     return p;
05545 }
05546 
05547 /* License: Ruby's */
05548 static void
05549 constat_reset(HANDLE h)
05550 {
05551     st_data_t data;
05552     struct constat *p;
05553     if (!conlist) return;
05554     if (!st_lookup(conlist, (st_data_t)h, &data)) return;
05555     p = (struct constat *)data;
05556     p->vt100.state = constat_init;
05557 }
05558 
05559 /* License: Ruby's */
05560 static DWORD
05561 constat_attr(int count, const int *seq, DWORD attr, DWORD default_attr)
05562 {
05563 #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
05564 #define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
05565     DWORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
05566     int rev = 0;
05567 
05568     if (!count) return attr;
05569     while (count-- > 0) {
05570         switch (*seq++) {
05571           case 0:
05572             attr = default_attr;
05573             rev = 0;
05574             bold = 0;
05575             break;
05576           case 1:
05577             bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
05578             break;
05579           case 4:
05580 #ifndef COMMON_LVB_UNDERSCORE
05581 #define COMMON_LVB_UNDERSCORE 0x8000
05582 #endif
05583             attr |= COMMON_LVB_UNDERSCORE;
05584             break;
05585           case 7:
05586             rev = 1;
05587             break;
05588 
05589           case 30:
05590             attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
05591             break;
05592           case 17:
05593           case 31:
05594             attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED;
05595             break;
05596           case 18:
05597           case 32:
05598             attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN;
05599             break;
05600           case 19:
05601           case 33:
05602             attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05603             break;
05604           case 20:
05605           case 34:
05606             attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE;
05607             break;
05608           case 21:
05609           case 35:
05610             attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
05611             break;
05612           case 22:
05613           case 36:
05614             attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
05615             break;
05616           case 23:
05617           case 37:
05618             attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05619             break;
05620 
05621           case 40:
05622             attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
05623             break;
05624           case 41:
05625             attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED;
05626             break;
05627           case 42:
05628             attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN;
05629             break;
05630           case 43:
05631             attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
05632             break;
05633           case 44:
05634             attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE;
05635             break;
05636           case 45:
05637             attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
05638             break;
05639           case 46:
05640             attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN;
05641             break;
05642           case 47:
05643             attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
05644             break;
05645         }
05646     }
05647     if (rev) {
05648         attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) |
05649             ((attr & FOREGROUND_MASK) << 4) |
05650             ((attr & BACKGROUND_MASK) >> 4);
05651     }
05652     return attr | bold;
05653 }
05654 
05655 /* License: Ruby's */
05656 static void
05657 constat_apply(HANDLE handle, struct constat *s, WCHAR w)
05658 {
05659     CONSOLE_SCREEN_BUFFER_INFO csbi;
05660     const int *seq = s->vt100.seq;
05661     int count = s->vt100.state;
05662     int arg1 = 1;
05663     COORD pos;
05664     DWORD written;
05665 
05666     if (!GetConsoleScreenBufferInfo(handle, &csbi)) return;
05667     if (count > 0 && seq[0] > 0) arg1 = seq[0];
05668     switch (w) {
05669       case L'm':
05670         SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr));
05671         break;
05672       case L'F':
05673         csbi.dwCursorPosition.X = 0;
05674       case L'A':
05675         csbi.dwCursorPosition.Y -= arg1;
05676         if (csbi.dwCursorPosition.Y < 0)
05677             csbi.dwCursorPosition.Y = 0;
05678         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05679         break;
05680       case L'E':
05681         csbi.dwCursorPosition.X = 0;
05682       case L'B':
05683       case L'e':
05684         csbi.dwCursorPosition.Y += arg1;
05685         if (csbi.dwCursorPosition.Y >= csbi.dwSize.Y)
05686             csbi.dwCursorPosition.Y = csbi.dwSize.Y;
05687         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05688         break;
05689       case L'C':
05690         csbi.dwCursorPosition.X += arg1;
05691         if (csbi.dwCursorPosition.X >= csbi.dwSize.X)
05692             csbi.dwCursorPosition.X = csbi.dwSize.X;
05693         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05694         break;
05695       case L'D':
05696         csbi.dwCursorPosition.X -= arg1;
05697         if (csbi.dwCursorPosition.X < 0)
05698             csbi.dwCursorPosition.X = 0;
05699         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05700         break;
05701       case L'G':
05702       case L'`':
05703         csbi.dwCursorPosition.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
05704         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05705         break;
05706       case L'd':
05707         csbi.dwCursorPosition.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
05708         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05709         break;
05710       case L'H':
05711       case L'f':
05712         pos.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
05713         if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1;
05714         pos.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
05715         SetConsoleCursorPosition(handle, pos);
05716         break;
05717       case L'J':
05718         switch (arg1) {
05719           case 0:       /* erase after cursor */
05720             FillConsoleOutputCharacterW(handle, L' ',
05721                                         csbi.dwSize.X * (csbi.dwSize.Y - csbi.dwCursorPosition.Y) - csbi.dwCursorPosition.X,
05722                                         csbi.dwCursorPosition, &written);
05723             break;
05724           case 1:       /* erase before cursor */
05725             pos.X = 0;
05726             pos.Y = csbi.dwCursorPosition.Y;
05727             FillConsoleOutputCharacterW(handle, L' ',
05728                                         csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X,
05729                                         pos, &written);
05730             break;
05731           case 2:       /* erase entire line */
05732             pos.X = 0;
05733             pos.Y = 0;
05734             FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X * csbi.dwSize.Y, pos, &written);
05735             break;
05736         }
05737         break;
05738       case L'K':
05739         switch (arg1) {
05740           case 0:       /* erase after cursor */
05741             FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written);
05742             break;
05743           case 1:       /* erase before cursor */
05744             pos.X = 0;
05745             pos.Y = csbi.dwCursorPosition.Y;
05746             FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written);
05747             break;
05748           case 2:       /* erase entire line */
05749             pos.X = 0;
05750             pos.Y = csbi.dwCursorPosition.Y;
05751             FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written);
05752             break;
05753         }
05754         break;
05755       case L's':
05756         s->vt100.saved = csbi.dwCursorPosition;
05757         break;
05758       case L'u':
05759         SetConsoleCursorPosition(handle, s->vt100.saved);
05760         break;
05761       case L'h':
05762         if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
05763             CONSOLE_CURSOR_INFO cci;
05764             GetConsoleCursorInfo(handle, &cci);
05765             cci.bVisible = TRUE;
05766             SetConsoleCursorInfo(handle, &cci);
05767         }
05768         break;
05769       case L'l':
05770         if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
05771             CONSOLE_CURSOR_INFO cci;
05772             GetConsoleCursorInfo(handle, &cci);
05773             cci.bVisible = FALSE;
05774             SetConsoleCursorInfo(handle, &cci);
05775         }
05776         break;
05777     }
05778 }
05779 
05780 /* License: Ruby's */
05781 static long
05782 constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
05783 {
05784     const WCHAR *ptr = *ptrp;
05785     long rest, len = *lenp;
05786     while (len-- > 0) {
05787         WCHAR wc = *ptr++;
05788         if (wc == 0x1b) {
05789             rest = *lenp - len - 1;
05790             s->vt100.state = constat_esc;
05791         }
05792         else if (s->vt100.state == constat_esc && wc == L'[') {
05793             rest = *lenp - len - 1;
05794             if (rest > 0) --rest;
05795             s->vt100.state = constat_seq;
05796             s->vt100.seq[0] = 0;
05797         }
05798         else if (s->vt100.state >= constat_seq) {
05799             if (wc >= L'0' && wc <= L'9') {
05800                 if (s->vt100.state < (int)numberof(s->vt100.seq)) {
05801                     int *seq = &s->vt100.seq[s->vt100.state];
05802                     *seq = (*seq * 10) + (wc - L'0');
05803                 }
05804             }
05805             else if (s->vt100.state == constat_seq && s->vt100.seq[0] == 0 && wc == L'?') {
05806                 s->vt100.seq[s->vt100.state++] = -1;
05807             }
05808             else {
05809                 do {
05810                     if (++s->vt100.state < (int)numberof(s->vt100.seq)) {
05811                         s->vt100.seq[s->vt100.state] = 0;
05812                     }
05813                     else {
05814                         s->vt100.state = (int)numberof(s->vt100.seq);
05815                     }
05816                 } while (0);
05817                 if (wc != L';') {
05818                     constat_apply(h, s, wc);
05819                     s->vt100.state = constat_init;
05820                 }
05821             }
05822             rest = 0;
05823         }
05824         else {
05825             continue;
05826         }
05827         *ptrp = ptr;
05828         *lenp = len;
05829         return rest;
05830     }
05831     len = *lenp;
05832     *ptrp = ptr;
05833     *lenp = 0;
05834     return len;
05835 }
05836 
05837 
05838 /* License: Ruby's */
05839 int
05840 rb_w32_close(int fd)
05841 {
05842     SOCKET sock = TO_SOCKET(fd);
05843     int save_errno = errno;
05844 
05845     if (!is_socket(sock)) {
05846         UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
05847         constat_delete((HANDLE)sock);
05848         return _close(fd);
05849     }
05850     _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
05851     socklist_delete(&sock, NULL);
05852     _close(fd);
05853     errno = save_errno;
05854     if (closesocket(sock) == SOCKET_ERROR) {
05855         errno = map_errno(WSAGetLastError());
05856         return -1;
05857     }
05858     return 0;
05859 }
05860 
05861 static int
05862 setup_overlapped(OVERLAPPED *ol, int fd)
05863 {
05864     memset(ol, 0, sizeof(*ol));
05865     if (!(_osfile(fd) & (FDEV | FPIPE))) {
05866         LONG high = 0;
05867         DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
05868         DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
05869 #ifndef INVALID_SET_FILE_POINTER
05870 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
05871 #endif
05872         if (low == INVALID_SET_FILE_POINTER) {
05873             DWORD err = GetLastError();
05874             if (err != NO_ERROR) {
05875                 errno = map_errno(err);
05876                 return -1;
05877             }
05878         }
05879         ol->Offset = low;
05880         ol->OffsetHigh = high;
05881     }
05882     ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
05883     if (!ol->hEvent) {
05884         errno = map_errno(GetLastError());
05885         return -1;
05886     }
05887     return 0;
05888 }
05889 
05890 static void
05891 finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
05892 {
05893     CloseHandle(ol->hEvent);
05894 
05895     if (!(_osfile(fd) & (FDEV | FPIPE))) {
05896         LONG high = ol->OffsetHigh;
05897         DWORD low = ol->Offset + size;
05898         if (low < ol->Offset)
05899             ++high;
05900         SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
05901     }
05902 }
05903 
05904 #undef read
05905 /* License: Ruby's */
05906 ssize_t
05907 rb_w32_read(int fd, void *buf, size_t size)
05908 {
05909     SOCKET sock = TO_SOCKET(fd);
05910     DWORD read;
05911     DWORD wait;
05912     DWORD err;
05913     size_t len;
05914     size_t ret;
05915     OVERLAPPED ol, *pol = NULL;
05916     BOOL isconsole;
05917     BOOL islineinput = FALSE;
05918     int start = 0;
05919 
05920     if (is_socket(sock))
05921         return rb_w32_recv(fd, buf, size, 0);
05922 
05923     // validate fd by using _get_osfhandle() because we cannot access _nhandle
05924     if (_get_osfhandle(fd) == -1) {
05925         return -1;
05926     }
05927 
05928     if (_osfile(fd) & FTEXT) {
05929         return _read(fd, buf, size);
05930     }
05931 
05932     MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05933 
05934     if (!size || _osfile(fd) & FEOFLAG) {
05935         _set_osflags(fd, _osfile(fd) & ~FEOFLAG);
05936         MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05937         return 0;
05938     }
05939 
05940     ret = 0;
05941     isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
05942     if (isconsole) {
05943         DWORD mode;
05944         GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
05945         islineinput = (mode & ENABLE_LINE_INPUT) != 0;
05946     }
05947   retry:
05948     /* get rid of console reading bug */
05949     if (isconsole) {
05950         constat_reset((HANDLE)_osfhnd(fd));
05951         if (start)
05952             len = 1;
05953         else {
05954             len = 0;
05955             start = 1;
05956         }
05957     }
05958     else
05959         len = size;
05960     size -= len;
05961 
05962     /* if have cancel_io, use Overlapped I/O */
05963     if (cancel_io) {
05964         if (setup_overlapped(&ol, fd)) {
05965             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05966             return -1;
05967         }
05968 
05969         pol = &ol;
05970     }
05971 
05972     if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
05973         err = GetLastError();
05974         if (err != ERROR_IO_PENDING) {
05975             if (pol) CloseHandle(ol.hEvent);
05976             if (err == ERROR_ACCESS_DENIED)
05977                 errno = EBADF;
05978             else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
05979                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05980                 return 0;
05981             }
05982             else
05983                 errno = map_errno(err);
05984 
05985             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05986             return -1;
05987         }
05988 
05989         if (pol) {
05990             wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
05991             if (wait != WAIT_OBJECT_0) {
05992                 if (wait == WAIT_OBJECT_0 + 1)
05993                     errno = EINTR;
05994                 else
05995                     errno = map_errno(GetLastError());
05996                 CloseHandle(ol.hEvent);
05997                 cancel_io((HANDLE)_osfhnd(fd));
05998                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05999                 return -1;
06000             }
06001 
06002             if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
06003                 (err = GetLastError()) != ERROR_HANDLE_EOF) {
06004                 int ret = 0;
06005                 if (err != ERROR_BROKEN_PIPE) {
06006                     errno = map_errno(err);
06007                     ret = -1;
06008                 }
06009                 CloseHandle(ol.hEvent);
06010                 cancel_io((HANDLE)_osfhnd(fd));
06011                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06012                 return ret;
06013             }
06014         }
06015     }
06016     else {
06017         err = GetLastError();
06018         errno = map_errno(err);
06019     }
06020 
06021     if (pol) {
06022         finish_overlapped(&ol, fd, read);
06023     }
06024 
06025     ret += read;
06026     if (read >= len) {
06027         buf = (char *)buf + read;
06028         if (err != ERROR_OPERATION_ABORTED &&
06029             !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0)
06030             goto retry;
06031     }
06032     if (read == 0)
06033         _set_osflags(fd, _osfile(fd) | FEOFLAG);
06034 
06035 
06036     MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06037 
06038     return ret;
06039 }
06040 
06041 #undef write
06042 /* License: Ruby's */
06043 ssize_t
06044 rb_w32_write(int fd, const void *buf, size_t size)
06045 {
06046     SOCKET sock = TO_SOCKET(fd);
06047     DWORD written;
06048     DWORD wait;
06049     DWORD err;
06050     size_t len;
06051     size_t ret;
06052     OVERLAPPED ol, *pol = NULL;
06053 
06054     if (is_socket(sock))
06055         return rb_w32_send(fd, buf, size, 0);
06056 
06057     // validate fd by using _get_osfhandle() because we cannot access _nhandle
06058     if (_get_osfhandle(fd) == -1) {
06059         return -1;
06060     }
06061 
06062     if ((_osfile(fd) & FTEXT) &&
06063         (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) {
06064         return _write(fd, buf, size);
06065     }
06066 
06067     MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
06068 
06069     if (!size || _osfile(fd) & FEOFLAG) {
06070         MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06071         return 0;
06072     }
06073 
06074     ret = 0;
06075   retry:
06076     /* get rid of console writing bug */
06077     len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size;
06078     size -= len;
06079 
06080     /* if have cancel_io, use Overlapped I/O */
06081     if (cancel_io) {
06082         if (setup_overlapped(&ol, fd)) {
06083             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06084             return -1;
06085         }
06086 
06087         pol = &ol;
06088     }
06089 
06090     if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) {
06091         err = GetLastError();
06092         if (err != ERROR_IO_PENDING) {
06093             if (pol) CloseHandle(ol.hEvent);
06094             if (err == ERROR_ACCESS_DENIED)
06095                 errno = EBADF;
06096             else
06097                 errno = map_errno(err);
06098 
06099             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06100             return -1;
06101         }
06102 
06103         if (pol) {
06104             wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
06105             if (wait != WAIT_OBJECT_0) {
06106                 if (wait == WAIT_OBJECT_0 + 1)
06107                     errno = EINTR;
06108                 else
06109                     errno = map_errno(GetLastError());
06110                 CloseHandle(ol.hEvent);
06111                 cancel_io((HANDLE)_osfhnd(fd));
06112                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06113                 return -1;
06114             }
06115 
06116             if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written,
06117                                      TRUE)) {
06118                 errno = map_errno(err);
06119                 CloseHandle(ol.hEvent);
06120                 cancel_io((HANDLE)_osfhnd(fd));
06121                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06122                 return -1;
06123             }
06124         }
06125     }
06126 
06127     if (pol) {
06128         finish_overlapped(&ol, fd, written);
06129     }
06130 
06131     ret += written;
06132     if (written == len) {
06133         buf = (const char *)buf + len;
06134         if (size > 0)
06135             goto retry;
06136     }
06137 
06138     MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06139 
06140     return ret;
06141 }
06142 
06143 /* License: Ruby's */
06144 long
06145 rb_w32_write_console(uintptr_t strarg, int fd)
06146 {
06147     static int disable;
06148     HANDLE handle;
06149     DWORD dwMode, reslen;
06150     VALUE str = strarg;
06151     rb_encoding *utf16 = rb_enc_find("UTF-16LE");
06152     const WCHAR *ptr, *next;
06153     struct constat *s;
06154     long len;
06155 
06156     if (disable) return -1L;
06157     handle = (HANDLE)_osfhnd(fd);
06158     if (!GetConsoleMode(handle, &dwMode) ||
06159         !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE"))
06160         return -1L;
06161 
06162     str = rb_str_encode(str, rb_enc_from_encoding(utf16),
06163                         ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
06164     ptr = (const WCHAR *)RSTRING_PTR(str);
06165     len = RSTRING_LEN(str) / sizeof(WCHAR);
06166     s = constat_handle(handle);
06167     while (len > 0) {
06168         long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
06169         if (curlen > 0) {
06170             if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) {
06171                 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
06172                     disable = TRUE;
06173                 return -1L;
06174             }
06175         }
06176         ptr = next;
06177     }
06178     RB_GC_GUARD(str);
06179     return (long)reslen;
06180 }
06181 
06182 /* License: Ruby's */
06183 static int
06184 unixtime_to_filetime(time_t time, FILETIME *ft)
06185 {
06186     ULARGE_INTEGER tmp;
06187 
06188     tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
06189     ft->dwLowDateTime = tmp.LowPart;
06190     ft->dwHighDateTime = tmp.HighPart;
06191     return 0;
06192 }
06193 
06194 /* License: Ruby's */
06195 static int
06196 wutime(const WCHAR *path, const struct utimbuf *times)
06197 {
06198     HANDLE hFile;
06199     FILETIME atime, mtime;
06200     struct stati64 stat;
06201     int ret = 0;
06202 
06203     if (wstati64(path, &stat)) {
06204         return -1;
06205     }
06206 
06207     if (times) {
06208         if (unixtime_to_filetime(times->actime, &atime)) {
06209             return -1;
06210         }
06211         if (unixtime_to_filetime(times->modtime, &mtime)) {
06212             return -1;
06213         }
06214     }
06215     else {
06216         GetSystemTimeAsFileTime(&atime);
06217         mtime = atime;
06218     }
06219 
06220     RUBY_CRITICAL({
06221         const DWORD attr = GetFileAttributesW(path);
06222         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
06223             SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
06224         hFile = CreateFileW(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
06225                             FILE_FLAG_BACKUP_SEMANTICS, 0);
06226         if (hFile == INVALID_HANDLE_VALUE) {
06227             errno = map_errno(GetLastError());
06228             ret = -1;
06229         }
06230         else {
06231             if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
06232                 errno = map_errno(GetLastError());
06233                 ret = -1;
06234             }
06235             CloseHandle(hFile);
06236         }
06237         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
06238             SetFileAttributesW(path, attr);
06239     });
06240 
06241     return ret;
06242 }
06243 
06244 /* License: Ruby's */
06245 int
06246 rb_w32_uutime(const char *path, const struct utimbuf *times)
06247 {
06248     WCHAR *wpath;
06249     int ret;
06250 
06251     if (!(wpath = utf8_to_wstr(path, NULL)))
06252         return -1;
06253     ret = wutime(wpath, times);
06254     free(wpath);
06255     return ret;
06256 }
06257 
06258 /* License: Ruby's */
06259 int
06260 rb_w32_utime(const char *path, const struct utimbuf *times)
06261 {
06262     WCHAR *wpath;
06263     int ret;
06264 
06265     if (!(wpath = filecp_to_wstr(path, NULL)))
06266         return -1;
06267     ret = wutime(wpath, times);
06268     free(wpath);
06269     return ret;
06270 }
06271 
06272 /* License: Ruby's */
06273 int
06274 rb_w32_uchdir(const char *path)
06275 {
06276     WCHAR *wpath;
06277     int ret;
06278 
06279     if (!(wpath = utf8_to_wstr(path, NULL)))
06280         return -1;
06281     ret = _wchdir(wpath);
06282     free(wpath);
06283     return ret;
06284 }
06285 
06286 /* License: Ruby's */
06287 static int
06288 wmkdir(const WCHAR *wpath, int mode)
06289 {
06290     int ret = -1;
06291 
06292     RUBY_CRITICAL(do {
06293         if (CreateDirectoryW(wpath, NULL) == FALSE) {
06294             errno = map_errno(GetLastError());
06295             break;
06296         }
06297         if (_wchmod(wpath, mode) == -1) {
06298             RemoveDirectoryW(wpath);
06299             break;
06300         }
06301         ret = 0;
06302     } while (0));
06303     return ret;
06304 }
06305 
06306 /* License: Ruby's */
06307 int
06308 rb_w32_umkdir(const char *path, int mode)
06309 {
06310     WCHAR *wpath;
06311     int ret;
06312 
06313     if (!(wpath = utf8_to_wstr(path, NULL)))
06314         return -1;
06315     ret = wmkdir(wpath, mode);
06316     free(wpath);
06317     return ret;
06318 }
06319 
06320 /* License: Ruby's */
06321 int
06322 rb_w32_mkdir(const char *path, int mode)
06323 {
06324     WCHAR *wpath;
06325     int ret;
06326 
06327     if (!(wpath = filecp_to_wstr(path, NULL)))
06328         return -1;
06329     ret = wmkdir(wpath, mode);
06330     free(wpath);
06331     return ret;
06332 }
06333 
06334 /* License: Ruby's */
06335 static int
06336 wrmdir(const WCHAR *wpath)
06337 {
06338     int ret = 0;
06339     RUBY_CRITICAL({
06340         const DWORD attr = GetFileAttributesW(wpath);
06341         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06342             SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
06343         }
06344         if (RemoveDirectoryW(wpath) == FALSE) {
06345             errno = map_errno(GetLastError());
06346             ret = -1;
06347             if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06348                 SetFileAttributesW(wpath, attr);
06349             }
06350         }
06351     });
06352     return ret;
06353 }
06354 
06355 /* License: Ruby's */
06356 int
06357 rb_w32_rmdir(const char *path)
06358 {
06359     WCHAR *wpath;
06360     int ret;
06361 
06362     if (!(wpath = filecp_to_wstr(path, NULL)))
06363         return -1;
06364     ret = wrmdir(wpath);
06365     free(wpath);
06366     return ret;
06367 }
06368 
06369 /* License: Ruby's */
06370 int
06371 rb_w32_urmdir(const char *path)
06372 {
06373     WCHAR *wpath;
06374     int ret;
06375 
06376     if (!(wpath = utf8_to_wstr(path, NULL)))
06377         return -1;
06378     ret = wrmdir(wpath);
06379     free(wpath);
06380     return ret;
06381 }
06382 
06383 /* License: Ruby's */
06384 static int
06385 wunlink(const WCHAR *path)
06386 {
06387     int ret = 0;
06388     RUBY_CRITICAL({
06389         const DWORD attr = GetFileAttributesW(path);
06390         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06391             SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
06392         }
06393         if (!DeleteFileW(path)) {
06394             errno = map_errno(GetLastError());
06395             ret = -1;
06396             if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06397                 SetFileAttributesW(path, attr);
06398             }
06399         }
06400     });
06401     return ret;
06402 }
06403 
06404 /* License: Ruby's */
06405 int
06406 rb_w32_uunlink(const char *path)
06407 {
06408     WCHAR *wpath;
06409     int ret;
06410 
06411     if (!(wpath = utf8_to_wstr(path, NULL)))
06412         return -1;
06413     ret = wunlink(wpath);
06414     free(wpath);
06415     return ret;
06416 }
06417 
06418 /* License: Ruby's */
06419 int
06420 rb_w32_unlink(const char *path)
06421 {
06422     WCHAR *wpath;
06423     int ret;
06424 
06425     if (!(wpath = filecp_to_wstr(path, NULL)))
06426         return -1;
06427     ret = wunlink(wpath);
06428     free(wpath);
06429     return ret;
06430 }
06431 
06432 /* License: Ruby's */
06433 int
06434 rb_w32_uchmod(const char *path, int mode)
06435 {
06436     WCHAR *wpath;
06437     int ret;
06438 
06439     if (!(wpath = utf8_to_wstr(path, NULL)))
06440         return -1;
06441     ret = _wchmod(wpath, mode);
06442     free(wpath);
06443     return ret;
06444 }
06445 
06446 #if !defined(__BORLANDC__)
06447 /* License: Ruby's */
06448 int
06449 rb_w32_isatty(int fd)
06450 {
06451     DWORD mode;
06452 
06453     // validate fd by using _get_osfhandle() because we cannot access _nhandle
06454     if (_get_osfhandle(fd) == -1) {
06455         return 0;
06456     }
06457     if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) {
06458         errno = ENOTTY;
06459         return 0;
06460     }
06461     return 1;
06462 }
06463 #endif
06464 
06465 //
06466 // Fix bcc32's stdio bug
06467 //
06468 
06469 #ifdef __BORLANDC__
06470 /* License: Ruby's */
06471 static int
06472 too_many_files(void)
06473 {
06474     FILE *f;
06475     for (f = _streams; f < _streams + _nfile; f++) {
06476         if (f->fd < 0) return 0;
06477     }
06478     return 1;
06479 }
06480 
06481 #undef fopen
06482 /* License: Ruby's */
06483 FILE *
06484 rb_w32_fopen(const char *path, const char *mode)
06485 {
06486     FILE *f = (errno = 0, fopen(path, mode));
06487     if (f == NULL && errno == 0) {
06488         if (too_many_files())
06489             errno = EMFILE;
06490     }
06491     return f;
06492 }
06493 
06494 /* License: Ruby's */
06495 FILE *
06496 rb_w32_fdopen(int handle, const char *type)
06497 {
06498     FILE *f = (errno = 0, _fdopen(handle, (char *)type));
06499     if (f == NULL && errno == 0) {
06500         if (handle < 0)
06501             errno = EBADF;
06502         else if (too_many_files())
06503             errno = EMFILE;
06504     }
06505     return f;
06506 }
06507 
06508 /* License: Ruby's */
06509 FILE *
06510 rb_w32_fsopen(const char *path, const char *mode, int shflags)
06511 {
06512     FILE *f = (errno = 0, _fsopen(path, mode, shflags));
06513     if (f == NULL && errno == 0) {
06514         if (too_many_files())
06515             errno = EMFILE;
06516     }
06517     return f;
06518 }
06519 #endif
06520 
06521 #if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
06522 extern long _ftol(double);
06523 /* License: Ruby's */
06524 long
06525 _ftol2(double d)
06526 {
06527     return _ftol(d);
06528 }
06529 
06530 /* License: Ruby's */
06531 long
06532 _ftol2_sse(double d)
06533 {
06534     return _ftol(d);
06535 }
06536 #endif
06537 
06538 #ifndef signbit
06539 /* License: Ruby's */
06540 int
06541 signbit(double x)
06542 {
06543     int *ip = (int *)(&x + 1) - 1;
06544     return *ip < 0;
06545 }
06546 #endif
06547 
06548 /* License: Ruby's */
06549 const char * WSAAPI
06550 rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
06551 {
06552     typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t);
06553     inet_ntop_t *pInetNtop;
06554     pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL);
06555     if (pInetNtop) {
06556         return pInetNtop(af, (void *)addr, numaddr, numaddr_len);
06557     }
06558     else {
06559         struct in_addr in;
06560         memcpy(&in.s_addr, addr, sizeof(in.s_addr));
06561         snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
06562     }
06563     return numaddr;
06564 }
06565 
06566 /* License: Ruby's */
06567 char
06568 rb_w32_fd_is_text(int fd)
06569 {
06570     return _osfile(fd) & FTEXT;
06571 }
06572 
06573 #if RUBY_MSVCRT_VERSION < 80 && !defined(__MINGW64__)
06574 /* License: Ruby's */
06575 static int
06576 unixtime_to_systemtime(const time_t t, SYSTEMTIME *st)
06577 {
06578     FILETIME ft;
06579     if (unixtime_to_filetime(t, &ft)) return -1;
06580     if (!FileTimeToSystemTime(&ft, st)) return -1;
06581     return 0;
06582 }
06583 
06584 /* License: Ruby's */
06585 static void
06586 systemtime_to_tm(const SYSTEMTIME *st, struct tm *t)
06587 {
06588     int y = st->wYear, m = st->wMonth, d = st->wDay;
06589     t->tm_sec  = st->wSecond;
06590     t->tm_min  = st->wMinute;
06591     t->tm_hour = st->wHour;
06592     t->tm_mday = st->wDay;
06593     t->tm_mon  = st->wMonth - 1;
06594     t->tm_year = y - 1900;
06595     t->tm_wday = st->wDayOfWeek;
06596     switch (m) {
06597       case 1:
06598         break;
06599       case 2:
06600         d += 31;
06601         break;
06602       default:
06603         d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
06604         d += ((m - 3) * 153 + 2) / 5;
06605         break;
06606     }
06607     t->tm_yday = d - 1;
06608 }
06609 
06610 /* License: Ruby's */
06611 static int
06612 systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
06613 {
06614     TIME_ZONE_INFORMATION stdtz;
06615     SYSTEMTIME sst;
06616 
06617     if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1;
06618     if (!tz) {
06619         GetTimeZoneInformation(&stdtz);
06620         tz = &stdtz;
06621     }
06622     if (tz->StandardBias == tz->DaylightBias) return 0;
06623     if (!tz->StandardDate.wMonth) return 0;
06624     if (!tz->DaylightDate.wMonth) return 0;
06625     if (tz != &stdtz) stdtz = *tz;
06626 
06627     stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
06628     if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0;
06629     if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
06630         return 0;
06631     return 1;
06632 }
06633 #endif
06634 
06635 #ifdef __MINGW64__
06636 # ifndef MINGW_HAS_SECURE_API
06637    _CRTIMP errno_t __cdecl _gmtime64_s(struct tm* tm, const __time64_t *time);
06638    _CRTIMP errno_t __cdecl _localtime64_s(struct tm* tm, const __time64_t *time);
06639 # endif
06640 # define gmtime_s _gmtime64_s
06641 # define localtime_s _localtime64_s
06642 #endif
06643 
06644 /* License: Ruby's */
06645 struct tm *
06646 gmtime_r(const time_t *tp, struct tm *rp)
06647 {
06648     int e = EINVAL;
06649     if (!tp || !rp) {
06650       error:
06651         errno = e;
06652         return NULL;
06653     }
06654 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
06655     e = gmtime_s(rp, tp);
06656     if (e != 0) goto error;
06657 #else
06658     {
06659         SYSTEMTIME st;
06660         if (unixtime_to_systemtime(*tp, &st)) goto error;
06661         rp->tm_isdst = 0;
06662         systemtime_to_tm(&st, rp);
06663     }
06664 #endif
06665     return rp;
06666 }
06667 
06668 /* License: Ruby's */
06669 struct tm *
06670 localtime_r(const time_t *tp, struct tm *rp)
06671 {
06672     int e = EINVAL;
06673     if (!tp || !rp) {
06674       error:
06675         errno = e;
06676         return NULL;
06677     }
06678 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
06679     e = localtime_s(rp, tp);
06680     if (e) goto error;
06681 #else
06682     {
06683         SYSTEMTIME gst, lst;
06684         if (unixtime_to_systemtime(*tp, &gst)) goto error;
06685         rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
06686         systemtime_to_tm(&lst, rp);
06687     }
06688 #endif
06689     return rp;
06690 }
06691 
06692 /* License: Ruby's */
06693 int
06694 rb_w32_wrap_io_handle(HANDLE h, int flags)
06695 {
06696     BOOL tmp;
06697     int len = sizeof(tmp);
06698     int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (char *)&tmp, &len);
06699     if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
06700         int f = 0;
06701         if (flags & O_NONBLOCK) {
06702             flags &= ~O_NONBLOCK;
06703             f = O_NONBLOCK;
06704         }
06705         socklist_insert((SOCKET)h, f);
06706     }
06707     else if (flags & O_NONBLOCK) {
06708         errno = EINVAL;
06709         return -1;
06710     }
06711     return rb_w32_open_osfhandle((intptr_t)h, flags);
06712 }
06713 
06714 /* License: Ruby's */
06715 int
06716 rb_w32_unwrap_io_handle(int fd)
06717 {
06718     SOCKET sock = TO_SOCKET(fd);
06719     _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
06720     if (!is_socket(sock)) {
06721         UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
06722         constat_delete((HANDLE)sock);
06723     }
06724     else {
06725         socklist_delete(&sock, NULL);
06726     }
06727     return _close(fd);
06728 }
06729