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