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