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