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