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