static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { HANDLE handle; if (fd == -1) { *dup = INVALID_HANDLE_VALUE; return ERROR_INVALID_HANDLE; } handle = uv__get_osfhandle(fd); return uv__duplicate_handle(loop, handle, dup); }
static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { HANDLE handle; if (fd == -1) { *dup = INVALID_HANDLE_VALUE; uv__set_artificial_error(loop, UV_EBADF); return -1; } handle = (HANDLE)_get_osfhandle(fd); return uv__duplicate_handle(loop, handle, dup); }
int uv__stdio_create(uv_loop_t* loop, uv_process_options_t* options, BYTE** buffer_ptr) { BYTE* buffer; int count, i; count = options->stdio_count; if (count < 0 || count > 255) { /* Only support FDs 0-255 */ uv__set_artificial_error(loop, UV_ENOTSUP); return -1; } else if (count < 3) { /* There should always be at least 3 stdio handles. */ count = 3; } /* Allocate the child stdio buffer */ buffer = malloc(CHILD_STDIO_SIZE(count)); if (buffer == NULL) { uv__set_artificial_error(loop, UV_ENOMEM); return -1; } /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */ /* clean up on failure. */ CHILD_STDIO_COUNT(buffer) = count; for (i = 0; i < count; i++) { CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; } for (i = 0; i < count; i++) { uv_stdio_container_t fdopt; if (i < options->stdio_count) { fdopt = options->stdio[i]; } else { fdopt.flags = UV_IGNORE; } switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM)) { case UV_IGNORE: /* Starting a process with no stdin/stout/stderr can confuse it. */ /* So no matter what the user specified, we make sure the first */ /* three FDs are always open in their typical modes, e.g. stdin */ /* be readable and stdout/err should be writable. For FDs > 2, don't */ /* do anything - all handles in the stdio buffer are initialized with */ /* INVALID_HANDLE_VALUE, which should be okay. */ if (i <= 2) { DWORD access = (i == 0) ? FILE_GENERIC_READ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; if (uv__create_nul_handle(loop, &CHILD_STDIO_HANDLE(buffer, i), access) < 0) { goto error; } CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; } break; case UV_CREATE_PIPE: { /* Create a pair of two connected pipe ends; one end is turned into */ /* an uv_pipe_t for use by the parent. The other one is given to */ /* the child. */ uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream; HANDLE child_pipe; /* Create a new, connected pipe pair. stdio[i].stream should point */ /* to an uninitialized, but not connected pipe handle. */ assert(fdopt.data.stream->type == UV_NAMED_PIPE); assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); if (uv__create_stdio_pipe_pair(loop, parent_pipe, &child_pipe, fdopt.flags) < 0) { goto error; } CHILD_STDIO_HANDLE(buffer, i) = child_pipe; CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; break; } case UV_INHERIT_FD: { /* Inherit a raw FD. */ HANDLE child_handle; /* Make an inheritable duplicate of the handle. */ if (uv__duplicate_fd(loop, fdopt.data.fd, &child_handle) < 0) { goto error; } /* Figure out what the type is. */ switch (GetFileType(child_handle)) { case FILE_TYPE_DISK: CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN; break; case FILE_TYPE_PIPE: CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; case FILE_TYPE_CHAR: case FILE_TYPE_REMOTE: CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; break; case FILE_TYPE_UNKNOWN: if (GetLastError != 0) { uv__set_sys_error(loop, GetLastError()); CloseHandle(child_handle); goto error; } CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; break; default: assert(0); } CHILD_STDIO_HANDLE(buffer, i) = child_handle; break; } case UV_INHERIT_STREAM: { /* Use an existing stream as the stdio handle for the child. */ HANDLE stream_handle, child_handle; unsigned char crt_flags; uv_stream_t* stream = fdopt.data.stream; /* Leech the handle out of the stream. */ if (stream->type == UV_TTY) { stream_handle = ((uv_tty_t*) stream)->handle; crt_flags = FOPEN | FDEV; } else if (stream->type == UV_NAMED_PIPE && stream->flags & UV_HANDLE_CONNECTED) { stream_handle = ((uv_pipe_t*) stream)->handle; crt_flags = FOPEN | FPIPE; } else { stream_handle = INVALID_HANDLE_VALUE; crt_flags = 0; } if (stream_handle == NULL || stream_handle == INVALID_HANDLE_VALUE) { /* The handle is already closed, or not yet created, or the */ /* stream type is not supported. */ uv__set_artificial_error(loop, UV_ENOTSUP); goto error; } /* Make an inheritable copy of the handle. */ if (uv__duplicate_handle(loop, stream_handle, &child_handle) < 0) { goto error; } CHILD_STDIO_HANDLE(buffer, i) = child_handle; CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags; break; } default: assert(0); } } *buffer_ptr = buffer; return 0; error: uv__stdio_destroy(buffer); return -1; }