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