diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-12-13 07:56:24 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-12-13 07:56:24 +0900 |
| commit | 5a5adafabf754163e9ce9022236a6e52b4e66a0b (patch) | |
| tree | 0fabe7197d2861c5d8ce626d2d805b79cf805651 | |
| parent | c863e0dac85b2251a77e2a137d7bac0548e23932 (diff) | |
| parent | b07269584ce9a255655cff167ecf09d1dddf62f7 (diff) | |
| download | mruby-5a5adafabf754163e9ce9022236a6e52b4e66a0b.tar.gz mruby-5a5adafabf754163e9ce9022236a6e52b4e66a0b.zip | |
Merge pull request #3886 from mattn/io-windows
implement popen/flock on Windows
| -rw-r--r-- | mrbgems/mruby-io/src/file.c | 16 | ||||
| -rw-r--r-- | mrbgems/mruby-io/src/io.c | 132 | ||||
| -rw-r--r-- | mrbgems/mruby-io/test/mruby_io_test.c | 14 |
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(); } |
