diff --git a/ChangeLog b/ChangeLog index 1a5052ab45..5484d2f375 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +Mon Oct 31 13:10:06 2011 NAKAMURA Usaku + + * win32/win32.c (setfl): extract from fcntl(). + + * win32/win32.c (dupfd): new function to support F_DUPFD. base on a + patch written by akr. + + * win32/win32.c (fcntl): use above functions. + + * include/ruby/win32.h (F_DUPFD): define. [experimental] + + * include/ruby/win32.h (F_SETFL): change the value to correspond with + other platforms. + Mon Oct 31 12:37:50 2011 Tanaka Akira * ext/pty/pty.c (get_device_once): use O_CLOEXEC for posix_openpt if diff --git a/include/ruby/win32.h b/include/ruby/win32.h index bba38dcf4a..b0150b6a19 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -569,7 +569,12 @@ extern char *rb_w32_strerror(int); # define EREMOTE WSAEREMOTE #endif -#define F_SETFL 1 +#define F_DUPFD 0 +//#define F_GETFD 1 +//#define F_SETFD 2 +//#define F_GETFL 3 +#define F_SETFL 4 +//#define FD_CLOEXEC 1 /* F_GETFD, F_SETFD */ #define O_NONBLOCK 1 #undef FD_SET diff --git a/win32/win32.c b/win32/win32.c index 6b201764f1..5851377ff2 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -3766,28 +3766,13 @@ void setprotoent (int stayopen) {} void setservent (int stayopen) {} /* License: Ruby's */ -int -fcntl(int fd, int cmd, ...) +static int +setfl(SOCKET sock, int arg) { - SOCKET sock = TO_SOCKET(fd); - va_list va; - int arg; int ret; int flag = 0; u_long ioctlArg; - if (!is_socket(sock)) { - errno = EBADF; - return -1; - } - if (cmd != F_SETFL) { - errno = EINVAL; - return -1; - } - - va_start(va, cmd); - arg = va_arg(va, int); - va_end(va); socklist_lookup(sock, &flag); if (arg & O_NONBLOCK) { flag |= O_NONBLOCK; @@ -3808,6 +3793,82 @@ fcntl(int fd, int cmd, ...) return ret; } +/* License: Ruby's */ +static int +dupfd(HANDLE hDup, char flags, int minfd) +{ + int save_errno; + int ret; + int fds[32]; + int filled = 0; + + do { + ret = _open_osfhandle((intptr_t)hDup, flags | FOPEN); + if (ret == -1) { + goto close_fds_and_return; + } + if (ret >= minfd) { + goto close_fds_and_return; + } + fds[filled++] = ret; + } while (filled < (sizeof(fds)/sizeof(fds[0]))); + + ret = dupfd(hDup, flags, minfd); + + close_fds_and_return: + save_errno = errno; + while (filled > 0) { + _osfhnd(fds[--filled]) = (intptr_t)INVALID_HANDLE_VALUE; + close(fds[filled]); + } + errno = save_errno; + + return ret; +} + +/* License: Ruby's */ +int +fcntl(int fd, int cmd, ...) +{ + va_list va; + int arg; + + if (cmd == F_SETFL) { + SOCKET sock = TO_SOCKET(fd); + if (!is_socket(sock)) { + errno = EBADF; + return -1; + } + + va_start(va, cmd); + arg = va_arg(va, int); + va_end(va); + return setfl(sock, arg); + } + else if (cmd == F_DUPFD) { + int ret; + HANDLE hDup; + if (!(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &hDup, 0L, TRUE, + DUPLICATE_SAME_ACCESS))) { + errno = map_errno(GetLastError()); + return -1; + } + + va_start(va, cmd); + arg = va_arg(va, int); + va_end(va); + + if ((ret = dupfd(hDup, _osfile(fd), arg)) == -1) + CloseHandle(hDup); + return ret; + } + else { + errno = EINVAL; + return -1; + } +} + #ifndef WNOHANG #define WNOHANG -1 #endif