diff --git a/collects/tests/racket/cat.rkt b/collects/tests/racket/cat.rkt new file mode 100644 index 0000000000..806957b820 --- /dev/null +++ b/collects/tests/racket/cat.rkt @@ -0,0 +1,24 @@ +#lang racket + +;; Implements a "cat.exe" executable under Windows for the +;; "subprocess.rktl" test. + +(require racket/port) + +(define files + (command-line + #:args + file + file)) + +(if (null? files) + (copy-port (current-input-port) + (current-output-port)) + (for ([f (in-list files)]) + (if (equal? f "-") + (copy-port (current-input-port) + (current-output-port)) + (if (file-exists? f) + (call-with-input-file* f (lambda (in) (copy-port in (current-output-port)))) + (raise-user-error 'cat "bad file ~a" f))))) +(flush-output) diff --git a/collects/tests/racket/subprocess.rktl b/collects/tests/racket/subprocess.rktl index 2cd91777b2..5d0d0d040e 100644 --- a/collects/tests/racket/subprocess.rktl +++ b/collects/tests/racket/subprocess.rktl @@ -8,7 +8,11 @@ (define self (parameterize ([current-directory (find-system-path 'orig-dir)]) (find-executable-path (find-system-path 'exec-file) #f))) -(define cat (find-executable-path "cat" #f)) +(define cat (find-executable-path + (if (eq? 'windows (system-type)) + "cat.exe" + "cat") + #f)) (define tmpfile (build-path (find-system-path 'temp-dir) "cattmp")) (define tmpfile2 (build-path (find-system-path 'temp-dir) "cattmp2")) diff --git a/src/racket/src/port.c b/src/racket/src/port.c index f0ef6029bd..012fc70638 100644 --- a/src/racket/src/port.c +++ b/src/racket/src/port.c @@ -7559,8 +7559,43 @@ static void close_subprocess_handle(void *sp, void *ignored) CloseHandle(subproc->handle); } +static void CopyFileHandleForSubprocess(int *hs, int pos) +{ + HANDLE h2; + int alt_pos = (pos ? 0 : 1); + + if (DuplicateHandle(GetCurrentProcess(), + (HANDLE)hs[pos], + GetCurrentProcess(), + &h2, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) { + hs[pos] = (int)h2; + hs[alt_pos] = 1; + } else { + hs[alt_pos] = 0; + } +} + +static void CloseFileHandleForSubprocess(int *hs, int pos) +{ + int alt_pos = (pos ? 0 : 1); + if (hs[alt_pos]) { + CloseHandle((HANDLE)hs[pos]); + } +} + +#define mzCOPY_FILE_HANDLE(array, pos) CopyFileHandleForSubprocess(array, pos) +#define mzCLOSE_FILE_HANDLE(array, pos) CloseFileHandleForSubprocess(array, pos) + #endif /* WINDOWS_PROCESSES */ +#ifndef mzCOPY_FILE_HANDLE +# define mzCOPY_FILE_HANDLE(array, pos) /* empty */ +# define mzCLOSE_FILE_HANDLE(array, pos) /* empty */ +#endif + /*********** All: The main system/process/execute function *************/ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) @@ -7616,6 +7651,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) else if (SAME_OBJ(op->sub_type, fd_output_port_type)) from_subprocess[1] = ((Scheme_FD *)op->port_data)->fd; # endif + mzCOPY_FILE_HANDLE(from_subprocess, 1); #endif } else scheme_wrong_type(name, "file-stream-output-port", 0, c, args); @@ -7639,6 +7675,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) else if (SAME_OBJ(ip->sub_type, fd_input_port_type)) to_subprocess[0] = ((Scheme_FD *)ip->port_data)->fd; # endif + mzCOPY_FILE_HANDLE(to_subprocess, 0); #endif } else scheme_wrong_type(name, "file-stream-input-port", 1, c, args); @@ -7662,6 +7699,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) else if (SAME_OBJ(op->sub_type, fd_output_port_type)) err_subprocess[1] = ((Scheme_FD *)op->port_data)->fd; # endif + mzCOPY_FILE_HANDLE(err_subprocess, 1); #endif } else scheme_wrong_type(name, "file-stream-output-port", 2, c, args); @@ -7736,23 +7774,33 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) /* Create needed pipes */ /*--------------------------------------*/ - if (!inport && PIPE_FUNC(to_subprocess, 1 _EXTRA_PIPE_ARGS)) + if (!inport && PIPE_FUNC(to_subprocess, 1 _EXTRA_PIPE_ARGS)) { + if (outport) { mzCLOSE_FILE_HANDLE(from_subprocess, 1); } + if (errport) { mzCLOSE_FILE_HANDLE(err_subprocess, 1); } scheme_raise_exn(MZEXN_FAIL, "%s: pipe failed (%e)", name, errno); + } if (!outport && PIPE_FUNC(from_subprocess, 0 _EXTRA_PIPE_ARGS)) { if (!inport) { MSC_IZE(close)(to_subprocess[0]); MSC_IZE(close)(to_subprocess[1]); + } else { + mzCLOSE_FILE_HANDLE(to_subprocess, 0); } + if (errport) { mzCLOSE_FILE_HANDLE(err_subprocess, 1); } scheme_raise_exn(MZEXN_FAIL, "%s: pipe failed (%e)", name, errno); } if (!errport && PIPE_FUNC(err_subprocess, 0 _EXTRA_PIPE_ARGS)) { if (!inport) { MSC_IZE(close)(to_subprocess[0]); MSC_IZE(close)(to_subprocess[1]); + } else { + mzCLOSE_FILE_HANDLE(to_subprocess, 0); } if (!outport) { MSC_IZE(close)(from_subprocess[0]); MSC_IZE(close)(from_subprocess[1]); + } else { + mzCLOSE_FILE_HANDLE(from_subprocess, 1); } scheme_raise_exn(MZEXN_FAIL, "%s: pipe failed (%e)", name, errno); } @@ -7892,14 +7940,20 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) if (!inport) { MSC_IZE(close)(to_subprocess[0]); MSC_IZE(close)(to_subprocess[1]); + } else { + mzCLOSE_FILE_HANDLE(to_subprocess, 0); } if (!outport) { MSC_IZE(close)(from_subprocess[0]); MSC_IZE(close)(from_subprocess[1]); + } else { + mzCLOSE_FILE_HANDLE(from_subprocess, 1); } if (!errport) { MSC_IZE(close)(err_subprocess[0]); MSC_IZE(close)(err_subprocess[1]); + } else { + mzCLOSE_FILE_HANDLE(err_subprocess, 1); } scheme_raise_exn(MZEXN_FAIL, "%s: fork failed (%e)", name, fork_errno); return scheme_false; @@ -8003,18 +8057,24 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) if (!inport) { mzCLOSE_PIPE_END(to_subprocess[0]); out = NULL; - } else + } else { + mzCLOSE_FILE_HANDLE(to_subprocess, 0); out = scheme_false; + } if (!outport) { mzCLOSE_PIPE_END(from_subprocess[1]); in = NULL; - } else + } else { + mzCLOSE_FILE_HANDLE(from_subprocess, 1); in = scheme_false; + } if (!errport) { mzCLOSE_PIPE_END(err_subprocess[1]); err = NULL; - } else + } else { + mzCLOSE_FILE_HANDLE(err_subprocess, 1); err = scheme_false; + } /*--------------------------------------*/ /* Create new port objects */