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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7