summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--include/ruby/win32.h7
-rw-r--r--win32/win32.c95
3 files changed, 98 insertions, 18 deletions
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 <usa@ruby-lang.org>
+
+ * 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 <akr@fsij.org>
* 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