Blame src/win/process-stdio.c

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