1e66f31c5Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2e66f31c5Sopenharmony_ci *
3e66f31c5Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
4e66f31c5Sopenharmony_ci * of this software and associated documentation files (the "Software"), to
5e66f31c5Sopenharmony_ci * deal in the Software without restriction, including without limitation the
6e66f31c5Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7e66f31c5Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
8e66f31c5Sopenharmony_ci * furnished to do so, subject to the following conditions:
9e66f31c5Sopenharmony_ci *
10e66f31c5Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
11e66f31c5Sopenharmony_ci * all copies or substantial portions of the Software.
12e66f31c5Sopenharmony_ci *
13e66f31c5Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14e66f31c5Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15e66f31c5Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16e66f31c5Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17e66f31c5Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18e66f31c5Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19e66f31c5Sopenharmony_ci * IN THE SOFTWARE.
20e66f31c5Sopenharmony_ci */
21e66f31c5Sopenharmony_ci
22e66f31c5Sopenharmony_ci#include <assert.h>
23e66f31c5Sopenharmony_ci#include <io.h>
24e66f31c5Sopenharmony_ci#include <stdio.h>
25e66f31c5Sopenharmony_ci#include <stdlib.h>
26e66f31c5Sopenharmony_ci
27e66f31c5Sopenharmony_ci#include "uv.h"
28e66f31c5Sopenharmony_ci#include "internal.h"
29e66f31c5Sopenharmony_ci#include "handle-inl.h"
30e66f31c5Sopenharmony_ci
31e66f31c5Sopenharmony_ci
32e66f31c5Sopenharmony_ci/*
33e66f31c5Sopenharmony_ci * The `child_stdio_buffer` buffer has the following layout:
34e66f31c5Sopenharmony_ci *   int number_of_fds
35e66f31c5Sopenharmony_ci *   unsigned char crt_flags[number_of_fds]
36e66f31c5Sopenharmony_ci *   HANDLE os_handle[number_of_fds]
37e66f31c5Sopenharmony_ci */
38e66f31c5Sopenharmony_ci#define CHILD_STDIO_SIZE(count)                     \
39e66f31c5Sopenharmony_ci    (sizeof(int) +                                  \
40e66f31c5Sopenharmony_ci     sizeof(unsigned char) * (count) +              \
41e66f31c5Sopenharmony_ci     sizeof(uintptr_t) * (count))
42e66f31c5Sopenharmony_ci
43e66f31c5Sopenharmony_ci#define CHILD_STDIO_COUNT(buffer)                   \
44e66f31c5Sopenharmony_ci    *((unsigned int*) (buffer))
45e66f31c5Sopenharmony_ci
46e66f31c5Sopenharmony_ci#define CHILD_STDIO_CRT_FLAGS(buffer, fd)           \
47e66f31c5Sopenharmony_ci    *((unsigned char*) (buffer) + sizeof(int) + fd)
48e66f31c5Sopenharmony_ci
49e66f31c5Sopenharmony_ci#define CHILD_STDIO_HANDLE(buffer, fd)              \
50e66f31c5Sopenharmony_ci    *((HANDLE*) ((unsigned char*) (buffer) +        \
51e66f31c5Sopenharmony_ci                 sizeof(int) +                      \
52e66f31c5Sopenharmony_ci                 sizeof(unsigned char) *            \
53e66f31c5Sopenharmony_ci                 CHILD_STDIO_COUNT((buffer)) +      \
54e66f31c5Sopenharmony_ci                 sizeof(HANDLE) * (fd)))
55e66f31c5Sopenharmony_ci
56e66f31c5Sopenharmony_ci
57e66f31c5Sopenharmony_ci/* CRT file descriptor mode flags */
58e66f31c5Sopenharmony_ci#define FOPEN       0x01
59e66f31c5Sopenharmony_ci#define FEOFLAG     0x02
60e66f31c5Sopenharmony_ci#define FCRLF       0x04
61e66f31c5Sopenharmony_ci#define FPIPE       0x08
62e66f31c5Sopenharmony_ci#define FNOINHERIT  0x10
63e66f31c5Sopenharmony_ci#define FAPPEND     0x20
64e66f31c5Sopenharmony_ci#define FDEV        0x40
65e66f31c5Sopenharmony_ci#define FTEXT       0x80
66e66f31c5Sopenharmony_ci
67e66f31c5Sopenharmony_ci
68e66f31c5Sopenharmony_ci/*
69e66f31c5Sopenharmony_ci * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
70e66f31c5Sopenharmony_ci * the parent process. Don't check for errors - the stdio handles may not be
71e66f31c5Sopenharmony_ci * valid, or may be closed already. There is no guarantee that this function
72e66f31c5Sopenharmony_ci * does a perfect job.
73e66f31c5Sopenharmony_ci */
74e66f31c5Sopenharmony_civoid uv_disable_stdio_inheritance(void) {
75e66f31c5Sopenharmony_ci  HANDLE handle;
76e66f31c5Sopenharmony_ci  STARTUPINFOW si;
77e66f31c5Sopenharmony_ci
78e66f31c5Sopenharmony_ci  /* Make the windows stdio handles non-inheritable. */
79e66f31c5Sopenharmony_ci  handle = GetStdHandle(STD_INPUT_HANDLE);
80e66f31c5Sopenharmony_ci  if (handle != NULL && handle != INVALID_HANDLE_VALUE)
81e66f31c5Sopenharmony_ci    SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
82e66f31c5Sopenharmony_ci
83e66f31c5Sopenharmony_ci  handle = GetStdHandle(STD_OUTPUT_HANDLE);
84e66f31c5Sopenharmony_ci  if (handle != NULL && handle != INVALID_HANDLE_VALUE)
85e66f31c5Sopenharmony_ci    SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
86e66f31c5Sopenharmony_ci
87e66f31c5Sopenharmony_ci  handle = GetStdHandle(STD_ERROR_HANDLE);
88e66f31c5Sopenharmony_ci  if (handle != NULL && handle != INVALID_HANDLE_VALUE)
89e66f31c5Sopenharmony_ci    SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
90e66f31c5Sopenharmony_ci
91e66f31c5Sopenharmony_ci  /* Make inherited CRT FDs non-inheritable. */
92e66f31c5Sopenharmony_ci  GetStartupInfoW(&si);
93e66f31c5Sopenharmony_ci  if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
94e66f31c5Sopenharmony_ci    uv__stdio_noinherit(si.lpReserved2);
95e66f31c5Sopenharmony_ci}
96e66f31c5Sopenharmony_ci
97e66f31c5Sopenharmony_ci
98e66f31c5Sopenharmony_cistatic int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
99e66f31c5Sopenharmony_ci  HANDLE current_process;
100e66f31c5Sopenharmony_ci
101e66f31c5Sopenharmony_ci
102e66f31c5Sopenharmony_ci  /* _get_osfhandle will sometimes return -2 in case of an error. This seems to
103e66f31c5Sopenharmony_ci   * happen when fd <= 2 and the process' corresponding stdio handle is set to
104e66f31c5Sopenharmony_ci   * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
105e66f31c5Sopenharmony_ci   * this situation goes unnoticed until someone tries to use the duplicate.
106e66f31c5Sopenharmony_ci   * Therefore we filter out known-invalid handles here. */
107e66f31c5Sopenharmony_ci  if (handle == INVALID_HANDLE_VALUE ||
108e66f31c5Sopenharmony_ci      handle == NULL ||
109e66f31c5Sopenharmony_ci      handle == (HANDLE) -2) {
110e66f31c5Sopenharmony_ci    *dup = INVALID_HANDLE_VALUE;
111e66f31c5Sopenharmony_ci    return ERROR_INVALID_HANDLE;
112e66f31c5Sopenharmony_ci  }
113e66f31c5Sopenharmony_ci
114e66f31c5Sopenharmony_ci  current_process = GetCurrentProcess();
115e66f31c5Sopenharmony_ci
116e66f31c5Sopenharmony_ci  if (!DuplicateHandle(current_process,
117e66f31c5Sopenharmony_ci                       handle,
118e66f31c5Sopenharmony_ci                       current_process,
119e66f31c5Sopenharmony_ci                       dup,
120e66f31c5Sopenharmony_ci                       0,
121e66f31c5Sopenharmony_ci                       TRUE,
122e66f31c5Sopenharmony_ci                       DUPLICATE_SAME_ACCESS)) {
123e66f31c5Sopenharmony_ci    *dup = INVALID_HANDLE_VALUE;
124e66f31c5Sopenharmony_ci    return GetLastError();
125e66f31c5Sopenharmony_ci  }
126e66f31c5Sopenharmony_ci
127e66f31c5Sopenharmony_ci  return 0;
128e66f31c5Sopenharmony_ci}
129e66f31c5Sopenharmony_ci
130e66f31c5Sopenharmony_ci
131e66f31c5Sopenharmony_cistatic int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
132e66f31c5Sopenharmony_ci  HANDLE handle;
133e66f31c5Sopenharmony_ci
134e66f31c5Sopenharmony_ci  if (fd == -1) {
135e66f31c5Sopenharmony_ci    *dup = INVALID_HANDLE_VALUE;
136e66f31c5Sopenharmony_ci    return ERROR_INVALID_HANDLE;
137e66f31c5Sopenharmony_ci  }
138e66f31c5Sopenharmony_ci
139e66f31c5Sopenharmony_ci  handle = uv__get_osfhandle(fd);
140e66f31c5Sopenharmony_ci  return uv__duplicate_handle(loop, handle, dup);
141e66f31c5Sopenharmony_ci}
142e66f31c5Sopenharmony_ci
143e66f31c5Sopenharmony_ci
144e66f31c5Sopenharmony_ciint uv__create_nul_handle(HANDLE* handle_ptr,
145e66f31c5Sopenharmony_ci    DWORD access) {
146e66f31c5Sopenharmony_ci  HANDLE handle;
147e66f31c5Sopenharmony_ci  SECURITY_ATTRIBUTES sa;
148e66f31c5Sopenharmony_ci
149e66f31c5Sopenharmony_ci  sa.nLength = sizeof sa;
150e66f31c5Sopenharmony_ci  sa.lpSecurityDescriptor = NULL;
151e66f31c5Sopenharmony_ci  sa.bInheritHandle = TRUE;
152e66f31c5Sopenharmony_ci
153e66f31c5Sopenharmony_ci  handle = CreateFileW(L"NUL",
154e66f31c5Sopenharmony_ci                       access,
155e66f31c5Sopenharmony_ci                       FILE_SHARE_READ | FILE_SHARE_WRITE,
156e66f31c5Sopenharmony_ci                       &sa,
157e66f31c5Sopenharmony_ci                       OPEN_EXISTING,
158e66f31c5Sopenharmony_ci                       0,
159e66f31c5Sopenharmony_ci                       NULL);
160e66f31c5Sopenharmony_ci  if (handle == INVALID_HANDLE_VALUE) {
161e66f31c5Sopenharmony_ci    return GetLastError();
162e66f31c5Sopenharmony_ci  }
163e66f31c5Sopenharmony_ci
164e66f31c5Sopenharmony_ci  *handle_ptr = handle;
165e66f31c5Sopenharmony_ci  return 0;
166e66f31c5Sopenharmony_ci}
167e66f31c5Sopenharmony_ci
168e66f31c5Sopenharmony_ci
169e66f31c5Sopenharmony_ciint uv__stdio_create(uv_loop_t* loop,
170e66f31c5Sopenharmony_ci                     const uv_process_options_t* options,
171e66f31c5Sopenharmony_ci                     BYTE** buffer_ptr) {
172e66f31c5Sopenharmony_ci  BYTE* buffer;
173e66f31c5Sopenharmony_ci  int count, i;
174e66f31c5Sopenharmony_ci  int err;
175e66f31c5Sopenharmony_ci
176e66f31c5Sopenharmony_ci  count = options->stdio_count;
177e66f31c5Sopenharmony_ci
178e66f31c5Sopenharmony_ci  if (count < 0 || count > 255) {
179e66f31c5Sopenharmony_ci    /* Only support FDs 0-255 */
180e66f31c5Sopenharmony_ci    return ERROR_NOT_SUPPORTED;
181e66f31c5Sopenharmony_ci  } else if (count < 3) {
182e66f31c5Sopenharmony_ci    /* There should always be at least 3 stdio handles. */
183e66f31c5Sopenharmony_ci    count = 3;
184e66f31c5Sopenharmony_ci  }
185e66f31c5Sopenharmony_ci
186e66f31c5Sopenharmony_ci  /* Allocate the child stdio buffer */
187e66f31c5Sopenharmony_ci  buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
188e66f31c5Sopenharmony_ci  if (buffer == NULL) {
189e66f31c5Sopenharmony_ci    return ERROR_OUTOFMEMORY;
190e66f31c5Sopenharmony_ci  }
191e66f31c5Sopenharmony_ci
192e66f31c5Sopenharmony_ci  /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
193e66f31c5Sopenharmony_ci   * up on failure. */
194e66f31c5Sopenharmony_ci  CHILD_STDIO_COUNT(buffer) = count;
195e66f31c5Sopenharmony_ci  for (i = 0; i < count; i++) {
196e66f31c5Sopenharmony_ci    CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
197e66f31c5Sopenharmony_ci    CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
198e66f31c5Sopenharmony_ci  }
199e66f31c5Sopenharmony_ci
200e66f31c5Sopenharmony_ci  for (i = 0; i < count; i++) {
201e66f31c5Sopenharmony_ci    uv_stdio_container_t fdopt;
202e66f31c5Sopenharmony_ci    if (i < options->stdio_count) {
203e66f31c5Sopenharmony_ci      fdopt = options->stdio[i];
204e66f31c5Sopenharmony_ci    } else {
205e66f31c5Sopenharmony_ci      fdopt.flags = UV_IGNORE;
206e66f31c5Sopenharmony_ci    }
207e66f31c5Sopenharmony_ci
208e66f31c5Sopenharmony_ci    switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
209e66f31c5Sopenharmony_ci            UV_INHERIT_STREAM)) {
210e66f31c5Sopenharmony_ci      case UV_IGNORE:
211e66f31c5Sopenharmony_ci        /* Starting a process with no stdin/stout/stderr can confuse it. So no
212e66f31c5Sopenharmony_ci         * matter what the user specified, we make sure the first three FDs are
213e66f31c5Sopenharmony_ci         * always open in their typical modes, e. g. stdin be readable and
214e66f31c5Sopenharmony_ci         * stdout/err should be writable. For FDs > 2, don't do anything - all
215e66f31c5Sopenharmony_ci         * handles in the stdio buffer are initialized with.
216e66f31c5Sopenharmony_ci         * INVALID_HANDLE_VALUE, which should be okay. */
217e66f31c5Sopenharmony_ci        if (i <= 2) {
218e66f31c5Sopenharmony_ci          DWORD access = (i == 0) ? FILE_GENERIC_READ :
219e66f31c5Sopenharmony_ci                                    FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
220e66f31c5Sopenharmony_ci
221e66f31c5Sopenharmony_ci          err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
222e66f31c5Sopenharmony_ci                                      access);
223e66f31c5Sopenharmony_ci          if (err)
224e66f31c5Sopenharmony_ci            goto error;
225e66f31c5Sopenharmony_ci
226e66f31c5Sopenharmony_ci          CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
227e66f31c5Sopenharmony_ci        }
228e66f31c5Sopenharmony_ci        break;
229e66f31c5Sopenharmony_ci
230e66f31c5Sopenharmony_ci      case UV_CREATE_PIPE: {
231e66f31c5Sopenharmony_ci        /* Create a pair of two connected pipe ends; one end is turned into an
232e66f31c5Sopenharmony_ci         * uv_pipe_t for use by the parent. The other one is given to the
233e66f31c5Sopenharmony_ci         * child. */
234e66f31c5Sopenharmony_ci        uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
235e66f31c5Sopenharmony_ci        HANDLE child_pipe = INVALID_HANDLE_VALUE;
236e66f31c5Sopenharmony_ci
237e66f31c5Sopenharmony_ci        /* Create a new, connected pipe pair. stdio[i]. stream should point to
238e66f31c5Sopenharmony_ci         * an uninitialized, but not connected pipe handle. */
239e66f31c5Sopenharmony_ci        assert(fdopt.data.stream->type == UV_NAMED_PIPE);
240e66f31c5Sopenharmony_ci        assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
241e66f31c5Sopenharmony_ci        assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
242e66f31c5Sopenharmony_ci
243e66f31c5Sopenharmony_ci        err = uv__create_stdio_pipe_pair(loop,
244e66f31c5Sopenharmony_ci                                         parent_pipe,
245e66f31c5Sopenharmony_ci                                         &child_pipe,
246e66f31c5Sopenharmony_ci                                         fdopt.flags);
247e66f31c5Sopenharmony_ci        if (err)
248e66f31c5Sopenharmony_ci          goto error;
249e66f31c5Sopenharmony_ci
250e66f31c5Sopenharmony_ci        CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
251e66f31c5Sopenharmony_ci        CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
252e66f31c5Sopenharmony_ci        break;
253e66f31c5Sopenharmony_ci      }
254e66f31c5Sopenharmony_ci
255e66f31c5Sopenharmony_ci      case UV_INHERIT_FD: {
256e66f31c5Sopenharmony_ci        /* Inherit a raw FD. */
257e66f31c5Sopenharmony_ci        HANDLE child_handle;
258e66f31c5Sopenharmony_ci
259e66f31c5Sopenharmony_ci        /* Make an inheritable duplicate of the handle. */
260e66f31c5Sopenharmony_ci        err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
261e66f31c5Sopenharmony_ci        if (err) {
262e66f31c5Sopenharmony_ci          /* If fdopt. data. fd is not valid and fd <= 2, then ignore the
263e66f31c5Sopenharmony_ci           * error. */
264e66f31c5Sopenharmony_ci          if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
265e66f31c5Sopenharmony_ci            CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
266e66f31c5Sopenharmony_ci            CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
267e66f31c5Sopenharmony_ci            break;
268e66f31c5Sopenharmony_ci          }
269e66f31c5Sopenharmony_ci          goto error;
270e66f31c5Sopenharmony_ci        }
271e66f31c5Sopenharmony_ci
272e66f31c5Sopenharmony_ci        /* Figure out what the type is. */
273e66f31c5Sopenharmony_ci        switch (GetFileType(child_handle)) {
274e66f31c5Sopenharmony_ci          case FILE_TYPE_DISK:
275e66f31c5Sopenharmony_ci            CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
276e66f31c5Sopenharmony_ci            break;
277e66f31c5Sopenharmony_ci
278e66f31c5Sopenharmony_ci          case FILE_TYPE_PIPE:
279e66f31c5Sopenharmony_ci            CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
280e66f31c5Sopenharmony_ci            break;
281e66f31c5Sopenharmony_ci
282e66f31c5Sopenharmony_ci          case FILE_TYPE_CHAR:
283e66f31c5Sopenharmony_ci          case FILE_TYPE_REMOTE:
284e66f31c5Sopenharmony_ci            CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
285e66f31c5Sopenharmony_ci            break;
286e66f31c5Sopenharmony_ci
287e66f31c5Sopenharmony_ci          case FILE_TYPE_UNKNOWN:
288e66f31c5Sopenharmony_ci            if (GetLastError() != 0) {
289e66f31c5Sopenharmony_ci              err = GetLastError();
290e66f31c5Sopenharmony_ci              CloseHandle(child_handle);
291e66f31c5Sopenharmony_ci              goto error;
292e66f31c5Sopenharmony_ci            }
293e66f31c5Sopenharmony_ci            CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
294e66f31c5Sopenharmony_ci            break;
295e66f31c5Sopenharmony_ci
296e66f31c5Sopenharmony_ci          default:
297e66f31c5Sopenharmony_ci            assert(0);
298e66f31c5Sopenharmony_ci            return -1;
299e66f31c5Sopenharmony_ci        }
300e66f31c5Sopenharmony_ci
301e66f31c5Sopenharmony_ci        CHILD_STDIO_HANDLE(buffer, i) = child_handle;
302e66f31c5Sopenharmony_ci        break;
303e66f31c5Sopenharmony_ci      }
304e66f31c5Sopenharmony_ci
305e66f31c5Sopenharmony_ci      case UV_INHERIT_STREAM: {
306e66f31c5Sopenharmony_ci        /* Use an existing stream as the stdio handle for the child. */
307e66f31c5Sopenharmony_ci        HANDLE stream_handle, child_handle;
308e66f31c5Sopenharmony_ci        unsigned char crt_flags;
309e66f31c5Sopenharmony_ci        uv_stream_t* stream = fdopt.data.stream;
310e66f31c5Sopenharmony_ci
311e66f31c5Sopenharmony_ci        /* Leech the handle out of the stream. */
312e66f31c5Sopenharmony_ci        if (stream->type == UV_TTY) {
313e66f31c5Sopenharmony_ci          stream_handle = ((uv_tty_t*) stream)->handle;
314e66f31c5Sopenharmony_ci          crt_flags = FOPEN | FDEV;
315e66f31c5Sopenharmony_ci        } else if (stream->type == UV_NAMED_PIPE &&
316e66f31c5Sopenharmony_ci                   stream->flags & UV_HANDLE_CONNECTION) {
317e66f31c5Sopenharmony_ci          stream_handle = ((uv_pipe_t*) stream)->handle;
318e66f31c5Sopenharmony_ci          crt_flags = FOPEN | FPIPE;
319e66f31c5Sopenharmony_ci        } else {
320e66f31c5Sopenharmony_ci          stream_handle = INVALID_HANDLE_VALUE;
321e66f31c5Sopenharmony_ci          crt_flags = 0;
322e66f31c5Sopenharmony_ci        }
323e66f31c5Sopenharmony_ci
324e66f31c5Sopenharmony_ci        if (stream_handle == NULL ||
325e66f31c5Sopenharmony_ci            stream_handle == INVALID_HANDLE_VALUE) {
326e66f31c5Sopenharmony_ci          /* The handle is already closed, or not yet created, or the stream
327e66f31c5Sopenharmony_ci           * type is not supported. */
328e66f31c5Sopenharmony_ci          err = ERROR_NOT_SUPPORTED;
329e66f31c5Sopenharmony_ci          goto error;
330e66f31c5Sopenharmony_ci        }
331e66f31c5Sopenharmony_ci
332e66f31c5Sopenharmony_ci        /* Make an inheritable copy of the handle. */
333e66f31c5Sopenharmony_ci        err = uv__duplicate_handle(loop, stream_handle, &child_handle);
334e66f31c5Sopenharmony_ci        if (err)
335e66f31c5Sopenharmony_ci          goto error;
336e66f31c5Sopenharmony_ci
337e66f31c5Sopenharmony_ci        CHILD_STDIO_HANDLE(buffer, i) = child_handle;
338e66f31c5Sopenharmony_ci        CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
339e66f31c5Sopenharmony_ci        break;
340e66f31c5Sopenharmony_ci      }
341e66f31c5Sopenharmony_ci
342e66f31c5Sopenharmony_ci      default:
343e66f31c5Sopenharmony_ci        assert(0);
344e66f31c5Sopenharmony_ci        return -1;
345e66f31c5Sopenharmony_ci    }
346e66f31c5Sopenharmony_ci  }
347e66f31c5Sopenharmony_ci
348e66f31c5Sopenharmony_ci  *buffer_ptr  = buffer;
349e66f31c5Sopenharmony_ci  return 0;
350e66f31c5Sopenharmony_ci
351e66f31c5Sopenharmony_ci error:
352e66f31c5Sopenharmony_ci  uv__stdio_destroy(buffer);
353e66f31c5Sopenharmony_ci  return err;
354e66f31c5Sopenharmony_ci}
355e66f31c5Sopenharmony_ci
356e66f31c5Sopenharmony_ci
357e66f31c5Sopenharmony_civoid uv__stdio_destroy(BYTE* buffer) {
358e66f31c5Sopenharmony_ci  int i, count;
359e66f31c5Sopenharmony_ci
360e66f31c5Sopenharmony_ci  count = CHILD_STDIO_COUNT(buffer);
361e66f31c5Sopenharmony_ci  for (i = 0; i < count; i++) {
362e66f31c5Sopenharmony_ci    HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
363e66f31c5Sopenharmony_ci    if (handle != INVALID_HANDLE_VALUE) {
364e66f31c5Sopenharmony_ci      CloseHandle(handle);
365e66f31c5Sopenharmony_ci    }
366e66f31c5Sopenharmony_ci  }
367e66f31c5Sopenharmony_ci
368e66f31c5Sopenharmony_ci  uv__free(buffer);
369e66f31c5Sopenharmony_ci}
370e66f31c5Sopenharmony_ci
371e66f31c5Sopenharmony_ci
372e66f31c5Sopenharmony_civoid uv__stdio_noinherit(BYTE* buffer) {
373e66f31c5Sopenharmony_ci  int i, count;
374e66f31c5Sopenharmony_ci
375e66f31c5Sopenharmony_ci  count = CHILD_STDIO_COUNT(buffer);
376e66f31c5Sopenharmony_ci  for (i = 0; i < count; i++) {
377e66f31c5Sopenharmony_ci    HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
378e66f31c5Sopenharmony_ci    if (handle != INVALID_HANDLE_VALUE) {
379e66f31c5Sopenharmony_ci      SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
380e66f31c5Sopenharmony_ci    }
381e66f31c5Sopenharmony_ci  }
382e66f31c5Sopenharmony_ci}
383e66f31c5Sopenharmony_ci
384e66f31c5Sopenharmony_ci
385e66f31c5Sopenharmony_ciint uv__stdio_verify(BYTE* buffer, WORD size) {
386e66f31c5Sopenharmony_ci  unsigned int count;
387e66f31c5Sopenharmony_ci
388e66f31c5Sopenharmony_ci  /* Check the buffer pointer. */
389e66f31c5Sopenharmony_ci  if (buffer == NULL)
390e66f31c5Sopenharmony_ci    return 0;
391e66f31c5Sopenharmony_ci
392e66f31c5Sopenharmony_ci  /* Verify that the buffer is at least big enough to hold the count. */
393e66f31c5Sopenharmony_ci  if (size < CHILD_STDIO_SIZE(0))
394e66f31c5Sopenharmony_ci    return 0;
395e66f31c5Sopenharmony_ci
396e66f31c5Sopenharmony_ci  /* Verify if the count is within range. */
397e66f31c5Sopenharmony_ci  count = CHILD_STDIO_COUNT(buffer);
398e66f31c5Sopenharmony_ci  if (count > 256)
399e66f31c5Sopenharmony_ci    return 0;
400e66f31c5Sopenharmony_ci
401e66f31c5Sopenharmony_ci  /* Verify that the buffer size is big enough to hold info for N FDs. */
402e66f31c5Sopenharmony_ci  if (size < CHILD_STDIO_SIZE(count))
403e66f31c5Sopenharmony_ci    return 0;
404e66f31c5Sopenharmony_ci
405e66f31c5Sopenharmony_ci  return 1;
406e66f31c5Sopenharmony_ci}
407e66f31c5Sopenharmony_ci
408e66f31c5Sopenharmony_ci
409e66f31c5Sopenharmony_ciWORD uv__stdio_size(BYTE* buffer) {
410e66f31c5Sopenharmony_ci  return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
411e66f31c5Sopenharmony_ci}
412e66f31c5Sopenharmony_ci
413e66f31c5Sopenharmony_ci
414e66f31c5Sopenharmony_ciHANDLE uv__stdio_handle(BYTE* buffer, int fd) {
415e66f31c5Sopenharmony_ci  return CHILD_STDIO_HANDLE(buffer, fd);
416e66f31c5Sopenharmony_ci}
417