summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-io
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-12-13 07:56:24 +0900
committerGitHub <[email protected]>2017-12-13 07:56:24 +0900
commit5a5adafabf754163e9ce9022236a6e52b4e66a0b (patch)
tree0fabe7197d2861c5d8ce626d2d805b79cf805651 /mrbgems/mruby-io
parentc863e0dac85b2251a77e2a137d7bac0548e23932 (diff)
parentb07269584ce9a255655cff167ecf09d1dddf62f7 (diff)
downloadmruby-5a5adafabf754163e9ce9022236a6e52b4e66a0b.tar.gz
mruby-5a5adafabf754163e9ce9022236a6e52b4e66a0b.zip
Merge pull request #3886 from mattn/io-windows
implement popen/flock on Windows
Diffstat (limited to 'mrbgems/mruby-io')
-rw-r--r--mrbgems/mruby-io/src/file.c16
-rw-r--r--mrbgems/mruby-io/src/io.c132
-rw-r--r--mrbgems/mruby-io/test/mruby_io_test.c14
3 files changed, 151 insertions, 11 deletions
diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c
index 17fdeeed5..bcfd42408 100644
--- a/mrbgems/mruby-io/src/file.c
+++ b/mrbgems/mruby-io/src/file.c
@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32) || defined(_WIN64)
+ #include <windows.h>
+ #include <io.h>
#define NULL_FILE "NUL"
#define UNLINK _unlink
#define GETCWD _getcwd
@@ -70,6 +72,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)
@@ -284,7 +298,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;
diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c
index 99ddf4e39..02aea381c 100644
--- a/mrbgems/mruby-io/src/io.c
+++ b/mrbgems/mruby-io/src/io.c
@@ -29,11 +29,16 @@
#define write _write
#define lseek _lseek
#define isatty _isatty
+ #define WEXITSTATUS(x) (x)
#else
#include <sys/wait.h>
#include <unistd.h>
#endif
+#ifdef _MSC_VER
+typedef mrb_int pid_t;
+#endif
+
#include <fcntl.h>
#include <errno.h>
@@ -70,7 +75,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 +95,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 +268,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 +288,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 +423,104 @@ 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;
+ 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 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,8 +587,8 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
fptr->fd2 = -1;
}
-#if !defined(_WIN32) && !defined(_WIN64)
if (fptr->pid != 0) {
+#if !defined(_WIN32) && !defined(_WIN64)
pid_t pid;
int status;
do {
@@ -496,10 +597,17 @@ 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);
+ CloseHandle(h);
+#endif
fptr->pid = 0;
/* Note: we don't raise an exception when waitpid(3) fails */
}
-#endif
if (!quiet && saved_errno != 0) {
errno = saved_errno;
@@ -736,6 +844,17 @@ mrb_io_close(mrb_state *mrb, mrb_value self)
}
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)
{
struct mrb_io *fptr;
@@ -1092,10 +1211,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 +1229,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 */
diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c
index e0596e93d..32887f066 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)
@@ -54,8 +56,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 +71,16 @@ 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();
+ }
+ close(fd0);
+ close(fd1);
#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();
}