|
Packit |
b5b901 |
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
Packit |
b5b901 |
*
|
|
Packit |
b5b901 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit |
b5b901 |
* of this software and associated documentation files (the "Software"), to
|
|
Packit |
b5b901 |
* deal in the Software without restriction, including without limitation the
|
|
Packit |
b5b901 |
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
Packit |
b5b901 |
* sell copies of the Software, and to permit persons to whom the Software is
|
|
Packit |
b5b901 |
* furnished to do so, subject to the following conditions:
|
|
Packit |
b5b901 |
*
|
|
Packit |
b5b901 |
* The above copyright notice and this permission notice shall be included in
|
|
Packit |
b5b901 |
* all copies or substantial portions of the Software.
|
|
Packit |
b5b901 |
*
|
|
Packit |
b5b901 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
Packit |
b5b901 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
Packit |
b5b901 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
Packit |
b5b901 |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
Packit |
b5b901 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
Packit |
b5b901 |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
Packit |
b5b901 |
* IN THE SOFTWARE.
|
|
Packit |
b5b901 |
*/
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
#include <assert.h>
|
|
Packit |
b5b901 |
#include <io.h>
|
|
Packit |
b5b901 |
#include <stdio.h>
|
|
Packit |
b5b901 |
#include <stdlib.h>
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
#include "uv.h"
|
|
Packit |
b5b901 |
#include "internal.h"
|
|
Packit |
b5b901 |
#include "handle-inl.h"
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/*
|
|
Packit |
b5b901 |
* The `child_stdio_buffer` buffer has the following layout:
|
|
Packit |
b5b901 |
* int number_of_fds
|
|
Packit |
b5b901 |
* unsigned char crt_flags[number_of_fds]
|
|
Packit |
b5b901 |
* HANDLE os_handle[number_of_fds]
|
|
Packit |
b5b901 |
*/
|
|
Packit |
b5b901 |
#define CHILD_STDIO_SIZE(count) \
|
|
Packit |
b5b901 |
(sizeof(int) + \
|
|
Packit |
b5b901 |
sizeof(unsigned char) * (count) + \
|
|
Packit |
b5b901 |
sizeof(uintptr_t) * (count))
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
#define CHILD_STDIO_COUNT(buffer) \
|
|
Packit |
b5b901 |
*((unsigned int*) (buffer))
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
|
|
Packit |
b5b901 |
*((unsigned char*) (buffer) + sizeof(int) + fd)
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
#define CHILD_STDIO_HANDLE(buffer, fd) \
|
|
Packit |
b5b901 |
*((HANDLE*) ((unsigned char*) (buffer) + \
|
|
Packit |
b5b901 |
sizeof(int) + \
|
|
Packit |
b5b901 |
sizeof(unsigned char) * \
|
|
Packit |
b5b901 |
CHILD_STDIO_COUNT((buffer)) + \
|
|
Packit |
b5b901 |
sizeof(HANDLE) * (fd)))
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* CRT file descriptor mode flags */
|
|
Packit |
b5b901 |
#define FOPEN 0x01
|
|
Packit |
b5b901 |
#define FEOFLAG 0x02
|
|
Packit |
b5b901 |
#define FCRLF 0x04
|
|
Packit |
b5b901 |
#define FPIPE 0x08
|
|
Packit |
b5b901 |
#define FNOINHERIT 0x10
|
|
Packit |
b5b901 |
#define FAPPEND 0x20
|
|
Packit |
b5b901 |
#define FDEV 0x40
|
|
Packit |
b5b901 |
#define FTEXT 0x80
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/*
|
|
Packit |
b5b901 |
* Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
|
|
Packit |
b5b901 |
* the parent process. Don't check for errors - the stdio handles may not be
|
|
Packit |
b5b901 |
* valid, or may be closed already. There is no guarantee that this function
|
|
Packit |
b5b901 |
* does a perfect job.
|
|
Packit |
b5b901 |
*/
|
|
Packit |
b5b901 |
void uv_disable_stdio_inheritance(void) {
|
|
Packit |
b5b901 |
HANDLE handle;
|
|
Packit |
b5b901 |
STARTUPINFOW si;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Make the windows stdio handles non-inheritable. */
|
|
Packit |
b5b901 |
handle = GetStdHandle(STD_INPUT_HANDLE);
|
|
Packit |
b5b901 |
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
|
|
Packit |
b5b901 |
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
Packit |
b5b901 |
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
|
|
Packit |
b5b901 |
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
handle = GetStdHandle(STD_ERROR_HANDLE);
|
|
Packit |
b5b901 |
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
|
|
Packit |
b5b901 |
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Make inherited CRT FDs non-inheritable. */
|
|
Packit |
b5b901 |
GetStartupInfoW(&si);
|
|
Packit |
b5b901 |
if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
|
|
Packit |
b5b901 |
uv__stdio_noinherit(si.lpReserved2);
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
|
Packit |
b5b901 |
uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
|
|
Packit |
b5b901 |
char pipe_name[64];
|
|
Packit |
b5b901 |
SECURITY_ATTRIBUTES sa;
|
|
Packit |
b5b901 |
DWORD server_access = 0;
|
|
Packit |
b5b901 |
DWORD client_access = 0;
|
|
Packit |
b5b901 |
HANDLE child_pipe = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
int err;
|
|
Packit |
b5b901 |
int overlap;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
if (flags & UV_READABLE_PIPE) {
|
|
Packit |
b5b901 |
/* The server needs inbound access too, otherwise CreateNamedPipe() won't
|
|
Packit |
b5b901 |
* give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
|
|
Packit |
b5b901 |
* state of the write buffer when we're trying to shutdown the pipe. */
|
|
Packit |
b5b901 |
server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
|
|
Packit |
b5b901 |
client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
if (flags & UV_WRITABLE_PIPE) {
|
|
Packit |
b5b901 |
server_access |= PIPE_ACCESS_INBOUND;
|
|
Packit |
b5b901 |
client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Create server pipe handle. */
|
|
Packit |
b5b901 |
err = uv_stdio_pipe_server(loop,
|
|
Packit |
b5b901 |
server_pipe,
|
|
Packit |
b5b901 |
server_access,
|
|
Packit |
b5b901 |
pipe_name,
|
|
Packit |
b5b901 |
sizeof(pipe_name));
|
|
Packit |
b5b901 |
if (err)
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Create child pipe handle. */
|
|
Packit |
b5b901 |
sa.nLength = sizeof sa;
|
|
Packit |
b5b901 |
sa.lpSecurityDescriptor = NULL;
|
|
Packit |
b5b901 |
sa.bInheritHandle = TRUE;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
|
|
Packit |
b5b901 |
child_pipe = CreateFileA(pipe_name,
|
|
Packit |
b5b901 |
client_access,
|
|
Packit |
b5b901 |
0,
|
|
Packit |
b5b901 |
&sa,
|
|
Packit |
b5b901 |
OPEN_EXISTING,
|
|
Packit |
b5b901 |
overlap ? FILE_FLAG_OVERLAPPED : 0,
|
|
Packit |
b5b901 |
NULL);
|
|
Packit |
b5b901 |
if (child_pipe == INVALID_HANDLE_VALUE) {
|
|
Packit |
b5b901 |
err = GetLastError();
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
#ifndef NDEBUG
|
|
Packit |
b5b901 |
/* Validate that the pipe was opened in the right mode. */
|
|
Packit |
b5b901 |
{
|
|
Packit |
b5b901 |
DWORD mode;
|
|
Packit |
b5b901 |
BOOL r = GetNamedPipeHandleState(child_pipe,
|
|
Packit |
b5b901 |
&mode,
|
|
Packit |
b5b901 |
NULL,
|
|
Packit |
b5b901 |
NULL,
|
|
Packit |
b5b901 |
NULL,
|
|
Packit |
b5b901 |
NULL,
|
|
Packit |
b5b901 |
0);
|
|
Packit |
b5b901 |
assert(r == TRUE);
|
|
Packit |
b5b901 |
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
#endif
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Do a blocking ConnectNamedPipe. This should not block because we have both
|
|
Packit |
b5b901 |
* ends of the pipe created. */
|
|
Packit |
b5b901 |
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
|
|
Packit |
b5b901 |
if (GetLastError() != ERROR_PIPE_CONNECTED) {
|
|
Packit |
b5b901 |
err = GetLastError();
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* The server end is now readable and/or writable. */
|
|
Packit |
b5b901 |
if (flags & UV_READABLE_PIPE)
|
|
Packit |
b5b901 |
server_pipe->flags |= UV_HANDLE_WRITABLE;
|
|
Packit |
b5b901 |
if (flags & UV_WRITABLE_PIPE)
|
|
Packit |
b5b901 |
server_pipe->flags |= UV_HANDLE_READABLE;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
*child_pipe_ptr = child_pipe;
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
error:
|
|
Packit |
b5b901 |
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
|
|
Packit |
b5b901 |
uv_pipe_cleanup(loop, server_pipe);
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
if (child_pipe != INVALID_HANDLE_VALUE) {
|
|
Packit |
b5b901 |
CloseHandle(child_pipe);
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
return err;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
|
|
Packit |
b5b901 |
HANDLE current_process;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* _get_osfhandle will sometimes return -2 in case of an error. This seems to
|
|
Packit |
b5b901 |
* happen when fd <= 2 and the process' corresponding stdio handle is set to
|
|
Packit |
b5b901 |
* NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
|
|
Packit |
b5b901 |
* this situation goes unnoticed until someone tries to use the duplicate.
|
|
Packit |
b5b901 |
* Therefore we filter out known-invalid handles here. */
|
|
Packit |
b5b901 |
if (handle == INVALID_HANDLE_VALUE ||
|
|
Packit |
b5b901 |
handle == NULL ||
|
|
Packit |
b5b901 |
handle == (HANDLE) -2) {
|
|
Packit |
b5b901 |
*dup = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
return ERROR_INVALID_HANDLE;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
current_process = GetCurrentProcess();
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
if (!DuplicateHandle(current_process,
|
|
Packit |
b5b901 |
handle,
|
|
Packit |
b5b901 |
current_process,
|
|
Packit |
b5b901 |
dup,
|
|
Packit |
b5b901 |
0,
|
|
Packit |
b5b901 |
TRUE,
|
|
Packit |
b5b901 |
DUPLICATE_SAME_ACCESS)) {
|
|
Packit |
b5b901 |
*dup = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
return GetLastError();
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
|
|
Packit |
b5b901 |
HANDLE handle;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
if (fd == -1) {
|
|
Packit |
b5b901 |
*dup = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
return ERROR_INVALID_HANDLE;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
handle = uv__get_osfhandle(fd);
|
|
Packit |
b5b901 |
return uv__duplicate_handle(loop, handle, dup);
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
int uv__create_nul_handle(HANDLE* handle_ptr,
|
|
Packit |
b5b901 |
DWORD access) {
|
|
Packit |
b5b901 |
HANDLE handle;
|
|
Packit |
b5b901 |
SECURITY_ATTRIBUTES sa;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
sa.nLength = sizeof sa;
|
|
Packit |
b5b901 |
sa.lpSecurityDescriptor = NULL;
|
|
Packit |
b5b901 |
sa.bInheritHandle = TRUE;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
handle = CreateFileW(L"NUL",
|
|
Packit |
b5b901 |
access,
|
|
Packit |
b5b901 |
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
Packit |
b5b901 |
&sa,
|
|
Packit |
b5b901 |
OPEN_EXISTING,
|
|
Packit |
b5b901 |
0,
|
|
Packit |
b5b901 |
NULL);
|
|
Packit |
b5b901 |
if (handle == INVALID_HANDLE_VALUE) {
|
|
Packit |
b5b901 |
return GetLastError();
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
*handle_ptr = handle;
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
int uv__stdio_create(uv_loop_t* loop,
|
|
Packit |
b5b901 |
const uv_process_options_t* options,
|
|
Packit |
b5b901 |
BYTE** buffer_ptr) {
|
|
Packit |
b5b901 |
BYTE* buffer;
|
|
Packit |
b5b901 |
int count, i;
|
|
Packit |
b5b901 |
int err;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
count = options->stdio_count;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
if (count < 0 || count > 255) {
|
|
Packit |
b5b901 |
/* Only support FDs 0-255 */
|
|
Packit |
b5b901 |
return ERROR_NOT_SUPPORTED;
|
|
Packit |
b5b901 |
} else if (count < 3) {
|
|
Packit |
b5b901 |
/* There should always be at least 3 stdio handles. */
|
|
Packit |
b5b901 |
count = 3;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Allocate the child stdio buffer */
|
|
Packit |
b5b901 |
buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
|
|
Packit |
b5b901 |
if (buffer == NULL) {
|
|
Packit |
b5b901 |
return ERROR_OUTOFMEMORY;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
|
|
Packit |
b5b901 |
* up on failure. */
|
|
Packit |
b5b901 |
CHILD_STDIO_COUNT(buffer) = count;
|
|
Packit |
b5b901 |
for (i = 0; i < count; i++) {
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
|
Packit |
b5b901 |
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
for (i = 0; i < count; i++) {
|
|
Packit |
b5b901 |
uv_stdio_container_t fdopt;
|
|
Packit |
b5b901 |
if (i < options->stdio_count) {
|
|
Packit |
b5b901 |
fdopt = options->stdio[i];
|
|
Packit |
b5b901 |
} else {
|
|
Packit |
b5b901 |
fdopt.flags = UV_IGNORE;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
|
|
Packit |
b5b901 |
UV_INHERIT_STREAM)) {
|
|
Packit |
b5b901 |
case UV_IGNORE:
|
|
Packit |
b5b901 |
/* Starting a process with no stdin/stout/stderr can confuse it. So no
|
|
Packit |
b5b901 |
* matter what the user specified, we make sure the first three FDs are
|
|
Packit |
b5b901 |
* always open in their typical modes, e. g. stdin be readable and
|
|
Packit |
b5b901 |
* stdout/err should be writable. For FDs > 2, don't do anything - all
|
|
Packit |
b5b901 |
* handles in the stdio buffer are initialized with.
|
|
Packit |
b5b901 |
* INVALID_HANDLE_VALUE, which should be okay. */
|
|
Packit |
b5b901 |
if (i <= 2) {
|
|
Packit |
b5b901 |
DWORD access = (i == 0) ? FILE_GENERIC_READ :
|
|
Packit |
b5b901 |
FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
|
|
Packit |
b5b901 |
access);
|
|
Packit |
b5b901 |
if (err)
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
case UV_CREATE_PIPE: {
|
|
Packit |
b5b901 |
/* Create a pair of two connected pipe ends; one end is turned into an
|
|
Packit |
b5b901 |
* uv_pipe_t for use by the parent. The other one is given to the
|
|
Packit |
b5b901 |
* child. */
|
|
Packit |
b5b901 |
uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
|
|
Packit |
b5b901 |
HANDLE child_pipe = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Create a new, connected pipe pair. stdio[i]. stream should point to
|
|
Packit |
b5b901 |
* an uninitialized, but not connected pipe handle. */
|
|
Packit |
b5b901 |
assert(fdopt.data.stream->type == UV_NAMED_PIPE);
|
|
Packit |
b5b901 |
assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
|
|
Packit |
b5b901 |
assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
err = uv__create_stdio_pipe_pair(loop,
|
|
Packit |
b5b901 |
parent_pipe,
|
|
Packit |
b5b901 |
&child_pipe,
|
|
Packit |
b5b901 |
fdopt.flags);
|
|
Packit |
b5b901 |
if (err)
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
case UV_INHERIT_FD: {
|
|
Packit |
b5b901 |
/* Inherit a raw FD. */
|
|
Packit |
b5b901 |
HANDLE child_handle;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Make an inheritable duplicate of the handle. */
|
|
Packit |
b5b901 |
err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
|
|
Packit |
b5b901 |
if (err) {
|
|
Packit |
b5b901 |
/* If fdopt. data. fd is not valid and fd <= 2, then ignore the
|
|
Packit |
b5b901 |
* error. */
|
|
Packit |
b5b901 |
if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
|
Packit |
b5b901 |
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Figure out what the type is. */
|
|
Packit |
b5b901 |
switch (GetFileType(child_handle)) {
|
|
Packit |
b5b901 |
case FILE_TYPE_DISK:
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
case FILE_TYPE_PIPE:
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
case FILE_TYPE_CHAR:
|
|
Packit |
b5b901 |
case FILE_TYPE_REMOTE:
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
case FILE_TYPE_UNKNOWN:
|
|
Packit |
b5b901 |
if (GetLastError() != 0) {
|
|
Packit |
b5b901 |
err = GetLastError();
|
|
Packit |
b5b901 |
CloseHandle(child_handle);
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
default:
|
|
Packit |
b5b901 |
assert(0);
|
|
Packit |
b5b901 |
return -1;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
case UV_INHERIT_STREAM: {
|
|
Packit |
b5b901 |
/* Use an existing stream as the stdio handle for the child. */
|
|
Packit |
b5b901 |
HANDLE stream_handle, child_handle;
|
|
Packit |
b5b901 |
unsigned char crt_flags;
|
|
Packit |
b5b901 |
uv_stream_t* stream = fdopt.data.stream;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Leech the handle out of the stream. */
|
|
Packit |
b5b901 |
if (stream->type == UV_TTY) {
|
|
Packit |
b5b901 |
stream_handle = ((uv_tty_t*) stream)->handle;
|
|
Packit |
b5b901 |
crt_flags = FOPEN | FDEV;
|
|
Packit |
b5b901 |
} else if (stream->type == UV_NAMED_PIPE &&
|
|
Packit |
b5b901 |
stream->flags & UV_HANDLE_CONNECTION) {
|
|
Packit |
b5b901 |
stream_handle = ((uv_pipe_t*) stream)->handle;
|
|
Packit |
b5b901 |
crt_flags = FOPEN | FPIPE;
|
|
Packit |
b5b901 |
} else {
|
|
Packit |
b5b901 |
stream_handle = INVALID_HANDLE_VALUE;
|
|
Packit |
b5b901 |
crt_flags = 0;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
if (stream_handle == NULL ||
|
|
Packit |
b5b901 |
stream_handle == INVALID_HANDLE_VALUE) {
|
|
Packit |
b5b901 |
/* The handle is already closed, or not yet created, or the stream
|
|
Packit |
b5b901 |
* type is not supported. */
|
|
Packit |
b5b901 |
err = ERROR_NOT_SUPPORTED;
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Make an inheritable copy of the handle. */
|
|
Packit |
b5b901 |
err = uv__duplicate_handle(loop, stream_handle, &child_handle);
|
|
Packit |
b5b901 |
if (err)
|
|
Packit |
b5b901 |
goto error;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
|
|
Packit |
b5b901 |
CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
|
|
Packit |
b5b901 |
break;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
default:
|
|
Packit |
b5b901 |
assert(0);
|
|
Packit |
b5b901 |
return -1;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
*buffer_ptr = buffer;
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
error:
|
|
Packit |
b5b901 |
uv__stdio_destroy(buffer);
|
|
Packit |
b5b901 |
return err;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
void uv__stdio_destroy(BYTE* buffer) {
|
|
Packit |
b5b901 |
int i, count;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
count = CHILD_STDIO_COUNT(buffer);
|
|
Packit |
b5b901 |
for (i = 0; i < count; i++) {
|
|
Packit |
b5b901 |
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
|
|
Packit |
b5b901 |
if (handle != INVALID_HANDLE_VALUE) {
|
|
Packit |
b5b901 |
CloseHandle(handle);
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
uv__free(buffer);
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
void uv__stdio_noinherit(BYTE* buffer) {
|
|
Packit |
b5b901 |
int i, count;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
count = CHILD_STDIO_COUNT(buffer);
|
|
Packit |
b5b901 |
for (i = 0; i < count; i++) {
|
|
Packit |
b5b901 |
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
|
|
Packit |
b5b901 |
if (handle != INVALID_HANDLE_VALUE) {
|
|
Packit |
b5b901 |
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
int uv__stdio_verify(BYTE* buffer, WORD size) {
|
|
Packit |
b5b901 |
unsigned int count;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Check the buffer pointer. */
|
|
Packit |
b5b901 |
if (buffer == NULL)
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Verify that the buffer is at least big enough to hold the count. */
|
|
Packit |
b5b901 |
if (size < CHILD_STDIO_SIZE(0))
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Verify if the count is within range. */
|
|
Packit |
b5b901 |
count = CHILD_STDIO_COUNT(buffer);
|
|
Packit |
b5b901 |
if (count > 256)
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
/* Verify that the buffer size is big enough to hold info for N FDs. */
|
|
Packit |
b5b901 |
if (size < CHILD_STDIO_SIZE(count))
|
|
Packit |
b5b901 |
return 0;
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
return 1;
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
WORD uv__stdio_size(BYTE* buffer) {
|
|
Packit |
b5b901 |
return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
|
|
Packit |
b5b901 |
}
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
|
|
Packit |
b5b901 |
HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
|
|
Packit |
b5b901 |
return CHILD_STDIO_HANDLE(buffer, fd);
|
|
Packit |
b5b901 |
}
|