|
Ruby
1.9.3p286(2012-10-12revision37165)
|
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 '\n': 01379 if (!quote) 01380 return TRUE; 01381 ptr++; 01382 break; 01383 01384 case '%': 01385 if (*++ptr != '_' && !ISALPHA(*ptr)) break; 01386 while (*++ptr == '_' || ISALNUM(*ptr)); 01387 if (*ptr++ == '%') return TRUE; 01388 break; 01389 01390 case '\\': 01391 ptr++; 01392 default: 01393 ptr = CharNext(ptr); 01394 break; 01395 } 01396 } 01397 return FALSE; 01398 } 01399 01400 static inline char * 01401 skipspace(char *ptr) 01402 { 01403 while (ISSPACE(*ptr)) 01404 ptr++; 01405 return ptr; 01406 } 01407 01408 int 01409 rb_w32_cmdvector(const char *cmd, char ***vec) 01410 { 01411 int globbing, len; 01412 int elements, strsz, done; 01413 int slashes, escape; 01414 char *ptr, *base, *buffer, *cmdline; 01415 char **vptr; 01416 char quote; 01417 NtCmdLineElement *curr, **tail; 01418 NtCmdLineElement *cmdhead = NULL, **cmdtail = &cmdhead; 01419 01420 // 01421 // just return if we don't have a command line 01422 // 01423 01424 while (ISSPACE(*cmd)) 01425 cmd++; 01426 if (!*cmd) { 01427 *vec = NULL; 01428 return 0; 01429 } 01430 01431 ptr = cmdline = strdup(cmd); 01432 01433 // 01434 // Ok, parse the command line, building a list of CmdLineElements. 01435 // When we've finished, and it's an input command (meaning that it's 01436 // the processes argv), we'll do globing and then build the argument 01437 // vector. 01438 // The outer loop does one interation for each element seen. 01439 // The inner loop does one interation for each character in the element. 01440 // 01441 01442 while (*(ptr = skipspace(ptr))) { 01443 base = ptr; 01444 quote = slashes = globbing = escape = 0; 01445 for (done = 0; !done && *ptr; ) { 01446 // 01447 // Switch on the current character. We only care about the 01448 // white-space characters, the wild-card characters, and the 01449 // quote characters. 01450 // 01451 01452 switch (*ptr) { 01453 case '\\': 01454 if (quote != '\'') slashes++; 01455 break; 01456 01457 case ' ': 01458 case '\t': 01459 case '\n': 01460 // 01461 // if we're not in a string, then we're finished with this 01462 // element 01463 // 01464 01465 if (!quote) { 01466 *ptr = 0; 01467 done = 1; 01468 } 01469 break; 01470 01471 case '*': 01472 case '?': 01473 case '[': 01474 case '{': 01475 // 01476 // record the fact that this element has a wildcard character 01477 // N.B. Don't glob if inside a single quoted string 01478 // 01479 01480 if (quote != '\'') 01481 globbing++; 01482 slashes = 0; 01483 break; 01484 01485 case '\'': 01486 case '\"': 01487 // 01488 // if we're already in a string, see if this is the 01489 // terminating close-quote. If it is, we're finished with 01490 // the string, but not neccessarily with the element. 01491 // If we're not already in a string, start one. 01492 // 01493 01494 if (!(slashes & 1)) { 01495 if (!quote) 01496 quote = *ptr; 01497 else if (quote == *ptr) { 01498 if (quote == '"' && quote == ptr[1]) 01499 ptr++; 01500 quote = '\0'; 01501 } 01502 } 01503 escape++; 01504 slashes = 0; 01505 break; 01506 01507 default: 01508 ptr = CharNext(ptr); 01509 slashes = 0; 01510 continue; 01511 } 01512 ptr++; 01513 } 01514 01515 // 01516 // when we get here, we've got a pair of pointers to the element, 01517 // base and ptr. Base points to the start of the element while ptr 01518 // points to the character following the element. 01519 // 01520 01521 len = ptr - base; 01522 if (done) --len; 01523 01524 // 01525 // if it's an input vector element and it's enclosed by quotes, 01526 // we can remove them. 01527 // 01528 01529 if (escape) { 01530 char *p = base, c; 01531 slashes = quote = 0; 01532 while (p < base + len) { 01533 switch (c = *p) { 01534 case '\\': 01535 p++; 01536 if (quote != '\'') slashes++; 01537 break; 01538 01539 case '\'': 01540 case '"': 01541 if (!(slashes & 1) && quote && quote != c) { 01542 p++; 01543 slashes = 0; 01544 break; 01545 } 01546 memcpy(p - ((slashes + 1) >> 1), p + (~slashes & 1), 01547 base + len - p); 01548 len -= ((slashes + 1) >> 1) + (~slashes & 1); 01549 p -= (slashes + 1) >> 1; 01550 if (!(slashes & 1)) { 01551 if (quote) { 01552 if (quote == '"' && quote == *p) 01553 p++; 01554 quote = '\0'; 01555 } 01556 else 01557 quote = c; 01558 } 01559 else 01560 p++; 01561 slashes = 0; 01562 break; 01563 01564 default: 01565 p = CharNext(p); 01566 slashes = 0; 01567 break; 01568 } 01569 } 01570 } 01571 01572 curr = (NtCmdLineElement *)calloc(sizeof(NtCmdLineElement), 1); 01573 if (!curr) goto do_nothing; 01574 curr->str = base; 01575 curr->len = len; 01576 01577 if (globbing && (tail = cmdglob(curr, cmdtail))) { 01578 cmdtail = tail; 01579 } 01580 else { 01581 *cmdtail = curr; 01582 cmdtail = &curr->next; 01583 } 01584 } 01585 01586 // 01587 // Almost done! 01588 // Count up the elements, then allocate space for a vector of pointers 01589 // (argv) and a string table for the elements. 01590 // 01591 01592 for (elements = 0, strsz = 0, curr = cmdhead; curr; curr = curr->next) { 01593 elements++; 01594 strsz += (curr->len + 1); 01595 } 01596 01597 len = (elements+1)*sizeof(char *) + strsz; 01598 buffer = (char *)malloc(len); 01599 if (!buffer) { 01600 do_nothing: 01601 while (curr = cmdhead) { 01602 cmdhead = curr->next; 01603 if (curr->flags & NTMALLOC) free(curr->str); 01604 free(curr); 01605 } 01606 free(cmdline); 01607 for (vptr = *vec; *vptr; ++vptr); 01608 return vptr - *vec; 01609 } 01610 01611 // 01612 // make vptr point to the start of the buffer 01613 // and ptr point to the area we'll consider the string table. 01614 // 01615 // buffer (*vec) 01616 // | 01617 // V ^---------------------V 01618 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 01619 // | | | .... | NULL | | ..... |\0 | | ..... |\0 |... 01620 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 01621 // |- elements+1 -| ^ 1st element ^ 2nd element 01622 01623 vptr = (char **) buffer; 01624 01625 ptr = buffer + (elements+1) * sizeof(char *); 01626 01627 while (curr = cmdhead) { 01628 strlcpy(ptr, curr->str, curr->len + 1); 01629 *vptr++ = ptr; 01630 ptr += curr->len + 1; 01631 cmdhead = curr->next; 01632 if (curr->flags & NTMALLOC) free(curr->str); 01633 free(curr); 01634 } 01635 *vptr = 0; 01636 01637 *vec = (char **) buffer; 01638 free(cmdline); 01639 return elements; 01640 } 01641 01642 // 01643 // UNIX compatible directory access functions for NT 01644 // 01645 01646 #define PATHLEN 1024 01647 01648 // 01649 // The idea here is to read all the directory names into a string table 01650 // (separated by nulls) and when one of the other dir functions is called 01651 // return the pointer to the current file name. 01652 // 01653 01654 #define GetBit(bits, i) ((bits)[(i) / CHAR_BIT] & (1 << (i) % CHAR_BIT)) 01655 #define SetBit(bits, i) ((bits)[(i) / CHAR_BIT] |= (1 << (i) % CHAR_BIT)) 01656 01657 #define BitOfIsDir(n) ((n) * 2) 01658 #define BitOfIsRep(n) ((n) * 2 + 1) 01659 #define DIRENT_PER_CHAR (CHAR_BIT / 2) 01660 01661 static HANDLE 01662 open_dir_handle(const WCHAR *filename, WIN32_FIND_DATAW *fd) 01663 { 01664 HANDLE fh; 01665 static const WCHAR wildcard[] = L"\\*"; 01666 WCHAR *scanname; 01667 WCHAR *p; 01668 int len; 01669 VALUE v; 01670 01671 // 01672 // Create the search pattern 01673 // 01674 len = lstrlenW(filename); 01675 scanname = ALLOCV_N(WCHAR, v, len + sizeof(wildcard) / sizeof(WCHAR)); 01676 lstrcpyW(scanname, filename); 01677 p = CharPrevW(scanname, scanname + len); 01678 if (*p == L'/' || *p == L'\\' || *p == L':') 01679 lstrcatW(scanname, wildcard + 1); 01680 else 01681 lstrcatW(scanname, wildcard); 01682 01683 // 01684 // do the FindFirstFile call 01685 // 01686 fh = FindFirstFileW(scanname, fd); 01687 ALLOCV_END(v); 01688 if (fh == INVALID_HANDLE_VALUE) { 01689 errno = map_errno(GetLastError()); 01690 } 01691 return fh; 01692 } 01693 01694 static DIR * 01695 opendir_internal(WCHAR *wpath, const char *filename) 01696 { 01697 struct stati64 sbuf; 01698 WIN32_FIND_DATAW fd; 01699 HANDLE fh; 01700 DIR *p; 01701 long len; 01702 long idx; 01703 WCHAR *tmpW; 01704 char *tmp; 01705 01706 // 01707 // check to see if we've got a directory 01708 // 01709 if (wstati64(wpath, &sbuf) < 0) { 01710 return NULL; 01711 } 01712 if (!(sbuf.st_mode & S_IFDIR) && 01713 (!ISALPHA(filename[0]) || filename[1] != ':' || filename[2] != '\0' || 01714 ((1 << ((filename[0] & 0x5f) - 'A')) & GetLogicalDrives()) == 0)) { 01715 errno = ENOTDIR; 01716 return NULL; 01717 } 01718 fh = open_dir_handle(wpath, &fd); 01719 if (fh == INVALID_HANDLE_VALUE) { 01720 return NULL; 01721 } 01722 01723 // 01724 // Get us a DIR structure 01725 // 01726 p = calloc(sizeof(DIR), 1); 01727 if (p == NULL) 01728 return NULL; 01729 01730 idx = 0; 01731 01732 // 01733 // loop finding all the files that match the wildcard 01734 // (which should be all of them in this directory!). 01735 // the variable idx should point one past the null terminator 01736 // of the previous string found. 01737 // 01738 do { 01739 len = lstrlenW(fd.cFileName) + 1; 01740 01741 // 01742 // bump the string table size by enough for the 01743 // new name and it's null terminator 01744 // 01745 tmpW = realloc(p->start, (idx + len) * sizeof(WCHAR)); 01746 if (!tmpW) { 01747 error: 01748 rb_w32_closedir(p); 01749 FindClose(fh); 01750 errno = ENOMEM; 01751 return NULL; 01752 } 01753 01754 p->start = tmpW; 01755 memcpy(&p->start[idx], fd.cFileName, len * sizeof(WCHAR)); 01756 01757 if (p->nfiles % DIRENT_PER_CHAR == 0) { 01758 tmp = realloc(p->bits, p->nfiles / DIRENT_PER_CHAR + 1); 01759 if (!tmp) 01760 goto error; 01761 p->bits = tmp; 01762 p->bits[p->nfiles / DIRENT_PER_CHAR] = 0; 01763 } 01764 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 01765 SetBit(p->bits, BitOfIsDir(p->nfiles)); 01766 if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) 01767 SetBit(p->bits, BitOfIsRep(p->nfiles)); 01768 01769 p->nfiles++; 01770 idx += len; 01771 } while (FindNextFileW(fh, &fd)); 01772 FindClose(fh); 01773 p->size = idx; 01774 p->curr = p->start; 01775 return p; 01776 } 01777 01778 static inline UINT 01779 filecp(void) 01780 { 01781 UINT cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP; 01782 return cp; 01783 } 01784 01785 static char * 01786 wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen, long *plen) 01787 { 01788 char *ptr; 01789 int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL) - 1; 01790 if (!(ptr = malloc(len + 1))) return 0; 01791 WideCharToMultiByte(cp, 0, wstr, clen, ptr, len + 1, NULL, NULL); 01792 if (plen) *plen = len; 01793 return ptr; 01794 } 01795 01796 static WCHAR * 01797 mbstr_to_wstr(UINT cp, const char *str, int clen, long *plen) 01798 { 01799 WCHAR *ptr; 01800 int len = MultiByteToWideChar(cp, 0, str, clen, NULL, 0) - 1; 01801 if (!(ptr = malloc(sizeof(WCHAR) * (len + 1)))) return 0; 01802 MultiByteToWideChar(cp, 0, str, clen, ptr, len + 1); 01803 if (plen) *plen = len; 01804 return ptr; 01805 } 01806 01807 DIR * 01808 rb_w32_opendir(const char *filename) 01809 { 01810 DIR *ret; 01811 WCHAR *wpath = filecp_to_wstr(filename, NULL); 01812 if (!wpath) 01813 return NULL; 01814 ret = opendir_internal(wpath, filename); 01815 free(wpath); 01816 return ret; 01817 } 01818 01819 DIR * 01820 rb_w32_uopendir(const char *filename) 01821 { 01822 DIR *ret; 01823 WCHAR *wpath = utf8_to_wstr(filename, NULL); 01824 if (!wpath) 01825 return NULL; 01826 ret = opendir_internal(wpath, filename); 01827 free(wpath); 01828 return ret; 01829 } 01830 01831 // 01832 // Move to next entry 01833 // 01834 01835 static void 01836 move_to_next_entry(DIR *dirp) 01837 { 01838 if (dirp->curr) { 01839 dirp->loc++; 01840 dirp->curr += lstrlenW(dirp->curr) + 1; 01841 if (dirp->curr >= (dirp->start + dirp->size)) { 01842 dirp->curr = NULL; 01843 } 01844 } 01845 } 01846 01847 // 01848 // Readdir just returns the current string pointer and bumps the 01849 // string pointer to the next entry. 01850 // 01851 static BOOL 01852 win32_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *dummy) 01853 { 01854 if (!(entry->d_name = wstr_to_filecp(file, &entry->d_namlen))) 01855 return FALSE; 01856 return TRUE; 01857 } 01858 01859 VALUE 01860 rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc) 01861 { 01862 static rb_encoding *utf16 = (rb_encoding *)-1; 01863 VALUE src; 01864 01865 if (utf16 == (rb_encoding *)-1) { 01866 utf16 = rb_enc_find("UTF-16LE"); 01867 if (utf16 == rb_ascii8bit_encoding()) 01868 utf16 = NULL; 01869 } 01870 if (!utf16) 01871 /* maybe miniruby */ 01872 return Qnil; 01873 01874 src = rb_enc_str_new((char *)wstr, lstrlenW(wstr) * sizeof(WCHAR), utf16); 01875 return rb_str_encode(src, rb_enc_from_encoding(enc), ECONV_UNDEF_REPLACE, Qnil); 01876 } 01877 01878 char * 01879 rb_w32_conv_from_wstr(const WCHAR *wstr, long *lenp, rb_encoding *enc) 01880 { 01881 VALUE str = rb_w32_conv_from_wchar(wstr, enc); 01882 long len; 01883 char *ptr; 01884 01885 if (NIL_P(str)) return wstr_to_filecp(wstr, lenp); 01886 *lenp = len = RSTRING_LEN(str); 01887 memcpy(ptr = malloc(len + 1), RSTRING_PTR(str), len); 01888 ptr[len] = '\0'; 01889 return ptr; 01890 } 01891 01892 static BOOL 01893 ruby_direct_conv(const WCHAR *file, struct direct *entry, rb_encoding *enc) 01894 { 01895 if (!(entry->d_name = rb_w32_conv_from_wstr(file, &entry->d_namlen, enc))) 01896 return FALSE; 01897 return TRUE; 01898 } 01899 01900 static struct direct * 01901 readdir_internal(DIR *dirp, BOOL (*conv)(const WCHAR *, struct direct *, rb_encoding *), rb_encoding *enc) 01902 { 01903 static int dummy = 0; 01904 01905 if (dirp->curr) { 01906 01907 // 01908 // first set up the structure to return 01909 // 01910 if (dirp->dirstr.d_name) 01911 free(dirp->dirstr.d_name); 01912 conv(dirp->curr, &dirp->dirstr, enc); 01913 01914 // 01915 // Fake inode 01916 // 01917 dirp->dirstr.d_ino = dummy++; 01918 01919 // 01920 // Attributes 01921 // 01922 dirp->dirstr.d_isdir = GetBit(dirp->bits, BitOfIsDir(dirp->loc)); 01923 dirp->dirstr.d_isrep = GetBit(dirp->bits, BitOfIsRep(dirp->loc)); 01924 01925 // 01926 // Now set up for the next call to readdir 01927 // 01928 01929 move_to_next_entry(dirp); 01930 01931 return &(dirp->dirstr); 01932 01933 } 01934 else 01935 return NULL; 01936 } 01937 01938 struct direct * 01939 rb_w32_readdir(DIR *dirp) 01940 { 01941 return readdir_internal(dirp, win32_direct_conv, NULL); 01942 } 01943 01944 struct direct * 01945 rb_w32_readdir_with_enc(DIR *dirp, rb_encoding *enc) 01946 { 01947 if (enc == rb_ascii8bit_encoding()) 01948 return readdir_internal(dirp, win32_direct_conv, NULL); 01949 else 01950 return readdir_internal(dirp, ruby_direct_conv, enc); 01951 } 01952 01953 // 01954 // Telldir returns the current string pointer position 01955 // 01956 01957 long 01958 rb_w32_telldir(DIR *dirp) 01959 { 01960 return dirp->loc; 01961 } 01962 01963 // 01964 // Seekdir moves the string pointer to a previously saved position 01965 // (Saved by telldir). 01966 01967 void 01968 rb_w32_seekdir(DIR *dirp, long loc) 01969 { 01970 if (dirp->loc > loc) rb_w32_rewinddir(dirp); 01971 01972 while (dirp->curr && dirp->loc < loc) { 01973 move_to_next_entry(dirp); 01974 } 01975 } 01976 01977 // 01978 // Rewinddir resets the string pointer to the start 01979 // 01980 01981 void 01982 rb_w32_rewinddir(DIR *dirp) 01983 { 01984 dirp->curr = dirp->start; 01985 dirp->loc = 0; 01986 } 01987 01988 // 01989 // This just free's the memory allocated by opendir 01990 // 01991 01992 void 01993 rb_w32_closedir(DIR *dirp) 01994 { 01995 if (dirp) { 01996 if (dirp->dirstr.d_name) 01997 free(dirp->dirstr.d_name); 01998 if (dirp->start) 01999 free(dirp->start); 02000 if (dirp->bits) 02001 free(dirp->bits); 02002 free(dirp); 02003 } 02004 } 02005 02006 #if (defined _MT || defined __MSVCRT__) && !defined __BORLANDC__ 02007 #define MSVCRT_THREADS 02008 #endif 02009 #ifdef MSVCRT_THREADS 02010 # define MTHREAD_ONLY(x) x 02011 # define STHREAD_ONLY(x) 02012 #elif defined(__BORLANDC__) 02013 # define MTHREAD_ONLY(x) 02014 # define STHREAD_ONLY(x) 02015 #else 02016 # define MTHREAD_ONLY(x) 02017 # define STHREAD_ONLY(x) x 02018 #endif 02019 02020 typedef struct { 02021 intptr_t osfhnd; /* underlying OS file HANDLE */ 02022 char osfile; /* attributes of file (e.g., open in text mode?) */ 02023 char pipech; /* one char buffer for handles opened on pipes */ 02024 #ifdef MSVCRT_THREADS 02025 int lockinitflag; 02026 CRITICAL_SECTION lock; 02027 #endif 02028 #if RT_VER >= 80 02029 char textmode; 02030 char pipech2[2]; 02031 #endif 02032 } ioinfo; 02033 02034 #if !defined _CRTIMP || defined __MINGW32__ 02035 #undef _CRTIMP 02036 #define _CRTIMP __declspec(dllimport) 02037 #endif 02038 02039 #if !defined(__BORLANDC__) 02040 EXTERN_C _CRTIMP ioinfo * __pioinfo[]; 02041 02042 #define IOINFO_L2E 5 02043 #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) 02044 #define _pioinfo(i) ((ioinfo*)((char*)(__pioinfo[i >> IOINFO_L2E]) + (i & (IOINFO_ARRAY_ELTS - 1)) * (sizeof(ioinfo) + pioinfo_extra))) 02045 #define _osfhnd(i) (_pioinfo(i)->osfhnd) 02046 #define _osfile(i) (_pioinfo(i)->osfile) 02047 #define _pipech(i) (_pioinfo(i)->pipech) 02048 02049 #if RT_VER >= 80 02050 static size_t pioinfo_extra = 0; /* workaround for VC++8 SP1 */ 02051 02052 static void 02053 set_pioinfo_extra(void) 02054 { 02055 int fd; 02056 02057 fd = _open("NUL", O_RDONLY); 02058 for (pioinfo_extra = 0; pioinfo_extra <= 64; pioinfo_extra += sizeof(void *)) { 02059 if (_osfhnd(fd) == _get_osfhandle(fd)) { 02060 break; 02061 } 02062 } 02063 _close(fd); 02064 02065 if (pioinfo_extra > 64) { 02066 /* not found, maybe something wrong... */ 02067 pioinfo_extra = 0; 02068 } 02069 } 02070 #else 02071 #define pioinfo_extra 0 02072 #endif 02073 02074 #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh) 02075 #define _set_osflags(fh, flags) (_osfile(fh) = (flags)) 02076 02077 #define FOPEN 0x01 /* file handle open */ 02078 #define FEOFLAG 0x02 /* end of file has been encountered */ 02079 #define FPIPE 0x08 /* file handle refers to a pipe */ 02080 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */ 02081 #define FAPPEND 0x20 /* file handle opened O_APPEND */ 02082 #define FDEV 0x40 /* file handle refers to device */ 02083 #define FTEXT 0x80 /* file handle is in text mode */ 02084 02085 static int is_socket(SOCKET); 02086 static int is_console(SOCKET); 02087 02088 int 02089 rb_w32_io_cancelable_p(int fd) 02090 { 02091 return cancel_io != NULL && (is_socket(TO_SOCKET(fd)) || !is_console(TO_SOCKET(fd))); 02092 } 02093 02094 static int 02095 rb_w32_open_osfhandle(intptr_t osfhandle, int flags) 02096 { 02097 int fh; 02098 char fileflags; /* _osfile flags */ 02099 HANDLE hF; 02100 02101 /* copy relevant flags from second parameter */ 02102 fileflags = FDEV; 02103 02104 if (flags & O_APPEND) 02105 fileflags |= FAPPEND; 02106 02107 if (flags & O_TEXT) 02108 fileflags |= FTEXT; 02109 02110 if (flags & O_NOINHERIT) 02111 fileflags |= FNOINHERIT; 02112 02113 /* attempt to allocate a C Runtime file handle */ 02114 hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 02115 fh = _open_osfhandle((intptr_t)hF, 0); 02116 CloseHandle(hF); 02117 if (fh == -1) { 02118 errno = EMFILE; /* too many open files */ 02119 _doserrno = 0L; /* not an OS error */ 02120 } 02121 else { 02122 02123 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fh)->lock))); 02124 /* the file is open. now, set the info in _osfhnd array */ 02125 _set_osfhnd(fh, osfhandle); 02126 02127 fileflags |= FOPEN; /* mark as open */ 02128 02129 _set_osflags(fh, fileflags); /* set osfile entry */ 02130 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fh)->lock)); 02131 } 02132 return fh; /* return handle */ 02133 } 02134 02135 static void 02136 init_stdhandle(void) 02137 { 02138 int nullfd = -1; 02139 int keep = 0; 02140 #define open_null(fd) \ 02141 (((nullfd < 0) ? \ 02142 (nullfd = open("NUL", O_RDWR)) : 0), \ 02143 ((nullfd == (fd)) ? (keep = 1) : dup2(nullfd, fd)), \ 02144 (fd)) 02145 02146 if (fileno(stdin) < 0) { 02147 stdin->_file = open_null(0); 02148 } 02149 else { 02150 setmode(fileno(stdin), O_BINARY); 02151 } 02152 if (fileno(stdout) < 0) { 02153 stdout->_file = open_null(1); 02154 } 02155 if (fileno(stderr) < 0) { 02156 stderr->_file = open_null(2); 02157 } 02158 if (nullfd >= 0 && !keep) close(nullfd); 02159 setvbuf(stderr, NULL, _IONBF, 0); 02160 } 02161 #else 02162 02163 #define _set_osfhnd(fh, osfh) (void)((fh), (osfh)) 02164 #define _set_osflags(fh, flags) (void)((fh), (flags)) 02165 02166 static void 02167 init_stdhandle(void) 02168 { 02169 } 02170 #endif 02171 02172 #ifdef __BORLANDC__ 02173 static int 02174 rb_w32_open_osfhandle(intptr_t osfhandle, int flags) 02175 { 02176 int fd = _open_osfhandle(osfhandle, flags); 02177 if (fd == -1) { 02178 errno = EMFILE; /* too many open files */ 02179 _doserrno = 0L; /* not an OS error */ 02180 } 02181 return fd; 02182 } 02183 #endif 02184 02185 #undef getsockopt 02186 02187 static int 02188 is_socket(SOCKET sock) 02189 { 02190 if (st_lookup(socklist, (st_data_t)sock, NULL)) 02191 return TRUE; 02192 else 02193 return FALSE; 02194 } 02195 02196 int 02197 rb_w32_is_socket(int fd) 02198 { 02199 return is_socket(TO_SOCKET(fd)); 02200 } 02201 02202 // 02203 // Since the errors returned by the socket error function 02204 // WSAGetLastError() are not known by the library routine strerror 02205 // we have to roll our own. 02206 // 02207 02208 #undef strerror 02209 02210 char * 02211 rb_w32_strerror(int e) 02212 { 02213 static char buffer[512]; 02214 DWORD source = 0; 02215 char *p; 02216 02217 #if defined __BORLANDC__ && defined ENOTEMPTY // _sys_errlist is broken 02218 switch (e) { 02219 case ENAMETOOLONG: 02220 return "Filename too long"; 02221 case ENOTEMPTY: 02222 return "Directory not empty"; 02223 } 02224 #endif 02225 02226 if (e < 0 || e > sys_nerr) { 02227 if (e < 0) 02228 e = GetLastError(); 02229 #if WSAEWOULDBLOCK != EWOULDBLOCK 02230 else if (e >= EADDRINUSE && e <= EWOULDBLOCK) { 02231 static int s = -1; 02232 int i; 02233 if (s < 0) 02234 for (s = 0; s < (int)(sizeof(errmap)/sizeof(*errmap)); s++) 02235 if (errmap[s].winerr == WSAEWOULDBLOCK) 02236 break; 02237 for (i = s; i < (int)(sizeof(errmap)/sizeof(*errmap)); i++) 02238 if (errmap[i].err == e) { 02239 e = errmap[i].winerr; 02240 break; 02241 } 02242 } 02243 #endif 02244 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 02245 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 02246 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 02247 buffer, sizeof(buffer), NULL) == 0 && 02248 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 02249 FORMAT_MESSAGE_IGNORE_INSERTS, &source, e, 0, 02250 buffer, sizeof(buffer), NULL) == 0) 02251 strlcpy(buffer, "Unknown Error", sizeof(buffer)); 02252 } 02253 else 02254 strlcpy(buffer, strerror(e), sizeof(buffer)); 02255 02256 p = buffer; 02257 while ((p = strpbrk(p, "\r\n")) != NULL) { 02258 memmove(p, p + 1, strlen(p)); 02259 } 02260 return buffer; 02261 } 02262 02263 // 02264 // various stubs 02265 // 02266 02267 02268 // Ownership 02269 // 02270 // Just pretend that everyone is a superuser. NT will let us know if 02271 // we don't really have permission to do something. 02272 // 02273 02274 #define ROOT_UID 0 02275 #define ROOT_GID 0 02276 02277 rb_uid_t 02278 getuid(void) 02279 { 02280 return ROOT_UID; 02281 } 02282 02283 rb_uid_t 02284 geteuid(void) 02285 { 02286 return ROOT_UID; 02287 } 02288 02289 rb_gid_t 02290 getgid(void) 02291 { 02292 return ROOT_GID; 02293 } 02294 02295 rb_gid_t 02296 getegid(void) 02297 { 02298 return ROOT_GID; 02299 } 02300 02301 int 02302 setuid(rb_uid_t uid) 02303 { 02304 return (uid == ROOT_UID ? 0 : -1); 02305 } 02306 02307 int 02308 setgid(rb_gid_t gid) 02309 { 02310 return (gid == ROOT_GID ? 0 : -1); 02311 } 02312 02313 // 02314 // File system stuff 02315 // 02316 02317 int 02318 ioctl(int i, int u, ...) 02319 { 02320 errno = EINVAL; 02321 return -1; 02322 } 02323 02324 void 02325 rb_w32_fdset(int fd, fd_set *set) 02326 { 02327 FD_SET(fd, set); 02328 } 02329 02330 #undef FD_CLR 02331 02332 void 02333 rb_w32_fdclr(int fd, fd_set *set) 02334 { 02335 unsigned int i; 02336 SOCKET s = TO_SOCKET(fd); 02337 02338 for (i = 0; i < set->fd_count; i++) { 02339 if (set->fd_array[i] == s) { 02340 memmove(&set->fd_array[i], &set->fd_array[i+1], 02341 sizeof(set->fd_array[0]) * (--set->fd_count - i)); 02342 break; 02343 } 02344 } 02345 } 02346 02347 #undef FD_ISSET 02348 02349 int 02350 rb_w32_fdisset(int fd, fd_set *set) 02351 { 02352 int ret; 02353 SOCKET s = TO_SOCKET(fd); 02354 if (s == (SOCKET)INVALID_HANDLE_VALUE) 02355 return 0; 02356 RUBY_CRITICAL(ret = __WSAFDIsSet(s, set)); 02357 return ret; 02358 } 02359 02360 void 02361 rb_w32_fd_copy(rb_fdset_t *dst, const fd_set *src, int max) 02362 { 02363 max = min(src->fd_count, (UINT)max); 02364 if ((UINT)dst->capa < (UINT)max) { 02365 dst->capa = (src->fd_count / FD_SETSIZE + 1) * FD_SETSIZE; 02366 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa); 02367 } 02368 02369 memcpy(dst->fdset->fd_array, src->fd_array, 02370 max * sizeof(src->fd_array[0])); 02371 dst->fdset->fd_count = src->fd_count; 02372 } 02373 02374 /* License: Ruby's */ 02375 void 02376 rb_w32_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src) 02377 { 02378 if ((UINT)dst->capa < src->fdset->fd_count) { 02379 dst->capa = (src->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE; 02380 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa); 02381 } 02382 02383 memcpy(dst->fdset->fd_array, src->fdset->fd_array, 02384 src->fdset->fd_count * sizeof(src->fdset->fd_array[0])); 02385 dst->fdset->fd_count = src->fdset->fd_count; 02386 } 02387 02388 // 02389 // Networking trampolines 02390 // These are used to avoid socket startup/shutdown overhead in case 02391 // the socket routines aren't used. 02392 // 02393 02394 #undef select 02395 02396 static int 02397 extract_fd(rb_fdset_t *dst, fd_set *src, int (*func)(SOCKET)) 02398 { 02399 unsigned int s = 0; 02400 unsigned int m = 0; 02401 if (!src) return 0; 02402 02403 while (s < src->fd_count) { 02404 SOCKET fd = src->fd_array[s]; 02405 02406 if (!func || (*func)(fd)) { 02407 if (dst) { /* move it to dst */ 02408 unsigned int d; 02409 02410 for (d = 0; d < dst->fdset->fd_count; d++) { 02411 if (dst->fdset->fd_array[d] == fd) 02412 break; 02413 } 02414 if (d == dst->fdset->fd_count) { 02415 if ((int)dst->fdset->fd_count >= dst->capa) { 02416 dst->capa = (dst->fdset->fd_count / FD_SETSIZE + 1) * FD_SETSIZE; 02417 dst->fdset = xrealloc(dst->fdset, sizeof(unsigned int) + sizeof(SOCKET) * dst->capa); 02418 } 02419 dst->fdset->fd_array[dst->fdset->fd_count++] = fd; 02420 } 02421 memmove( 02422 &src->fd_array[s], 02423 &src->fd_array[s+1], 02424 sizeof(src->fd_array[0]) * (--src->fd_count - s)); 02425 } 02426 else { 02427 m++; 02428 s++; 02429 } 02430 } 02431 else s++; 02432 } 02433 02434 return dst ? dst->fdset->fd_count : m; 02435 } 02436 02437 static int 02438 copy_fd(fd_set *dst, fd_set *src) 02439 { 02440 unsigned int s; 02441 if (!src || !dst) return 0; 02442 02443 for (s = 0; s < src->fd_count; ++s) { 02444 SOCKET fd = src->fd_array[s]; 02445 unsigned int d; 02446 for (d = 0; d < dst->fd_count; ++d) { 02447 if (dst->fd_array[d] == fd) 02448 break; 02449 } 02450 if (d == dst->fd_count && d < FD_SETSIZE) { 02451 dst->fd_array[dst->fd_count++] = fd; 02452 } 02453 } 02454 02455 return dst->fd_count; 02456 } 02457 02458 static int 02459 is_not_socket(SOCKET sock) 02460 { 02461 return !is_socket(sock); 02462 } 02463 02464 static int 02465 is_pipe(SOCKET sock) /* DONT call this for SOCKET! it clains it is PIPE. */ 02466 { 02467 int ret; 02468 02469 RUBY_CRITICAL({ 02470 ret = (GetFileType((HANDLE)sock) == FILE_TYPE_PIPE); 02471 }); 02472 02473 return ret; 02474 } 02475 02476 static int 02477 is_readable_pipe(SOCKET sock) /* call this for pipe only */ 02478 { 02479 int ret; 02480 DWORD n = 0; 02481 02482 RUBY_CRITICAL( 02483 if (PeekNamedPipe((HANDLE)sock, NULL, 0, NULL, &n, NULL)) { 02484 ret = (n > 0); 02485 } 02486 else { 02487 ret = (GetLastError() == ERROR_BROKEN_PIPE); /* pipe was closed */ 02488 } 02489 ); 02490 02491 return ret; 02492 } 02493 02494 static int 02495 is_console(SOCKET sock) /* DONT call this for SOCKET! */ 02496 { 02497 int ret; 02498 DWORD n = 0; 02499 INPUT_RECORD ir; 02500 02501 RUBY_CRITICAL( 02502 ret = (PeekConsoleInput((HANDLE)sock, &ir, 1, &n)) 02503 ); 02504 02505 return ret; 02506 } 02507 02508 static int 02509 is_readable_console(SOCKET sock) /* call this for console only */ 02510 { 02511 int ret = 0; 02512 DWORD n = 0; 02513 INPUT_RECORD ir; 02514 02515 RUBY_CRITICAL( 02516 if (PeekConsoleInput((HANDLE)sock, &ir, 1, &n) && n > 0) { 02517 if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown && 02518 ir.Event.KeyEvent.uChar.AsciiChar) { 02519 ret = 1; 02520 } 02521 else { 02522 ReadConsoleInput((HANDLE)sock, &ir, 1, &n); 02523 } 02524 } 02525 ); 02526 02527 return ret; 02528 } 02529 02530 static int 02531 is_invalid_handle(SOCKET sock) 02532 { 02533 return (HANDLE)sock == INVALID_HANDLE_VALUE; 02534 } 02535 02536 static int 02537 do_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, 02538 struct timeval *timeout) 02539 { 02540 int r = 0; 02541 02542 if (nfds == 0) { 02543 if (timeout) 02544 rb_w32_sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000); 02545 else 02546 rb_w32_sleep(INFINITE); 02547 } 02548 else { 02549 RUBY_CRITICAL( 02550 EnterCriticalSection(&select_mutex); 02551 r = select(nfds, rd, wr, ex, timeout); 02552 LeaveCriticalSection(&select_mutex); 02553 if (r == SOCKET_ERROR) { 02554 errno = map_errno(WSAGetLastError()); 02555 r = -1; 02556 } 02557 ); 02558 } 02559 02560 return r; 02561 } 02562 02563 /* 02564 * rest -= wait 02565 * return 0 if rest is smaller than wait. 02566 */ 02567 int 02568 rb_w32_time_subtract(struct timeval *rest, const struct timeval *wait) 02569 { 02570 if (rest->tv_sec < wait->tv_sec) { 02571 return 0; 02572 } 02573 while (rest->tv_usec < wait->tv_usec) { 02574 if (rest->tv_sec <= wait->tv_sec) { 02575 return 0; 02576 } 02577 rest->tv_sec -= 1; 02578 rest->tv_usec += 1000 * 1000; 02579 } 02580 rest->tv_sec -= wait->tv_sec; 02581 rest->tv_usec -= wait->tv_usec; 02582 return rest->tv_sec != 0 || rest->tv_usec != 0; 02583 } 02584 02585 static inline int 02586 compare(const struct timeval *t1, const struct timeval *t2) 02587 { 02588 if (t1->tv_sec < t2->tv_sec) 02589 return -1; 02590 if (t1->tv_sec > t2->tv_sec) 02591 return 1; 02592 if (t1->tv_usec < t2->tv_usec) 02593 return -1; 02594 if (t1->tv_usec > t2->tv_usec) 02595 return 1; 02596 return 0; 02597 } 02598 02599 #undef Sleep 02600 02601 int rb_w32_check_interrupt(void *); /* @internal */ 02602 02603 /* @internal */ 02604 int 02605 rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, 02606 struct timeval *timeout, void *th) 02607 { 02608 int r; 02609 rb_fdset_t pipe_rd; 02610 rb_fdset_t cons_rd; 02611 rb_fdset_t else_rd; 02612 rb_fdset_t else_wr; 02613 rb_fdset_t except; 02614 int nonsock = 0; 02615 struct timeval limit = {0, 0}; 02616 02617 if (nfds < 0 || (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))) { 02618 errno = EINVAL; 02619 return -1; 02620 } 02621 02622 if (timeout) { 02623 if (timeout->tv_sec < 0 || 02624 timeout->tv_usec < 0 || 02625 timeout->tv_usec >= 1000000) { 02626 errno = EINVAL; 02627 return -1; 02628 } 02629 gettimeofday(&limit, NULL); 02630 limit.tv_sec += timeout->tv_sec; 02631 limit.tv_usec += timeout->tv_usec; 02632 if (limit.tv_usec >= 1000000) { 02633 limit.tv_usec -= 1000000; 02634 limit.tv_sec++; 02635 } 02636 } 02637 02638 if (!NtSocketsInitialized) { 02639 StartSockets(); 02640 } 02641 02642 // assume else_{rd,wr} (other than socket, pipe reader, console reader) 02643 // are always readable/writable. but this implementation still has 02644 // problem. if pipe's buffer is full, writing to pipe will block 02645 // until some data is read from pipe. but ruby is single threaded system, 02646 // so whole system will be blocked forever. 02647 02648 rb_fd_init(&else_rd); 02649 nonsock += extract_fd(&else_rd, rd, is_not_socket); 02650 02651 rb_fd_init(&else_wr); 02652 nonsock += extract_fd(&else_wr, wr, is_not_socket); 02653 02654 // check invalid handles 02655 if (extract_fd(NULL, else_rd.fdset, is_invalid_handle) > 0 || 02656 extract_fd(NULL, else_wr.fdset, is_invalid_handle) > 0) { 02657 rb_fd_term(&else_wr); 02658 rb_fd_term(&else_rd); 02659 errno = EBADF; 02660 return -1; 02661 } 02662 02663 rb_fd_init(&pipe_rd); 02664 extract_fd(&pipe_rd, else_rd.fdset, is_pipe); // should not call is_pipe for socket 02665 02666 rb_fd_init(&cons_rd); 02667 extract_fd(&cons_rd, else_rd.fdset, is_console); // ditto 02668 02669 rb_fd_init(&except); 02670 extract_fd(&except, ex, is_not_socket); // drop only 02671 02672 r = 0; 02673 if (rd && (int)rd->fd_count > r) r = (int)rd->fd_count; 02674 if (wr && (int)wr->fd_count > r) r = (int)wr->fd_count; 02675 if (ex && (int)ex->fd_count > r) r = (int)ex->fd_count; 02676 if (nfds > r) nfds = r; 02677 02678 { 02679 struct timeval rest; 02680 struct timeval wait; 02681 struct timeval zero; 02682 wait.tv_sec = 0; wait.tv_usec = 10 * 1000; // 10ms 02683 zero.tv_sec = 0; zero.tv_usec = 0; // 0ms 02684 for (;;) { 02685 if (th && rb_w32_check_interrupt(th) != WAIT_TIMEOUT) { 02686 r = -1; 02687 break; 02688 } 02689 if (nonsock) { 02690 // modifying {else,pipe,cons}_rd is safe because 02691 // if they are modified, function returns immediately. 02692 extract_fd(&else_rd, pipe_rd.fdset, is_readable_pipe); 02693 extract_fd(&else_rd, cons_rd.fdset, is_readable_console); 02694 } 02695 02696 if (else_rd.fdset->fd_count || else_wr.fdset->fd_count) { 02697 r = do_select(nfds, rd, wr, ex, &zero); // polling 02698 if (r < 0) break; // XXX: should I ignore error and return signaled handles? 02699 r += copy_fd(rd, else_rd.fdset); 02700 r += copy_fd(wr, else_wr.fdset); 02701 if (ex) 02702 r += ex->fd_count; 02703 break; 02704 } 02705 else { 02706 struct timeval *dowait = &wait; 02707 02708 fd_set orig_rd; 02709 fd_set orig_wr; 02710 fd_set orig_ex; 02711 02712 FD_ZERO(&orig_rd); 02713 FD_ZERO(&orig_wr); 02714 FD_ZERO(&orig_ex); 02715 02716 if (rd) copy_fd(&orig_rd, rd); 02717 if (wr) copy_fd(&orig_wr, wr); 02718 if (ex) copy_fd(&orig_ex, ex); 02719 r = do_select(nfds, rd, wr, ex, &zero); // polling 02720 if (r != 0) break; // signaled or error 02721 if (rd) copy_fd(rd, &orig_rd); 02722 if (wr) copy_fd(wr, &orig_wr); 02723 if (ex) copy_fd(ex, &orig_ex); 02724 02725 if (timeout) { 02726 struct timeval now; 02727 gettimeofday(&now, NULL); 02728 rest = limit; 02729 if (!rb_w32_time_subtract(&rest, &now)) break; 02730 if (compare(&rest, &wait) < 0) dowait = &rest; 02731 } 02732 Sleep(dowait->tv_sec * 1000 + dowait->tv_usec / 1000); 02733 } 02734 } 02735 } 02736 02737 rb_fd_term(&except); 02738 rb_fd_term(&cons_rd); 02739 rb_fd_term(&pipe_rd); 02740 rb_fd_term(&else_wr); 02741 rb_fd_term(&else_rd); 02742 02743 return r; 02744 } 02745 02746 int WSAAPI 02747 rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, 02748 struct timeval *timeout) 02749 { 02750 return rb_w32_select_with_thread(nfds, rd, wr, ex, timeout, 0); 02751 } 02752 02753 static FARPROC 02754 get_wsa_extension_function(SOCKET s, GUID *guid) 02755 { 02756 DWORD dmy; 02757 FARPROC ptr = NULL; 02758 02759 WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, guid, sizeof(*guid), 02760 &ptr, sizeof(ptr), &dmy, NULL, NULL); 02761 if (!ptr) 02762 errno = ENOSYS; 02763 return ptr; 02764 } 02765 02766 #undef accept 02767 02768 int WSAAPI 02769 rb_w32_accept(int s, struct sockaddr *addr, int *addrlen) 02770 { 02771 SOCKET r; 02772 int fd; 02773 02774 if (!NtSocketsInitialized) { 02775 StartSockets(); 02776 } 02777 RUBY_CRITICAL({ 02778 HANDLE h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 02779 fd = rb_w32_open_osfhandle((intptr_t)h, O_RDWR|O_BINARY|O_NOINHERIT); 02780 if (fd != -1) { 02781 r = accept(TO_SOCKET(s), addr, addrlen); 02782 if (r != INVALID_SOCKET) { 02783 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 02784 _set_osfhnd(fd, r); 02785 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 02786 CloseHandle(h); 02787 st_insert(socklist, (st_data_t)r, (st_data_t)0); 02788 } 02789 else { 02790 errno = map_errno(WSAGetLastError()); 02791 close(fd); 02792 fd = -1; 02793 } 02794 } 02795 else 02796 CloseHandle(h); 02797 }); 02798 return fd; 02799 } 02800 02801 #undef bind 02802 02803 int WSAAPI 02804 rb_w32_bind(int s, const struct sockaddr *addr, int addrlen) 02805 { 02806 int r; 02807 02808 if (!NtSocketsInitialized) { 02809 StartSockets(); 02810 } 02811 RUBY_CRITICAL({ 02812 r = bind(TO_SOCKET(s), addr, addrlen); 02813 if (r == SOCKET_ERROR) 02814 errno = map_errno(WSAGetLastError()); 02815 }); 02816 return r; 02817 } 02818 02819 #undef connect 02820 02821 int WSAAPI 02822 rb_w32_connect(int s, const struct sockaddr *addr, int addrlen) 02823 { 02824 int r; 02825 if (!NtSocketsInitialized) { 02826 StartSockets(); 02827 } 02828 RUBY_CRITICAL({ 02829 r = connect(TO_SOCKET(s), addr, addrlen); 02830 if (r == SOCKET_ERROR) { 02831 int err = WSAGetLastError(); 02832 if (err != WSAEWOULDBLOCK) 02833 errno = map_errno(err); 02834 else 02835 errno = EINPROGRESS; 02836 } 02837 }); 02838 return r; 02839 } 02840 02841 02842 #undef getpeername 02843 02844 int WSAAPI 02845 rb_w32_getpeername(int s, struct sockaddr *addr, int *addrlen) 02846 { 02847 int r; 02848 if (!NtSocketsInitialized) { 02849 StartSockets(); 02850 } 02851 RUBY_CRITICAL({ 02852 r = getpeername(TO_SOCKET(s), addr, addrlen); 02853 if (r == SOCKET_ERROR) 02854 errno = map_errno(WSAGetLastError()); 02855 }); 02856 return r; 02857 } 02858 02859 #undef getsockname 02860 02861 int WSAAPI 02862 rb_w32_getsockname(int s, struct sockaddr *addr, int *addrlen) 02863 { 02864 int r; 02865 if (!NtSocketsInitialized) { 02866 StartSockets(); 02867 } 02868 RUBY_CRITICAL({ 02869 r = getsockname(TO_SOCKET(s), addr, addrlen); 02870 if (r == SOCKET_ERROR) 02871 errno = map_errno(WSAGetLastError()); 02872 }); 02873 return r; 02874 } 02875 02876 int WSAAPI 02877 rb_w32_getsockopt(int s, int level, int optname, char *optval, int *optlen) 02878 { 02879 int r; 02880 if (!NtSocketsInitialized) { 02881 StartSockets(); 02882 } 02883 RUBY_CRITICAL({ 02884 r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen); 02885 if (r == SOCKET_ERROR) 02886 errno = map_errno(WSAGetLastError()); 02887 }); 02888 return r; 02889 } 02890 02891 #undef ioctlsocket 02892 02893 int WSAAPI 02894 rb_w32_ioctlsocket(int s, long cmd, u_long *argp) 02895 { 02896 int r; 02897 if (!NtSocketsInitialized) { 02898 StartSockets(); 02899 } 02900 RUBY_CRITICAL({ 02901 r = ioctlsocket(TO_SOCKET(s), cmd, argp); 02902 if (r == SOCKET_ERROR) 02903 errno = map_errno(WSAGetLastError()); 02904 }); 02905 return r; 02906 } 02907 02908 #undef listen 02909 02910 int WSAAPI 02911 rb_w32_listen(int s, int backlog) 02912 { 02913 int r; 02914 if (!NtSocketsInitialized) { 02915 StartSockets(); 02916 } 02917 RUBY_CRITICAL({ 02918 r = listen(TO_SOCKET(s), backlog); 02919 if (r == SOCKET_ERROR) 02920 errno = map_errno(WSAGetLastError()); 02921 }); 02922 return r; 02923 } 02924 02925 #undef recv 02926 #undef recvfrom 02927 #undef send 02928 #undef sendto 02929 02930 static int 02931 finish_overlapped_socket(SOCKET s, WSAOVERLAPPED *wol, int result, DWORD *len, DWORD size) 02932 { 02933 DWORD flg; 02934 int err; 02935 02936 if (result != SOCKET_ERROR) 02937 *len = size; 02938 else if ((err = WSAGetLastError()) == WSA_IO_PENDING) { 02939 switch (rb_w32_wait_events_blocking(&wol->hEvent, 1, INFINITE)) { 02940 case WAIT_OBJECT_0: 02941 RUBY_CRITICAL( 02942 result = WSAGetOverlappedResult(s, wol, &size, TRUE, &flg) 02943 ); 02944 if (result) { 02945 *len = size; 02946 break; 02947 } 02948 /* thru */ 02949 default: 02950 errno = map_errno(WSAGetLastError()); 02951 /* thru */ 02952 case WAIT_OBJECT_0 + 1: 02953 /* interrupted */ 02954 *len = -1; 02955 cancel_io((HANDLE)s); 02956 break; 02957 } 02958 } 02959 else { 02960 errno = map_errno(err); 02961 *len = -1; 02962 } 02963 CloseHandle(wol->hEvent); 02964 02965 return result; 02966 } 02967 02968 static int 02969 overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags, 02970 struct sockaddr *addr, int *addrlen) 02971 { 02972 int r; 02973 int ret; 02974 int mode; 02975 st_data_t data; 02976 DWORD flg; 02977 WSAOVERLAPPED wol; 02978 WSABUF wbuf; 02979 SOCKET s; 02980 02981 if (!NtSocketsInitialized) 02982 StartSockets(); 02983 02984 s = TO_SOCKET(fd); 02985 st_lookup(socklist, (st_data_t)s, &data); 02986 mode = (int)data; 02987 if (!cancel_io || (mode & O_NONBLOCK)) { 02988 RUBY_CRITICAL({ 02989 if (input) { 02990 if (addr && addrlen) 02991 r = recvfrom(s, buf, len, flags, addr, addrlen); 02992 else 02993 r = recv(s, buf, len, flags); 02994 } 02995 else { 02996 if (addr && addrlen) 02997 r = sendto(s, buf, len, flags, addr, *addrlen); 02998 else 02999 r = send(s, buf, len, flags); 03000 } 03001 if (r == SOCKET_ERROR) 03002 errno = map_errno(WSAGetLastError()); 03003 }); 03004 } 03005 else { 03006 DWORD size; 03007 DWORD rlen; 03008 wbuf.len = len; 03009 wbuf.buf = buf; 03010 memset(&wol, 0, sizeof(wol)); 03011 RUBY_CRITICAL({ 03012 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 03013 if (input) { 03014 flg = flags; 03015 if (addr && addrlen) 03016 ret = WSARecvFrom(s, &wbuf, 1, &size, &flg, addr, addrlen, 03017 &wol, NULL); 03018 else 03019 ret = WSARecv(s, &wbuf, 1, &size, &flg, &wol, NULL); 03020 } 03021 else { 03022 if (addr && addrlen) 03023 ret = WSASendTo(s, &wbuf, 1, &size, flags, addr, *addrlen, 03024 &wol, NULL); 03025 else 03026 ret = WSASend(s, &wbuf, 1, &size, flags, &wol, NULL); 03027 } 03028 }); 03029 03030 finish_overlapped_socket(s, &wol, ret, &rlen, size); 03031 r = (int)rlen; 03032 } 03033 03034 return r; 03035 } 03036 03037 int WSAAPI 03038 rb_w32_recv(int fd, char *buf, int len, int flags) 03039 { 03040 return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL); 03041 } 03042 03043 int WSAAPI 03044 rb_w32_recvfrom(int fd, char *buf, int len, int flags, 03045 struct sockaddr *from, int *fromlen) 03046 { 03047 return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen); 03048 } 03049 03050 int WSAAPI 03051 rb_w32_send(int fd, const char *buf, int len, int flags) 03052 { 03053 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL); 03054 } 03055 03056 int WSAAPI 03057 rb_w32_sendto(int fd, const char *buf, int len, int flags, 03058 const struct sockaddr *to, int tolen) 03059 { 03060 return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, 03061 (struct sockaddr *)to, &tolen); 03062 } 03063 03064 #if !defined(MSG_TRUNC) && !defined(__MINGW32__) 03065 typedef struct { 03066 SOCKADDR *name; 03067 int namelen; 03068 WSABUF *lpBuffers; 03069 DWORD dwBufferCount; 03070 WSABUF Control; 03071 DWORD dwFlags; 03072 } WSAMSG; 03073 #endif 03074 #ifndef WSAID_WSARECVMSG 03075 #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} 03076 #endif 03077 #ifndef WSAID_WSASENDMSG 03078 #define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}} 03079 #endif 03080 03081 #define msghdr_to_wsamsg(msg, wsamsg) \ 03082 do { \ 03083 int i; \ 03084 (wsamsg)->name = (msg)->msg_name; \ 03085 (wsamsg)->namelen = (msg)->msg_namelen; \ 03086 (wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \ 03087 (wsamsg)->dwBufferCount = (msg)->msg_iovlen; \ 03088 for (i = 0; i < (msg)->msg_iovlen; ++i) { \ 03089 (wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \ 03090 (wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \ 03091 } \ 03092 (wsamsg)->Control.buf = (msg)->msg_control; \ 03093 (wsamsg)->Control.len = (msg)->msg_controllen; \ 03094 (wsamsg)->dwFlags = (msg)->msg_flags; \ 03095 } while (0) 03096 03097 int 03098 recvmsg(int fd, struct msghdr *msg, int flags) 03099 { 03100 typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE); 03101 static WSARecvMsg_t pWSARecvMsg = NULL; 03102 WSAMSG wsamsg; 03103 SOCKET s; 03104 st_data_t data; 03105 int mode; 03106 DWORD len; 03107 int ret; 03108 03109 if (!NtSocketsInitialized) 03110 StartSockets(); 03111 03112 s = TO_SOCKET(fd); 03113 03114 if (!pWSARecvMsg) { 03115 static GUID guid = WSAID_WSARECVMSG; 03116 pWSARecvMsg = (WSARecvMsg_t)get_wsa_extension_function(s, &guid); 03117 if (!pWSARecvMsg) 03118 return -1; 03119 } 03120 03121 msghdr_to_wsamsg(msg, &wsamsg); 03122 wsamsg.dwFlags |= flags; 03123 03124 st_lookup(socklist, (st_data_t)s, &data); 03125 mode = (int)data; 03126 if (!cancel_io || (mode & O_NONBLOCK)) { 03127 RUBY_CRITICAL({ 03128 if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) { 03129 errno = map_errno(WSAGetLastError()); 03130 len = -1; 03131 } 03132 }); 03133 } 03134 else { 03135 DWORD size; 03136 WSAOVERLAPPED wol; 03137 memset(&wol, 0, sizeof(wol)); 03138 RUBY_CRITICAL({ 03139 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 03140 ret = pWSARecvMsg(s, &wsamsg, &size, &wol, NULL); 03141 }); 03142 03143 ret = finish_overlapped_socket(s, &wol, ret, &len, size); 03144 } 03145 if (ret == SOCKET_ERROR) 03146 return -1; 03147 03148 /* WSAMSG to msghdr */ 03149 msg->msg_name = wsamsg.name; 03150 msg->msg_namelen = wsamsg.namelen; 03151 msg->msg_flags = wsamsg.dwFlags; 03152 03153 return len; 03154 } 03155 03156 int 03157 sendmsg(int fd, const struct msghdr *msg, int flags) 03158 { 03159 typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE); 03160 static WSASendMsg_t pWSASendMsg = NULL; 03161 WSAMSG wsamsg; 03162 SOCKET s; 03163 st_data_t data; 03164 int mode; 03165 DWORD len; 03166 int ret; 03167 03168 if (!NtSocketsInitialized) 03169 StartSockets(); 03170 03171 s = TO_SOCKET(fd); 03172 03173 if (!pWSASendMsg) { 03174 static GUID guid = WSAID_WSASENDMSG; 03175 pWSASendMsg = (WSASendMsg_t)get_wsa_extension_function(s, &guid); 03176 if (!pWSASendMsg) 03177 return -1; 03178 } 03179 03180 msghdr_to_wsamsg(msg, &wsamsg); 03181 03182 st_lookup(socklist, (st_data_t)s, &data); 03183 mode = (int)data; 03184 if (!cancel_io || (mode & O_NONBLOCK)) { 03185 RUBY_CRITICAL({ 03186 if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) { 03187 errno = map_errno(WSAGetLastError()); 03188 len = -1; 03189 } 03190 }); 03191 } 03192 else { 03193 DWORD size; 03194 WSAOVERLAPPED wol; 03195 memset(&wol, 0, sizeof(wol)); 03196 RUBY_CRITICAL({ 03197 wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 03198 ret = pWSASendMsg(s, &wsamsg, flags, &size, &wol, NULL); 03199 }); 03200 03201 finish_overlapped_socket(s, &wol, ret, &len, size); 03202 } 03203 03204 return len; 03205 } 03206 03207 #undef setsockopt 03208 03209 int WSAAPI 03210 rb_w32_setsockopt(int s, int level, int optname, const char *optval, int optlen) 03211 { 03212 int r; 03213 if (!NtSocketsInitialized) { 03214 StartSockets(); 03215 } 03216 RUBY_CRITICAL({ 03217 r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen); 03218 if (r == SOCKET_ERROR) 03219 errno = map_errno(WSAGetLastError()); 03220 }); 03221 return r; 03222 } 03223 03224 #undef shutdown 03225 03226 int WSAAPI 03227 rb_w32_shutdown(int s, int how) 03228 { 03229 int r; 03230 if (!NtSocketsInitialized) { 03231 StartSockets(); 03232 } 03233 RUBY_CRITICAL({ 03234 r = shutdown(TO_SOCKET(s), how); 03235 if (r == SOCKET_ERROR) 03236 errno = map_errno(WSAGetLastError()); 03237 }); 03238 return r; 03239 } 03240 03241 static SOCKET 03242 open_ifs_socket(int af, int type, int protocol) 03243 { 03244 unsigned long proto_buffers_len = 0; 03245 int error_code; 03246 SOCKET out = INVALID_SOCKET; 03247 03248 if (WSAEnumProtocols(NULL, NULL, &proto_buffers_len) == SOCKET_ERROR) { 03249 error_code = WSAGetLastError(); 03250 if (error_code == WSAENOBUFS) { 03251 WSAPROTOCOL_INFO *proto_buffers; 03252 int protocols_available = 0; 03253 03254 proto_buffers = (WSAPROTOCOL_INFO *)malloc(proto_buffers_len); 03255 if (!proto_buffers) { 03256 WSASetLastError(WSA_NOT_ENOUGH_MEMORY); 03257 return INVALID_SOCKET; 03258 } 03259 03260 protocols_available = 03261 WSAEnumProtocols(NULL, proto_buffers, &proto_buffers_len); 03262 if (protocols_available != SOCKET_ERROR) { 03263 int i; 03264 for (i = 0; i < protocols_available; i++) { 03265 if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) || 03266 (type != proto_buffers[i].iSocketType) || 03267 (protocol != 0 && protocol != proto_buffers[i].iProtocol)) 03268 continue; 03269 03270 if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0) 03271 continue; 03272 03273 out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0, 03274 WSA_FLAG_OVERLAPPED); 03275 break; 03276 } 03277 if (out == INVALID_SOCKET) 03278 out = WSASocket(af, type, protocol, NULL, 0, 0); 03279 } 03280 03281 free(proto_buffers); 03282 } 03283 } 03284 03285 return out; 03286 } 03287 03288 #undef socket 03289 03290 int WSAAPI 03291 rb_w32_socket(int af, int type, int protocol) 03292 { 03293 SOCKET s; 03294 int fd; 03295 03296 if (!NtSocketsInitialized) { 03297 StartSockets(); 03298 } 03299 RUBY_CRITICAL({ 03300 s = open_ifs_socket(af, type, protocol); 03301 if (s == INVALID_SOCKET) { 03302 errno = map_errno(WSAGetLastError()); 03303 fd = -1; 03304 } 03305 else { 03306 fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT); 03307 if (fd != -1) 03308 st_insert(socklist, (st_data_t)s, (st_data_t)0); 03309 else 03310 closesocket(s); 03311 } 03312 }); 03313 return fd; 03314 } 03315 03316 #undef gethostbyaddr 03317 03318 struct hostent * WSAAPI 03319 rb_w32_gethostbyaddr(const char *addr, int len, int type) 03320 { 03321 struct hostent *r; 03322 if (!NtSocketsInitialized) { 03323 StartSockets(); 03324 } 03325 RUBY_CRITICAL({ 03326 r = gethostbyaddr(addr, len, type); 03327 if (r == NULL) 03328 errno = map_errno(WSAGetLastError()); 03329 }); 03330 return r; 03331 } 03332 03333 #undef gethostbyname 03334 03335 struct hostent * WSAAPI 03336 rb_w32_gethostbyname(const char *name) 03337 { 03338 struct hostent *r; 03339 if (!NtSocketsInitialized) { 03340 StartSockets(); 03341 } 03342 RUBY_CRITICAL({ 03343 r = gethostbyname(name); 03344 if (r == NULL) 03345 errno = map_errno(WSAGetLastError()); 03346 }); 03347 return r; 03348 } 03349 03350 #undef gethostname 03351 03352 int WSAAPI 03353 rb_w32_gethostname(char *name, int len) 03354 { 03355 int r; 03356 if (!NtSocketsInitialized) { 03357 StartSockets(); 03358 } 03359 RUBY_CRITICAL({ 03360 r = gethostname(name, len); 03361 if (r == SOCKET_ERROR) 03362 errno = map_errno(WSAGetLastError()); 03363 }); 03364 return r; 03365 } 03366 03367 #undef getprotobyname 03368 03369 struct protoent * WSAAPI 03370 rb_w32_getprotobyname(const char *name) 03371 { 03372 struct protoent *r; 03373 if (!NtSocketsInitialized) { 03374 StartSockets(); 03375 } 03376 RUBY_CRITICAL({ 03377 r = getprotobyname(name); 03378 if (r == NULL) 03379 errno = map_errno(WSAGetLastError()); 03380 }); 03381 return r; 03382 } 03383 03384 #undef getprotobynumber 03385 03386 struct protoent * WSAAPI 03387 rb_w32_getprotobynumber(int num) 03388 { 03389 struct protoent *r; 03390 if (!NtSocketsInitialized) { 03391 StartSockets(); 03392 } 03393 RUBY_CRITICAL({ 03394 r = getprotobynumber(num); 03395 if (r == NULL) 03396 errno = map_errno(WSAGetLastError()); 03397 }); 03398 return r; 03399 } 03400 03401 #undef getservbyname 03402 03403 struct servent * WSAAPI 03404 rb_w32_getservbyname(const char *name, const char *proto) 03405 { 03406 struct servent *r; 03407 if (!NtSocketsInitialized) { 03408 StartSockets(); 03409 } 03410 RUBY_CRITICAL({ 03411 r = getservbyname(name, proto); 03412 if (r == NULL) 03413 errno = map_errno(WSAGetLastError()); 03414 }); 03415 return r; 03416 } 03417 03418 #undef getservbyport 03419 03420 struct servent * WSAAPI 03421 rb_w32_getservbyport(int port, const char *proto) 03422 { 03423 struct servent *r; 03424 if (!NtSocketsInitialized) { 03425 StartSockets(); 03426 } 03427 RUBY_CRITICAL({ 03428 r = getservbyport(port, proto); 03429 if (r == NULL) 03430 errno = map_errno(WSAGetLastError()); 03431 }); 03432 return r; 03433 } 03434 03435 static int 03436 socketpair_internal(int af, int type, int protocol, SOCKET *sv) 03437 { 03438 SOCKET svr = INVALID_SOCKET, r = INVALID_SOCKET, w = INVALID_SOCKET; 03439 struct sockaddr_in sock_in4; 03440 #ifdef INET6 03441 struct sockaddr_in6 sock_in6; 03442 #endif 03443 struct sockaddr *addr; 03444 int ret = -1; 03445 int len; 03446 03447 if (!NtSocketsInitialized) { 03448 StartSockets(); 03449 } 03450 03451 switch (af) { 03452 case AF_INET: 03453 #if defined PF_INET && PF_INET != AF_INET 03454 case PF_INET: 03455 #endif 03456 sock_in4.sin_family = AF_INET; 03457 sock_in4.sin_port = 0; 03458 sock_in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 03459 addr = (struct sockaddr *)&sock_in4; 03460 len = sizeof(sock_in4); 03461 break; 03462 #ifdef INET6 03463 case AF_INET6: 03464 memset(&sock_in6, 0, sizeof(sock_in6)); 03465 sock_in6.sin6_family = AF_INET6; 03466 sock_in6.sin6_addr = IN6ADDR_LOOPBACK_INIT; 03467 addr = (struct sockaddr *)&sock_in6; 03468 len = sizeof(sock_in6); 03469 break; 03470 #endif 03471 default: 03472 errno = EAFNOSUPPORT; 03473 return -1; 03474 } 03475 if (type != SOCK_STREAM) { 03476 errno = EPROTOTYPE; 03477 return -1; 03478 } 03479 03480 sv[0] = (SOCKET)INVALID_HANDLE_VALUE; 03481 sv[1] = (SOCKET)INVALID_HANDLE_VALUE; 03482 RUBY_CRITICAL({ 03483 do { 03484 svr = open_ifs_socket(af, type, protocol); 03485 if (svr == INVALID_SOCKET) 03486 break; 03487 if (bind(svr, addr, len) < 0) 03488 break; 03489 if (getsockname(svr, addr, &len) < 0) 03490 break; 03491 if (type == SOCK_STREAM) 03492 listen(svr, 5); 03493 03494 w = open_ifs_socket(af, type, protocol); 03495 if (w == INVALID_SOCKET) 03496 break; 03497 if (connect(w, addr, len) < 0) 03498 break; 03499 03500 r = accept(svr, addr, &len); 03501 if (r == INVALID_SOCKET) 03502 break; 03503 03504 ret = 0; 03505 } while (0); 03506 03507 if (ret < 0) { 03508 errno = map_errno(WSAGetLastError()); 03509 if (r != INVALID_SOCKET) 03510 closesocket(r); 03511 if (w != INVALID_SOCKET) 03512 closesocket(w); 03513 } 03514 else { 03515 sv[0] = r; 03516 sv[1] = w; 03517 } 03518 if (svr != INVALID_SOCKET) 03519 closesocket(svr); 03520 }); 03521 03522 return ret; 03523 } 03524 03525 int 03526 rb_w32_socketpair(int af, int type, int protocol, int *sv) 03527 { 03528 SOCKET pair[2]; 03529 03530 if (socketpair_internal(af, type, protocol, pair) < 0) 03531 return -1; 03532 sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT); 03533 if (sv[0] == -1) { 03534 closesocket(pair[0]); 03535 closesocket(pair[1]); 03536 return -1; 03537 } 03538 sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT); 03539 if (sv[1] == -1) { 03540 rb_w32_close(sv[0]); 03541 closesocket(pair[1]); 03542 return -1; 03543 } 03544 st_insert(socklist, (st_data_t)pair[0], (st_data_t)0); 03545 st_insert(socklist, (st_data_t)pair[1], (st_data_t)0); 03546 03547 return 0; 03548 } 03549 03550 // 03551 // Networking stubs 03552 // 03553 03554 void endhostent(void) {} 03555 void endnetent(void) {} 03556 void endprotoent(void) {} 03557 void endservent(void) {} 03558 03559 struct netent *getnetent (void) {return (struct netent *) NULL;} 03560 03561 struct netent *getnetbyaddr(long net, int type) {return (struct netent *)NULL;} 03562 03563 struct netent *getnetbyname(const char *name) {return (struct netent *)NULL;} 03564 03565 struct protoent *getprotoent (void) {return (struct protoent *) NULL;} 03566 03567 struct servent *getservent (void) {return (struct servent *) NULL;} 03568 03569 void sethostent (int stayopen) {} 03570 03571 void setnetent (int stayopen) {} 03572 03573 void setprotoent (int stayopen) {} 03574 03575 void setservent (int stayopen) {} 03576 03577 int 03578 fcntl(int fd, int cmd, ...) 03579 { 03580 SOCKET sock = TO_SOCKET(fd); 03581 va_list va; 03582 int arg; 03583 int ret; 03584 int flag = 0; 03585 st_data_t data; 03586 u_long ioctlArg; 03587 03588 if (!is_socket(sock)) { 03589 errno = EBADF; 03590 return -1; 03591 } 03592 if (cmd != F_SETFL) { 03593 errno = EINVAL; 03594 return -1; 03595 } 03596 03597 va_start(va, cmd); 03598 arg = va_arg(va, int); 03599 va_end(va); 03600 st_lookup(socklist, (st_data_t)sock, &data); 03601 flag = (int)data; 03602 if (arg & O_NONBLOCK) { 03603 flag |= O_NONBLOCK; 03604 ioctlArg = 1; 03605 } 03606 else { 03607 flag &= ~O_NONBLOCK; 03608 ioctlArg = 0; 03609 } 03610 RUBY_CRITICAL({ 03611 ret = ioctlsocket(sock, FIONBIO, &ioctlArg); 03612 if (ret == 0) 03613 st_insert(socklist, (st_data_t)sock, (st_data_t)flag); 03614 else 03615 errno = map_errno(WSAGetLastError()); 03616 }); 03617 03618 return ret; 03619 } 03620 03621 #ifndef WNOHANG 03622 #define WNOHANG -1 03623 #endif 03624 03625 static rb_pid_t 03626 poll_child_status(struct ChildRecord *child, int *stat_loc) 03627 { 03628 DWORD exitcode; 03629 DWORD err; 03630 03631 if (!GetExitCodeProcess(child->hProcess, &exitcode)) { 03632 /* If an error occured, return immediatly. */ 03633 error_exit: 03634 err = GetLastError(); 03635 if (err == ERROR_INVALID_PARAMETER) 03636 errno = ECHILD; 03637 else { 03638 if (GetLastError() == ERROR_INVALID_HANDLE) 03639 errno = EINVAL; 03640 else 03641 errno = map_errno(GetLastError()); 03642 } 03643 CloseChildHandle(child); 03644 return -1; 03645 } 03646 if (exitcode != STILL_ACTIVE) { 03647 rb_pid_t pid; 03648 /* If already died, wait process's real termination. */ 03649 if (rb_w32_wait_events_blocking(&child->hProcess, 1, INFINITE) != WAIT_OBJECT_0) { 03650 goto error_exit; 03651 } 03652 pid = child->pid; 03653 CloseChildHandle(child); 03654 if (stat_loc) *stat_loc = exitcode << 8; 03655 return pid; 03656 } 03657 return 0; 03658 } 03659 03660 rb_pid_t 03661 waitpid(rb_pid_t pid, int *stat_loc, int options) 03662 { 03663 DWORD timeout; 03664 03665 if (options == WNOHANG) { 03666 timeout = 0; 03667 } 03668 else { 03669 timeout = INFINITE; 03670 } 03671 03672 if (pid == -1) { 03673 int count = 0; 03674 int ret; 03675 HANDLE events[MAXCHILDNUM]; 03676 03677 FOREACH_CHILD(child) { 03678 if (!child->pid || child->pid < 0) continue; 03679 if ((pid = poll_child_status(child, stat_loc))) return pid; 03680 events[count++] = child->hProcess; 03681 } END_FOREACH_CHILD; 03682 if (!count) { 03683 errno = ECHILD; 03684 return -1; 03685 } 03686 03687 ret = rb_w32_wait_events_blocking(events, count, timeout); 03688 if (ret == WAIT_TIMEOUT) return 0; 03689 if ((ret -= WAIT_OBJECT_0) == count) { 03690 return -1; 03691 } 03692 if (ret > count) { 03693 errno = map_errno(GetLastError()); 03694 return -1; 03695 } 03696 03697 return poll_child_status(FindChildSlotByHandle(events[ret]), stat_loc); 03698 } 03699 else { 03700 struct ChildRecord* child = FindChildSlot(pid); 03701 if (!child) { 03702 errno = ECHILD; 03703 return -1; 03704 } 03705 03706 while (!(pid = poll_child_status(child, stat_loc))) { 03707 /* wait... */ 03708 if (rb_w32_wait_events_blocking(&child->hProcess, 1, timeout) != WAIT_OBJECT_0) { 03709 /* still active */ 03710 pid = 0; 03711 break; 03712 } 03713 } 03714 } 03715 03716 return pid; 03717 } 03718 03719 #include <sys/timeb.h> 03720 03721 static int 03722 filetime_to_timeval(const FILETIME* ft, struct timeval *tv) 03723 { 03724 ULARGE_INTEGER tmp; 03725 unsigned LONG_LONG lt; 03726 03727 tmp.LowPart = ft->dwLowDateTime; 03728 tmp.HighPart = ft->dwHighDateTime; 03729 lt = tmp.QuadPart; 03730 03731 /* lt is now 100-nanosec intervals since 1601/01/01 00:00:00 UTC, 03732 convert it into UNIX time (since 1970/01/01 00:00:00 UTC). 03733 the first leap second is at 1972/06/30, so we doesn't need to think 03734 about it. */ 03735 lt /= 10; /* to usec */ 03736 lt -= (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60 * 1000 * 1000; 03737 03738 tv->tv_sec = (long)(lt / (1000 * 1000)); 03739 tv->tv_usec = (long)(lt % (1000 * 1000)); 03740 03741 return tv->tv_sec > 0 ? 0 : -1; 03742 } 03743 03744 int _cdecl 03745 gettimeofday(struct timeval *tv, struct timezone *tz) 03746 { 03747 FILETIME ft; 03748 03749 GetSystemTimeAsFileTime(&ft); 03750 filetime_to_timeval(&ft, tv); 03751 03752 return 0; 03753 } 03754 03755 char * 03756 rb_w32_getcwd(char *buffer, int size) 03757 { 03758 char *p = buffer; 03759 int len; 03760 03761 len = GetCurrentDirectory(0, NULL); 03762 if (!len) { 03763 errno = map_errno(GetLastError()); 03764 return NULL; 03765 } 03766 03767 if (p) { 03768 if (size < len) { 03769 errno = ERANGE; 03770 return NULL; 03771 } 03772 } 03773 else { 03774 p = malloc(len); 03775 size = len; 03776 if (!p) { 03777 errno = ENOMEM; 03778 return NULL; 03779 } 03780 } 03781 03782 if (!GetCurrentDirectory(size, p)) { 03783 errno = map_errno(GetLastError()); 03784 if (!buffer) 03785 free(p); 03786 return NULL; 03787 } 03788 03789 translate_char(p, '\\', '/'); 03790 03791 return p; 03792 } 03793 03794 int 03795 chown(const char *path, int owner, int group) 03796 { 03797 return 0; 03798 } 03799 03800 int 03801 rb_w32_uchown(const char *path, int owner, int group) 03802 { 03803 return 0; 03804 } 03805 03806 int 03807 kill(int pid, int sig) 03808 { 03809 int ret = 0; 03810 DWORD err; 03811 03812 if (pid < 0 || pid == 0 && sig != SIGINT) { 03813 errno = EINVAL; 03814 return -1; 03815 } 03816 03817 (void)IfWin95(pid = -pid, 0); 03818 if ((unsigned int)pid == GetCurrentProcessId() && 03819 (sig != 0 && sig != SIGKILL)) { 03820 if ((ret = raise(sig)) != 0) { 03821 /* MSVCRT doesn't set errno... */ 03822 errno = EINVAL; 03823 } 03824 return ret; 03825 } 03826 03827 switch (sig) { 03828 case 0: 03829 RUBY_CRITICAL({ 03830 HANDLE hProc = 03831 OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid); 03832 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) { 03833 if (GetLastError() == ERROR_INVALID_PARAMETER) { 03834 errno = ESRCH; 03835 } 03836 else { 03837 errno = EPERM; 03838 } 03839 ret = -1; 03840 } 03841 else { 03842 CloseHandle(hProc); 03843 } 03844 }); 03845 break; 03846 03847 case SIGINT: 03848 RUBY_CRITICAL({ 03849 DWORD ctrlEvent = CTRL_C_EVENT; 03850 if (pid != 0) { 03851 /* CTRL+C signal cannot be generated for process groups. 03852 * Instead, we use CTRL+BREAK signal. */ 03853 ctrlEvent = CTRL_BREAK_EVENT; 03854 } 03855 if (!GenerateConsoleCtrlEvent(ctrlEvent, (DWORD)pid)) { 03856 if ((err = GetLastError()) == 0) 03857 errno = EPERM; 03858 else 03859 errno = map_errno(GetLastError()); 03860 ret = -1; 03861 } 03862 }); 03863 break; 03864 03865 case SIGKILL: 03866 RUBY_CRITICAL({ 03867 HANDLE hProc; 03868 struct ChildRecord* child = FindChildSlot(pid); 03869 if (child) { 03870 hProc = child->hProcess; 03871 } 03872 else { 03873 hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid); 03874 } 03875 if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) { 03876 if (GetLastError() == ERROR_INVALID_PARAMETER) { 03877 errno = ESRCH; 03878 } 03879 else { 03880 errno = EPERM; 03881 } 03882 ret = -1; 03883 } 03884 else { 03885 DWORD status; 03886 if (!GetExitCodeProcess(hProc, &status)) { 03887 errno = map_errno(GetLastError()); 03888 ret = -1; 03889 } 03890 else if (status == STILL_ACTIVE) { 03891 if (!TerminateProcess(hProc, 0)) { 03892 errno = EPERM; 03893 ret = -1; 03894 } 03895 } 03896 else { 03897 errno = ESRCH; 03898 ret = -1; 03899 } 03900 if (!child) { 03901 CloseHandle(hProc); 03902 } 03903 } 03904 }); 03905 break; 03906 03907 default: 03908 errno = EINVAL; 03909 ret = -1; 03910 break; 03911 } 03912 03913 return ret; 03914 } 03915 03916 static int 03917 wlink(const WCHAR *from, const WCHAR *to) 03918 { 03919 typedef BOOL (WINAPI link_func)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); 03920 static link_func *pCreateHardLinkW = NULL; 03921 static int myerrno = 0; 03922 03923 if (!pCreateHardLinkW && !myerrno) { 03924 pCreateHardLinkW = (link_func *)get_proc_address("kernel32", "CreateHardLinkW", NULL); 03925 if (!pCreateHardLinkW) 03926 myerrno = ENOSYS; 03927 } 03928 if (!pCreateHardLinkW) { 03929 errno = myerrno; 03930 return -1; 03931 } 03932 03933 if (!pCreateHardLinkW(to, from, NULL)) { 03934 errno = map_errno(GetLastError()); 03935 return -1; 03936 } 03937 03938 return 0; 03939 } 03940 03941 int 03942 rb_w32_ulink(const char *from, const char *to) 03943 { 03944 WCHAR *wfrom; 03945 WCHAR *wto; 03946 int ret; 03947 03948 if (!(wfrom = utf8_to_wstr(from, NULL))) 03949 return -1; 03950 if (!(wto = utf8_to_wstr(to, NULL))) { 03951 free(wfrom); 03952 return -1; 03953 } 03954 ret = wlink(wfrom, wto); 03955 free(wto); 03956 free(wfrom); 03957 return ret; 03958 } 03959 03960 int 03961 link(const char *from, const char *to) 03962 { 03963 WCHAR *wfrom; 03964 WCHAR *wto; 03965 int ret; 03966 03967 if (!(wfrom = filecp_to_wstr(from, NULL))) 03968 return -1; 03969 if (!(wto = filecp_to_wstr(to, NULL))) { 03970 free(wfrom); 03971 return -1; 03972 } 03973 ret = wlink(wfrom, wto); 03974 free(wto); 03975 free(wfrom); 03976 return ret; 03977 } 03978 03979 int 03980 wait(int *status) 03981 { 03982 return waitpid(-1, status, 0); 03983 } 03984 03985 char * 03986 rb_w32_getenv(const char *name) 03987 { 03988 int len = strlen(name); 03989 char *env; 03990 03991 if (len == 0) return NULL; 03992 if (envarea) FreeEnvironmentStrings(envarea); 03993 envarea = GetEnvironmentStrings(); 03994 if (!envarea) { 03995 map_errno(GetLastError()); 03996 return NULL; 03997 } 03998 03999 for (env = envarea; *env; env += strlen(env) + 1) 04000 if (strncasecmp(env, name, len) == 0 && *(env + len) == '=') 04001 return env + len + 1; 04002 04003 return NULL; 04004 } 04005 04006 static int 04007 wrename(const WCHAR *oldpath, const WCHAR *newpath) 04008 { 04009 int res = 0; 04010 int oldatts; 04011 int newatts; 04012 04013 oldatts = GetFileAttributesW(oldpath); 04014 newatts = GetFileAttributesW(newpath); 04015 04016 if (oldatts == -1) { 04017 errno = map_errno(GetLastError()); 04018 return -1; 04019 } 04020 04021 RUBY_CRITICAL({ 04022 if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY) 04023 SetFileAttributesW(newpath, newatts & ~ FILE_ATTRIBUTE_READONLY); 04024 04025 if (!MoveFileW(oldpath, newpath)) 04026 res = -1; 04027 04028 if (res) { 04029 switch (GetLastError()) { 04030 case ERROR_ALREADY_EXISTS: 04031 case ERROR_FILE_EXISTS: 04032 if (IsWinNT()) { 04033 if (MoveFileExW(oldpath, newpath, MOVEFILE_REPLACE_EXISTING)) 04034 res = 0; 04035 } 04036 else { 04037 for (;;) { 04038 if (!DeleteFileW(newpath) && GetLastError() != ERROR_FILE_NOT_FOUND) 04039 break; 04040 else if (MoveFileW(oldpath, newpath)) { 04041 res = 0; 04042 break; 04043 } 04044 } 04045 } 04046 } 04047 } 04048 04049 if (res) 04050 errno = map_errno(GetLastError()); 04051 else 04052 SetFileAttributesW(newpath, oldatts); 04053 }); 04054 04055 return res; 04056 } 04057 04058 int rb_w32_urename(const char *from, const char *to) 04059 { 04060 WCHAR *wfrom; 04061 WCHAR *wto; 04062 int ret = -1; 04063 04064 if (!(wfrom = utf8_to_wstr(from, NULL))) 04065 return -1; 04066 if (!(wto = utf8_to_wstr(to, NULL))) { 04067 free(wfrom); 04068 return -1; 04069 } 04070 ret = wrename(wfrom, wto); 04071 free(wto); 04072 free(wfrom); 04073 return ret; 04074 } 04075 04076 int rb_w32_rename(const char *from, const char *to) 04077 { 04078 WCHAR *wfrom; 04079 WCHAR *wto; 04080 int ret = -1; 04081 04082 if (!(wfrom = filecp_to_wstr(from, NULL))) 04083 return -1; 04084 if (!(wto = filecp_to_wstr(to, NULL))) { 04085 free(wfrom); 04086 return -1; 04087 } 04088 ret = wrename(wfrom, wto); 04089 free(wto); 04090 free(wfrom); 04091 return ret; 04092 } 04093 04094 static int 04095 isUNCRoot(const WCHAR *path) 04096 { 04097 if (path[0] == L'\\' && path[1] == L'\\') { 04098 const WCHAR *p; 04099 for (p = path + 2; *p; p++) { 04100 if (*p == L'\\') 04101 break; 04102 } 04103 if (p[0] && p[1]) { 04104 for (p++; *p; p++) { 04105 if (*p == L'\\') 04106 break; 04107 } 04108 if (!p[0] || !p[1] || (p[1] == L'.' && !p[2])) 04109 return 1; 04110 } 04111 } 04112 return 0; 04113 } 04114 04115 #define COPY_STAT(src, dest, size_cast) do { \ 04116 (dest).st_dev = (src).st_dev; \ 04117 (dest).st_ino = (src).st_ino; \ 04118 (dest).st_mode = (src).st_mode; \ 04119 (dest).st_nlink = (src).st_nlink; \ 04120 (dest).st_uid = (src).st_uid; \ 04121 (dest).st_gid = (src).st_gid; \ 04122 (dest).st_rdev = (src).st_rdev; \ 04123 (dest).st_size = size_cast(src).st_size; \ 04124 (dest).st_atime = (src).st_atime; \ 04125 (dest).st_mtime = (src).st_mtime; \ 04126 (dest).st_ctime = (src).st_ctime; \ 04127 } while (0) 04128 04129 static time_t filetime_to_unixtime(const FILETIME *ft); 04130 04131 #undef fstat 04132 int 04133 rb_w32_fstat(int fd, struct stat *st) 04134 { 04135 BY_HANDLE_FILE_INFORMATION info; 04136 int ret = fstat(fd, st); 04137 04138 if (ret) return ret; 04139 #ifdef __BORLANDC__ 04140 st->st_mode &= ~(S_IWGRP | S_IWOTH); 04141 #endif 04142 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) { 04143 #ifdef __BORLANDC__ 04144 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { 04145 st->st_mode |= S_IWUSR; 04146 } 04147 #endif 04148 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime); 04149 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime); 04150 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime); 04151 } 04152 return ret; 04153 } 04154 04155 int 04156 rb_w32_fstati64(int fd, struct stati64 *st) 04157 { 04158 BY_HANDLE_FILE_INFORMATION info; 04159 struct stat tmp; 04160 int ret = fstat(fd, &tmp); 04161 04162 if (ret) return ret; 04163 #ifdef __BORLANDC__ 04164 tmp.st_mode &= ~(S_IWGRP | S_IWOTH); 04165 #endif 04166 COPY_STAT(tmp, *st, +); 04167 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) { 04168 #ifdef __BORLANDC__ 04169 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { 04170 st->st_mode |= S_IWUSR; 04171 } 04172 #endif 04173 st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow; 04174 st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime); 04175 st->st_mtime = filetime_to_unixtime(&info.ftLastWriteTime); 04176 st->st_ctime = filetime_to_unixtime(&info.ftCreationTime); 04177 } 04178 return ret; 04179 } 04180 04181 static time_t 04182 filetime_to_unixtime(const FILETIME *ft) 04183 { 04184 struct timeval tv; 04185 04186 if (filetime_to_timeval(ft, &tv) == (time_t)-1) 04187 return 0; 04188 else 04189 return tv.tv_sec; 04190 } 04191 04192 static unsigned 04193 fileattr_to_unixmode(DWORD attr, const WCHAR *path) 04194 { 04195 unsigned mode = 0; 04196 04197 if (attr & FILE_ATTRIBUTE_READONLY) { 04198 mode |= S_IREAD; 04199 } 04200 else { 04201 mode |= S_IREAD | S_IWRITE | S_IWUSR; 04202 } 04203 04204 if (attr & FILE_ATTRIBUTE_DIRECTORY) { 04205 mode |= S_IFDIR | S_IEXEC; 04206 } 04207 else { 04208 mode |= S_IFREG; 04209 } 04210 04211 if (path && (mode & S_IFREG)) { 04212 const WCHAR *end = path + lstrlenW(path); 04213 while (path < end) { 04214 end = CharPrevW(path, end); 04215 if (*end == L'.') { 04216 if ((_wcsicmp(end, L".bat") == 0) || 04217 (_wcsicmp(end, L".cmd") == 0) || 04218 (_wcsicmp(end, L".com") == 0) || 04219 (_wcsicmp(end, L".exe") == 0)) { 04220 mode |= S_IEXEC; 04221 } 04222 break; 04223 } 04224 } 04225 } 04226 04227 mode |= (mode & 0700) >> 3; 04228 mode |= (mode & 0700) >> 6; 04229 04230 return mode; 04231 } 04232 04233 static int 04234 check_valid_dir(const WCHAR *path) 04235 { 04236 WIN32_FIND_DATAW fd; 04237 HANDLE fh; 04238 04239 /* GetFileAttributes() determines "..." as directory. */ 04240 /* We recheck it by FindFirstFile(). */ 04241 if (wcsstr(path, L"...") == NULL) 04242 return 0; 04243 04244 fh = open_dir_handle(path, &fd); 04245 if (fh == INVALID_HANDLE_VALUE) 04246 return -1; 04247 FindClose(fh); 04248 return 0; 04249 } 04250 04251 static int 04252 winnt_stat(const WCHAR *path, struct stati64 *st) 04253 { 04254 HANDLE h; 04255 WIN32_FIND_DATAW wfd; 04256 WIN32_FILE_ATTRIBUTE_DATA wfa; 04257 04258 memset(st, 0, sizeof(*st)); 04259 st->st_nlink = 1; 04260 04261 if (wcspbrk(path, L"?*")) { 04262 errno = ENOENT; 04263 return -1; 04264 } 04265 if (GetFileAttributesExW(path, GetFileExInfoStandard, (void*)&wfa)) { 04266 if (wfa.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 04267 if (check_valid_dir(path)) return -1; 04268 st->st_size = 0; 04269 } 04270 else { 04271 st->st_size = ((__int64)wfa.nFileSizeHigh << 32) | wfa.nFileSizeLow; 04272 } 04273 st->st_mode = fileattr_to_unixmode(wfa.dwFileAttributes, path); 04274 st->st_atime = filetime_to_unixtime(&wfa.ftLastAccessTime); 04275 st->st_mtime = filetime_to_unixtime(&wfa.ftLastWriteTime); 04276 st->st_ctime = filetime_to_unixtime(&wfa.ftCreationTime); 04277 } 04278 else { 04279 /* GetFileAttributesEx failed; check why. */ 04280 int e = GetLastError(); 04281 04282 if ((e == ERROR_FILE_NOT_FOUND) || (e == ERROR_INVALID_NAME) 04283 || (e == ERROR_PATH_NOT_FOUND || (e == ERROR_BAD_NETPATH))) { 04284 errno = map_errno(e); 04285 return -1; 04286 } 04287 04288 /* Fall back to FindFirstFile for ERROR_SHARING_VIOLATION */ 04289 h = FindFirstFileW(path, &wfd); 04290 if (h != INVALID_HANDLE_VALUE) { 04291 FindClose(h); 04292 st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path); 04293 st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime); 04294 st->st_mtime = filetime_to_unixtime(&wfd.ftLastWriteTime); 04295 st->st_ctime = filetime_to_unixtime(&wfd.ftCreationTime); 04296 st->st_size = ((__int64)wfd.nFileSizeHigh << 32) | wfd.nFileSizeLow; 04297 } 04298 else { 04299 errno = map_errno(GetLastError()); 04300 return -1; 04301 } 04302 } 04303 04304 st->st_dev = st->st_rdev = (iswalpha(path[0]) && path[1] == L':') ? 04305 towupper(path[0]) - L'A' : _getdrive() - 1; 04306 04307 return 0; 04308 } 04309 04310 #ifdef WIN95 04311 static int 04312 win95_stat(const WCHAR *path, struct stati64 *st) 04313 { 04314 int ret = _wstati64(path, st); 04315 if (ret) return ret; 04316 if (st->st_mode & S_IFDIR) { 04317 return check_valid_dir(path); 04318 } 04319 return 0; 04320 } 04321 #else 04322 #define win95_stat(path, st) -1 04323 #endif 04324 04325 int 04326 rb_w32_stat(const char *path, struct stat *st) 04327 { 04328 struct stati64 tmp; 04329 04330 if (rb_w32_stati64(path, &tmp)) return -1; 04331 COPY_STAT(tmp, *st, (_off_t)); 04332 return 0; 04333 } 04334 04335 static int 04336 wstati64(const WCHAR *path, struct stati64 *st) 04337 { 04338 const WCHAR *p; 04339 WCHAR *buf1, *s, *end; 04340 int len, size; 04341 int ret; 04342 VALUE v; 04343 04344 if (!path || !st) { 04345 errno = EFAULT; 04346 return -1; 04347 } 04348 size = lstrlenW(path) + 2; 04349 buf1 = ALLOCV_N(WCHAR, v, size); 04350 for (p = path, s = buf1; *p; p++, s++) { 04351 if (*p == L'/') 04352 *s = L'\\'; 04353 else 04354 *s = *p; 04355 } 04356 *s = '\0'; 04357 len = s - buf1; 04358 if (!len || L'\"' == *(--s)) { 04359 errno = ENOENT; 04360 return -1; 04361 } 04362 end = buf1 + len - 1; 04363 04364 if (isUNCRoot(buf1)) { 04365 if (*end == L'.') 04366 *end = L'\0'; 04367 else if (*end != L'\\') 04368 lstrcatW(buf1, L"\\"); 04369 } 04370 else if (*end == L'\\' || (buf1 + 1 == end && *end == L':')) 04371 lstrcatW(buf1, L"."); 04372 04373 ret = IsWinNT() ? winnt_stat(buf1, st) : win95_stat(buf1, st); 04374 if (ret == 0) { 04375 st->st_mode &= ~(S_IWGRP | S_IWOTH); 04376 } 04377 if (v) 04378 ALLOCV_END(v); 04379 04380 return ret; 04381 } 04382 04383 int 04384 rb_w32_ustati64(const char *path, struct stati64 *st) 04385 { 04386 WCHAR *wpath; 04387 int ret; 04388 04389 if (!(wpath = utf8_to_wstr(path, NULL))) 04390 return -1; 04391 ret = wstati64(wpath, st); 04392 free(wpath); 04393 return ret; 04394 } 04395 04396 int 04397 rb_w32_stati64(const char *path, struct stati64 *st) 04398 { 04399 WCHAR *wpath; 04400 int ret; 04401 04402 if (!(wpath = filecp_to_wstr(path, NULL))) 04403 return -1; 04404 ret = wstati64(wpath, st); 04405 free(wpath); 04406 return ret; 04407 } 04408 04409 int 04410 rb_w32_access(const char *path, int mode) 04411 { 04412 struct stati64 stat; 04413 if (rb_w32_stati64(path, &stat) != 0) 04414 return -1; 04415 mode <<= 6; 04416 if ((stat.st_mode & mode) != mode) { 04417 errno = EACCES; 04418 return -1; 04419 } 04420 return 0; 04421 } 04422 04423 int 04424 rb_w32_uaccess(const char *path, int mode) 04425 { 04426 struct stati64 stat; 04427 if (rb_w32_ustati64(path, &stat) != 0) 04428 return -1; 04429 mode <<= 6; 04430 if ((stat.st_mode & mode) != mode) { 04431 errno = EACCES; 04432 return -1; 04433 } 04434 return 0; 04435 } 04436 04437 static int 04438 rb_chsize(HANDLE h, off_t size) 04439 { 04440 long upos, lpos, usize, lsize, uend, lend; 04441 off_t end; 04442 int ret = -1; 04443 DWORD e; 04444 04445 if (((lpos = SetFilePointer(h, 0, (upos = 0, &upos), SEEK_CUR)) == -1L && 04446 (e = GetLastError())) || 04447 ((lend = GetFileSize(h, (DWORD *)&uend)) == -1L && (e = GetLastError()))) { 04448 errno = map_errno(e); 04449 return -1; 04450 } 04451 end = ((off_t)uend << 32) | (unsigned long)lend; 04452 usize = (long)(size >> 32); 04453 lsize = (long)size; 04454 if (SetFilePointer(h, lsize, &usize, SEEK_SET) == (DWORD)-1L && 04455 (e = GetLastError())) { 04456 errno = map_errno(e); 04457 } 04458 else if (!SetEndOfFile(h)) { 04459 errno = map_errno(GetLastError()); 04460 } 04461 else { 04462 ret = 0; 04463 } 04464 SetFilePointer(h, lpos, &upos, SEEK_SET); 04465 return ret; 04466 } 04467 04468 int 04469 rb_w32_truncate(const char *path, off_t length) 04470 { 04471 HANDLE h; 04472 int ret; 04473 #ifdef WIN95 04474 if (IsWin95()) { 04475 int fd = open(path, O_WRONLY), e = 0; 04476 if (fd == -1) return -1; 04477 ret = chsize(fd, (unsigned long)length); 04478 if (ret == -1) e = errno; 04479 close(fd); 04480 if (ret == -1) errno = e; 04481 return ret; 04482 } 04483 #endif 04484 h = CreateFile(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); 04485 if (h == INVALID_HANDLE_VALUE) { 04486 errno = map_errno(GetLastError()); 04487 return -1; 04488 } 04489 ret = rb_chsize(h, length); 04490 CloseHandle(h); 04491 return ret; 04492 } 04493 04494 int 04495 rb_w32_ftruncate(int fd, off_t length) 04496 { 04497 HANDLE h; 04498 04499 #ifdef WIN95 04500 if (IsWin95()) { 04501 return chsize(fd, (unsigned long)length); 04502 } 04503 #endif 04504 h = (HANDLE)_get_osfhandle(fd); 04505 if (h == (HANDLE)-1) return -1; 04506 return rb_chsize(h, length); 04507 } 04508 04509 #ifdef __BORLANDC__ 04510 off_t 04511 _filelengthi64(int fd) 04512 { 04513 DWORD u, l; 04514 int e; 04515 04516 l = GetFileSize((HANDLE)_get_osfhandle(fd), &u); 04517 if (l == (DWORD)-1L && (e = GetLastError())) { 04518 errno = map_errno(e); 04519 return (off_t)-1; 04520 } 04521 return ((off_t)u << 32) | l; 04522 } 04523 04524 off_t 04525 _lseeki64(int fd, off_t offset, int whence) 04526 { 04527 long u, l; 04528 int e; 04529 HANDLE h = (HANDLE)_get_osfhandle(fd); 04530 04531 if (!h) { 04532 errno = EBADF; 04533 return -1; 04534 } 04535 u = (long)(offset >> 32); 04536 if ((l = SetFilePointer(h, (long)offset, &u, whence)) == -1L && 04537 (e = GetLastError())) { 04538 errno = map_errno(e); 04539 return -1; 04540 } 04541 return ((off_t)u << 32) | l; 04542 } 04543 #endif 04544 04545 int 04546 fseeko(FILE *stream, off_t offset, int whence) 04547 { 04548 off_t pos; 04549 switch (whence) { 04550 case SEEK_CUR: 04551 if (fgetpos(stream, (fpos_t *)&pos)) 04552 return -1; 04553 pos += offset; 04554 break; 04555 case SEEK_END: 04556 if ((pos = _filelengthi64(fileno(stream))) == (off_t)-1) 04557 return -1; 04558 pos += offset; 04559 break; 04560 default: 04561 pos = offset; 04562 break; 04563 } 04564 return fsetpos(stream, (fpos_t *)&pos); 04565 } 04566 04567 off_t 04568 rb_w32_ftello(FILE *stream) 04569 { 04570 off_t pos; 04571 if (fgetpos(stream, (fpos_t *)&pos)) return (off_t)-1; 04572 return pos; 04573 } 04574 04575 static long 04576 filetime_to_clock(FILETIME *ft) 04577 { 04578 __int64 qw = ft->dwHighDateTime; 04579 qw <<= 32; 04580 qw |= ft->dwLowDateTime; 04581 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */ 04582 return (long) qw; 04583 } 04584 04585 int 04586 rb_w32_times(struct tms *tmbuf) 04587 { 04588 FILETIME create, exit, kernel, user; 04589 04590 if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) { 04591 tmbuf->tms_utime = filetime_to_clock(&user); 04592 tmbuf->tms_stime = filetime_to_clock(&kernel); 04593 tmbuf->tms_cutime = 0; 04594 tmbuf->tms_cstime = 0; 04595 } 04596 else { 04597 tmbuf->tms_utime = clock(); 04598 tmbuf->tms_stime = 0; 04599 tmbuf->tms_cutime = 0; 04600 tmbuf->tms_cstime = 0; 04601 } 04602 return 0; 04603 } 04604 04605 #define yield_once() Sleep(0) 04606 #define yield_until(condition) do yield_once(); while (!(condition)) 04607 04608 static void 04609 catch_interrupt(void) 04610 { 04611 yield_once(); 04612 RUBY_CRITICAL(rb_w32_wait_events(NULL, 0, 0)); 04613 } 04614 04615 #if defined __BORLANDC__ 04616 #undef read 04617 int 04618 read(int fd, void *buf, size_t size) 04619 { 04620 int ret = _read(fd, buf, size); 04621 if ((ret < 0) && (errno == EPIPE)) { 04622 errno = 0; 04623 ret = 0; 04624 } 04625 catch_interrupt(); 04626 return ret; 04627 } 04628 #endif 04629 04630 #undef fgetc 04631 int 04632 rb_w32_getc(FILE* stream) 04633 { 04634 int c; 04635 if (enough_to_get(stream->FILE_COUNT)) { 04636 c = (unsigned char)*stream->FILE_READPTR++; 04637 } 04638 else { 04639 c = _filbuf(stream); 04640 #if defined __BORLANDC__ 04641 if ((c == EOF) && (errno == EPIPE)) { 04642 clearerr(stream); 04643 } 04644 #endif 04645 catch_interrupt(); 04646 } 04647 return c; 04648 } 04649 04650 #undef fputc 04651 int 04652 rb_w32_putc(int c, FILE* stream) 04653 { 04654 if (enough_to_put(stream->FILE_COUNT)) { 04655 c = (unsigned char)(*stream->FILE_READPTR++ = (char)c); 04656 } 04657 else { 04658 c = _flsbuf(c, stream); 04659 catch_interrupt(); 04660 } 04661 return c; 04662 } 04663 04664 struct asynchronous_arg_t { 04665 /* output field */ 04666 void* stackaddr; 04667 int errnum; 04668 04669 /* input field */ 04670 uintptr_t (*func)(uintptr_t self, int argc, uintptr_t* argv); 04671 uintptr_t self; 04672 int argc; 04673 uintptr_t* argv; 04674 }; 04675 04676 static DWORD WINAPI 04677 call_asynchronous(PVOID argp) 04678 { 04679 DWORD ret; 04680 struct asynchronous_arg_t *arg = argp; 04681 arg->stackaddr = &argp; 04682 ret = (DWORD)arg->func(arg->self, arg->argc, arg->argv); 04683 arg->errnum = errno; 04684 return ret; 04685 } 04686 04687 uintptr_t 04688 rb_w32_asynchronize(asynchronous_func_t func, uintptr_t self, 04689 int argc, uintptr_t* argv, uintptr_t intrval) 04690 { 04691 DWORD val; 04692 BOOL interrupted = FALSE; 04693 HANDLE thr; 04694 04695 RUBY_CRITICAL({ 04696 struct asynchronous_arg_t arg; 04697 04698 arg.stackaddr = NULL; 04699 arg.errnum = 0; 04700 arg.func = func; 04701 arg.self = self; 04702 arg.argc = argc; 04703 arg.argv = argv; 04704 04705 thr = CreateThread(NULL, 0, call_asynchronous, &arg, 0, &val); 04706 04707 if (thr) { 04708 yield_until(arg.stackaddr); 04709 04710 if (rb_w32_wait_events_blocking(&thr, 1, INFINITE) != WAIT_OBJECT_0) { 04711 interrupted = TRUE; 04712 04713 if (TerminateThread(thr, intrval)) { 04714 yield_once(); 04715 } 04716 } 04717 04718 GetExitCodeThread(thr, &val); 04719 CloseHandle(thr); 04720 04721 if (interrupted) { 04722 /* must release stack of killed thread, why doesn't Windows? */ 04723 MEMORY_BASIC_INFORMATION m; 04724 04725 memset(&m, 0, sizeof(m)); 04726 if (!VirtualQuery(arg.stackaddr, &m, sizeof(m))) { 04727 Debug(fprintf(stderr, "couldn't get stack base:%p:%d\n", 04728 arg.stackaddr, GetLastError())); 04729 } 04730 else if (!VirtualFree(m.AllocationBase, 0, MEM_RELEASE)) { 04731 Debug(fprintf(stderr, "couldn't release stack:%p:%d\n", 04732 m.AllocationBase, GetLastError())); 04733 } 04734 errno = EINTR; 04735 } 04736 else { 04737 errno = arg.errnum; 04738 } 04739 } 04740 }); 04741 04742 if (!thr) { 04743 rb_fatal("failed to launch waiter thread:%ld", GetLastError()); 04744 } 04745 04746 return val; 04747 } 04748 04749 char ** 04750 rb_w32_get_environ(void) 04751 { 04752 char *envtop, *env; 04753 char **myenvtop, **myenv; 04754 int num; 04755 04756 /* 04757 * We avoid values started with `='. If you want to deal those values, 04758 * change this function, and some functions in hash.c which recognize 04759 * `=' as delimiter or rb_w32_getenv() and ruby_setenv(). 04760 * CygWin deals these values by changing first `=' to '!'. But we don't 04761 * use such trick and follow cmd.exe's way that just doesn't show these 04762 * values. 04763 * (U.N. 2001-11-15) 04764 */ 04765 envtop = GetEnvironmentStrings(); 04766 for (env = envtop, num = 0; *env; env += strlen(env) + 1) 04767 if (*env != '=') num++; 04768 04769 myenvtop = (char **)malloc(sizeof(char *) * (num + 1)); 04770 for (env = envtop, myenv = myenvtop; *env; env += strlen(env) + 1) { 04771 if (*env != '=') { 04772 if (!(*myenv = strdup(env))) { 04773 break; 04774 } 04775 myenv++; 04776 } 04777 } 04778 *myenv = NULL; 04779 FreeEnvironmentStrings(envtop); 04780 04781 return myenvtop; 04782 } 04783 04784 void 04785 rb_w32_free_environ(char **env) 04786 { 04787 char **t = env; 04788 04789 while (*t) free(*t++); 04790 free(env); 04791 } 04792 04793 rb_pid_t 04794 rb_w32_getpid(void) 04795 { 04796 rb_pid_t pid; 04797 04798 pid = GetCurrentProcessId(); 04799 04800 (void)IfWin95(pid = -pid, 0); 04801 04802 return pid; 04803 } 04804 04805 04806 rb_pid_t 04807 rb_w32_getppid(void) 04808 { 04809 typedef long (WINAPI query_func)(HANDLE, int, void *, ULONG, ULONG *); 04810 static query_func *pNtQueryInformationProcess = NULL; 04811 rb_pid_t ppid = 0; 04812 04813 if (!IsWin95() && rb_w32_osver() >= 5) { 04814 if (!pNtQueryInformationProcess) 04815 pNtQueryInformationProcess = (query_func *)get_proc_address("ntdll.dll", "NtQueryInformationProcess", NULL); 04816 if (pNtQueryInformationProcess) { 04817 struct { 04818 long ExitStatus; 04819 void* PebBaseAddress; 04820 uintptr_t AffinityMask; 04821 uintptr_t BasePriority; 04822 uintptr_t UniqueProcessId; 04823 uintptr_t ParentProcessId; 04824 } pbi; 04825 ULONG len; 04826 long ret = pNtQueryInformationProcess(GetCurrentProcess(), 0, &pbi, sizeof(pbi), &len); 04827 if (!ret) { 04828 ppid = pbi.ParentProcessId; 04829 } 04830 } 04831 } 04832 04833 return ppid; 04834 } 04835 04836 int 04837 rb_w32_uopen(const char *file, int oflag, ...) 04838 { 04839 WCHAR *wfile; 04840 int ret; 04841 int pmode; 04842 04843 va_list arg; 04844 va_start(arg, oflag); 04845 pmode = va_arg(arg, int); 04846 va_end(arg); 04847 04848 if (!(wfile = utf8_to_wstr(file, NULL))) 04849 return -1; 04850 ret = rb_w32_wopen(wfile, oflag, pmode); 04851 free(wfile); 04852 return ret; 04853 } 04854 04855 int 04856 rb_w32_open(const char *file, int oflag, ...) 04857 { 04858 WCHAR *wfile; 04859 int ret; 04860 int pmode; 04861 04862 va_list arg; 04863 va_start(arg, oflag); 04864 pmode = va_arg(arg, int); 04865 va_end(arg); 04866 04867 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) 04868 return _open(file, oflag, pmode); 04869 04870 if (!(wfile = filecp_to_wstr(file, NULL))) 04871 return -1; 04872 ret = rb_w32_wopen(wfile, oflag, pmode); 04873 free(wfile); 04874 return ret; 04875 } 04876 04877 int 04878 rb_w32_wopen(const WCHAR *file, int oflag, ...) 04879 { 04880 char flags = 0; 04881 int fd; 04882 DWORD access; 04883 DWORD create; 04884 DWORD attr = FILE_ATTRIBUTE_NORMAL; 04885 SECURITY_ATTRIBUTES sec; 04886 HANDLE h; 04887 04888 if ((oflag & O_TEXT) || !(oflag & O_BINARY)) { 04889 va_list arg; 04890 int pmode; 04891 va_start(arg, oflag); 04892 pmode = va_arg(arg, int); 04893 va_end(arg); 04894 return _wopen(file, oflag, pmode); 04895 } 04896 04897 sec.nLength = sizeof(sec); 04898 sec.lpSecurityDescriptor = NULL; 04899 if (oflag & O_NOINHERIT) { 04900 sec.bInheritHandle = FALSE; 04901 flags |= FNOINHERIT; 04902 } 04903 else { 04904 sec.bInheritHandle = TRUE; 04905 } 04906 oflag &= ~O_NOINHERIT; 04907 04908 /* always open with binary mode */ 04909 oflag &= ~(O_BINARY | O_TEXT); 04910 04911 switch (oflag & (O_RDWR | O_RDONLY | O_WRONLY)) { 04912 case O_RDWR: 04913 access = GENERIC_READ | GENERIC_WRITE; 04914 break; 04915 case O_RDONLY: 04916 access = GENERIC_READ; 04917 break; 04918 case O_WRONLY: 04919 access = GENERIC_WRITE; 04920 break; 04921 default: 04922 errno = EINVAL; 04923 return -1; 04924 } 04925 oflag &= ~(O_RDWR | O_RDONLY | O_WRONLY); 04926 04927 switch (oflag & (O_CREAT | O_EXCL | O_TRUNC)) { 04928 case O_CREAT: 04929 create = OPEN_ALWAYS; 04930 break; 04931 case 0: 04932 case O_EXCL: 04933 create = OPEN_EXISTING; 04934 break; 04935 case O_CREAT | O_EXCL: 04936 case O_CREAT | O_EXCL | O_TRUNC: 04937 create = CREATE_NEW; 04938 break; 04939 case O_TRUNC: 04940 case O_TRUNC | O_EXCL: 04941 create = TRUNCATE_EXISTING; 04942 break; 04943 case O_CREAT | O_TRUNC: 04944 create = CREATE_ALWAYS; 04945 break; 04946 default: 04947 errno = EINVAL; 04948 return -1; 04949 } 04950 if (oflag & O_CREAT) { 04951 va_list arg; 04952 int pmode; 04953 va_start(arg, oflag); 04954 pmode = va_arg(arg, int); 04955 va_end(arg); 04956 /* TODO: we need to check umask here, but it's not exported... */ 04957 if (!(pmode & S_IWRITE)) 04958 attr = FILE_ATTRIBUTE_READONLY; 04959 } 04960 oflag &= ~(O_CREAT | O_EXCL | O_TRUNC); 04961 04962 if (oflag & O_TEMPORARY) { 04963 attr |= FILE_FLAG_DELETE_ON_CLOSE; 04964 access |= DELETE; 04965 } 04966 oflag &= ~O_TEMPORARY; 04967 04968 if (oflag & _O_SHORT_LIVED) 04969 attr |= FILE_ATTRIBUTE_TEMPORARY; 04970 oflag &= ~_O_SHORT_LIVED; 04971 04972 switch (oflag & (O_SEQUENTIAL | O_RANDOM)) { 04973 case 0: 04974 break; 04975 case O_SEQUENTIAL: 04976 attr |= FILE_FLAG_SEQUENTIAL_SCAN; 04977 break; 04978 case O_RANDOM: 04979 attr |= FILE_FLAG_RANDOM_ACCESS; 04980 break; 04981 default: 04982 errno = EINVAL; 04983 return -1; 04984 } 04985 oflag &= ~(O_SEQUENTIAL | O_RANDOM); 04986 04987 if (oflag & ~O_APPEND) { 04988 errno = EINVAL; 04989 return -1; 04990 } 04991 04992 /* allocate a C Runtime file handle */ 04993 RUBY_CRITICAL({ 04994 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 04995 fd = _open_osfhandle((intptr_t)h, 0); 04996 CloseHandle(h); 04997 }); 04998 if (fd == -1) { 04999 errno = EMFILE; 05000 return -1; 05001 } 05002 RUBY_CRITICAL({ 05003 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 05004 _set_osfhnd(fd, (intptr_t)INVALID_HANDLE_VALUE); 05005 _set_osflags(fd, 0); 05006 05007 h = CreateFileW(file, access, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec, 05008 create, attr, NULL); 05009 if (h == INVALID_HANDLE_VALUE) { 05010 errno = map_errno(GetLastError()); 05011 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05012 fd = -1; 05013 goto quit; 05014 } 05015 05016 switch (GetFileType(h)) { 05017 case FILE_TYPE_CHAR: 05018 flags |= FDEV; 05019 break; 05020 case FILE_TYPE_PIPE: 05021 flags |= FPIPE; 05022 break; 05023 case FILE_TYPE_UNKNOWN: 05024 errno = map_errno(GetLastError()); 05025 CloseHandle(h); 05026 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05027 fd = -1; 05028 goto quit; 05029 } 05030 if (!(flags & (FDEV | FPIPE)) && (oflag & O_APPEND)) 05031 flags |= FAPPEND; 05032 05033 _set_osfhnd(fd, (intptr_t)h); 05034 _osfile(fd) = flags | FOPEN; 05035 05036 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05037 quit: 05038 ; 05039 }); 05040 05041 return fd; 05042 } 05043 05044 int 05045 rb_w32_fclose(FILE *fp) 05046 { 05047 int fd = fileno(fp); 05048 SOCKET sock = TO_SOCKET(fd); 05049 int save_errno = errno; 05050 05051 if (fflush(fp)) return -1; 05052 if (!is_socket(sock)) { 05053 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); 05054 return fclose(fp); 05055 } 05056 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); 05057 fclose(fp); 05058 errno = save_errno; 05059 if (closesocket(sock) == SOCKET_ERROR) { 05060 errno = map_errno(WSAGetLastError()); 05061 return -1; 05062 } 05063 return 0; 05064 } 05065 05066 int 05067 rb_w32_pipe(int fds[2]) 05068 { 05069 static DWORD serial = 0; 05070 char name[] = "\\\\.\\pipe\\ruby0000000000000000-0000000000000000"; 05071 char *p; 05072 SECURITY_ATTRIBUTES sec; 05073 HANDLE hRead, hWrite, h; 05074 int fdRead, fdWrite; 05075 int ret; 05076 05077 /* if doesn't have CancelIo, use default pipe function */ 05078 if (!cancel_io) 05079 return _pipe(fds, 65536L, _O_NOINHERIT); 05080 05081 p = strchr(name, '0'); 05082 snprintf(p, strlen(p) + 1, "%"PRI_PIDT_PREFIX"x-%lx", rb_w32_getpid(), serial++); 05083 05084 sec.nLength = sizeof(sec); 05085 sec.lpSecurityDescriptor = NULL; 05086 sec.bInheritHandle = FALSE; 05087 05088 RUBY_CRITICAL({ 05089 hRead = CreateNamedPipe(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 05090 0, 2, 65536, 65536, 0, &sec); 05091 }); 05092 if (hRead == INVALID_HANDLE_VALUE) { 05093 DWORD err = GetLastError(); 05094 if (err == ERROR_PIPE_BUSY) 05095 errno = EMFILE; 05096 else 05097 errno = map_errno(GetLastError()); 05098 return -1; 05099 } 05100 05101 RUBY_CRITICAL({ 05102 hWrite = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sec, 05103 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 05104 }); 05105 if (hWrite == INVALID_HANDLE_VALUE) { 05106 errno = map_errno(GetLastError()); 05107 CloseHandle(hRead); 05108 return -1; 05109 } 05110 05111 RUBY_CRITICAL(do { 05112 ret = 0; 05113 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 05114 fdRead = _open_osfhandle((intptr_t)h, 0); 05115 CloseHandle(h); 05116 if (fdRead == -1) { 05117 errno = EMFILE; 05118 CloseHandle(hWrite); 05119 CloseHandle(hRead); 05120 ret = -1; 05121 break; 05122 } 05123 05124 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdRead)->lock))); 05125 _set_osfhnd(fdRead, (intptr_t)hRead); 05126 _set_osflags(fdRead, FOPEN | FPIPE | FNOINHERIT); 05127 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdRead)->lock))); 05128 } while (0)); 05129 if (ret) 05130 return ret; 05131 05132 RUBY_CRITICAL(do { 05133 h = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL); 05134 fdWrite = _open_osfhandle((intptr_t)h, 0); 05135 CloseHandle(h); 05136 if (fdWrite == -1) { 05137 errno = EMFILE; 05138 CloseHandle(hWrite); 05139 ret = -1; 05140 break; 05141 } 05142 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fdWrite)->lock))); 05143 _set_osfhnd(fdWrite, (intptr_t)hWrite); 05144 _set_osflags(fdWrite, FOPEN | FPIPE | FNOINHERIT); 05145 MTHREAD_ONLY(LeaveCriticalSection(&(_pioinfo(fdWrite)->lock))); 05146 } while (0)); 05147 if (ret) { 05148 rb_w32_close(fdRead); 05149 return ret; 05150 } 05151 05152 fds[0] = fdRead; 05153 fds[1] = fdWrite; 05154 05155 return 0; 05156 } 05157 05158 int 05159 rb_w32_close(int fd) 05160 { 05161 SOCKET sock = TO_SOCKET(fd); 05162 int save_errno = errno; 05163 st_data_t key; 05164 05165 if (!is_socket(sock)) { 05166 UnlockFile((HANDLE)sock, 0, 0, LK_LEN, LK_LEN); 05167 return _close(fd); 05168 } 05169 _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE); 05170 key = (st_data_t)sock; 05171 st_delete(socklist, &key, NULL); 05172 sock = (SOCKET)key; 05173 _close(fd); 05174 errno = save_errno; 05175 if (closesocket(sock) == SOCKET_ERROR) { 05176 errno = map_errno(WSAGetLastError()); 05177 return -1; 05178 } 05179 return 0; 05180 } 05181 05182 #undef read 05183 ssize_t 05184 rb_w32_read(int fd, void *buf, size_t size) 05185 { 05186 SOCKET sock = TO_SOCKET(fd); 05187 DWORD read; 05188 DWORD wait; 05189 DWORD err; 05190 size_t len; 05191 size_t ret; 05192 OVERLAPPED ol, *pol = NULL; 05193 BOOL isconsole; 05194 BOOL islineinput = FALSE; 05195 int start = 0; 05196 05197 if (is_socket(sock)) 05198 return rb_w32_recv(fd, buf, size, 0); 05199 05200 // validate fd by using _get_osfhandle() because we cannot access _nhandle 05201 if (_get_osfhandle(fd) == -1) { 05202 return -1; 05203 } 05204 05205 if (_osfile(fd) & FTEXT) { 05206 return _read(fd, buf, size); 05207 } 05208 05209 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 05210 05211 if (!size || _osfile(fd) & FEOFLAG) { 05212 _set_osflags(fd, _osfile(fd) & ~FEOFLAG); 05213 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05214 return 0; 05215 } 05216 05217 ret = 0; 05218 isconsole = is_console(_osfhnd(fd)); 05219 if (isconsole) { 05220 DWORD mode; 05221 GetConsoleMode((HANDLE)_osfhnd(fd),&mode); 05222 islineinput = (mode & ENABLE_LINE_INPUT) != 0; 05223 } 05224 retry: 05225 /* get rid of console reading bug */ 05226 if (isconsole) { 05227 if (start) 05228 len = 1; 05229 else { 05230 len = 0; 05231 start = 1; 05232 } 05233 } 05234 else 05235 len = size; 05236 size -= len; 05237 05238 /* if have cancel_io, use Overlapped I/O */ 05239 if (cancel_io) { 05240 memset(&ol, 0, sizeof(ol)); 05241 if (!(_osfile(fd) & (FDEV | FPIPE))) { 05242 LONG high = 0; 05243 DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, 05244 FILE_CURRENT); 05245 #ifndef INVALID_SET_FILE_POINTER 05246 #define INVALID_SET_FILE_POINTER ((DWORD)-1) 05247 #endif 05248 if (low == INVALID_SET_FILE_POINTER) { 05249 errno = map_errno(GetLastError()); 05250 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05251 return -1; 05252 } 05253 ol.Offset = low; 05254 ol.OffsetHigh = high; 05255 } 05256 ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 05257 if (!ol.hEvent) { 05258 errno = map_errno(GetLastError()); 05259 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05260 return -1; 05261 } 05262 05263 pol = &ol; 05264 } 05265 05266 if (!ReadFile((HANDLE)_osfhnd(fd), buf, len, &read, pol)) { 05267 err = GetLastError(); 05268 if (err != ERROR_IO_PENDING) { 05269 if (pol) CloseHandle(ol.hEvent); 05270 if (err == ERROR_ACCESS_DENIED) 05271 errno = EBADF; 05272 else if (err == ERROR_BROKEN_PIPE || err == ERROR_HANDLE_EOF) { 05273 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05274 return 0; 05275 } 05276 else 05277 errno = map_errno(err); 05278 05279 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05280 return -1; 05281 } 05282 05283 if (pol) { 05284 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE); 05285 if (wait != WAIT_OBJECT_0) { 05286 if (wait == WAIT_OBJECT_0 + 1) 05287 errno = EINTR; 05288 else 05289 errno = map_errno(GetLastError()); 05290 CloseHandle(ol.hEvent); 05291 cancel_io((HANDLE)_osfhnd(fd)); 05292 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05293 return -1; 05294 } 05295 05296 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &read, TRUE) && 05297 (err = GetLastError()) != ERROR_HANDLE_EOF) { 05298 int ret = 0; 05299 if (err != ERROR_BROKEN_PIPE) { 05300 errno = map_errno(err); 05301 ret = -1; 05302 } 05303 CloseHandle(ol.hEvent); 05304 cancel_io((HANDLE)_osfhnd(fd)); 05305 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05306 return ret; 05307 } 05308 } 05309 } 05310 05311 if (pol) { 05312 CloseHandle(ol.hEvent); 05313 05314 if (!(_osfile(fd) & (FDEV | FPIPE))) { 05315 LONG high = ol.OffsetHigh; 05316 DWORD low = ol.Offset + read; 05317 if (low < ol.Offset) 05318 ++high; 05319 SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN); 05320 } 05321 } 05322 05323 ret += read; 05324 if (read >= len) { 05325 buf = (char *)buf + read; 05326 if (!(isconsole && len == 1 && (!islineinput || *((char *)buf - 1) == '\n')) && size > 0) 05327 goto retry; 05328 } 05329 if (read == 0) 05330 _set_osflags(fd, _osfile(fd) | FEOFLAG); 05331 05332 05333 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05334 05335 return ret; 05336 } 05337 05338 #undef write 05339 ssize_t 05340 rb_w32_write(int fd, const void *buf, size_t size) 05341 { 05342 SOCKET sock = TO_SOCKET(fd); 05343 DWORD written; 05344 DWORD wait; 05345 DWORD err; 05346 size_t len; 05347 size_t ret; 05348 OVERLAPPED ol, *pol = NULL; 05349 05350 if (is_socket(sock)) 05351 return rb_w32_send(fd, buf, size, 0); 05352 05353 // validate fd by using _get_osfhandle() because we cannot access _nhandle 05354 if (_get_osfhandle(fd) == -1) { 05355 return -1; 05356 } 05357 05358 if ((_osfile(fd) & FTEXT) && 05359 (!(_osfile(fd) & FPIPE) || fd == fileno(stdout) || fd == fileno(stderr))) { 05360 return _write(fd, buf, size); 05361 } 05362 05363 MTHREAD_ONLY(EnterCriticalSection(&(_pioinfo(fd)->lock))); 05364 05365 if (!size || _osfile(fd) & FEOFLAG) { 05366 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05367 return 0; 05368 } 05369 05370 ret = 0; 05371 retry: 05372 /* get rid of console writing bug */ 05373 len = (_osfile(fd) & FDEV) ? min(32 * 1024, size) : size; 05374 size -= len; 05375 05376 /* if have cancel_io, use Overlapped I/O */ 05377 if (cancel_io) { 05378 memset(&ol, 0, sizeof(ol)); 05379 if (!(_osfile(fd) & (FDEV | FPIPE))) { 05380 LONG high = 0; 05381 DWORD method = _osfile(fd) & FAPPEND ? FILE_END : FILE_CURRENT; 05382 DWORD low = SetFilePointer((HANDLE)_osfhnd(fd), 0, &high, method); 05383 #ifndef INVALID_SET_FILE_POINTER 05384 #define INVALID_SET_FILE_POINTER ((DWORD)-1) 05385 #endif 05386 if (low == INVALID_SET_FILE_POINTER) { 05387 errno = map_errno(GetLastError()); 05388 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05389 return -1; 05390 } 05391 ol.Offset = low; 05392 ol.OffsetHigh = high; 05393 } 05394 ol.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); 05395 if (!ol.hEvent) { 05396 errno = map_errno(GetLastError()); 05397 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05398 return -1; 05399 } 05400 05401 pol = &ol; 05402 } 05403 05404 if (!WriteFile((HANDLE)_osfhnd(fd), buf, len, &written, pol)) { 05405 err = GetLastError(); 05406 if (err != ERROR_IO_PENDING) { 05407 if (pol) CloseHandle(ol.hEvent); 05408 if (err == ERROR_ACCESS_DENIED) 05409 errno = EBADF; 05410 else 05411 errno = map_errno(err); 05412 05413 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05414 return -1; 05415 } 05416 05417 if (pol) { 05418 wait = rb_w32_wait_events_blocking(&ol.hEvent, 1, INFINITE); 05419 if (wait != WAIT_OBJECT_0) { 05420 if (wait == WAIT_OBJECT_0 + 1) 05421 errno = EINTR; 05422 else 05423 errno = map_errno(GetLastError()); 05424 CloseHandle(ol.hEvent); 05425 cancel_io((HANDLE)_osfhnd(fd)); 05426 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05427 return -1; 05428 } 05429 05430 if (!GetOverlappedResult((HANDLE)_osfhnd(fd), &ol, &written, 05431 TRUE)) { 05432 errno = map_errno(err); 05433 CloseHandle(ol.hEvent); 05434 cancel_io((HANDLE)_osfhnd(fd)); 05435 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05436 return -1; 05437 } 05438 } 05439 } 05440 05441 if (pol) { 05442 CloseHandle(ol.hEvent); 05443 05444 if (!(_osfile(fd) & (FDEV | FPIPE))) { 05445 LONG high = ol.OffsetHigh; 05446 DWORD low = ol.Offset + written; 05447 if (low < ol.Offset) 05448 ++high; 05449 SetFilePointer((HANDLE)_osfhnd(fd), low, &high, FILE_BEGIN); 05450 } 05451 } 05452 05453 ret += written; 05454 if (written == len) { 05455 buf = (const char *)buf + len; 05456 if (size > 0) 05457 goto retry; 05458 } 05459 05460 MTHREAD_ONLY(LeaveCriticalSection(&_pioinfo(fd)->lock)); 05461 05462 return ret; 05463 } 05464 05465 long 05466 rb_w32_write_console(uintptr_t strarg, int fd) 05467 { 05468 static int disable; 05469 HANDLE handle; 05470 DWORD dwMode, reslen; 05471 VALUE str = strarg; 05472 05473 if (disable) return -1L; 05474 handle = (HANDLE)_osfhnd(fd); 05475 if (!GetConsoleMode(handle, &dwMode) || 05476 !rb_econv_has_convpath_p(rb_enc_name(rb_enc_get(str)), "UTF-16LE")) 05477 return -1L; 05478 05479 str = rb_str_encode(str, rb_enc_from_encoding(rb_enc_find("UTF-16LE")), 05480 ECONV_INVALID_REPLACE|ECONV_UNDEF_REPLACE, Qnil); 05481 if (!WriteConsoleW(handle, (LPWSTR)RSTRING_PTR(str), RSTRING_LEN(str)/2, 05482 &reslen, NULL)) { 05483 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 05484 disable = TRUE; 05485 return -1L; 05486 } 05487 return (long)reslen; 05488 } 05489 05490 static int 05491 unixtime_to_filetime(time_t time, FILETIME *ft) 05492 { 05493 ULARGE_INTEGER tmp; 05494 05495 tmp.QuadPart = ((LONG_LONG)time + (LONG_LONG)((1970-1601)*365.2425) * 24 * 60 * 60) * 10 * 1000 * 1000; 05496 ft->dwLowDateTime = tmp.LowPart; 05497 ft->dwHighDateTime = tmp.HighPart; 05498 return 0; 05499 } 05500 05501 static int 05502 wutime(const WCHAR *path, const struct utimbuf *times) 05503 { 05504 HANDLE hFile; 05505 FILETIME atime, mtime; 05506 struct stati64 stat; 05507 int ret = 0; 05508 05509 if (wstati64(path, &stat)) { 05510 return -1; 05511 } 05512 05513 if (times) { 05514 if (unixtime_to_filetime(times->actime, &atime)) { 05515 return -1; 05516 } 05517 if (unixtime_to_filetime(times->modtime, &mtime)) { 05518 return -1; 05519 } 05520 } 05521 else { 05522 GetSystemTimeAsFileTime(&atime); 05523 mtime = atime; 05524 } 05525 05526 RUBY_CRITICAL({ 05527 const DWORD attr = GetFileAttributesW(path); 05528 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) 05529 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY); 05530 hFile = CreateFileW(path, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 05531 IsWin95() ? 0 : FILE_FLAG_BACKUP_SEMANTICS, 0); 05532 if (hFile == INVALID_HANDLE_VALUE) { 05533 errno = map_errno(GetLastError()); 05534 ret = -1; 05535 } 05536 else { 05537 if (!SetFileTime(hFile, NULL, &atime, &mtime)) { 05538 errno = map_errno(GetLastError()); 05539 ret = -1; 05540 } 05541 CloseHandle(hFile); 05542 } 05543 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) 05544 SetFileAttributesW(path, attr); 05545 }); 05546 05547 return ret; 05548 } 05549 05550 int 05551 rb_w32_uutime(const char *path, const struct utimbuf *times) 05552 { 05553 WCHAR *wpath; 05554 int ret; 05555 05556 if (!(wpath = utf8_to_wstr(path, NULL))) 05557 return -1; 05558 ret = wutime(wpath, times); 05559 free(wpath); 05560 return ret; 05561 } 05562 05563 int 05564 rb_w32_utime(const char *path, const struct utimbuf *times) 05565 { 05566 WCHAR *wpath; 05567 int ret; 05568 05569 if (!(wpath = filecp_to_wstr(path, NULL))) 05570 return -1; 05571 ret = wutime(wpath, times); 05572 free(wpath); 05573 return ret; 05574 } 05575 05576 int 05577 rb_w32_uchdir(const char *path) 05578 { 05579 WCHAR *wpath; 05580 int ret; 05581 05582 if (!(wpath = utf8_to_wstr(path, NULL))) 05583 return -1; 05584 ret = _wchdir(wpath); 05585 free(wpath); 05586 return ret; 05587 } 05588 05589 static int 05590 wmkdir(const WCHAR *wpath, int mode) 05591 { 05592 int ret = -1; 05593 05594 RUBY_CRITICAL(do { 05595 if (CreateDirectoryW(wpath, NULL) == FALSE) { 05596 errno = map_errno(GetLastError()); 05597 break; 05598 } 05599 if (_wchmod(wpath, mode) == -1) { 05600 RemoveDirectoryW(wpath); 05601 break; 05602 } 05603 ret = 0; 05604 } while (0)); 05605 return ret; 05606 } 05607 05608 int 05609 rb_w32_umkdir(const char *path, int mode) 05610 { 05611 WCHAR *wpath; 05612 int ret; 05613 05614 if (!(wpath = utf8_to_wstr(path, NULL))) 05615 return -1; 05616 ret = wmkdir(wpath, mode); 05617 free(wpath); 05618 return ret; 05619 } 05620 05621 int 05622 rb_w32_mkdir(const char *path, int mode) 05623 { 05624 WCHAR *wpath; 05625 int ret; 05626 05627 if (!(wpath = filecp_to_wstr(path, NULL))) 05628 return -1; 05629 ret = wmkdir(wpath, mode); 05630 free(wpath); 05631 return ret; 05632 } 05633 05634 static int 05635 wrmdir(const WCHAR *wpath) 05636 { 05637 int ret = 0; 05638 RUBY_CRITICAL({ 05639 const DWORD attr = GetFileAttributesW(wpath); 05640 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 05641 SetFileAttributesW(wpath, attr & ~FILE_ATTRIBUTE_READONLY); 05642 } 05643 if (RemoveDirectoryW(wpath) == FALSE) { 05644 errno = map_errno(GetLastError()); 05645 ret = -1; 05646 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 05647 SetFileAttributesW(wpath, attr); 05648 } 05649 } 05650 }); 05651 return ret; 05652 } 05653 05654 int 05655 rb_w32_rmdir(const char *path) 05656 { 05657 WCHAR *wpath; 05658 int ret; 05659 05660 if (!(wpath = filecp_to_wstr(path, NULL))) 05661 return -1; 05662 ret = wrmdir(wpath); 05663 free(wpath); 05664 return ret; 05665 } 05666 05667 int 05668 rb_w32_urmdir(const char *path) 05669 { 05670 WCHAR *wpath; 05671 int ret; 05672 05673 if (!(wpath = utf8_to_wstr(path, NULL))) 05674 return -1; 05675 ret = wrmdir(wpath); 05676 free(wpath); 05677 return ret; 05678 } 05679 05680 static int 05681 wunlink(const WCHAR *path) 05682 { 05683 int ret = 0; 05684 RUBY_CRITICAL({ 05685 const DWORD attr = GetFileAttributesW(path); 05686 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 05687 SetFileAttributesW(path, attr & ~FILE_ATTRIBUTE_READONLY); 05688 } 05689 if (!DeleteFileW(path)) { 05690 errno = map_errno(GetLastError()); 05691 ret = -1; 05692 if (attr != (DWORD)-1 && (attr & FILE_ATTRIBUTE_READONLY)) { 05693 SetFileAttributesW(path, attr); 05694 } 05695 } 05696 }); 05697 return ret; 05698 } 05699 05700 int 05701 rb_w32_uunlink(const char *path) 05702 { 05703 WCHAR *wpath; 05704 int ret; 05705 05706 if (!(wpath = utf8_to_wstr(path, NULL))) 05707 return -1; 05708 ret = wunlink(wpath); 05709 free(wpath); 05710 return ret; 05711 } 05712 05713 int 05714 rb_w32_unlink(const char *path) 05715 { 05716 WCHAR *wpath; 05717 int ret; 05718 05719 if (!(wpath = filecp_to_wstr(path, NULL))) 05720 return -1; 05721 ret = wunlink(wpath); 05722 free(wpath); 05723 return ret; 05724 } 05725 05726 int 05727 rb_w32_uchmod(const char *path, int mode) 05728 { 05729 WCHAR *wpath; 05730 int ret; 05731 05732 if (!(wpath = utf8_to_wstr(path, NULL))) 05733 return -1; 05734 ret = _wchmod(wpath, mode); 05735 free(wpath); 05736 return ret; 05737 } 05738 05739 #if !defined(__BORLANDC__) 05740 int 05741 rb_w32_isatty(int fd) 05742 { 05743 DWORD mode; 05744 05745 // validate fd by using _get_osfhandle() because we cannot access _nhandle 05746 if (_get_osfhandle(fd) == -1) { 05747 return 0; 05748 } 05749 if (!GetConsoleMode((HANDLE)_osfhnd(fd), &mode)) { 05750 errno = ENOTTY; 05751 return 0; 05752 } 05753 return 1; 05754 } 05755 #endif 05756 05757 // 05758 // Fix bcc32's stdio bug 05759 // 05760 05761 #ifdef __BORLANDC__ 05762 static int 05763 too_many_files(void) 05764 { 05765 FILE *f; 05766 for (f = _streams; f < _streams + _nfile; f++) { 05767 if (f->fd < 0) return 0; 05768 } 05769 return 1; 05770 } 05771 05772 #undef fopen 05773 FILE * 05774 rb_w32_fopen(const char *path, const char *mode) 05775 { 05776 FILE *f = (errno = 0, fopen(path, mode)); 05777 if (f == NULL && errno == 0) { 05778 if (too_many_files()) 05779 errno = EMFILE; 05780 } 05781 return f; 05782 } 05783 05784 FILE * 05785 rb_w32_fdopen(int handle, const char *type) 05786 { 05787 FILE *f = (errno = 0, _fdopen(handle, (char *)type)); 05788 if (f == NULL && errno == 0) { 05789 if (handle < 0) 05790 errno = EBADF; 05791 else if (too_many_files()) 05792 errno = EMFILE; 05793 } 05794 return f; 05795 } 05796 05797 FILE * 05798 rb_w32_fsopen(const char *path, const char *mode, int shflags) 05799 { 05800 FILE *f = (errno = 0, _fsopen(path, mode, shflags)); 05801 if (f == NULL && errno == 0) { 05802 if (too_many_files()) 05803 errno = EMFILE; 05804 } 05805 return f; 05806 } 05807 #endif 05808 05809 #if defined(_MSC_VER) && RT_VER <= 60 05810 extern long _ftol(double); 05811 long 05812 _ftol2(double d) 05813 { 05814 return _ftol(d); 05815 } 05816 long 05817 _ftol2_sse(double d) 05818 { 05819 return _ftol(d); 05820 } 05821 #endif 05822 05823 #ifndef signbit 05824 int 05825 signbit(double x) 05826 { 05827 int *ip = (int *)(&x + 1) - 1; 05828 return *ip < 0; 05829 } 05830 #endif 05831 05832 char * WSAAPI 05833 rb_w32_inet_ntop(int af, void *addr, char *numaddr, size_t numaddr_len) 05834 { 05835 typedef char *(WSAAPI inet_ntop_t)(int, void *, char *, size_t); 05836 inet_ntop_t *pInetNtop; 05837 pInetNtop = (inet_ntop_t *)get_proc_address("ws2_32", "inet_ntop", NULL); 05838 if(pInetNtop){ 05839 return pInetNtop(af,addr,numaddr,numaddr_len); 05840 }else{ 05841 struct in_addr in; 05842 memcpy(&in.s_addr, addr, sizeof(in.s_addr)); 05843 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in)); 05844 } 05845 return numaddr; 05846 } 05847 05848 char 05849 rb_w32_fd_is_text(int fd) { 05850 return _osfile(fd) & FTEXT; 05851 } 05852
1.7.6.1