Ruby  2.0.0p481(2014-05-08revision45883)
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                 SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
02921                 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
02922                 _set_osfhnd(fd, r);
02923                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
02924                 CloseHandle(h);
02925                 socklist_insert(r, 0);
02926             }
02927             else {
02928                 errno = map_errno(WSAGetLastError());
02929                 close(fd);
02930                 fd = -1;
02931             }
02932         }
02933         else
02934             CloseHandle(h);
02935     });
02936     return fd;
02937 }
02938 
02939 #undef bind
02940 
02941 /* License: Artistic or GPL */
02942 int WSAAPI
02943 rb_w32_bind(int s, const struct sockaddr *addr, int addrlen)
02944 {
02945     int r;
02946 
02947     if (!NtSocketsInitialized) {
02948         StartSockets();
02949     }
02950     RUBY_CRITICAL({
02951         r = bind(TO_SOCKET(s), addr, addrlen);
02952         if (r == SOCKET_ERROR)
02953             errno = map_errno(WSAGetLastError());
02954     });
02955     return r;
02956 }
02957 
02958 #undef connect
02959 
02960 /* License: Artistic or GPL */
02961 int WSAAPI
02962 rb_w32_connect(int s, const struct sockaddr *addr, int addrlen)
02963 {
02964     int r;
02965     if (!NtSocketsInitialized) {
02966         StartSockets();
02967     }
02968     RUBY_CRITICAL({
02969         r = connect(TO_SOCKET(s), addr, addrlen);
02970         if (r == SOCKET_ERROR) {
02971             int err = WSAGetLastError();
02972             if (err != WSAEWOULDBLOCK)
02973                 errno = map_errno(err);
02974             else
02975                 errno = EINPROGRESS;
02976         }
02977     });
02978     return r;
02979 }
02980 
02981 
02982 #undef getpeername
02983 
02984 /* License: Artistic or GPL */
02985 int WSAAPI
02986 rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen)
02987 {
02988     int r;
02989     if (!NtSocketsInitialized) {
02990         StartSockets();
02991     }
02992     RUBY_CRITICAL({
02993         r = getpeername(TO_SOCKET(s), addr, addrlen);
02994         if (r == SOCKET_ERROR)
02995             errno = map_errno(WSAGetLastError());
02996     });
02997     return r;
02998 }
02999 
03000 #undef getsockname
03001 
03002 /* License: Artistic or GPL */
03003 int WSAAPI
03004 rb_w32_getsockname(int fd, struct sockaddr *addr, int *addrlen)
03005 {
03006     int sock;
03007     int r;
03008     if (!NtSocketsInitialized) {
03009         StartSockets();
03010     }
03011     RUBY_CRITICAL({
03012         sock = TO_SOCKET(fd);
03013         r = getsockname(sock, addr, addrlen);
03014         if (r == SOCKET_ERROR) {
03015             DWORD wsaerror = WSAGetLastError();
03016             if (wsaerror == WSAEINVAL) {
03017                 int flags;
03018                 if (socklist_lookup(sock, &flags)) {
03019                     int af = GET_FAMILY(flags);
03020                     if (af) {
03021                         memset(addr, 0, *addrlen);
03022                         addr->sa_family = af;
03023                         return 0;
03024                     }
03025                 }
03026             }
03027             errno = map_errno(wsaerror);
03028         }
03029     });
03030     return r;
03031 }
03032 
03033 #undef getsockopt
03034 
03035 /* License: Artistic or GPL */
03036 int WSAAPI
03037 rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen)
03038 {
03039     int r;
03040     if (!NtSocketsInitialized) {
03041         StartSockets();
03042     }
03043     RUBY_CRITICAL({
03044         r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen);
03045         if (r == SOCKET_ERROR)
03046             errno = map_errno(WSAGetLastError());
03047     });
03048     return r;
03049 }
03050 
03051 #undef ioctlsocket
03052 
03053 /* License: Artistic or GPL */
03054 int WSAAPI
03055 rb_w32_ioctlsocket(int s, long cmd, u_long *argp)
03056 {
03057     int r;
03058     if (!NtSocketsInitialized) {
03059         StartSockets();
03060     }
03061     RUBY_CRITICAL({
03062         r = ioctlsocket(TO_SOCKET(s), cmd, argp);
03063         if (r == SOCKET_ERROR)
03064             errno = map_errno(WSAGetLastError());
03065     });
03066     return r;
03067 }
03068 
03069 #undef listen
03070 
03071 /* License: Artistic or GPL */
03072 int WSAAPI
03073 rb_w32_listen(int s, int backlog)
03074 {
03075     int r;
03076     if (!NtSocketsInitialized) {
03077         StartSockets();
03078     }
03079     RUBY_CRITICAL({
03080         r = listen(TO_SOCKET(s), backlog);
03081         if (r == SOCKET_ERROR)
03082             errno = map_errno(WSAGetLastError());
03083     });
03084     return r;
03085 }
03086 
03087 #undef recv
03088 #undef recvfrom
03089 #undef send
03090 #undef sendto
03091 
03092 /* License: Ruby's */
03093 static int
03094 finish_overlapped_socket(BOOL input, SOCKET s, WSAOVERLAPPED *wol, int result, DWORD *len, DWORD size)
03095 {
03096     DWORD flg;
03097     int err;
03098 
03099     if (result != SOCKET_ERROR)
03100         *len = size;
03101     else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
03102         switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) {
03103           case WAIT_OBJECT_0:
03104             RUBY_CRITICAL(
03105                 result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg)
03106                 );
03107             if (result) {
03108                 *len = size;
03109                 break;
03110             }
03111             /* thru */
03112           default:
03113             if ((err = WSAGetLastError()) == WSAECONNABORTED && !input)
03114                 errno = EPIPE;
03115             else
03116                 errno = map_errno(WSAGetLastError());
03117             /* thru */
03118           case WAIT_OBJECT_0 + 1:
03119             /* interrupted */
03120             *len = -1;
03121             cancel_io((HANDLE)s);
03122             break;
03123         }
03124     }
03125     else {
03126         if (err == WSAECONNABORTED && !input)
03127             errno = EPIPE;
03128         else
03129             errno = map_errno(err);
03130         *len = -1;
03131     }
03132     CloseHandle(wol->hEvent);
03133 
03134     return result;
03135 }
03136 
03137 /* License: Artistic or GPL */
03138 static int
03139 overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
03140                      struct sockaddr *addr, int *addrlen)
03141 {
03142     int r;
03143     int ret;
03144     int mode = 0;
03145     DWORD flg;
03146     WSAOVERLAPPED wol;
03147     WSABUF wbuf;
03148     SOCKET s;
03149 
03150     if (!NtSocketsInitialized)
03151         StartSockets();
03152 
03153     s = TO_SOCKET(fd);
03154     socklist_lookup(s, &mode);
03155     if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
03156         RUBY_CRITICAL({
03157             if (input) {
03158                 if (addr && addrlen)
03159                     r = recvfrom(s, buf, len, flags, addr, addrlen);
03160                 else
03161                     r = recv(s, buf, len, flags);
03162                 if (r == SOCKET_ERROR)
03163                     errno = map_errno(WSAGetLastError());
03164             }
03165             else {
03166                 if (addr && addrlen)
03167                     r = sendto(s, buf, len, flags, addr, *addrlen);
03168                 else
03169                     r = send(s, buf, len, flags);
03170                 if (r == SOCKET_ERROR) {
03171                     DWORD err = WSAGetLastError();
03172                     if (err == WSAECONNABORTED)
03173                         errno = EPIPE;
03174                     else
03175                         errno = map_errno(err);
03176                 }
03177             }
03178         });
03179     }
03180     else {
03181         DWORD size;
03182         DWORD rlen;
03183         wbuf.len = len;
03184         wbuf.buf = buf;
03185         memset(&wol, 0, sizeof(wol));
03186         RUBY_CRITICAL({
03187             wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03188             if (input) {
03189                 flg = flags;
03190                 if (addr && addrlen)
03191                     ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen,
03192                                       &wol, NULL);
03193                 else
03194                     ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL);
03195             }
03196             else {
03197                 if (addr && addrlen)
03198                     ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen,
03199                                     &wol, NULL);
03200                 else
03201                     ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL);
03202             }
03203         });
03204 
03205         finish_overlapped_socket(input, s, &wol, ret, &rlen, size);
03206         r = (int)rlen;
03207     }
03208 
03209     return r;
03210 }
03211 
03212 /* License: Ruby's */
03213 int WSAAPI
03214 rb_w32_recv(int fd, char *buf, int len, int flags)
03215 {
03216     return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
03217 }
03218 
03219 /* License: Ruby's */
03220 int WSAAPI
03221 rb_w32_recvfrom(int fd, char *buf, int len, int flags,
03222                 struct sockaddr *from, int *fromlen)
03223 {
03224     return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
03225 }
03226 
03227 /* License: Ruby's */
03228 int WSAAPI
03229 rb_w32_send(int fd, const char *buf, int len, int flags)
03230 {
03231     return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL);
03232 }
03233 
03234 /* License: Ruby's */
03235 int WSAAPI
03236 rb_w32_sendto(int fd, const char *buf, int len, int flags,
03237               const struct sockaddr *to, int tolen)
03238 {
03239     return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
03240                                 (struct sockaddr *)to, &tolen);
03241 }
03242 
03243 #if !defined(MSG_TRUNC) && !defined(__MINGW32__)
03244 /* License: Ruby's */
03245 typedef struct {
03246     SOCKADDR *name;
03247     int namelen;
03248     WSABUF *lpBuffers;
03249     DWORD dwBufferCount;
03250     WSABUF Control;
03251     DWORD dwFlags;
03252 } WSAMSG;
03253 #endif
03254 #ifndef WSAID_WSARECVMSG
03255 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
03256 #endif
03257 #ifndef WSAID_WSASENDMSG
03258 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
03259 #endif
03260 
03261 /* License: Ruby's */
03262 #define msghdr_to_wsamsg(msg, wsamsg) \
03263     do { \
03264         int i; \
03265         (wsamsg)->name = (msg)->msg_name; \
03266         (wsamsg)->namelen = (msg)->msg_namelen; \
03267         (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
03268         (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
03269         for (i = 0; i < (msg)->msg_iovlen; ++i) { \
03270             (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
03271             (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
03272         } \
03273         (wsamsg)->Control.buf = (msg)->msg_control; \
03274         (wsamsg)->Control.len = (msg)->msg_controllen; \
03275         (wsamsg)->dwFlags = (msg)->msg_flags; \
03276     } while (0)
03277 
03278 /* License: Ruby's */
03279 int
03280 recvmsg(int fd, struct msghdr *msg, int flags)
03281 {
03282     typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
03283     static WSARecvMsg_t pWSARecvMsg = NULL;
03284     WSAMSG wsamsg;
03285     SOCKET s;
03286     int mode = 0;
03287     DWORD len;
03288     int ret;
03289 
03290     if (!NtSocketsInitialized)
03291         StartSockets();
03292 
03293     s = TO_SOCKET(fd);
03294 
03295     if (!pWSARecvMsg) {
03296         static GUID guid = WSAID_WSARECVMSG;
03297         pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid);
03298         if (!pWSARecvMsg)
03299             return -1;
03300     }
03301 
03302     msghdr_to_wsamsg(msg, &wsamsg);
03303     wsamsg.dwFlags |= flags;
03304 
03305     socklist_lookup(s, &mode);
03306     if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
03307         RUBY_CRITICAL({
03308             if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
03309                 errno = map_errno(WSAGetLastError());
03310                 len = -1;
03311             }
03312         });
03313     }
03314     else {
03315         DWORD size;
03316         WSAOVERLAPPED wol;
03317         memset(&wol, 0, sizeof(wol));
03318         RUBY_CRITICAL({
03319             wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03320             ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL);
03321         });
03322 
03323         ret = finish_overlapped_socket(TRUE, s, &wol, ret, &len, size);
03324     }
03325     if (ret == SOCKET_ERROR)
03326         return -1;
03327 
03328     /* WSAMSG to msghdr */
03329     msg->msg_name = wsamsg.name;
03330     msg->msg_namelen = wsamsg.namelen;
03331     msg->msg_flags = wsamsg.dwFlags;
03332 
03333     return len;
03334 }
03335 
03336 /* License: Ruby's */
03337 int
03338 sendmsg(int fd, const struct msghdr *msg, int flags)
03339 {
03340     typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
03341     static WSASendMsg_t pWSASendMsg = NULL;
03342     WSAMSG wsamsg;
03343     SOCKET s;
03344     int mode = 0;
03345     DWORD len;
03346     int ret;
03347 
03348     if (!NtSocketsInitialized)
03349         StartSockets();
03350 
03351     s = TO_SOCKET(fd);
03352 
03353     if (!pWSASendMsg) {
03354         static GUID guid = WSAID_WSASENDMSG;
03355         pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid);
03356         if (!pWSASendMsg)
03357             return -1;
03358     }
03359 
03360     msghdr_to_wsamsg(msg, &wsamsg);
03361 
03362     socklist_lookup(s, &mode);
03363     if (!cancel_io || (GET_FLAGS(mode) & O_NONBLOCK)) {
03364         RUBY_CRITICAL({
03365             if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
03366                 errno = map_errno(WSAGetLastError());
03367                 len = -1;
03368             }
03369         });
03370     }
03371     else {
03372         DWORD size;
03373         WSAOVERLAPPED wol;
03374         memset(&wol, 0, sizeof(wol));
03375         RUBY_CRITICAL({
03376             wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
03377             ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL);
03378         });
03379 
03380         finish_overlapped_socket(FALSE, s, &wol, ret, &len, size);
03381     }
03382 
03383     return len;
03384 }
03385 
03386 #undef setsockopt
03387 
03388 /* License: Artistic or GPL */
03389 int WSAAPI
03390 rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen)
03391 {
03392     int r;
03393     if (!NtSocketsInitialized) {
03394         StartSockets();
03395     }
03396     RUBY_CRITICAL({
03397         r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen);
03398         if (r == SOCKET_ERROR)
03399             errno = map_errno(WSAGetLastError());
03400     });
03401     return r;
03402 }
03403 
03404 #undef shutdown
03405 
03406 /* License: Artistic or GPL */
03407 int WSAAPI
03408 rb_w32_shutdown(int s, int how)
03409 {
03410     int r;
03411     if (!NtSocketsInitialized) {
03412         StartSockets();
03413     }
03414     RUBY_CRITICAL({
03415         r = shutdown(TO_SOCKET(s), how);
03416         if (r == SOCKET_ERROR)
03417             errno = map_errno(WSAGetLastError());
03418     });
03419     return r;
03420 }
03421 
03422 /* License: Ruby's */
03423 static SOCKET
03424 open_ifs_socket(int af, int type, int protocol)
03425 {
03426     unsigned long proto_buffers_len = 0;
03427     int error_code;
03428     SOCKET out = INVALID_SOCKET;
03429 
03430     if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) {
03431         error_code = WSAGetLastError();
03432         if (error_code == WSAENOBUFS) {
03433             WSAPROTOCOL_INFO *proto_buffers;
03434             int protocols_available = 0;
03435 
03436             proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len);
03437             if (!proto_buffers) {
03438                 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
03439                 return INVALID_SOCKET;
03440             }
03441 
03442             protocols_available =
03443                 WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len);
03444             if (protocols_available != SOCKET_ERROR) {
03445                 int i;
03446                 for (i = 0; i < protocols_available; i++) {
03447                     if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) ||
03448                         (type != proto_buffers[i].iSocketType) ||
03449                         (protocol != 0 && protocol != proto_buffers[i].iProtocol))
03450                         continue;
03451 
03452                     if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
03453                         continue;
03454 
03455                     out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
03456                                     WSA_FLAG_OVERLAPPED);
03457                     break;
03458                 }
03459                 if (out == INVALID_SOCKET)
03460                     out = WSASocket(af, type, protocol, NULL, 0, 0);
03461                 if (out != INVALID_SOCKET)
03462                     SetHandleInformation((HANDLE)out, HANDLE_FLAG_INHERIT, 0);
03463             }
03464 
03465             free(proto_buffers);
03466         }
03467     }
03468 
03469     return out;
03470 }
03471 
03472 #undef socket
03473 
03474 /* License: Artistic or GPL */
03475 int WSAAPI
03476 rb_w32_socket(int af, int type, int protocol)
03477 {
03478     SOCKET s;
03479     int fd;
03480 
03481     if (!NtSocketsInitialized) {
03482         StartSockets();
03483     }
03484     RUBY_CRITICAL({
03485         s = open_ifs_socket(af, type, protocol);
03486         if (s == INVALID_SOCKET) {
03487             errno = map_errno(WSAGetLastError());
03488             fd = -1;
03489         }
03490         else {
03491             fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
03492             if (fd != -1)
03493                 socklist_insert(s, MAKE_SOCKDATA(af, 0));
03494             else
03495                 closesocket(s);
03496         }
03497     });
03498     return fd;
03499 }
03500 
03501 #undef gethostbyaddr
03502 
03503 /* License: Artistic or GPL */
03504 struct hostent * WSAAPI
03505 rb_w32_gethostbyaddr(const char *addr, int len, int type)
03506 {
03507     struct hostent *r;
03508     if (!NtSocketsInitialized) {
03509         StartSockets();
03510     }
03511     RUBY_CRITICAL({
03512         r = gethostbyaddr(addr, len, type);
03513         if (r == NULL)
03514             errno = map_errno(WSAGetLastError());
03515     });
03516     return r;
03517 }
03518 
03519 #undef gethostbyname
03520 
03521 /* License: Artistic or GPL */
03522 struct hostent * WSAAPI
03523 rb_w32_gethostbyname(const char *name)
03524 {
03525     struct hostent *r;
03526     if (!NtSocketsInitialized) {
03527         StartSockets();
03528     }
03529     RUBY_CRITICAL({
03530         r = gethostbyname(name);
03531         if (r == NULL)
03532             errno = map_errno(WSAGetLastError());
03533     });
03534     return r;
03535 }
03536 
03537 #undef gethostname
03538 
03539 /* License: Artistic or GPL */
03540 int WSAAPI
03541 rb_w32_gethostname(char *name, int len)
03542 {
03543     int r;
03544     if (!NtSocketsInitialized) {
03545         StartSockets();
03546     }
03547     RUBY_CRITICAL({
03548         r = gethostname(name, len);
03549         if (r == SOCKET_ERROR)
03550             errno = map_errno(WSAGetLastError());
03551     });
03552     return r;
03553 }
03554 
03555 #undef getprotobyname
03556 
03557 /* License: Artistic or GPL */
03558 struct protoent * WSAAPI
03559 rb_w32_getprotobyname(const char *name)
03560 {
03561     struct protoent *r;
03562     if (!NtSocketsInitialized) {
03563         StartSockets();
03564     }
03565     RUBY_CRITICAL({
03566         r = getprotobyname(name);
03567         if (r == NULL)
03568             errno = map_errno(WSAGetLastError());
03569     });
03570     return r;
03571 }
03572 
03573 #undef getprotobynumber
03574 
03575 /* License: Artistic or GPL */
03576 struct protoent * WSAAPI
03577 rb_w32_getprotobynumber(int num)
03578 {
03579     struct protoent *r;
03580     if (!NtSocketsInitialized) {
03581         StartSockets();
03582     }
03583     RUBY_CRITICAL({
03584         r = getprotobynumber(num);
03585         if (r == NULL)
03586             errno = map_errno(WSAGetLastError());
03587     });
03588     return r;
03589 }
03590 
03591 #undef getservbyname
03592 
03593 /* License: Artistic or GPL */
03594 struct servent * WSAAPI
03595 rb_w32_getservbyname(const char *name, const char *proto)
03596 {
03597     struct servent *r;
03598     if (!NtSocketsInitialized) {
03599         StartSockets();
03600     }
03601     RUBY_CRITICAL({
03602         r = getservbyname(name, proto);
03603         if (r == NULL)
03604             errno = map_errno(WSAGetLastError());
03605     });
03606     return r;
03607 }
03608 
03609 #undef getservbyport
03610 
03611 /* License: Artistic or GPL */
03612 struct servent * WSAAPI
03613 rb_w32_getservbyport(int port, const char *proto)
03614 {
03615     struct servent *r;
03616     if (!NtSocketsInitialized) {
03617         StartSockets();
03618     }
03619     RUBY_CRITICAL({
03620         r = getservbyport(port, proto);
03621         if (r == NULL)
03622             errno = map_errno(WSAGetLastError());
03623     });
03624     return r;
03625 }
03626 
03627 /* License: Ruby's */
03628 static int
03629 socketpair_internal(int af, int type, int protocol, SOCKET *sv)
03630 {
03631     SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET;
03632     struct sockaddr_in sock_in4;
03633 #ifdef INET6
03634     struct sockaddr_in6 sock_in6;
03635 #endif
03636     struct sockaddr *addr;
03637     int ret = -1;
03638     int len;
03639 
03640     if (!NtSocketsInitialized) {
03641         StartSockets();
03642     }
03643 
03644     switch (af) {
03645       case AF_INET:
03646 #if defined PF_INET && PF_INET != AF_INET
03647       case PF_INET:
03648 #endif
03649         sock_in4.sin_family = AF_INET;
03650         sock_in4.sin_port = 0;
03651         sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
03652         addr = (struct sockaddr *)&sock_in4;
03653         len = sizeof(sock_in4);
03654         break;
03655 #ifdef INET6
03656       case AF_INET6:
03657         memset(&sock_in6, 0, sizeof(sock_in6));
03658         sock_in6.sin6_family = AF_INET6;
03659         sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT;
03660         addr = (struct sockaddr *)&sock_in6;
03661         len = sizeof(sock_in6);
03662         break;
03663 #endif
03664       default:
03665         errno = EAFNOSUPPORT;
03666         return -1;
03667     }
03668     if (type != SOCK_STREAM) {
03669         errno = EPROTOTYPE;
03670         return -1;
03671     }
03672 
03673     sv[0] = (SOCKET)INVALID_HANDLE_VALUE;
03674     sv[1] = (SOCKET)INVALID_HANDLE_VALUE;
03675     RUBY_CRITICAL({
03676         do {
03677             svr = open_ifs_socket(af, type, protocol);
03678             if (svr == INVALID_SOCKET)
03679                 break;
03680             if (bind(svr, addr, len) < 0)
03681                 break;
03682             if (getsockname(svr, addr, &len) < 0)
03683                 break;
03684             if (type == SOCK_STREAM)
03685                 listen(svr, 5);
03686 
03687             w = open_ifs_socket(af, type, protocol);
03688             if (w == INVALID_SOCKET)
03689                 break;
03690             if (connect(w, addr, len) < 0)
03691                 break;
03692 
03693             r = accept(svr, addr, &len);
03694             if (r == INVALID_SOCKET)
03695                 break;
03696             SetHandleInformation((HANDLE)r, HANDLE_FLAG_INHERIT, 0);
03697 
03698             ret = 0;
03699         } while (0);
03700 
03701         if (ret < 0) {
03702             errno = map_errno(WSAGetLastError());
03703             if (r != INVALID_SOCKET)
03704                 closesocket(r);
03705             if (w != INVALID_SOCKET)
03706                 closesocket(w);
03707         }
03708         else {
03709             sv[0] = r;
03710             sv[1] = w;
03711         }
03712         if (svr != INVALID_SOCKET)
03713             closesocket(svr);
03714     });
03715 
03716     return ret;
03717 }
03718 
03719 /* License: Ruby's */
03720 int
03721 rb_w32_socketpair(int af, int type, int protocol, int *sv)
03722 {
03723     SOCKET pair[2];
03724 
03725     if (socketpair_internal(af, type, protocol, pair) < 0)
03726         return -1;
03727     sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
03728     if (sv[0] == -1) {
03729         closesocket(pair[0]);
03730         closesocket(pair[1]);
03731         return -1;
03732     }
03733     sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
03734     if (sv[1] == -1) {
03735         rb_w32_close(sv[0]);
03736         closesocket(pair[1]);
03737         return -1;
03738     }
03739     socklist_insert(pair[0], MAKE_SOCKDATA(af, 0));
03740     socklist_insert(pair[1], MAKE_SOCKDATA(af, 0));
03741 
03742     return 0;
03743 }
03744 
03745 //
03746 // Networking stubs
03747 //
03748 
03749 void endhostent(void) {}
03750 void endnetent(void) {}
03751 void endprotoent(void) {}
03752 void endservent(void) {}
03753 
03754 struct netent *getnetent (void) {return (struct netent *) NULL;}
03755 
03756 struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;}
03757 
03758 struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;}
03759 
03760 struct protoent *getprotoent (void) {return (struct protoent *) NULL;}
03761 
03762 struct servent *getservent (void) {return (struct servent *) NULL;}
03763 
03764 void sethostent (int stayopen) {}
03765 
03766 void setnetent (int stayopen) {}
03767 
03768 void setprotoent (int stayopen) {}
03769 
03770 void setservent (int stayopen) {}
03771 
03772 /* License: Ruby's */
03773 static int
03774 setfl(SOCKET sock, int arg)
03775 {
03776     int ret;
03777     int af = 0;
03778     int flag = 0;
03779     u_long ioctlArg;
03780 
03781     socklist_lookup(sock, &flag);
03782     af = GET_FAMILY(flag);
03783     flag = GET_FLAGS(flag);
03784     if (arg & O_NONBLOCK) {
03785         flag |= O_NONBLOCK;
03786         ioctlArg = 1;
03787     }
03788     else {
03789         flag &= ~O_NONBLOCK;
03790         ioctlArg = 0;
03791     }
03792     RUBY_CRITICAL({
03793         ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
03794         if (ret == 0)
03795             socklist_insert(sock, MAKE_SOCKDATA(af, flag));
03796         else
03797             errno = map_errno(WSAGetLastError());
03798     });
03799 
03800     return ret;
03801 }
03802 
03803 /* License: Ruby's */
03804 static int
03805 dupfd(HANDLE hDup, char flags, int minfd)
03806 {
03807     int save_errno;
03808     int ret;
03809     int fds[32];
03810     int filled = 0;
03811 
03812     do {
03813         ret = _open_osfhandle((intptr_t)hDup, flags | FOPEN);
03814         if (ret == -1) {
03815             goto close_fds_and_return;
03816         }
03817         if (ret >= minfd) {
03818             goto close_fds_and_return;
03819         }
03820         fds[filled++] = ret;
03821     } while (filled < (int)numberof(fds));
03822 
03823     ret = dupfd(hDup, flags, minfd);
03824 
03825   close_fds_and_return:
03826     save_errno = errno;
03827     while (filled > 0) {
03828         int fd = fds[--filled];
03829         _osfhnd(fd) = (intptr_t)INVALID_HANDLE_VALUE;
03830         close(fd);
03831     }
03832     errno = save_errno;
03833 
03834     return ret;
03835 }
03836 
03837 /* License: Ruby's */
03838 int
03839 fcntl(int fd, int cmd, ...)
03840 {
03841     va_list va;
03842     int arg;
03843 
03844     if (cmd == F_SETFL) {
03845         SOCKET sock = TO_SOCKET(fd);
03846         if (!is_socket(sock)) {
03847             errno = EBADF;
03848             return -1;
03849         }
03850 
03851         va_start(va, cmd);
03852         arg = va_arg(va, int);
03853         va_end(va);
03854         return setfl(sock, arg);
03855     }
03856     else if (cmd == F_DUPFD) {
03857         int ret;
03858         HANDLE hDup;
03859         if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd),
03860                               GetCurrentProcess(), &hDup, 0L,
03861                               !(_osfile(fd) & FNOINHERIT),
03862                               DUPLICATE_SAME_ACCESS))) {
03863             errno = map_errno(GetLastError());
03864             return -1;
03865         }
03866 
03867         va_start(va, cmd);
03868         arg = va_arg(va, int);
03869         va_end(va);
03870 
03871         if ((ret = dupfd(hDup, _osfile(fd), arg)) == -1)
03872             CloseHandle(hDup);
03873         return ret;
03874     }
03875     else {
03876         errno = EINVAL;
03877         return -1;
03878     }
03879 }
03880 
03881 #ifndef WNOHANG
03882 #define WNOHANG -1
03883 #endif
03884 
03885 /* License: Ruby's */
03886 static rb_pid_t
03887 poll_child_status(struct ChildRecord *child, int *stat_loc)
03888 {
03889     DWORD exitcode;
03890     DWORD err;
03891 
03892     if (!GetExitCodeProcess(child->hProcess, &exitcode)) {
03893         /* If an error occured, return immediatly. */
03894     error_exit:
03895         err = GetLastError();
03896         if (err == ERROR_INVALID_PARAMETER)
03897             errno = ECHILD;
03898         else {
03899             if (GetLastError() == ERROR_INVALID_HANDLE)
03900                 errno = EINVAL;
03901             else
03902                 errno = map_errno(GetLastError());
03903         }
03904         CloseChildHandle(child);
03905         return -1;
03906     }
03907     if (exitcode != STILL_ACTIVE) {
03908         rb_pid_t pid;
03909         /* If already died, wait process's real termination. */
03910         if (rb_w32_wait_events_blocking(&child->hProcess, 1, INFINITE) != WAIT_OBJECT_0) {
03911             goto error_exit;
03912         }
03913         pid = child->pid;
03914         CloseChildHandle(child);
03915         if (stat_loc) *stat_loc = exitcode << 8;
03916         return pid;
03917     }
03918     return 0;
03919 }
03920 
03921 /* License: Artistic or GPL */
03922 rb_pid_t
03923 waitpid(rb_pid_t pid, int *stat_loc, int options)
03924 {
03925     DWORD timeout;
03926 
03927     /* Artistic or GPL part start */
03928     if (options == WNOHANG) {
03929         timeout = 0;
03930     }
03931     else {
03932         timeout = INFINITE;
03933     }
03934     /* Artistic or GPL part end */
03935 
03936     if (pid == -1) {
03937         int count = 0;
03938         int ret;
03939         HANDLE events[MAXCHILDNUM];
03940         struct ChildRecord* cause;
03941 
03942         FOREACH_CHILD(child) {
03943             if (!child->pid || child->pid < 0) continue;
03944             if ((pid = poll_child_status(child, stat_loc))) return pid;
03945             events[count++] = child->hProcess;
03946         } END_FOREACH_CHILD;
03947         if (!count) {
03948             errno = ECHILD;
03949             return -1;
03950         }
03951 
03952         ret = rb_w32_wait_events_blocking(events, count, timeout);
03953         if (ret == WAIT_TIMEOUT) return 0;
03954         if ((ret -= WAIT_OBJECT_0) == count) {
03955             return -1;
03956         }
03957         if (ret > count) {
03958             errno = map_errno(GetLastError());
03959             return -1;
03960         }
03961 
03962         cause = FindChildSlotByHandle(events[ret]);
03963         if (!cause) {
03964             errno = ECHILD;
03965             return -1;
03966         }
03967         return poll_child_status(cause, stat_loc);
03968     }
03969     else {
03970         struct ChildRecord* child = FindChildSlot(pid);
03971         if (!child) {
03972             errno = ECHILD;
03973             return -1;
03974         }
03975 
03976         while (!(pid = poll_child_status(child, stat_loc))) {
03977             /* wait... */
03978             if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) {
03979                 /* still active */
03980                 pid = 0;
03981                 break;
03982             }
03983         }
03984     }
03985 
03986     return pid;
03987 }
03988 
03989 #include <sys/timeb.h>
03990 
03991 /* License: Ruby's */
03992 static int
03993 filetime_to_timeval(const FILETIME* ft, struct timeval *tv)
03994 {
03995     ULARGE_INTEGER tmp;
03996     unsigned LONG_LONG lt;
03997 
03998     tmp.LowPart = ft->dwLowDateTime;
03999     tmp.HighPart = ft->dwHighDateTime;
04000     lt = tmp.QuadPart;
04001 
04002     /* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC,
04003        convert it into UNIX time (since 1970/01/01 00:00:00 UTC).
04004        the first leap second is at 1972/06/30, so we doesn't need to think
04005        about it. */
04006     lt /= 10;   /* to usec */
04007     lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000;
04008 
04009     tv->tv_sec = (long)(lt / (1000 * 1000));
04010     tv->tv_usec = (long)(lt % (1000 * 1000));
04011 
04012     return tv->tv_sec > 0 ? 0 : -1;
04013 }
04014 
04015 /* License: Ruby's */
04016 int _cdecl
04017 gettimeofday(struct timeval *tv, struct timezone *tz)
04018 {
04019     FILETIME ft;
04020 
04021     GetSystemTimeAsFileTime(&ft);
04022     filetime_to_timeval(&ft, tv);
04023 
04024     return 0;
04025 }
04026 
04027 /* License: Ruby's */
04028 char *
04029 rb_w32_getcwd(char *buffer, int size)
04030 {
04031     char *p = buffer;
04032     int len;
04033 
04034     len = GetCurrentDirectory(0, NULL);
04035     if (!len) {
04036         errno = map_errno(GetLastError());
04037         return NULL;
04038     }
04039 
04040     if (p) {
04041         if (size < len) {
04042             errno = ERANGE;
04043             return NULL;
04044         }
04045     }
04046     else {
04047         p = malloc(len);
04048         size = len;
04049         if (!p) {
04050             errno = ENOMEM;
04051             return NULL;
04052         }
04053     }
04054 
04055     if (!GetCurrentDirectory(size, p)) {
04056         errno = map_errno(GetLastError());
04057         if (!buffer)
04058             free(p);
04059         return NULL;
04060     }
04061 
04062     translate_char(p, '\\', '/');
04063 
04064     return p;
04065 }
04066 
04067 /* License: Artistic or GPL */
04068 int
04069 chown(const char *path, int owner, int group)
04070 {
04071     return 0;
04072 }
04073 
04074 /* License: Artistic or GPL */
04075 int
04076 rb_w32_uchown(const char *path, int owner, int group)
04077 {
04078     return 0;
04079 }
04080 
04081 /* License: Ruby's */
04082 int
04083 kill(int pid, int sig)
04084 {
04085     int ret = 0;
04086     DWORD err;
04087 
04088     if (pid < 0 || pid == 0 && sig != SIGINT) {
04089         errno = EINVAL;
04090         return -1;
04091     }
04092 
04093     if ((unsigned int)pid == GetCurrentProcessId() &&
04094         (sig != 0 && sig != SIGKILL)) {
04095         if ((ret = raise(sig)) != 0) {
04096             /* MSVCRT doesn't set errno... */
04097             errno = EINVAL;
04098         }
04099         return ret;
04100     }
04101 
04102     switch (sig) {
04103       case 0:
04104         RUBY_CRITICAL({
04105             HANDLE hProc =
04106                 OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
04107             if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
04108                 if (GetLastError() == ERROR_INVALID_PARAMETER) {
04109                     errno = ESRCH;
04110                 }
04111                 else {
04112                     errno = EPERM;
04113                 }
04114                 ret = -1;
04115             }
04116             else {
04117                 CloseHandle(hProc);
04118             }
04119         });
04120         break;
04121 
04122       case SIGINT:
04123         RUBY_CRITICAL({
04124             DWORD ctrlEvent = CTRL_C_EVENT;
04125             if (pid != 0) {
04126                 /* CTRL+C signal cannot be generated for process groups.
04127                  * Instead, we use CTRL+BREAK signal. */
04128                 ctrlEvent = CTRL_BREAK_EVENT;
04129             }
04130             if (!GenerateConsoleCtrlEvent(ctrlEvent, (DWORD)pid)) {
04131                 if ((err = GetLastError()) == 0)
04132                     errno = EPERM;
04133                 else
04134                     errno = map_errno(GetLastError());
04135                 ret = -1;
04136             }
04137         });
04138         break;
04139 
04140       case SIGKILL:
04141         RUBY_CRITICAL({
04142             HANDLE hProc;
04143             struct ChildRecord* child = FindChildSlot(pid);
04144             if (child) {
04145                 hProc = child->hProcess;
04146             }
04147             else {
04148                 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
04149             }
04150             if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
04151                 if (GetLastError() == ERROR_INVALID_PARAMETER) {
04152                     errno = ESRCH;
04153                 }
04154                 else {
04155                     errno = EPERM;
04156                 }
04157                 ret = -1;
04158             }
04159             else {
04160                 DWORD status;
04161                 if (!GetExitCodeProcess(hProc, &status)) {
04162                     errno = map_errno(GetLastError());
04163                     ret = -1;
04164                 }
04165                 else if (status == STILL_ACTIVE) {
04166                     if (!TerminateProcess(hProc, 0)) {
04167                         errno = EPERM;
04168                         ret = -1;
04169                     }
04170                 }
04171                 else {
04172                     errno = ESRCH;
04173                     ret = -1;
04174                 }
04175                 if (!child) {
04176                     CloseHandle(hProc);
04177                 }
04178             }
04179         });
04180         break;
04181 
04182       default:
04183         errno = EINVAL;
04184         ret = -1;
04185         break;
04186     }
04187 
04188     return ret;
04189 }
04190 
04191 /* License: Ruby's */
04192 static int
04193 wlink(const WCHAR *from, const WCHAR *to)
04194 {
04195     typedef BOOL (WINAPI link_func)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
04196     static link_func *pCreateHardLinkW = NULL;
04197     static int myerrno = 0;
04198 
04199     if (!pCreateHardLinkW && !myerrno) {
04200         pCreateHardLinkW = (link_func *)get_proc_address("kernel32", "CreateHardLinkW", NULL);
04201         if (!pCreateHardLinkW)
04202             myerrno = ENOSYS;
04203     }
04204     if (!pCreateHardLinkW) {
04205         errno = myerrno;
04206         return -1;
04207     }
04208 
04209     if (!pCreateHardLinkW(to, from, NULL)) {
04210         errno = map_errno(GetLastError());
04211         return -1;
04212     }
04213 
04214     return 0;
04215 }
04216 
04217 /* License: Ruby's */
04218 int
04219 rb_w32_ulink(const char *from, const char *to)
04220 {
04221     WCHAR *wfrom;
04222     WCHAR *wto;
04223     int ret;
04224 
04225     if (!(wfrom = utf8_to_wstr(from, NULL)))
04226         return -1;
04227     if (!(wto = utf8_to_wstr(to, NULL))) {
04228         free(wfrom);
04229         return -1;
04230     }
04231     ret = wlink(wfrom, wto);
04232     free(wto);
04233     free(wfrom);
04234     return ret;
04235 }
04236 
04237 /* License: Ruby's */
04238 int
04239 link(const char *from, const char *to)
04240 {
04241     WCHAR *wfrom;
04242     WCHAR *wto;
04243     int ret;
04244 
04245     if (!(wfrom = filecp_to_wstr(from, NULL)))
04246         return -1;
04247     if (!(wto = filecp_to_wstr(to, NULL))) {
04248         free(wfrom);
04249         return -1;
04250     }
04251     ret = wlink(wfrom, wto);
04252     free(wto);
04253     free(wfrom);
04254     return ret;
04255 }
04256 
04257 /* License: Ruby's */
04258 int
04259 wait(int *status)
04260 {
04261     return waitpid(-1, status, 0);
04262 }
04263 
04264 /* License: Ruby's */
04265 char *
04266 rb_w32_ugetenv(const char *name)
04267 {
04268     WCHAR *wenvarea, *wenv;
04269     int len = strlen(name);
04270     char *env;
04271     int wlen;
04272 
04273     if (len == 0) return NULL;
04274 
04275     if (uenvarea) {
04276         free(uenvarea);
04277         uenvarea = NULL;
04278     }
04279     if (envarea) {
04280         FreeEnvironmentStrings(envarea);
04281         envarea = NULL;
04282     }
04283     wenvarea = GetEnvironmentStringsW();
04284     if (!wenvarea) {
04285         map_errno(GetLastError());
04286         return NULL;
04287     }
04288     for (wenv = wenvarea, wlen = 1; *wenv; wenv += lstrlenW(wenv) + 1)
04289         wlen += lstrlenW(wenv) + 1;
04290     uenvarea = wstr_to_mbstr(CP_UTF8, wenvarea, wlen, NULL);
04291     FreeEnvironmentStringsW(wenvarea);
04292     if (!uenvarea)
04293         return NULL;
04294 
04295     for (env = uenvarea; *env; env += strlen(env) + 1)
04296         if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
04297             return env + len + 1;
04298 
04299     return NULL;
04300 }
04301 
04302 /* License: Ruby's */
04303 char *
04304 rb_w32_getenv(const char *name)
04305 {
04306     int len = strlen(name);
04307     char *env;
04308 
04309     if (len == 0) return NULL;
04310     if (uenvarea) {
04311         free(uenvarea);
04312         uenvarea = NULL;
04313     }
04314     if (envarea) {
04315         FreeEnvironmentStrings(envarea);
04316         envarea = NULL;
04317     }
04318     envarea = GetEnvironmentStrings();
04319     if (!envarea) {
04320         map_errno(GetLastError());
04321         return NULL;
04322     }
04323 
04324     for (env = envarea; *env; env += strlen(env) + 1)
04325         if (strncasecmp(env, name, len) == 0 && *(env + len) == '=')
04326             return env + len + 1;
04327 
04328     return NULL;
04329 }
04330 
04331 /* License: Artistic or GPL */
04332 static int
04333 wrename(const WCHAR *oldpath, const WCHAR *newpath)
04334 {
04335     int res = 0;
04336     int oldatts;
04337     int newatts;
04338 
04339     oldatts = GetFileAttributesW(oldpath);
04340     newatts = GetFileAttributesW(newpath);
04341 
04342     if (oldatts == -1) {
04343         errno = map_errno(GetLastError());
04344         return -1;
04345     }
04346 
04347     RUBY_CRITICAL({
04348         if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY)
04349             SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY);
04350 
04351         if (!MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
04352             res = -1;
04353 
04354         if (res)
04355             errno = map_errno(GetLastError());
04356         else
04357             SetFileAttributesW(newpath, oldatts);
04358     });
04359 
04360     return res;
04361 }
04362 
04363 /* License: Ruby's */
04364 int rb_w32_urename(const char *from, const char *to)
04365 {
04366     WCHAR *wfrom;
04367     WCHAR *wto;
04368     int ret = -1;
04369 
04370     if (!(wfrom = utf8_to_wstr(from, NULL)))
04371         return -1;
04372     if (!(wto = utf8_to_wstr(to, NULL))) {
04373         free(wfrom);
04374         return -1;
04375     }
04376     ret = wrename(wfrom, wto);
04377     free(wto);
04378     free(wfrom);
04379     return ret;
04380 }
04381 
04382 /* License: Ruby's */
04383 int rb_w32_rename(const char *from, const char *to)
04384 {
04385     WCHAR *wfrom;
04386     WCHAR *wto;
04387     int ret = -1;
04388 
04389     if (!(wfrom = filecp_to_wstr(from, NULL)))
04390         return -1;
04391     if (!(wto = filecp_to_wstr(to, NULL))) {
04392         free(wfrom);
04393         return -1;
04394     }
04395     ret = wrename(wfrom, wto);
04396     free(wto);
04397     free(wfrom);
04398     return ret;
04399 }
04400 
04401 /* License: Ruby's */
04402 static int
04403 isUNCRoot(const WCHAR *path)
04404 {
04405     if (path[0] == L'\\' && path[1] == L'\\') {
04406         const WCHAR *p = path + 2;
04407         if (p[0] == L'?' && p[1] == L'\\') {
04408             p += 2;
04409         }
04410         for (; *p; p++) {
04411             if (*p == L'\\')
04412                 break;
04413         }
04414         if (p[0] && p[1]) {
04415             for (p++; *p; p++) {
04416                 if (*p == L'\\')
04417                     break;
04418             }
04419             if (!p[0] || !p[1] || (p[1] == L'.' && !p[2]))
04420                 return 1;
04421         }
04422     }
04423     return 0;
04424 }
04425 
04426 #define COPY_STAT(src, dest, size_cast) do {    \
04427         (dest).st_dev   = (src).st_dev;         \
04428         (dest).st_ino   = (src).st_ino;         \
04429         (dest).st_mode  = (src).st_mode;        \
04430         (dest).st_nlink = (src).st_nlink;       \
04431         (dest).st_uid   = (src).st_uid;         \
04432         (dest).st_gid   = (src).st_gid;         \
04433         (dest).st_rdev  = (src).st_rdev;        \
04434         (dest).st_size  = size_cast(src).st_size; \
04435         (dest).st_atime = (src).st_atime;       \
04436         (dest).st_mtime = (src).st_mtime;       \
04437         (dest).st_ctime = (src).st_ctime;       \
04438     } while (0)
04439 
04440 static time_t filetime_to_unixtime(const FILETIME *ft);
04441 
04442 #undef fstat
04443 /* License: Ruby's */
04444 int
04445 rb_w32_fstat(int fd, struct stat *st)
04446 {
04447     BY_HANDLE_FILE_INFORMATION info;
04448     int ret = fstat(fd, st);
04449 
04450     if (ret) return ret;
04451 #ifdef __BORLANDC__
04452     st->st_mode &= ~(S_IWGRP | S_IWOTH);
04453 #endif
04454     if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
04455 #ifdef __BORLANDC__
04456         if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04457             st->st_mode |= S_IWUSR;
04458         }
04459 #endif
04460         st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
04461         st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
04462         st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
04463     }
04464     return ret;
04465 }
04466 
04467 /* License: Ruby's */
04468 int
04469 rb_w32_fstati64(int fd, struct stati64 *st)
04470 {
04471     BY_HANDLE_FILE_INFORMATION info;
04472     struct stat tmp;
04473     int ret = fstat(fd, &tmp);
04474 
04475     if (ret) return ret;
04476 #ifdef __BORLANDC__
04477     tmp.st_mode &= ~(S_IWGRP | S_IWOTH);
04478 #endif
04479     COPY_STAT(tmp, *st, +);
04480     if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
04481 #ifdef __BORLANDC__
04482         if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
04483             st->st_mode |= S_IWUSR;
04484         }
04485 #endif
04486         st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow;
04487         st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime);
04488         st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime);
04489         st->st_ctime = filetime_to_unixtime(&info.ftCreationTime);
04490     }
04491     return ret;
04492 }
04493 
04494 /* License: Ruby's */
04495 static time_t
04496 filetime_to_unixtime(const FILETIME *ft)
04497 {
04498     struct timeval tv;
04499 
04500     if (filetime_to_timeval(ft, &tv) == (time_t)-1)
04501         return 0;
04502     else
04503         return tv.tv_sec;
04504 }
04505 
04506 /* License: Ruby's */
04507 static unsigned
04508 fileattr_to_unixmode(DWORD attr, const WCHAR *path)
04509 {
04510     unsigned mode = 0;
04511 
04512     if (attr & FILE_ATTRIBUTE_READONLY) {
04513         mode |= S_IREAD;
04514     }
04515     else {
04516         mode |= S_IREAD | S_IWRITE | S_IWUSR;
04517     }
04518 
04519     if (attr & FILE_ATTRIBUTE_DIRECTORY) {
04520         mode |= S_IFDIR | S_IEXEC;
04521     }
04522     else {
04523         mode |= S_IFREG;
04524     }
04525 
04526     if (path && (mode & S_IFREG)) {
04527         const WCHAR *end = path + lstrlenW(path);
04528         while (path < end) {
04529             end = CharPrevW(path, end);
04530             if (*end == L'.') {
04531                 if ((_wcsicmp(end, L".bat") == 0) ||
04532                     (_wcsicmp(end, L".cmd") == 0) ||
04533                     (_wcsicmp(end, L".com") == 0) ||
04534                     (_wcsicmp(end, L".exe") == 0)) {
04535                     mode |= S_IEXEC;
04536                 }
04537                 break;
04538             }
04539         }
04540     }
04541 
04542     mode |= (mode & 0700) >> 3;
04543     mode |= (mode & 0700) >> 6;
04544 
04545     return mode;
04546 }
04547 
04548 /* License: Ruby's */
04549 static int
04550 check_valid_dir(const WCHAR *path)
04551 {
04552     WIN32_FIND_DATAW fd;
04553     HANDLE fh;
04554     WCHAR full[MAX_PATH];
04555     WCHAR *dmy;
04556     WCHAR *p, *q;
04557 
04558     /* GetFileAttributes() determines "..." as directory. */
04559     /* We recheck it by FindFirstFile(). */
04560     if (!(p = wcsstr(path, L"...")))
04561         return 0;
04562     q = p + wcsspn(p, L".");
04563     if ((p == path || wcschr(L":/\\", *(p - 1))) &&
04564         (!*q || wcschr(L":/\\", *q))) {
04565         errno = ENOENT;
04566         return -1;
04567     }
04568 
04569     /* if the specified path is the root of a drive and the drive is empty, */
04570     /* FindFirstFile() returns INVALID_HANDLE_VALUE. */
04571     if (!GetFullPathNameW(path, sizeof(full) / sizeof(WCHAR), full, &dmy)) {
04572         errno = map_errno(GetLastError());
04573         return -1;
04574     }
04575     if (full[1] == L':' && !full[3] && GetDriveTypeW(full) != DRIVE_NO_ROOT_DIR)
04576         return 0;
04577 
04578     fh = open_dir_handle(path, &fd);
04579     if (fh == INVALID_HANDLE_VALUE)
04580         return -1;
04581     FindClose(fh);
04582     return 0;
04583 }
04584 
04585 /* License: Ruby's */
04586 static int
04587 winnt_stat(const WCHAR *path, struct stati64 *st)
04588 {
04589     HANDLE h;
04590     WIN32_FIND_DATAW wfd;
04591     WIN32_FILE_ATTRIBUTE_DATA wfa;
04592     const WCHAR *p = path;
04593 
04594     memset(st, 0, sizeof(*st));
04595     st->st_nlink = 1;
04596 
04597     if (wcsncmp(p, L"\\\\?\\", 4) == 0) p += 4;
04598     if (wcspbrk(p, L"?*")) {
04599         errno = ENOENT;
04600         return -1;
04601     }
04602     if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) {
04603         if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
04604             if (check_valid_dir(path)) return -1;
04605             st->st_size = 0;
04606         }
04607         else {
04608             st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow;
04609         }
04610         st->st_mode  = fileattr_to_unixmode(wfa.dwFileAttributes, path);
04611         st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime);
04612         st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime);
04613         st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime);
04614     }
04615     else {
04616         /* GetFileAttributesEx failed; check why. */
04617         int e = GetLastError();
04618 
04619         if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME)
04620             || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) {
04621             errno = map_errno(e);
04622             return -1;
04623         }
04624 
04625         /* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */
04626         h = FindFirstFileW(path, &wfd);
04627         if (h != INVALID_HANDLE_VALUE) {
04628             FindClose(h);
04629             st->st_mode  = fileattr_to_unixmode(wfd.dwFileAttributes, path);
04630             st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime);
04631             st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime);
04632             st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime);
04633             st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow;
04634         }
04635         else {
04636             errno = map_errno(GetLastError());
04637             return -1;
04638         }
04639     }
04640 
04641     st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ?
04642         towupper(path[0]) - L'A' : _getdrive() - 1;
04643 
04644     return 0;
04645 }
04646 
04647 /* License: Ruby's */
04648 int
04649 rb_w32_stat(const char *path, struct stat *st)
04650 {
04651     struct stati64 tmp;
04652 
04653     if (rb_w32_stati64(path, &tmp)) return -1;
04654     COPY_STAT(tmp, *st, (_off_t));
04655     return 0;
04656 }
04657 
04658 /* License: Ruby's */
04659 static int
04660 wstati64(const WCHAR *path, struct stati64 *st)
04661 {
04662     const WCHAR *p;
04663     WCHAR *buf1, *s, *end;
04664     int len, size;
04665     int ret;
04666     VALUE v;
04667 
04668     if (!path || !st) {
04669         errno = EFAULT;
04670         return -1;
04671     }
04672     size = lstrlenW(path) + 2;
04673     buf1 = ALLOCV_N(WCHAR, v, size);
04674     for (p = path, s = buf1; *p; p++, s++) {
04675         if (*p == L'/')
04676             *s = L'\\';
04677         else
04678             *s = *p;
04679     }
04680     *s = '\0';
04681     len = s - buf1;
04682     if (!len || L'\"' == *(--s)) {
04683         errno = ENOENT;
04684         return -1;
04685     }
04686     end = buf1 + len - 1;
04687 
04688     if (isUNCRoot(buf1)) {
04689         if (*end == L'.')
04690             *end = L'\0';
04691         else if (*end != L'\\')
04692             lstrcatW(buf1, L"\\");
04693     }
04694     else if (*end == L'\\' || (buf1 + 1 == end && *end == L':'))
04695         lstrcatW(buf1, L".");
04696 
04697     ret = winnt_stat(buf1, st);
04698     if (ret == 0) {
04699         st->st_mode &= ~(S_IWGRP | S_IWOTH);
04700     }
04701     if (v)
04702         ALLOCV_END(v);
04703 
04704     return ret;
04705 }
04706 
04707 /* License: Ruby's */
04708 int
04709 rb_w32_ustati64(const char *path, struct stati64 *st)
04710 {
04711     WCHAR *wpath;
04712     int ret;
04713 
04714     if (!(wpath = utf8_to_wstr(path, NULL)))
04715         return -1;
04716     ret = wstati64(wpath, st);
04717     free(wpath);
04718     return ret;
04719 }
04720 
04721 /* License: Ruby's */
04722 int
04723 rb_w32_stati64(const char *path, struct stati64 *st)
04724 {
04725     WCHAR *wpath;
04726     int ret;
04727 
04728     if (!(wpath = filecp_to_wstr(path, NULL)))
04729         return -1;
04730     ret = wstati64(wpath, st);
04731     free(wpath);
04732     return ret;
04733 }
04734 
04735 /* License: Ruby's */
04736 int
04737 rb_w32_access(const char *path, int mode)
04738 {
04739     struct stati64 stat;
04740     if (rb_w32_stati64(path, &stat) != 0)
04741         return -1;
04742     mode <<= 6;
04743     if ((stat.st_mode & mode) != mode) {
04744         errno = EACCES;
04745         return -1;
04746     }
04747     return 0;
04748 }
04749 
04750 /* License: Ruby's */
04751 int
04752 rb_w32_uaccess(const char *path, int mode)
04753 {
04754     struct stati64 stat;
04755     if (rb_w32_ustati64(path, &stat) != 0)
04756         return -1;
04757     mode <<= 6;
04758     if ((stat.st_mode & mode) != mode) {
04759         errno = EACCES;
04760         return -1;
04761     }
04762     return 0;
04763 }
04764 
04765 /* License: Ruby's */
04766 static int
04767 rb_chsize(HANDLE h, off_t size)
04768 {
04769     long upos, lpos, usize, lsize;
04770     int ret = -1;
04771     DWORD e;
04772 
04773     if ((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L &&
04774         (e = GetLastError())) {
04775         errno = map_errno(e);
04776         return -1;
04777     }
04778     usize = (long)(size >> 32);
04779     lsize = (long)size;
04780     if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L &&
04781         (e = GetLastError())) {
04782         errno = map_errno(e);
04783     }
04784     else if (!SetEndOfFile(h)) {
04785         errno = map_errno(GetLastError());
04786     }
04787     else {
04788         ret = 0;
04789     }
04790     SetFilePointer(h, lpos, &upos, SEEK_SET);
04791     return ret;
04792 }
04793 
04794 /* License: Ruby's */
04795 int
04796 rb_w32_truncate(const char *path, off_t length)
04797 {
04798     HANDLE h;
04799     int ret;
04800     h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
04801     if (h == INVALID_HANDLE_VALUE) {
04802         errno = map_errno(GetLastError());
04803         return -1;
04804     }
04805     ret = rb_chsize(h, length);
04806     CloseHandle(h);
04807     return ret;
04808 }
04809 
04810 /* License: Ruby's */
04811 int
04812 rb_w32_ftruncate(int fd, off_t length)
04813 {
04814     HANDLE h;
04815 
04816     h = (HANDLE)_get_osfhandle(fd);
04817     if (h == (HANDLE)-1) return -1;
04818     return rb_chsize(h, length);
04819 }
04820 
04821 #ifdef __BORLANDC__
04822 /* License: Ruby's */
04823 off_t
04824 _filelengthi64(int fd)
04825 {
04826     DWORD u, l;
04827     int e;
04828 
04829     l = GetFileSize((HANDLE)_get_osfhandle(fd), &u);
04830     if (l == (DWORD)-1L && (e = GetLastError())) {
04831         errno = map_errno(e);
04832         return (off_t)-1;
04833     }
04834     return ((off_t)u << 32) | l;
04835 }
04836 
04837 /* License: Ruby's */
04838 off_t
04839 _lseeki64(int fd, off_t offset, int whence)
04840 {
04841     long u, l;
04842     int e;
04843     HANDLE h = (HANDLE)_get_osfhandle(fd);
04844 
04845     if (!h) {
04846         errno = EBADF;
04847         return -1;
04848     }
04849     u = (long)(offset >> 32);
04850     if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L &&
04851         (e = GetLastError())) {
04852         errno = map_errno(e);
04853         return -1;
04854     }
04855     return ((off_t)u << 32) | l;
04856 }
04857 #endif
04858 
04859 /* License: Ruby's */
04860 int
04861 fseeko(FILE *stream, off_t offset, int whence)
04862 {
04863     off_t pos;
04864     switch (whence) {
04865       case SEEK_CUR:
04866         if (fgetpos(stream, (fpos_t *)&pos))
04867             return -1;
04868         pos += offset;
04869         break;
04870       case SEEK_END:
04871         if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1)
04872             return -1;
04873         pos += offset;
04874         break;
04875       default:
04876         pos = offset;
04877         break;
04878     }
04879     return fsetpos(stream, (fpos_t *)&pos);
04880 }
04881 
04882 /* License: Ruby's */
04883 off_t
04884 rb_w32_ftello(FILE *stream)
04885 {
04886     off_t pos;
04887     if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1;
04888     return pos;
04889 }
04890 
04891 /* License: Ruby's */
04892 static long
04893 filetime_to_clock(FILETIME *ft)
04894 {
04895     __int64 qw = ft->dwHighDateTime;
04896     qw <<= 32;
04897     qw |= ft->dwLowDateTime;
04898     qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
04899     return (long) qw;
04900 }
04901 
04902 /* License: Ruby's */
04903 int
04904 rb_w32_times(struct tms *tmbuf)
04905 {
04906     FILETIME create, exit, kernel, user;
04907 
04908     if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) {
04909         tmbuf->tms_utime = filetime_to_clock(&user);
04910         tmbuf->tms_stime = filetime_to_clock(&kernel);
04911         tmbuf->tms_cutime = 0;
04912         tmbuf->tms_cstime = 0;
04913     }
04914     else {
04915         tmbuf->tms_utime = clock();
04916         tmbuf->tms_stime = 0;
04917         tmbuf->tms_cutime = 0;
04918         tmbuf->tms_cstime = 0;
04919     }
04920     return 0;
04921 }
04922 
04923 #define yield_once() Sleep(0)
04924 #define yield_until(condition) do yield_once(); while (!(condition))
04925 
04926 /* License: Ruby's */
04927 static void
04928 catch_interrupt(void)
04929 {
04930     yield_once();
04931     RUBY_CRITICAL(rb_w32_wait_events(NULL, 0, 0));
04932 }
04933 
04934 #if defined __BORLANDC__
04935 #undef read
04936 /* License: Ruby's */
04937 int
04938 read(int fd, void *buf, size_t size)
04939 {
04940     int ret = _read(fd, buf, size);
04941     if ((ret < 0) && (errno == EPIPE)) {
04942         errno = 0;
04943         ret = 0;
04944     }
04945     catch_interrupt();
04946     return ret;
04947 }
04948 #endif
04949 
04950 
04951 #define FILE_COUNT _cnt
04952 #define FILE_READPTR _ptr
04953 
04954 #undef fgetc
04955 /* License: Ruby's */
04956 int
04957 rb_w32_getc(FILE* stream)
04958 {
04959     int c;
04960     if (enough_to_get(stream->FILE_COUNT)) {
04961         c = (unsigned char)*stream->FILE_READPTR++;
04962     }
04963     else {
04964         c = _filbuf(stream);
04965 #if defined __BORLANDC__
04966         if ((c == EOF) && (errno == EPIPE)) {
04967             clearerr(stream);
04968         }
04969 #endif
04970         catch_interrupt();
04971     }
04972     return c;
04973 }
04974 
04975 #undef fputc
04976 /* License: Ruby's */
04977 int
04978 rb_w32_putc(int c, FILE* stream)
04979 {
04980     if (enough_to_put(stream->FILE_COUNT)) {
04981         c = (unsigned char)(*stream->FILE_READPTR++ = (char)c);
04982     }
04983     else {
04984         c = _flsbuf(c, stream);
04985         catch_interrupt();
04986     }
04987     return c;
04988 }
04989 
04990 /* License: Ruby's */
04991 struct asynchronous_arg_t {
04992     /* output field */
04993     void* stackaddr;
04994     int errnum;
04995 
04996     /* input field */
04997     uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv);
04998     uintptr_t self;
04999     int argc;
05000     uintptr_t* argv;
05001 };
05002 
05003 /* License: Ruby's */
05004 static DWORD WINAPI
05005 call_asynchronous(PVOID argp)
05006 {
05007     DWORD ret;
05008     struct asynchronous_arg_t *arg = argp;
05009     arg->stackaddr = &argp;
05010     ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv);
05011     arg->errnum = errno;
05012     return ret;
05013 }
05014 
05015 /* License: Ruby's */
05016 uintptr_t
05017 rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self,
05018                     int argc, uintptr_t* argv, uintptr_t intrval)
05019 {
05020     DWORD val;
05021     BOOL interrupted = FALSE;
05022     HANDLE thr;
05023 
05024     RUBY_CRITICAL({
05025         struct asynchronous_arg_t arg;
05026 
05027         arg.stackaddr = NULL;
05028         arg.errnum = 0;
05029         arg.func = func;
05030         arg.self = self;
05031         arg.argc = argc;
05032         arg.argv = argv;
05033 
05034         thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val);
05035 
05036         if (thr) {
05037             yield_until(arg.stackaddr);
05038 
05039             if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) {
05040                 interrupted = TRUE;
05041 
05042                 if (TerminateThread(thr, intrval)) {
05043                     yield_once();
05044                 }
05045             }
05046 
05047             GetExitCodeThread(thr, &val);
05048             CloseHandle(thr);
05049 
05050             if (interrupted) {
05051                 /* must release stack of killed thread, why doesn't Windows? */
05052                 MEMORY_BASIC_INFORMATION m;
05053 
05054                 memset(&m, 0, sizeof(m));
05055                 if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) {
05056                     Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n",
05057                                   arg.stackaddr, GetLastError()));
05058                 }
05059                 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) {
05060                     Debug(fprintf(stderr, "couldn't release stack:%p:%d\n",
05061                                   m.AllocationBase, GetLastError()));
05062                 }
05063                 errno = EINTR;
05064             }
05065             else {
05066                 errno = arg.errnum;
05067             }
05068         }
05069     });
05070 
05071     if (!thr) {
05072         rb_fatal("failed to launch waiter thread:%ld", GetLastError());
05073     }
05074 
05075     return val;
05076 }
05077 
05078 /* License: Ruby's */
05079 char **
05080 rb_w32_get_environ(void)
05081 {
05082     WCHAR *envtop, *env;
05083     char **myenvtop, **myenv;
05084     int num;
05085 
05086     /*
05087      * We avoid values started with `='. If you want to deal those values,
05088      * change this function, and some functions in hash.c which recognize
05089      * `=' as delimiter or rb_w32_getenv() and ruby_setenv().
05090      * CygWin deals these values by changing first `=' to '!'. But we don't
05091      * use such trick and follow cmd.exe's way that just doesn't show these
05092      * values.
05093      *
05094      * This function returns UTF-8 strings.
05095      */
05096     envtop = GetEnvironmentStringsW();
05097     for (env = envtop, num = 0; *env; env += lstrlenW(env) + 1)
05098         if (*env != '=') num++;
05099 
05100     myenvtop = (char **)malloc(sizeof(char *) * (num + 1));
05101     for (env = envtop, myenv = myenvtop; *env; env += lstrlenW(env) + 1) {
05102         if (*env != '=') {
05103             if (!(*myenv = wstr_to_utf8(env, NULL))) {
05104                 break;
05105             }
05106             myenv++;
05107         }
05108     }
05109     *myenv = NULL;
05110     FreeEnvironmentStringsW(envtop);
05111 
05112     return myenvtop;
05113 }
05114 
05115 /* License: Ruby's */
05116 void
05117 rb_w32_free_environ(char **env)
05118 {
05119     char **t = env;
05120 
05121     while (*t) free(*t++);
05122     free(env);
05123 }
05124 
05125 /* License: Ruby's */
05126 rb_pid_t
05127 rb_w32_getpid(void)
05128 {
05129     return GetCurrentProcessId();
05130 }
05131 
05132 
05133 /* License: Ruby's */
05134 rb_pid_t
05135 rb_w32_getppid(void)
05136 {
05137     typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *);
05138     static query_func *pNtQueryInformationProcess = NULL;
05139     rb_pid_t ppid = 0;
05140 
05141     if (rb_w32_osver() >= 5) {
05142         if (!pNtQueryInformationProcess)
05143             pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL);
05144         if (pNtQueryInformationProcess) {
05145             struct {
05146                 long ExitStatus;
05147                 void* PebBaseAddress;
05148                 uintptr_t AffinityMask;
05149                 uintptr_t BasePriority;
05150                 uintptr_t UniqueProcessId;
05151                 uintptr_t ParentProcessId;
05152             } pbi;
05153             ULONG len;
05154             long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len);
05155             if (!ret) {
05156                 ppid = pbi.ParentProcessId;
05157             }
05158         }
05159     }
05160 
05161     return ppid;
05162 }
05163 
05164 /* License: Ruby's */
05165 int
05166 rb_w32_uopen(const char *file, int oflag, ...)
05167 {
05168     WCHAR *wfile;
05169     int ret;
05170     int pmode;
05171 
05172     va_list arg;
05173     va_start(arg, oflag);
05174     pmode = va_arg(arg, int);
05175     va_end(arg);
05176 
05177     if (!(wfile = utf8_to_wstr(file, NULL)))
05178         return -1;
05179     ret = rb_w32_wopen(wfile, oflag, pmode);
05180     free(wfile);
05181     return ret;
05182 }
05183 
05184 /* License: Ruby's */
05185 static int
05186 check_if_wdir(const WCHAR *wfile)
05187 {
05188     DWORD attr = GetFileAttributesW(wfile);
05189     if (attr == (DWORD)-1L ||
05190         !(attr & FILE_ATTRIBUTE_DIRECTORY) ||
05191         check_valid_dir(wfile)) {
05192         return FALSE;
05193     }
05194     errno = EISDIR;
05195     return TRUE;
05196 }
05197 
05198 /* License: Ruby's */
05199 static int
05200 check_if_dir(const char *file)
05201 {
05202     WCHAR *wfile;
05203     int ret;
05204 
05205     if (!(wfile = filecp_to_wstr(file, NULL)))
05206         return FALSE;
05207     ret = check_if_wdir(wfile);
05208     free(wfile);
05209     return ret;
05210 }
05211 
05212 /* License: Ruby's */
05213 int
05214 rb_w32_open(const char *file, int oflag, ...)
05215 {
05216     WCHAR *wfile;
05217     int ret;
05218     int pmode;
05219 
05220     va_list arg;
05221     va_start(arg, oflag);
05222     pmode = va_arg(arg, int);
05223     va_end(arg);
05224 
05225     if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
05226         ret = _open(file, oflag, pmode);
05227         if (ret == -1 && errno == EACCES) check_if_dir(file);
05228         return ret;
05229     }
05230 
05231     if (!(wfile = filecp_to_wstr(file, NULL)))
05232         return -1;
05233     ret = rb_w32_wopen(wfile, oflag, pmode);
05234     free(wfile);
05235     return ret;
05236 }
05237 
05238 int
05239 rb_w32_wopen(const WCHAR *file, int oflag, ...)
05240 {
05241     char flags = 0;
05242     int fd;
05243     DWORD access;
05244     DWORD create;
05245     DWORD attr = FILE_ATTRIBUTE_NORMAL;
05246     SECURITY_ATTRIBUTES sec;
05247     HANDLE h;
05248 
05249     if ((oflag & O_TEXT) || !(oflag & O_BINARY)) {
05250         va_list arg;
05251         int pmode;
05252         va_start(arg, oflag);
05253         pmode = va_arg(arg, int);
05254         va_end(arg);
05255         fd = _wopen(file, oflag, pmode);
05256         if (fd == -1 && errno == EACCES) check_if_wdir(file);
05257         return fd;
05258     }
05259 
05260     sec.nLength = sizeof(sec);
05261     sec.lpSecurityDescriptor = NULL;
05262     if (oflag & O_NOINHERIT) {
05263         sec.bInheritHandle = FALSE;
05264         flags |= FNOINHERIT;
05265     }
05266     else {
05267         sec.bInheritHandle = TRUE;
05268     }
05269     oflag &= ~O_NOINHERIT;
05270 
05271     /* always open with binary mode */
05272     oflag &= ~(O_BINARY | O_TEXT);
05273 
05274     switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) {
05275       case O_RDWR:
05276         access = GENERIC_READ | GENERIC_WRITE;
05277         break;
05278       case O_RDONLY:
05279         access = GENERIC_READ;
05280         break;
05281       case O_WRONLY:
05282         access = GENERIC_WRITE;
05283         break;
05284       default:
05285         errno = EINVAL;
05286         return -1;
05287     }
05288     oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY);
05289 
05290     switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) {
05291       case O_CREAT:
05292         create = OPEN_ALWAYS;
05293         break;
05294       case 0:
05295       case O_EXCL:
05296         create = OPEN_EXISTING;
05297         break;
05298       case O_CREAT | O_EXCL:
05299       case O_CREAT | O_EXCL | O_TRUNC:
05300         create = CREATE_NEW;
05301         break;
05302       case O_TRUNC:
05303       case O_TRUNC | O_EXCL:
05304         create = TRUNCATE_EXISTING;
05305         break;
05306       case O_CREAT | O_TRUNC:
05307         create = CREATE_ALWAYS;
05308         break;
05309       default:
05310         errno = EINVAL;
05311         return -1;
05312     }
05313     if (oflag & O_CREAT) {
05314         va_list arg;
05315         int pmode;
05316         va_start(arg, oflag);
05317         pmode = va_arg(arg, int);
05318         va_end(arg);
05319         /* TODO: we need to check umask here, but it's not exported... */
05320         if (!(pmode & S_IWRITE))
05321             attr = FILE_ATTRIBUTE_READONLY;
05322     }
05323     oflag &= ~(O_CREAT | O_EXCL | O_TRUNC);
05324 
05325     if (oflag & O_TEMPORARY) {
05326         attr |= FILE_FLAG_DELETE_ON_CLOSE;
05327         access |= DELETE;
05328     }
05329     oflag &= ~O_TEMPORARY;
05330 
05331     if (oflag & _O_SHORT_LIVED)
05332         attr |= FILE_ATTRIBUTE_TEMPORARY;
05333     oflag &= ~_O_SHORT_LIVED;
05334 
05335     switch (oflag & (O_SEQUENTIAL | O_RANDOM)) {
05336       case 0:
05337         break;
05338       case O_SEQUENTIAL:
05339         attr |= FILE_FLAG_SEQUENTIAL_SCAN;
05340         break;
05341       case O_RANDOM:
05342         attr |= FILE_FLAG_RANDOM_ACCESS;
05343         break;
05344       default:
05345         errno = EINVAL;
05346         return -1;
05347     }
05348     oflag &= ~(O_SEQUENTIAL | O_RANDOM);
05349 
05350     if (oflag & ~O_APPEND) {
05351         errno = EINVAL;
05352         return -1;
05353     }
05354 
05355     /* allocate a C Runtime file handle */
05356     RUBY_CRITICAL({
05357         h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05358         fd = _open_osfhandle((intptr_t)h, 0);
05359         CloseHandle(h);
05360     });
05361     if (fd == -1) {
05362         errno = EMFILE;
05363         return -1;
05364     }
05365     RUBY_CRITICAL({
05366         MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05367         _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE);
05368         _set_osflags(fd, 0);
05369 
05370         h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec,
05371                         create, attr, NULL);
05372         if (h == INVALID_HANDLE_VALUE) {
05373             DWORD e = GetLastError();
05374             if (e != ERROR_ACCESS_DENIED || !check_if_wdir(file))
05375                 errno = map_errno(e);
05376             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05377             fd = -1;
05378             goto quit;
05379         }
05380 
05381         switch (GetFileType(h)) {
05382           case FILE_TYPE_CHAR:
05383             flags |= FDEV;
05384             break;
05385           case FILE_TYPE_PIPE:
05386             flags |= FPIPE;
05387             break;
05388           case FILE_TYPE_UNKNOWN:
05389             errno = map_errno(GetLastError());
05390             CloseHandle(h);
05391             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05392             fd = -1;
05393             goto quit;
05394         }
05395         if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND))
05396             flags |= FAPPEND;
05397 
05398         _set_osfhnd(fd, (intptr_t)h);
05399         _osfile(fd) = flags | FOPEN;
05400 
05401         MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05402       quit:
05403         ;
05404     });
05405 
05406     return fd;
05407 }
05408 
05409 /* License: Ruby's */
05410 int
05411 rb_w32_fclose(FILE *fp)
05412 {
05413     int fd = fileno(fp);
05414     SOCKET sock = TO_SOCKET(fd);
05415     int save_errno = errno;
05416 
05417     if (fflush(fp)) return -1;
05418     if (!is_socket(sock)) {
05419         UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
05420         return fclose(fp);
05421     }
05422     _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
05423     fclose(fp);
05424     errno = save_errno;
05425     if (closesocket(sock) == SOCKET_ERROR) {
05426         errno = map_errno(WSAGetLastError());
05427         return -1;
05428     }
05429     return 0;
05430 }
05431 
05432 /* License: Ruby's */
05433 int
05434 rb_w32_pipe(int fds[2])
05435 {
05436     static DWORD serial = 0;
05437     char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000";
05438     char *p;
05439     SECURITY_ATTRIBUTES sec;
05440     HANDLE hRead, hWrite, h;
05441     int fdRead, fdWrite;
05442     int ret;
05443 
05444     /* if doesn't have CancelIo, use default pipe function */
05445     if (!cancel_io)
05446         return _pipe(fds, 65536L, _O_NOINHERIT);
05447 
05448     p = strchr(name, '0');
05449     snprintf(p, strlen(p) + 1, "%"PRI_PIDT_PREFIX"x-%lx", rb_w32_getpid(), serial++);
05450 
05451     sec.nLength = sizeof(sec);
05452     sec.lpSecurityDescriptor = NULL;
05453     sec.bInheritHandle = FALSE;
05454 
05455     RUBY_CRITICAL({
05456         hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
05457                                 0, 2, 65536, 65536, 0, &sec);
05458     });
05459     if (hRead == INVALID_HANDLE_VALUE) {
05460         DWORD err = GetLastError();
05461         if (err == ERROR_PIPE_BUSY)
05462             errno = EMFILE;
05463         else
05464             errno = map_errno(GetLastError());
05465         return -1;
05466     }
05467 
05468     RUBY_CRITICAL({
05469         hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec,
05470                             OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
05471     });
05472     if (hWrite == INVALID_HANDLE_VALUE) {
05473         errno = map_errno(GetLastError());
05474         CloseHandle(hRead);
05475         return -1;
05476     }
05477 
05478     RUBY_CRITICAL(do {
05479         ret = 0;
05480         h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05481         fdRead = _open_osfhandle((intptr_t)h, 0);
05482         CloseHandle(h);
05483         if (fdRead == -1) {
05484             errno = EMFILE;
05485             CloseHandle(hWrite);
05486             CloseHandle(hRead);
05487             ret = -1;
05488             break;
05489         }
05490 
05491         MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock)));
05492         _set_osfhnd(fdRead, (intptr_t)hRead);
05493         _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT);
05494         MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock)));
05495     } while (0));
05496     if (ret)
05497         return ret;
05498 
05499     RUBY_CRITICAL(do {
05500         h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
05501         fdWrite = _open_osfhandle((intptr_t)h, 0);
05502         CloseHandle(h);
05503         if (fdWrite == -1) {
05504             errno = EMFILE;
05505             CloseHandle(hWrite);
05506             ret = -1;
05507             break;
05508         }
05509         MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock)));
05510         _set_osfhnd(fdWrite, (intptr_t)hWrite);
05511         _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT);
05512         MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock)));
05513     } while (0));
05514     if (ret) {
05515         rb_w32_close(fdRead);
05516         return ret;
05517     }
05518 
05519     fds[0] = fdRead;
05520     fds[1] = fdWrite;
05521 
05522     return 0;
05523 }
05524 
05525 /* License: Ruby's */
05526 static struct constat *
05527 constat_handle(HANDLE h)
05528 {
05529     st_data_t data;
05530     struct constat *p;
05531     if (!conlist) {
05532         conlist = st_init_numtable();
05533     }
05534     if (st_lookup(conlist, (st_data_t)h, &data)) {
05535         p = (struct constat *)data;
05536     }
05537     else {
05538         CONSOLE_SCREEN_BUFFER_INFO csbi;
05539         p = ALLOC(struct constat);
05540         p->vt100.state = constat_init;
05541         p->vt100.attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05542         p->vt100.saved.X = p->vt100.saved.Y = 0;
05543         if (GetConsoleScreenBufferInfo(h, &csbi)) {
05544             p->vt100.attr = csbi.wAttributes;
05545         }
05546         st_insert(conlist, (st_data_t)h, (st_data_t)p);
05547     }
05548     return p;
05549 }
05550 
05551 /* License: Ruby's */
05552 static void
05553 constat_reset(HANDLE h)
05554 {
05555     st_data_t data;
05556     struct constat *p;
05557     if (!conlist) return;
05558     if (!st_lookup(conlist, (st_data_t)h, &data)) return;
05559     p = (struct constat *)data;
05560     p->vt100.state = constat_init;
05561 }
05562 
05563 /* License: Ruby's */
05564 static DWORD
05565 constat_attr(int count, const int *seq, DWORD attr, DWORD default_attr)
05566 {
05567 #define FOREGROUND_MASK (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
05568 #define BACKGROUND_MASK (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
05569     DWORD bold = attr & (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
05570     int rev = 0;
05571 
05572     if (!count) return attr;
05573     while (count-- > 0) {
05574         switch (*seq++) {
05575           case 0:
05576             attr = default_attr;
05577             rev = 0;
05578             bold = 0;
05579             break;
05580           case 1:
05581             bold |= rev ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
05582             break;
05583           case 4:
05584 #ifndef COMMON_LVB_UNDERSCORE
05585 #define COMMON_LVB_UNDERSCORE 0x8000
05586 #endif
05587             attr |= COMMON_LVB_UNDERSCORE;
05588             break;
05589           case 7:
05590             rev = 1;
05591             break;
05592 
05593           case 30:
05594             attr &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
05595             break;
05596           case 17:
05597           case 31:
05598             attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_GREEN) | FOREGROUND_RED;
05599             break;
05600           case 18:
05601           case 32:
05602             attr = attr & ~(FOREGROUND_BLUE | FOREGROUND_RED) | FOREGROUND_GREEN;
05603             break;
05604           case 19:
05605           case 33:
05606             attr = attr & ~FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05607             break;
05608           case 20:
05609           case 34:
05610             attr = attr & ~(FOREGROUND_GREEN | FOREGROUND_RED) | FOREGROUND_BLUE;
05611             break;
05612           case 21:
05613           case 35:
05614             attr = attr & ~FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
05615             break;
05616           case 22:
05617           case 36:
05618             attr = attr & ~FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
05619             break;
05620           case 23:
05621           case 37:
05622             attr |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
05623             break;
05624 
05625           case 40:
05626             attr &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED);
05627             break;
05628           case 41:
05629             attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_GREEN) | BACKGROUND_RED;
05630             break;
05631           case 42:
05632             attr = attr & ~(BACKGROUND_BLUE | BACKGROUND_RED) | BACKGROUND_GREEN;
05633             break;
05634           case 43:
05635             attr = attr & ~BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
05636             break;
05637           case 44:
05638             attr = attr & ~(BACKGROUND_GREEN | BACKGROUND_RED) | BACKGROUND_BLUE;
05639             break;
05640           case 45:
05641             attr = attr & ~BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
05642             break;
05643           case 46:
05644             attr = attr & ~BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN;
05645             break;
05646           case 47:
05647             attr |= BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED;
05648             break;
05649         }
05650     }
05651     if (rev) {
05652         attr = attr & ~(FOREGROUND_MASK | BACKGROUND_MASK) |
05653             ((attr & FOREGROUND_MASK) << 4) |
05654             ((attr & BACKGROUND_MASK) >> 4);
05655     }
05656     return attr | bold;
05657 }
05658 
05659 /* License: Ruby's */
05660 static void
05661 constat_apply(HANDLE handle, struct constat *s, WCHAR w)
05662 {
05663     CONSOLE_SCREEN_BUFFER_INFO csbi;
05664     const int *seq = s->vt100.seq;
05665     int count = s->vt100.state;
05666     int arg1 = 1;
05667     COORD pos;
05668     DWORD written;
05669 
05670     if (!GetConsoleScreenBufferInfo(handle, &csbi)) return;
05671     if (count > 0 && seq[0] > 0) arg1 = seq[0];
05672     switch (w) {
05673       case L'm':
05674         SetConsoleTextAttribute(handle, constat_attr(count, seq, csbi.wAttributes, s->vt100.attr));
05675         break;
05676       case L'F':
05677         csbi.dwCursorPosition.X = 0;
05678       case L'A':
05679         csbi.dwCursorPosition.Y -= arg1;
05680         if (csbi.dwCursorPosition.Y < 0)
05681             csbi.dwCursorPosition.Y = 0;
05682         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05683         break;
05684       case L'E':
05685         csbi.dwCursorPosition.X = 0;
05686       case L'B':
05687       case L'e':
05688         csbi.dwCursorPosition.Y += arg1;
05689         if (csbi.dwCursorPosition.Y >= csbi.dwSize.Y)
05690             csbi.dwCursorPosition.Y = csbi.dwSize.Y;
05691         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05692         break;
05693       case L'C':
05694         csbi.dwCursorPosition.X += arg1;
05695         if (csbi.dwCursorPosition.X >= csbi.dwSize.X)
05696             csbi.dwCursorPosition.X = csbi.dwSize.X;
05697         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05698         break;
05699       case L'D':
05700         csbi.dwCursorPosition.X -= arg1;
05701         if (csbi.dwCursorPosition.X < 0)
05702             csbi.dwCursorPosition.X = 0;
05703         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05704         break;
05705       case L'G':
05706       case L'`':
05707         csbi.dwCursorPosition.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
05708         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05709         break;
05710       case L'd':
05711         csbi.dwCursorPosition.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
05712         SetConsoleCursorPosition(handle, csbi.dwCursorPosition);
05713         break;
05714       case L'H':
05715       case L'f':
05716         pos.Y = (arg1 > csbi.dwSize.Y ? csbi.dwSize.Y : arg1) - 1;
05717         if (count < 2 || (arg1 = seq[1]) <= 0) arg1 = 1;
05718         pos.X = (arg1 > csbi.dwSize.X ? csbi.dwSize.X : arg1) - 1;
05719         SetConsoleCursorPosition(handle, pos);
05720         break;
05721       case L'J':
05722         switch (arg1) {
05723           case 0:       /* erase after cursor */
05724             FillConsoleOutputCharacterW(handle, L' ',
05725                                         csbi.dwSize.X * (csbi.dwSize.Y - csbi.dwCursorPosition.Y) - csbi.dwCursorPosition.X,
05726                                         csbi.dwCursorPosition, &written);
05727             break;
05728           case 1:       /* erase before cursor */
05729             pos.X = 0;
05730             pos.Y = csbi.dwCursorPosition.Y;
05731             FillConsoleOutputCharacterW(handle, L' ',
05732                                         csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X,
05733                                         pos, &written);
05734             break;
05735           case 2:       /* erase entire line */
05736             pos.X = 0;
05737             pos.Y = 0;
05738             FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X * csbi.dwSize.Y, pos, &written);
05739             break;
05740         }
05741         break;
05742       case L'K':
05743         switch (arg1) {
05744           case 0:       /* erase after cursor */
05745             FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X - csbi.dwCursorPosition.X, csbi.dwCursorPosition, &written);
05746             break;
05747           case 1:       /* erase before cursor */
05748             pos.X = 0;
05749             pos.Y = csbi.dwCursorPosition.Y;
05750             FillConsoleOutputCharacterW(handle, L' ', csbi.dwCursorPosition.X, pos, &written);
05751             break;
05752           case 2:       /* erase entire line */
05753             pos.X = 0;
05754             pos.Y = csbi.dwCursorPosition.Y;
05755             FillConsoleOutputCharacterW(handle, L' ', csbi.dwSize.X, pos, &written);
05756             break;
05757         }
05758         break;
05759       case L's':
05760         s->vt100.saved = csbi.dwCursorPosition;
05761         break;
05762       case L'u':
05763         SetConsoleCursorPosition(handle, s->vt100.saved);
05764         break;
05765       case L'h':
05766         if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
05767             CONSOLE_CURSOR_INFO cci;
05768             GetConsoleCursorInfo(handle, &cci);
05769             cci.bVisible = TRUE;
05770             SetConsoleCursorInfo(handle, &cci);
05771         }
05772         break;
05773       case L'l':
05774         if (count >= 2 && seq[0] == -1 && seq[1] == 25) {
05775             CONSOLE_CURSOR_INFO cci;
05776             GetConsoleCursorInfo(handle, &cci);
05777             cci.bVisible = FALSE;
05778             SetConsoleCursorInfo(handle, &cci);
05779         }
05780         break;
05781     }
05782 }
05783 
05784 /* License: Ruby's */
05785 static long
05786 constat_parse(HANDLE h, struct constat *s, const WCHAR **ptrp, long *lenp)
05787 {
05788     const WCHAR *ptr = *ptrp;
05789     long rest, len = *lenp;
05790     while (len-- > 0) {
05791         WCHAR wc = *ptr++;
05792         if (wc == 0x1b) {
05793             rest = *lenp - len - 1;
05794             s->vt100.state = constat_esc;
05795         }
05796         else if (s->vt100.state == constat_esc && wc == L'[') {
05797             rest = *lenp - len - 1;
05798             if (rest > 0) --rest;
05799             s->vt100.state = constat_seq;
05800             s->vt100.seq[0] = 0;
05801         }
05802         else if (s->vt100.state >= constat_seq) {
05803             if (wc >= L'0' && wc <= L'9') {
05804                 if (s->vt100.state < (int)numberof(s->vt100.seq)) {
05805                     int *seq = &s->vt100.seq[s->vt100.state];
05806                     *seq = (*seq * 10) + (wc - L'0');
05807                 }
05808             }
05809             else if (s->vt100.state == constat_seq && s->vt100.seq[0] == 0 && wc == L'?') {
05810                 s->vt100.seq[s->vt100.state++] = -1;
05811             }
05812             else {
05813                 do {
05814                     if (++s->vt100.state < (int)numberof(s->vt100.seq)) {
05815                         s->vt100.seq[s->vt100.state] = 0;
05816                     }
05817                     else {
05818                         s->vt100.state = (int)numberof(s->vt100.seq);
05819                     }
05820                 } while (0);
05821                 if (wc != L';') {
05822                     constat_apply(h, s, wc);
05823                     s->vt100.state = constat_init;
05824                 }
05825             }
05826             rest = 0;
05827         }
05828         else {
05829             continue;
05830         }
05831         *ptrp = ptr;
05832         *lenp = len;
05833         return rest;
05834     }
05835     len = *lenp;
05836     *ptrp = ptr;
05837     *lenp = 0;
05838     return len;
05839 }
05840 
05841 
05842 /* License: Ruby's */
05843 int
05844 rb_w32_close(int fd)
05845 {
05846     SOCKET sock = TO_SOCKET(fd);
05847     int save_errno = errno;
05848 
05849     if (!is_socket(sock)) {
05850         UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
05851         constat_delete((HANDLE)sock);
05852         return _close(fd);
05853     }
05854     _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
05855     socklist_delete(&sock, NULL);
05856     _close(fd);
05857     errno = save_errno;
05858     if (closesocket(sock) == SOCKET_ERROR) {
05859         errno = map_errno(WSAGetLastError());
05860         return -1;
05861     }
05862     return 0;
05863 }
05864 
05865 static int
05866 setup_overlapped(OVERLAPPED *ol, int fd)
05867 {
05868     memset(ol, 0, sizeof(*ol));
05869     if (!(_osfile(fd) & (FDEV | FPIPE))) {
05870         LONG high = 0;
05871         DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT;
05872         DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method);
05873 #ifndef INVALID_SET_FILE_POINTER
05874 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
05875 #endif
05876         if (low == INVALID_SET_FILE_POINTER) {
05877             DWORD err = GetLastError();
05878             if (err != NO_ERROR) {
05879                 errno = map_errno(err);
05880                 return -1;
05881             }
05882         }
05883         ol->Offset = low;
05884         ol->OffsetHigh = high;
05885     }
05886     ol->hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
05887     if (!ol->hEvent) {
05888         errno = map_errno(GetLastError());
05889         return -1;
05890     }
05891     return 0;
05892 }
05893 
05894 static void
05895 finish_overlapped(OVERLAPPED *ol, int fd, DWORD size)
05896 {
05897     CloseHandle(ol->hEvent);
05898 
05899     if (!(_osfile(fd) & (FDEV | FPIPE))) {
05900         LONG high = ol->OffsetHigh;
05901         DWORD low = ol->Offset + size;
05902         if (low < ol->Offset)
05903             ++high;
05904         SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN);
05905     }
05906 }
05907 
05908 #undef read
05909 /* License: Ruby's */
05910 ssize_t
05911 rb_w32_read(int fd, void *buf, size_t size)
05912 {
05913     SOCKET sock = TO_SOCKET(fd);
05914     DWORD read;
05915     DWORD wait;
05916     DWORD err;
05917     size_t len;
05918     size_t ret;
05919     OVERLAPPED ol, *pol = NULL;
05920     BOOL isconsole;
05921     BOOL islineinput = FALSE;
05922     int start = 0;
05923 
05924     if (is_socket(sock))
05925         return rb_w32_recv(fd, buf, size, 0);
05926 
05927     // validate fd by using _get_osfhandle() because we cannot access _nhandle
05928     if (_get_osfhandle(fd) == -1) {
05929         return -1;
05930     }
05931 
05932     if (_osfile(fd) & FTEXT) {
05933         return _read(fd, buf, size);
05934     }
05935 
05936     MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
05937 
05938     if (!size || _osfile(fd) & FEOFLAG) {
05939         _set_osflags(fd, _osfile(fd) & ~FEOFLAG);
05940         MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05941         return 0;
05942     }
05943 
05944     ret = 0;
05945     isconsole = is_console(_osfhnd(fd)) && (osver.dwMajorVersion < 6 || (osver.dwMajorVersion == 6 && osver.dwMinorVersion < 2));
05946     if (isconsole) {
05947         DWORD mode;
05948         GetConsoleMode((HANDLE)_osfhnd(fd),&mode);
05949         islineinput = (mode & ENABLE_LINE_INPUT) != 0;
05950     }
05951   retry:
05952     /* get rid of console reading bug */
05953     if (isconsole) {
05954         constat_reset((HANDLE)_osfhnd(fd));
05955         if (start)
05956             len = 1;
05957         else {
05958             len = 0;
05959             start = 1;
05960         }
05961     }
05962     else
05963         len = size;
05964     size -= len;
05965 
05966     /* if have cancel_io, use Overlapped I/O */
05967     if (cancel_io) {
05968         if (setup_overlapped(&ol, fd)) {
05969             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05970             return -1;
05971         }
05972 
05973         pol = &ol;
05974     }
05975 
05976     if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) {
05977         err = GetLastError();
05978         if (err != ERROR_IO_PENDING) {
05979             if (pol) CloseHandle(ol.hEvent);
05980             if (err == ERROR_ACCESS_DENIED)
05981                 errno = EBADF;
05982             else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) {
05983                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05984                 return 0;
05985             }
05986             else
05987                 errno = map_errno(err);
05988 
05989             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
05990             return -1;
05991         }
05992 
05993         if (pol) {
05994             wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
05995             if (wait != WAIT_OBJECT_0) {
05996                 if (wait == WAIT_OBJECT_0 + 1)
05997                     errno = EINTR;
05998                 else
05999                     errno = map_errno(GetLastError());
06000                 CloseHandle(ol.hEvent);
06001                 cancel_io((HANDLE)_osfhnd(fd));
06002                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06003                 return -1;
06004             }
06005 
06006             if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) &&
06007                 (err = GetLastError()) != ERROR_HANDLE_EOF) {
06008                 int ret = 0;
06009                 if (err != ERROR_BROKEN_PIPE) {
06010                     errno = map_errno(err);
06011                     ret = -1;
06012                 }
06013                 CloseHandle(ol.hEvent);
06014                 cancel_io((HANDLE)_osfhnd(fd));
06015                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06016                 return ret;
06017             }
06018         }
06019     }
06020     else {
06021         err = GetLastError();
06022         errno = map_errno(err);
06023     }
06024 
06025     if (pol) {
06026         finish_overlapped(&ol, fd, read);
06027     }
06028 
06029     ret += read;
06030     if (read >= len) {
06031         buf = (char *)buf + read;
06032         if (err != ERROR_OPERATION_ABORTED &&
06033             !(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0)
06034             goto retry;
06035     }
06036     if (read == 0)
06037         _set_osflags(fd, _osfile(fd) | FEOFLAG);
06038 
06039 
06040     MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06041 
06042     return ret;
06043 }
06044 
06045 #undef write
06046 /* License: Ruby's */
06047 ssize_t
06048 rb_w32_write(int fd, const void *buf, size_t size)
06049 {
06050     SOCKET sock = TO_SOCKET(fd);
06051     DWORD written;
06052     DWORD wait;
06053     DWORD err;
06054     size_t len;
06055     size_t ret;
06056     OVERLAPPED ol, *pol = NULL;
06057 
06058     if (is_socket(sock))
06059         return rb_w32_send(fd, buf, size, 0);
06060 
06061     // validate fd by using _get_osfhandle() because we cannot access _nhandle
06062     if (_get_osfhandle(fd) == -1) {
06063         return -1;
06064     }
06065 
06066     if ((_osfile(fd) & FTEXT) &&
06067         (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) {
06068         return _write(fd, buf, size);
06069     }
06070 
06071     MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock)));
06072 
06073     if (!size || _osfile(fd) & FEOFLAG) {
06074         MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06075         return 0;
06076     }
06077 
06078     ret = 0;
06079   retry:
06080     /* get rid of console writing bug */
06081     len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size;
06082     size -= len;
06083 
06084     /* if have cancel_io, use Overlapped I/O */
06085     if (cancel_io) {
06086         if (setup_overlapped(&ol, fd)) {
06087             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06088             return -1;
06089         }
06090 
06091         pol = &ol;
06092     }
06093 
06094     if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) {
06095         err = GetLastError();
06096         if (err != ERROR_IO_PENDING) {
06097             if (pol) CloseHandle(ol.hEvent);
06098             if (err == ERROR_ACCESS_DENIED)
06099                 errno = EBADF;
06100             else
06101                 errno = map_errno(err);
06102 
06103             MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06104             return -1;
06105         }
06106 
06107         if (pol) {
06108             wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE);
06109             if (wait != WAIT_OBJECT_0) {
06110                 if (wait == WAIT_OBJECT_0 + 1)
06111                     errno = EINTR;
06112                 else
06113                     errno = map_errno(GetLastError());
06114                 CloseHandle(ol.hEvent);
06115                 cancel_io((HANDLE)_osfhnd(fd));
06116                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06117                 return -1;
06118             }
06119 
06120             if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written,
06121                                      TRUE)) {
06122                 errno = map_errno(err);
06123                 CloseHandle(ol.hEvent);
06124                 cancel_io((HANDLE)_osfhnd(fd));
06125                 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06126                 return -1;
06127             }
06128         }
06129     }
06130 
06131     if (pol) {
06132         finish_overlapped(&ol, fd, written);
06133     }
06134 
06135     ret += written;
06136     if (written == len) {
06137         buf = (const char *)buf + len;
06138         if (size > 0)
06139             goto retry;
06140     }
06141 
06142     MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock));
06143 
06144     return ret;
06145 }
06146 
06147 /* License: Ruby's */
06148 long
06149 rb_w32_write_console(uintptr_t strarg, int fd)
06150 {
06151     static int disable;
06152     HANDLE handle;
06153     DWORD dwMode, reslen;
06154     VALUE str = strarg;
06155     rb_encoding *utf16 = rb_enc_find("UTF-16LE");
06156     const WCHAR *ptr, *next;
06157     struct constat *s;
06158     long len;
06159 
06160     if (disable) return -1L;
06161     handle = (HANDLE)_osfhnd(fd);
06162     if (!GetConsoleMode(handle, &dwMode) ||
06163         !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE"))
06164         return -1L;
06165 
06166     str = rb_str_encode(str, rb_enc_from_encoding(utf16),
06167                         ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil);
06168     ptr = (const WCHAR *)RSTRING_PTR(str);
06169     len = RSTRING_LEN(str) / sizeof(WCHAR);
06170     s = constat_handle(handle);
06171     while (len > 0) {
06172         long curlen = constat_parse(handle, s, (next = ptr, &next), &len);
06173         if (curlen > 0) {
06174             if (!WriteConsoleW(handle, ptr, curlen, &reslen, NULL)) {
06175                 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
06176                     disable = TRUE;
06177                 return -1L;
06178             }
06179         }
06180         ptr = next;
06181     }
06182     RB_GC_GUARD(str);
06183     return (long)reslen;
06184 }
06185 
06186 /* License: Ruby's */
06187 static int
06188 unixtime_to_filetime(time_t time, FILETIME *ft)
06189 {
06190     ULARGE_INTEGER tmp;
06191 
06192     tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000;
06193     ft->dwLowDateTime = tmp.LowPart;
06194     ft->dwHighDateTime = tmp.HighPart;
06195     return 0;
06196 }
06197 
06198 /* License: Ruby's */
06199 static int
06200 wutime(const WCHAR *path, const struct utimbuf *times)
06201 {
06202     HANDLE hFile;
06203     FILETIME atime, mtime;
06204     struct stati64 stat;
06205     int ret = 0;
06206 
06207     if (wstati64(path, &stat)) {
06208         return -1;
06209     }
06210 
06211     if (times) {
06212         if (unixtime_to_filetime(times->actime, &atime)) {
06213             return -1;
06214         }
06215         if (unixtime_to_filetime(times->modtime, &mtime)) {
06216             return -1;
06217         }
06218     }
06219     else {
06220         GetSystemTimeAsFileTime(&atime);
06221         mtime = atime;
06222     }
06223 
06224     RUBY_CRITICAL({
06225         const DWORD attr = GetFileAttributesW(path);
06226         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
06227             SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
06228         hFile = CreateFileW(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING,
06229                             FILE_FLAG_BACKUP_SEMANTICS, 0);
06230         if (hFile == INVALID_HANDLE_VALUE) {
06231             errno = map_errno(GetLastError());
06232             ret = -1;
06233         }
06234         else {
06235             if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
06236                 errno = map_errno(GetLastError());
06237                 ret = -1;
06238             }
06239             CloseHandle(hFile);
06240         }
06241         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY))
06242             SetFileAttributesW(path, attr);
06243     });
06244 
06245     return ret;
06246 }
06247 
06248 /* License: Ruby's */
06249 int
06250 rb_w32_uutime(const char *path, const struct utimbuf *times)
06251 {
06252     WCHAR *wpath;
06253     int ret;
06254 
06255     if (!(wpath = utf8_to_wstr(path, NULL)))
06256         return -1;
06257     ret = wutime(wpath, times);
06258     free(wpath);
06259     return ret;
06260 }
06261 
06262 /* License: Ruby's */
06263 int
06264 rb_w32_utime(const char *path, const struct utimbuf *times)
06265 {
06266     WCHAR *wpath;
06267     int ret;
06268 
06269     if (!(wpath = filecp_to_wstr(path, NULL)))
06270         return -1;
06271     ret = wutime(wpath, times);
06272     free(wpath);
06273     return ret;
06274 }
06275 
06276 /* License: Ruby's */
06277 int
06278 rb_w32_uchdir(const char *path)
06279 {
06280     WCHAR *wpath;
06281     int ret;
06282 
06283     if (!(wpath = utf8_to_wstr(path, NULL)))
06284         return -1;
06285     ret = _wchdir(wpath);
06286     free(wpath);
06287     return ret;
06288 }
06289 
06290 /* License: Ruby's */
06291 static int
06292 wmkdir(const WCHAR *wpath, int mode)
06293 {
06294     int ret = -1;
06295 
06296     RUBY_CRITICAL(do {
06297         if (CreateDirectoryW(wpath, NULL) == FALSE) {
06298             errno = map_errno(GetLastError());
06299             break;
06300         }
06301         if (_wchmod(wpath, mode) == -1) {
06302             RemoveDirectoryW(wpath);
06303             break;
06304         }
06305         ret = 0;
06306     } while (0));
06307     return ret;
06308 }
06309 
06310 /* License: Ruby's */
06311 int
06312 rb_w32_umkdir(const char *path, int mode)
06313 {
06314     WCHAR *wpath;
06315     int ret;
06316 
06317     if (!(wpath = utf8_to_wstr(path, NULL)))
06318         return -1;
06319     ret = wmkdir(wpath, mode);
06320     free(wpath);
06321     return ret;
06322 }
06323 
06324 /* License: Ruby's */
06325 int
06326 rb_w32_mkdir(const char *path, int mode)
06327 {
06328     WCHAR *wpath;
06329     int ret;
06330 
06331     if (!(wpath = filecp_to_wstr(path, NULL)))
06332         return -1;
06333     ret = wmkdir(wpath, mode);
06334     free(wpath);
06335     return ret;
06336 }
06337 
06338 /* License: Ruby's */
06339 static int
06340 wrmdir(const WCHAR *wpath)
06341 {
06342     int ret = 0;
06343     RUBY_CRITICAL({
06344         const DWORD attr = GetFileAttributesW(wpath);
06345         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06346             SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY);
06347         }
06348         if (RemoveDirectoryW(wpath) == FALSE) {
06349             errno = map_errno(GetLastError());
06350             ret = -1;
06351             if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06352                 SetFileAttributesW(wpath, attr);
06353             }
06354         }
06355     });
06356     return ret;
06357 }
06358 
06359 /* License: Ruby's */
06360 int
06361 rb_w32_rmdir(const char *path)
06362 {
06363     WCHAR *wpath;
06364     int ret;
06365 
06366     if (!(wpath = filecp_to_wstr(path, NULL)))
06367         return -1;
06368     ret = wrmdir(wpath);
06369     free(wpath);
06370     return ret;
06371 }
06372 
06373 /* License: Ruby's */
06374 int
06375 rb_w32_urmdir(const char *path)
06376 {
06377     WCHAR *wpath;
06378     int ret;
06379 
06380     if (!(wpath = utf8_to_wstr(path, NULL)))
06381         return -1;
06382     ret = wrmdir(wpath);
06383     free(wpath);
06384     return ret;
06385 }
06386 
06387 /* License: Ruby's */
06388 static int
06389 wunlink(const WCHAR *path)
06390 {
06391     int ret = 0;
06392     RUBY_CRITICAL({
06393         const DWORD attr = GetFileAttributesW(path);
06394         if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06395             SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY);
06396         }
06397         if (!DeleteFileW(path)) {
06398             errno = map_errno(GetLastError());
06399             ret = -1;
06400             if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) {
06401                 SetFileAttributesW(path, attr);
06402             }
06403         }
06404     });
06405     return ret;
06406 }
06407 
06408 /* License: Ruby's */
06409 int
06410 rb_w32_uunlink(const char *path)
06411 {
06412     WCHAR *wpath;
06413     int ret;
06414 
06415     if (!(wpath = utf8_to_wstr(path, NULL)))
06416         return -1;
06417     ret = wunlink(wpath);
06418     free(wpath);
06419     return ret;
06420 }
06421 
06422 /* License: Ruby's */
06423 int
06424 rb_w32_unlink(const char *path)
06425 {
06426     WCHAR *wpath;
06427     int ret;
06428 
06429     if (!(wpath = filecp_to_wstr(path, NULL)))
06430         return -1;
06431     ret = wunlink(wpath);
06432     free(wpath);
06433     return ret;
06434 }
06435 
06436 /* License: Ruby's */
06437 int
06438 rb_w32_uchmod(const char *path, int mode)
06439 {
06440     WCHAR *wpath;
06441     int ret;
06442 
06443     if (!(wpath = utf8_to_wstr(path, NULL)))
06444         return -1;
06445     ret = _wchmod(wpath, mode);
06446     free(wpath);
06447     return ret;
06448 }
06449 
06450 #if !defined(__BORLANDC__)
06451 /* License: Ruby's */
06452 int
06453 rb_w32_isatty(int fd)
06454 {
06455     DWORD mode;
06456 
06457     // validate fd by using _get_osfhandle() because we cannot access _nhandle
06458     if (_get_osfhandle(fd) == -1) {
06459         return 0;
06460     }
06461     if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) {
06462         errno = ENOTTY;
06463         return 0;
06464     }
06465     return 1;
06466 }
06467 #endif
06468 
06469 //
06470 // Fix bcc32's stdio bug
06471 //
06472 
06473 #ifdef __BORLANDC__
06474 /* License: Ruby's */
06475 static int
06476 too_many_files(void)
06477 {
06478     FILE *f;
06479     for (f = _streams; f < _streams + _nfile; f++) {
06480         if (f->fd < 0) return 0;
06481     }
06482     return 1;
06483 }
06484 
06485 #undef fopen
06486 /* License: Ruby's */
06487 FILE *
06488 rb_w32_fopen(const char *path, const char *mode)
06489 {
06490     FILE *f = (errno = 0, fopen(path, mode));
06491     if (f == NULL && errno == 0) {
06492         if (too_many_files())
06493             errno = EMFILE;
06494     }
06495     return f;
06496 }
06497 
06498 /* License: Ruby's */
06499 FILE *
06500 rb_w32_fdopen(int handle, const char *type)
06501 {
06502     FILE *f = (errno = 0, _fdopen(handle, (char *)type));
06503     if (f == NULL && errno == 0) {
06504         if (handle < 0)
06505             errno = EBADF;
06506         else if (too_many_files())
06507             errno = EMFILE;
06508     }
06509     return f;
06510 }
06511 
06512 /* License: Ruby's */
06513 FILE *
06514 rb_w32_fsopen(const char *path, const char *mode, int shflags)
06515 {
06516     FILE *f = (errno = 0, _fsopen(path, mode, shflags));
06517     if (f == NULL && errno == 0) {
06518         if (too_many_files())
06519             errno = EMFILE;
06520     }
06521     return f;
06522 }
06523 #endif
06524 
06525 #if defined(_MSC_VER) && RUBY_MSVCRT_VERSION <= 60
06526 extern long _ftol(double);
06527 /* License: Ruby's */
06528 long
06529 _ftol2(double d)
06530 {
06531     return _ftol(d);
06532 }
06533 
06534 /* License: Ruby's */
06535 long
06536 _ftol2_sse(double d)
06537 {
06538     return _ftol(d);
06539 }
06540 #endif
06541 
06542 #ifndef signbit
06543 /* License: Ruby's */
06544 int
06545 signbit(double x)
06546 {
06547     int *ip = (int *)(&x + 1) - 1;
06548     return *ip < 0;
06549 }
06550 #endif
06551 
06552 /* License: Ruby's */
06553 const char * WSAAPI
06554 rb_w32_inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
06555 {
06556     typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t);
06557     inet_ntop_t *pInetNtop;
06558     pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL);
06559     if (pInetNtop) {
06560         return pInetNtop(af, (void *)addr, numaddr, numaddr_len);
06561     }
06562     else {
06563         struct in_addr in;
06564         memcpy(&in.s_addr, addr, sizeof(in.s_addr));
06565         snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
06566     }
06567     return numaddr;
06568 }
06569 
06570 /* License: Ruby's */
06571 char
06572 rb_w32_fd_is_text(int fd)
06573 {
06574     return _osfile(fd) & FTEXT;
06575 }
06576 
06577 #if RUBY_MSVCRT_VERSION < 80 && !defined(__MINGW64__)
06578 /* License: Ruby's */
06579 static int
06580 unixtime_to_systemtime(const time_t t, SYSTEMTIME *st)
06581 {
06582     FILETIME ft;
06583     if (unixtime_to_filetime(t, &ft)) return -1;
06584     if (!FileTimeToSystemTime(&ft, st)) return -1;
06585     return 0;
06586 }
06587 
06588 /* License: Ruby's */
06589 static void
06590 systemtime_to_tm(const SYSTEMTIME *st, struct tm *t)
06591 {
06592     int y = st->wYear, m = st->wMonth, d = st->wDay;
06593     t->tm_sec  = st->wSecond;
06594     t->tm_min  = st->wMinute;
06595     t->tm_hour = st->wHour;
06596     t->tm_mday = st->wDay;
06597     t->tm_mon  = st->wMonth - 1;
06598     t->tm_year = y - 1900;
06599     t->tm_wday = st->wDayOfWeek;
06600     switch (m) {
06601       case 1:
06602         break;
06603       case 2:
06604         d += 31;
06605         break;
06606       default:
06607         d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
06608         d += ((m - 3) * 153 + 2) / 5;
06609         break;
06610     }
06611     t->tm_yday = d - 1;
06612 }
06613 
06614 /* License: Ruby's */
06615 static int
06616 systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
06617 {
06618     TIME_ZONE_INFORMATION stdtz;
06619     SYSTEMTIME sst;
06620 
06621     if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1;
06622     if (!tz) {
06623         GetTimeZoneInformation(&stdtz);
06624         tz = &stdtz;
06625     }
06626     if (tz->StandardBias == tz->DaylightBias) return 0;
06627     if (!tz->StandardDate.wMonth) return 0;
06628     if (!tz->DaylightDate.wMonth) return 0;
06629     if (tz != &stdtz) stdtz = *tz;
06630 
06631     stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
06632     if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0;
06633     if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
06634         return 0;
06635     return 1;
06636 }
06637 #endif
06638 
06639 #ifdef __MINGW64__
06640 # ifndef MINGW_HAS_SECURE_API
06641    _CRTIMP errno_t __cdecl _gmtime64_s(struct tm* tm, const __time64_t *time);
06642    _CRTIMP errno_t __cdecl _localtime64_s(struct tm* tm, const __time64_t *time);
06643 # endif
06644 # define gmtime_s _gmtime64_s
06645 # define localtime_s _localtime64_s
06646 #endif
06647 
06648 /* License: Ruby's */
06649 struct tm *
06650 gmtime_r(const time_t *tp, struct tm *rp)
06651 {
06652     int e = EINVAL;
06653     if (!tp || !rp) {
06654       error:
06655         errno = e;
06656         return NULL;
06657     }
06658 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
06659     e = gmtime_s(rp, tp);
06660     if (e != 0) goto error;
06661 #else
06662     {
06663         SYSTEMTIME st;
06664         if (unixtime_to_systemtime(*tp, &st)) goto error;
06665         rp->tm_isdst = 0;
06666         systemtime_to_tm(&st, rp);
06667     }
06668 #endif
06669     return rp;
06670 }
06671 
06672 /* License: Ruby's */
06673 struct tm *
06674 localtime_r(const time_t *tp, struct tm *rp)
06675 {
06676     int e = EINVAL;
06677     if (!tp || !rp) {
06678       error:
06679         errno = e;
06680         return NULL;
06681     }
06682 #if RUBY_MSVCRT_VERSION >= 80 || defined(__MINGW64__)
06683     e = localtime_s(rp, tp);
06684     if (e) goto error;
06685 #else
06686     {
06687         SYSTEMTIME gst, lst;
06688         if (unixtime_to_systemtime(*tp, &gst)) goto error;
06689         rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
06690         systemtime_to_tm(&lst, rp);
06691     }
06692 #endif
06693     return rp;
06694 }
06695 
06696 /* License: Ruby's */
06697 int
06698 rb_w32_wrap_io_handle(HANDLE h, int flags)
06699 {
06700     BOOL tmp;
06701     int len = sizeof(tmp);
06702     int r = getsockopt((SOCKET)h, SOL_SOCKET, SO_DEBUG, (char *)&tmp, &len);
06703     if (r != SOCKET_ERROR || WSAGetLastError() != WSAENOTSOCK) {
06704         int f = 0;
06705         if (flags & O_NONBLOCK) {
06706             flags &= ~O_NONBLOCK;
06707             f = O_NONBLOCK;
06708         }
06709         socklist_insert((SOCKET)h, f);
06710     }
06711     else if (flags & O_NONBLOCK) {
06712         errno = EINVAL;
06713         return -1;
06714     }
06715     return rb_w32_open_osfhandle((intptr_t)h, flags);
06716 }
06717 
06718 /* License: Ruby's */
06719 int
06720 rb_w32_unwrap_io_handle(int fd)
06721 {
06722     SOCKET sock = TO_SOCKET(fd);
06723     _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
06724     if (!is_socket(sock)) {
06725         UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN);
06726         constat_delete((HANDLE)sock);
06727     }
06728     else {
06729         socklist_delete(&sock, NULL);
06730     }
06731     return _close(fd);
06732 }
06733