From 7ac32d7a16734ea66de15319bcff2fd429abae7f Mon Sep 17 00:00:00 2001 From: nobu Date: Sat, 20 Dec 2008 09:28:29 +0000 Subject: * dln.c (dln_find_1): supplements an extension for executable files on DOSish platforms. * io.c (pipe_open): use rb_w32_aspawn() for array form. * win32/win32.c (rb_w32_pipe_exec): no longer used. * win32/win32.c (rb_w32_spawn, rb_w32_aspawn): deals with batch files and commands with extensions. [ruby-core:20695] * win32/win32.c (has_redirection): supports environment variables references. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20892 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 15 +++ dln.c | 63 ++++++++++-- io.c | 16 ++-- win32/win32.c | 304 +++++++++++++++++++++++----------------------------------- 4 files changed, 196 insertions(+), 202 deletions(-) diff --git a/ChangeLog b/ChangeLog index a5e8628fe2..e09dfe8a4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +Sat Dec 20 18:28:26 2008 Nobuyoshi Nakada + + * dln.c (dln_find_1): supplements an extension for executable + files on DOSish platforms. + + * io.c (pipe_open): use rb_w32_aspawn() for array form. + + * win32/win32.c (rb_w32_pipe_exec): no longer used. + + * win32/win32.c (rb_w32_spawn, rb_w32_aspawn): deals with batch + files and commands with extensions. [ruby-core:20695] + + * win32/win32.c (has_redirection): supports environment variables + references. + Sat Dec 20 10:59:16 2008 Yuki Sonoda (Yugui) * lib/irb/locale.rb (IRB::Locale#initialize) diff --git a/dln.c b/dln.c index bb64c52a0f..d3408fb0f6 100644 --- a/dln.c +++ b/dln.c @@ -1518,28 +1518,70 @@ dln_find_1(const char *fname, const char *path, char *fbuf, int size, register const char *ep; register char *bp; struct stat st; + int i, fspace; +#ifdef DOSISH + int is_abs = 0, has_path = 0, has_ext = 0; + const char *p = fname; +#endif #define RETURN_IF(expr) if (expr) return (char *)fname; RETURN_IF(!fname); - RETURN_IF(fname[0] == '/'); - RETURN_IF(strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0); - RETURN_IF(exe_flag && strchr(fname, '/')); #ifdef DOSISH - RETURN_IF(fname[0] == '\\'); +# ifndef CharNext +# define CharNext(p) ((p)+1) +# endif # ifdef DOSISH_DRIVE_LETTER - RETURN_IF(strlen(fname) > 2 && fname[1] == ':'); + if (((p[0] | 0x20) - 'a') < 26 && p[1] == ':') { + p += 2; + is_abs = 1; + } # endif - RETURN_IF(strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0); - RETURN_IF(exe_flag && strchr(fname, '\\')); + switch (*p) { + case '/': case '\\': + is_abs = 1; + p++; + } + has_path = is_abs; + while (*p) { + switch (*p) { + case '/': case '\\': + has_path = 1; + has_ext = 0; + p++; + break; + case '.': + has_ext = 1; + p++; + break; + default: + p = CharNext(p); + } + } + ep = bp = 0; + if (!exe_flag) { + RETURN_IF(is_abs); + } + else if (has_path) { + RETURN_IF(has_ext); + i = p - fname; + if (i + 1 > size) goto toolong; + fspace = size - i - 1; + bp = fbuf; + ep = p; + memcpy(fbuf, fname, i + 1); + goto needs_extension; + } #endif + RETURN_IF(fname[0] == '/'); + RETURN_IF(strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0); + RETURN_IF(exe_flag && strchr(fname, '/')); + #undef RETURN_IF for (dp = path;; dp = ++ep) { register int l; - int i; - int fspace; /* extract a component */ ep = strchr(dp, PATH_SEP[0]); @@ -1602,7 +1644,7 @@ dln_find_1(const char *fname, const char *path, char *fbuf, int size, memcpy(bp, fname, i + 1); #if defined(DOSISH) - if (exe_flag) { + if (exe_flag && !has_ext) { static const char extension[][5] = { #if defined(__EMX__) || defined(_WIN32) ".exe", ".com", ".cmd", ".bat", @@ -1611,6 +1653,7 @@ dln_find_1(const char *fname, const char *path, char *fbuf, int size, }; int j; + needs_extension: for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) { if (fspace < strlen(extension[j])) { fprintf(stderr, "openpath: pathname too long (ignored)\n"); diff --git a/io.c b/io.c index 12c6bbba58..f5efd3719b 100644 --- a/io.c +++ b/io.c @@ -13,6 +13,7 @@ #include "ruby/ruby.h" #include "ruby/io.h" +#include "dln.h" #include #include @@ -4446,9 +4447,8 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode, int status; struct popen_arg arg; #elif defined(_WIN32) - int openmode = rb_io_modestr_oflags(modestr); - const char *exename = NULL; - volatile VALUE cmdbuf; + volatile VALUE argbuf; + char **args; struct rb_exec_arg sarg; int pair[2], write_pair[2]; #endif @@ -4557,8 +4557,6 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode, } #elif defined(_WIN32) if (argc) { - volatile VALUE argbuf; - char **args; int i; if (argc >= FIXNUM_MAX / sizeof(char *)) { @@ -4570,10 +4568,6 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode, args[i] = StringValueCStr(argv[i]); } args[i] = NULL; - exename = cmd; - cmdbuf = rb_str_tmp_new(rb_w32_argv_size(args)); - cmd = rb_w32_join_argv(RSTRING_PTR(cmdbuf), args); - rb_str_resize(argbuf, 0); } switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) { case FMODE_READABLE|FMODE_WRITABLE: @@ -4610,7 +4604,9 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode, rb_exec_arg_fixup(eargp); rb_run_exec_options(eargp, &sarg); } - while ((pid = rb_w32_spawn(P_NOWAIT, cmd, exename)) == -1) { + while ((pid = (args ? + rb_w32_aspawn(P_NOWAIT, 0, args) : + rb_w32_spawn(P_NOWAIT, cmd, 0))) == -1) { /* exec failed */ switch (errno) { case EAGAIN: diff --git a/win32/win32.c b/win32/win32.c index 872fcd013c..6cffc21ade 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -349,6 +349,17 @@ flock(int fd, int oper) (DWORD)-1); } +static inline char * +translate_char(char *p, int from, int to) +{ + while (*p) { + if ((unsigned char)*p == from) + *p = to; + p = CharNext(p); + } + return p; +} + static void init_env(void) { @@ -377,11 +388,7 @@ init_env(void) alloc->lpVtbl->Release(alloc); } if (f) { - char *p = env; - while (*p) { - if (*p == '\\') *p = '/'; - p = CharNext(p); - } + char *p = translate_char(env, '\\', '/'); if (p - env == 2 && env[1] == ':') { *p++ = '/'; *p = 0; @@ -752,143 +759,33 @@ rb_w32_join_argv(char *cmd, char *const *argv) return cmd; } -rb_pid_t -rb_w32_pipe_exec(const char *cmd, const char *prog, int mode, int *pipe, - int *write_pipe) -{ - struct ChildRecord* child; - HANDLE hIn, hOut; - HANDLE hDupIn, hDupOut; - HANDLE hCurProc; - SECURITY_ATTRIBUTES sa; - BOOL reading, writing; - int ret; - - /* Figure out what we're doing... */ - if (mode & O_RDWR) { - reading = writing = TRUE; - } - else if (mode & O_WRONLY) { - reading = FALSE; - writing = TRUE; - } - else { - reading = TRUE; - writing = FALSE; - } - mode &= ~(O_RDWR|O_RDONLY|O_WRONLY|O_TEXT); - mode |= O_BINARY; - - sa.nLength = sizeof (SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - ret = -1; - - RUBY_CRITICAL(do { - /* create pipe */ - hCurProc = GetCurrentProcess(); - hIn = hOut = hDupIn = hDupOut = NULL; - if (reading) { - HANDLE hTmpIn; - if (!CreatePipe(&hTmpIn, &hOut, &sa, 2048L)) { - errno = map_errno(GetLastError()); - break; - } - if (!DuplicateHandle(hCurProc, hTmpIn, hCurProc, &hDupIn, 0, - FALSE, DUPLICATE_SAME_ACCESS)) { - errno = map_errno(GetLastError()); - CloseHandle(hTmpIn); - CloseHandle(hOut); - break; - } - CloseHandle(hTmpIn); - hTmpIn = NULL; - } - if (writing) { - HANDLE hTmpOut; - if (!CreatePipe(&hIn, &hTmpOut, &sa, 2048L)) { - errno = map_errno(GetLastError()); - break; - } - if (!DuplicateHandle(hCurProc, hTmpOut, hCurProc, &hDupOut, 0, - FALSE, DUPLICATE_SAME_ACCESS)) { - errno = map_errno(GetLastError()); - CloseHandle(hIn); - CloseHandle(hTmpOut); - break; - } - CloseHandle(hTmpOut); - hTmpOut = NULL; - } - - /* create child process */ - child = CreateChild(cmd, prog, &sa, hIn, hOut, NULL); - if (!child) { - if (hIn) - CloseHandle(hIn); - if (hOut) - CloseHandle(hOut); - if (hDupIn) - CloseHandle(hDupIn); - if (hDupOut) - CloseHandle(hDupOut); - break; - } - - /* associate handle to file descritor */ - if (reading) { - *pipe = rb_w32_open_osfhandle((intptr_t)hDupIn, O_RDONLY | mode); - if (writing) - *write_pipe = rb_w32_open_osfhandle((intptr_t)hDupOut, - O_WRONLY | mode); - } - else { - *pipe = rb_w32_open_osfhandle((intptr_t)hDupOut, O_WRONLY | mode); - } - if (hIn) - CloseHandle(hIn); - if (hOut) - CloseHandle(hOut); - if (reading && writing && *write_pipe == -1) { - if (*pipe != -1) - rb_w32_close(*pipe); - else - CloseHandle(hDupIn); - CloseHandle(hDupOut); - CloseChildHandle(child); - break; - } - else if (*pipe == -1) { - if (reading) - CloseHandle(hDupIn); - else - CloseHandle(hDupOut); - CloseChildHandle(child); - break; - } - - ret = child->pid; - } while (0)); +#ifdef HAVE_SYS_PARAM_H +# include +#else +# define MAXPATHLEN 512 +#endif - return ret; -} +#define STRNDUPA(ptr, src, len) \ + (((char *)memcpy(((ptr) = ALLOCA_N(char, (len) + 1)), (src), (len)))[len] = 0) -rb_pid_t -rb_w32_spawn(int mode, const char *cmd, const char *prog) +static int +check_spawn_mode(int mode) { - struct ChildRecord *child; - DWORD exitcode; - switch (mode) { case P_NOWAIT: case P_OVERLAY: - break; + return 0; default: errno = EINVAL; return -1; } +} + +static rb_pid_t +child_result(struct ChildRecord *child, int mode) +{ + DWORD exitcode; - child = CreateChild(cmd, prog, NULL, NULL, NULL, NULL); if (!child) { return -1; } @@ -906,22 +803,6 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog) } } -rb_pid_t -rb_w32_aspawn(int mode, const char *prog, char *const *argv) -{ - int len = rb_w32_argv_size(argv); - char *cmd = ALLOCA_N(char, len); - - if (!prog) prog = argv[0]; - return rb_w32_spawn(mode, rb_w32_join_argv(cmd, argv), prog); -} - -#ifdef HAVE_SYS_PARAM_H -# include -#else -# define MAXPATHLEN 512 -#endif - static struct ChildRecord * CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HANDLE hOutput, HANDLE hError) @@ -931,10 +812,7 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa, STARTUPINFO aStartupInfo; PROCESS_INFORMATION aProcessInformation; SECURITY_ATTRIBUTES sa; - const char *shell; struct ChildRecord *child; - char *p = NULL; - char fbuf[MAXPATHLEN]; if (!cmd && !prog) { errno = EFAULT; @@ -981,6 +859,40 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa, dwCreationFlags = (NORMAL_PRIORITY_CLASS); + RUBY_CRITICAL({ + fRet = CreateProcess(prog, (char *)cmd, psa, psa, + psa->bInheritHandle, dwCreationFlags, NULL, NULL, + &aStartupInfo, &aProcessInformation); + errno = map_errno(GetLastError()); + }); + + if (!fRet) { + child->pid = 0; /* release the slot */ + return NULL; + } + + CloseHandle(aProcessInformation.hThread); + + child->hProcess = aProcessInformation.hProcess; + child->pid = (rb_pid_t)aProcessInformation.dwProcessId; + + if (!IsWinNT()) { + /* On Win9x, make pid positive similarly to cygwin and perl */ + child->pid = -child->pid; + } + + return child; +} + +rb_pid_t +rb_w32_spawn(int mode, const char *cmd, const char *prog) +{ + char fbuf[MAXPATHLEN]; + char *p = NULL; + const char *shell = NULL; + + if (check_spawn_mode(mode)) return -1; + if (prog) { if (!(p = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) { shell = prog; @@ -1024,20 +936,17 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa, p = dln_find_exe_r(cmd, NULL, fbuf, sizeof(fbuf)); break; } - if (strchr(".:*?\"/\\", *prog)) { + if (strchr(":*?\"/\\", *prog)) { if (cmd[len]) { - char *tmp = ALLOCA_N(char, len + 1); - memcpy(tmp, cmd, len); - tmp[len] = 0; - cmd = tmp; + STRNDUPA(p, cmd, len); } + p = dln_find_exe_r(p ? p : cmd, NULL, fbuf, sizeof(fbuf)); + cmd += len; break; } if (ISSPACE(*prog) || strchr("<>|", *prog)) { len = prog - cmd; - p = ALLOCA_N(char, len + 1); - memcpy(p, cmd, len); - p[len] = 0; + STRNDUPA(p, cmd, len); p = dln_find_exe_r(p, NULL, fbuf, sizeof(fbuf)); break; } @@ -1047,36 +956,61 @@ CreateChild(const char *cmd, const char *prog, SECURITY_ATTRIBUTES *psa, } if (p) { shell = p; - while (*p) { - if ((unsigned char)*p == '/') - *p = '\\'; - p = CharNext(p); - } + translate_char(p, '/', '\\'); } - RUBY_CRITICAL({ - fRet = CreateProcess(shell, (char *)cmd, psa, psa, - psa->bInheritHandle, dwCreationFlags, NULL, NULL, - &aStartupInfo, &aProcessInformation); - errno = map_errno(GetLastError()); - }); - - if (!fRet) { - child->pid = 0; /* release the slot */ - return NULL; - } + return child_result(CreateChild(cmd, shell, NULL, NULL, NULL, NULL), mode); +} - CloseHandle(aProcessInformation.hThread); +rb_pid_t +rb_w32_aspawn(int mode, const char *prog, char *const *argv) +{ + int len, differ = 0, c_switch =0; + const char *shell; + char *cmd, fbuf[MAXPATHLEN]; - child->hProcess = aProcessInformation.hProcess; - child->pid = (rb_pid_t)aProcessInformation.dwProcessId; + if (check_spawn_mode(mode)) return -1; - if (!IsWinNT()) { - /* On Win9x, make pid positive similarly to cygwin and perl */ - child->pid = -child->pid; + if (!prog) prog = argv[0]; + if ((shell = getenv("COMSPEC")) && + (has_redirection(prog) || + is_internal_cmd(prog, !is_command_com(shell)))) { + prog = shell; + c_switch = 1; + differ = 1; + } + else if ((cmd = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf)))) { + if (cmd == prog) strlcpy(cmd = fbuf, prog, sizeof(fbuf)); + translate_char(cmd, '/', '\\'); + prog = cmd; + argv++; + differ = 1; + } + else if (strchr(prog, '/')) { + strlcpy(fbuf, prog, sizeof(fbuf)); + translate_char(fbuf, '/', '\\'); + prog = fbuf; + argv++; + differ = 1; + } + if (differ) { + char *progs[2]; + progs[0] = (char *)prog; + progs[1] = NULL; + len = rb_w32_argv_size(progs); + if (c_switch) len += 3; + if (argv[0]) len += rb_w32_argv_size(argv); + cmd = ALLOCA_N(char, len); + rb_w32_join_argv(cmd, progs); + if (c_switch) strlcat(cmd, " /c", len); + if (argv[0]) rb_w32_join_argv(cmd + strlcat(cmd, " ", len), argv); } - - return child; + else { + len = rb_w32_argv_size(argv); + cmd = ALLOCA_N(char, len); + rb_w32_join_argv(cmd, argv); + } + return child_result(CreateChild(cmd, prog, NULL, NULL, NULL, NULL), mode); } typedef struct _NtCmdLineElement { @@ -1176,6 +1110,12 @@ has_redirection(const char *cmd) ptr++; break; + case '%': + if (*++ptr != '_' && !ISALPHA(*ptr)) break; + while (*++ptr == '_' || ISALNUM(*ptr)); + if (*ptr++ == '%') return TRUE; + break; + case '\\': ptr++; default: -- cgit v1.2.3