From b8ca0b7cd826545449a2066ddc9c4308c1e76805 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 12 Dec 2017 18:07:38 +0900 Subject: implement popen on Windows --- mrbgems/mruby-io/src/io.c | 128 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 7 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 99ddf4e39..c8eb1f787 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -29,6 +29,7 @@ #define write _write #define lseek _lseek #define isatty _isatty + #define WEXITSTATUS(x) (x) #else #include #include @@ -70,7 +71,6 @@ io_get_open_fptr(mrb_state *mrb, mrb_value self) return fptr; } -#if !defined(_WIN32) && !defined(_WIN64) static void io_set_process_status(mrb_state *mrb, pid_t pid, int status) { @@ -91,7 +91,6 @@ io_set_process_status(mrb_state *mrb, pid_t pid, int status) } mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$?"), v); } -#endif static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode) @@ -265,7 +264,6 @@ mrb_io_alloc(mrb_state *mrb) #define NOFILE 64 #endif -#ifndef _WIN32 static int option_to_fd(mrb_state *mrb, mrb_value obj, const char *key) { @@ -286,6 +284,7 @@ option_to_fd(mrb_state *mrb, mrb_value obj, const char *key) return -1; /* never reached */ } +#ifndef _WIN32 mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { @@ -420,6 +419,105 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) } return result; } +#else +mrb_value +mrb_io_s_popen(mrb_state *mrb, mrb_value klass) +{ + mrb_value cmd, io, result; + mrb_value mode = mrb_str_new_cstr(mrb, "r"); + mrb_value opt = mrb_hash_new(mrb); + + struct mrb_io *fptr; + const char *pname; + int pid = 0, flags; + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES saAttr; + + HANDLE ifd[2]; + HANDLE ofd[2]; + + int doexec; + int saved_errno; + int opt_in, opt_out, opt_err; + + ifd[0] = INVALID_HANDLE_VALUE; + ifd[1] = INVALID_HANDLE_VALUE; + ofd[0] = INVALID_HANDLE_VALUE; + ofd[1] = INVALID_HANDLE_VALUE; + + mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); + io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + + pname = mrb_string_value_cstr(mrb, &cmd); + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + + doexec = (strcmp("-", pname) != 0); + opt_in = option_to_fd(mrb, opt, "in"); + opt_out = option_to_fd(mrb, opt, "out"); + opt_err = option_to_fd(mrb, opt, "err"); + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (flags & FMODE_READABLE) { + if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0) + || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) { + mrb_sys_fail(mrb, "pipe"); + } + } + + if (flags & FMODE_WRITABLE) { + if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0) + || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) { + mrb_sys_fail(mrb, "pipe"); + } + } + + if (doexec) { + ZeroMemory(&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags |= STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + si.dwFlags |= STARTF_USESTDHANDLES; + if (flags & FMODE_READABLE) { + si.hStdOutput = ofd[1]; + si.hStdError = ofd[1]; + } + if (flags & FMODE_WRITABLE) { + si.hStdInput = ifd[0]; + } + if (!CreateProcess( + NULL, (char*)pname, NULL, NULL, + TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { + CloseHandle(ifd[0]); + CloseHandle(ifd[1]); + CloseHandle(ofd[0]); + CloseHandle(ofd[1]); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); + } + CloseHandle(pi.hThread); + CloseHandle(ifd[0]); + CloseHandle(ofd[1]); + pid = pi.dwProcessId; + } + + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + + fptr = mrb_io_alloc(mrb); + fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0); + fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0); + fptr->pid = pid; + fptr->readable = ((flags & FMODE_READABLE) != 0); + fptr->writable = ((flags & FMODE_WRITABLE) != 0); + fptr->sync = 0; + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = fptr; + return io; +} #endif mrb_value @@ -486,9 +584,9 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) fptr->fd2 = -1; } -#if !defined(_WIN32) && !defined(_WIN64) if (fptr->pid != 0) { pid_t pid; +#if !defined(_WIN32) && !defined(_WIN64) int status; do { pid = waitpid(fptr->pid, &status, 0); @@ -496,10 +594,16 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) if (!quiet && pid == fptr->pid) { io_set_process_status(mrb, pid, status); } +#else + HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid); + DWORD status; + if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status)) + if (!quiet) + io_set_process_status(mrb, fptr->pid, (int)status); +#endif fptr->pid = 0; /* Note: we don't raise an exception when waitpid(3) fails */ } -#endif if (!quiet && saved_errno != 0) { errno = saved_errno; @@ -735,6 +839,17 @@ mrb_io_close(mrb_state *mrb, mrb_value self) return mrb_nil_value(); } +mrb_value +mrb_io_close_write(mrb_state *mrb, mrb_value self) +{ + struct mrb_io *fptr; + fptr = io_get_open_fptr(mrb, self); + if (close((int)fptr->fd2) == -1) { + mrb_sys_fail(mrb, "close"); + } + return mrb_nil_value(); +} + mrb_value mrb_io_closed(mrb_state *mrb, mrb_value io) { @@ -1092,10 +1207,8 @@ mrb_init_io(mrb_state *mrb) MRB_SET_INSTANCE_TT(io, MRB_TT_DATA); mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */ -#ifndef _WIN32 mrb_define_class_method(mrb, io, "_popen", mrb_io_s_popen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "_sysclose", mrb_io_s_sysclose, MRB_ARGS_REQ(1)); -#endif mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); @@ -1112,6 +1225,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_method(mrb, io, "sysseek", mrb_io_sysseek, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "syswrite", mrb_io_syswrite, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "close", mrb_io_close, MRB_ARGS_NONE()); /* 15.2.20.5.1 */ + mrb_define_method(mrb, io, "close_write", mrb_io_close_write, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1)); mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */ -- cgit v1.2.3 From d549603a8a7022baf889fb2b1d762f18c9898127 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 12 Dec 2017 18:11:15 +0900 Subject: close handle --- mrbgems/mruby-io/src/io.c | 1 + 1 file changed, 1 insertion(+) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index c8eb1f787..0eb007504 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -600,6 +600,7 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status)) if (!quiet) io_set_process_status(mrb, fptr->pid, (int)status); + CloseHandle(h); #endif fptr->pid = 0; /* Note: we don't raise an exception when waitpid(3) fails */ -- cgit v1.2.3 From 06ec17de6052f5c7b64c1fcc07d9f631c3616596 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 12 Dec 2017 18:38:02 +0900 Subject: add definition for pid_t on MSVC --- mrbgems/mruby-io/src/io.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 0eb007504..c5f7a8f5a 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -35,6 +35,10 @@ #include #endif +#ifdef _MSC_VER +typedef int pid_t; +#endif + #include #include -- cgit v1.2.3 From f6f8bb2416993cc22c73647408fd66704fb1a759 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 12 Dec 2017 18:41:49 +0900 Subject: fix compilation error --- mrbgems/mruby-io/src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index c5f7a8f5a..b114b4563 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -36,7 +36,7 @@ #endif #ifdef _MSC_VER -typedef int pid_t; +typedef mrb_int pid_t; #endif #include -- cgit v1.2.3 From df2c3771f806e12ae62a2cf9d506580b348335b1 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 12 Dec 2017 18:43:25 +0900 Subject: fix compilation error --- mrbgems/mruby-io/src/io.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index b114b4563..02aea381c 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -427,7 +427,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { - mrb_value cmd, io, result; + mrb_value cmd, io; mrb_value mode = mrb_str_new_cstr(mrb, "r"); mrb_value opt = mrb_hash_new(mrb); @@ -442,7 +442,6 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) HANDLE ofd[2]; int doexec; - int saved_errno; int opt_in, opt_out, opt_err; ifd[0] = INVALID_HANDLE_VALUE; @@ -589,8 +588,8 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) } if (fptr->pid != 0) { - pid_t pid; #if !defined(_WIN32) && !defined(_WIN64) + pid_t pid; int status; do { pid = waitpid(fptr->pid, &status, 0); -- cgit v1.2.3 From f1ea7a31c091d3caa74ed0fe9f411ed17db4680f Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 12 Dec 2017 23:21:41 +0900 Subject: implement flock on Windows --- mrbgems/mruby-io/src/file.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 19603c856..e38e6a2b6 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -24,6 +24,7 @@ #include #include #if defined(_WIN32) || defined(_WIN64) + #include #define NULL_FILE "NUL" #define UNLINK _unlink #define GETCWD _getcwd @@ -70,6 +71,18 @@ #define STAT(p, s) stat(p, s) +#ifdef _WIN32 +static int +flock(int fd, int operation) { + OVERLAPPED ov; + HANDLE h = (HANDLE)_get_osfhandle(fd); + DWORD flags; + flags = ((operation & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0) + | ((operation & LOCK_SH) ? LOCKFILE_EXCLUSIVE_LOCK : 0); + memset(&ov, 0, sizeof(ov)); + return LockFileEx(h, flags, 0, 0xffffffff, 0xffffffff, &ov) ? 0 : -1; +} +#endif mrb_value mrb_file_s_umask(mrb_state *mrb, mrb_value klass) @@ -283,7 +296,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) mrb_value mrb_file_flock(mrb_state *mrb, mrb_value self) { -#if defined(_WIN32) || defined(_WIN64) || defined(sun) +#if defined(sun) mrb_raise(mrb, E_NOTIMP_ERROR, "flock is not supported on Illumos/Solaris/Windows"); #else mrb_int operation; -- cgit v1.2.3 From 7ff907f6805007588775a5d872b4c6d9cb15746e Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 13 Dec 2017 00:07:51 +0900 Subject: fix test --- mrbgems/mruby-io/test/mruby_io_test.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index e0596e93d..53824522d 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -54,8 +54,8 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) { char rfname[] = "tmp.mruby-io-test-r.XXXXXXXX"; char wfname[] = "tmp.mruby-io-test-w.XXXXXXXX"; - char symlinkname[] = "tmp.mruby-io-test.XXXXXXXX"; - char socketname[] = "/tmp/mruby-io-test.XXXXXXXX"; + char symlinkname[] = "tmp.mruby-io-test-l.XXXXXXXX"; + char socketname[] = "tmp.mruby-io-test-s.XXXXXXXX"; char msg[] = "mruby io test\n"; mode_t mask; int fd0, fd1; @@ -69,10 +69,14 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) mask = umask(077); fd0 = mkstemp(rfname); fd1 = mkstemp(wfname); + if (fd0 == -1 || fd1 == -1) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file"); + return mrb_nil_value(); + } #if !defined(_WIN32) && !defined(_WIN64) fd2 = mkstemp(symlinkname); fd3 = mkstemp(socketname); - if (fd0 == -1 || fd1 == -1 || fd2 == -1 || fd3 == -1) { + if (fd2 == -1 || fd3 == -1) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file"); return mrb_nil_value(); } -- cgit v1.2.3 From 7c8c9f9532324fd8c93afa22ed365c74e7e7e610 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 13 Dec 2017 00:08:10 +0900 Subject: mingw have mkstemp --- mrbgems/mruby-io/test/mruby_io_test.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index 53824522d..7e25dddc2 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -15,12 +15,14 @@ typedef int mode_t; #endif +#ifdef _MSC_VER static int mkstemp(char *p) { _mktemp(p); return 0; } +#endif static char* mkdtemp(char *temp) -- cgit v1.2.3 From e0e23b17655ae599dbb402cf0beb0c59e8ebd3c6 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 13 Dec 2017 00:18:02 +0900 Subject: close file descriptors --- mrbgems/mruby-io/test/mruby_io_test.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index 7e25dddc2..32887f066 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -75,6 +75,8 @@ mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file"); return mrb_nil_value(); } + close(fd0); + close(fd1); #if !defined(_WIN32) && !defined(_WIN64) fd2 = mkstemp(symlinkname); fd3 = mkstemp(socketname); -- cgit v1.2.3 From b07269584ce9a255655cff167ecf09d1dddf62f7 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Wed, 13 Dec 2017 00:21:30 +0900 Subject: fix build for MSVC --- mrbgems/mruby-io/src/file.c | 1 + 1 file changed, 1 insertion(+) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index e38e6a2b6..11b05d31c 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -25,6 +25,7 @@ #include #if defined(_WIN32) || defined(_WIN64) #include + #include #define NULL_FILE "NUL" #define UNLINK _unlink #define GETCWD _getcwd -- cgit v1.2.3