LCOV - code coverage report
Current view: top level - glib - gspawn-win32.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 64.7 % 712 461
Test Date: 2026-08-11 05:12:37 Functions: 72.0 % 25 18
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* gspawn-win32.c - Process launching on Win32
       2                 :             :  *
       3                 :             :  *  Copyright 2000 Red Hat, Inc.
       4                 :             :  *  Copyright 2003 Tor Lillqvist
       5                 :             :  *
       6                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       7                 :             :  *
       8                 :             :  * This library is free software; you can redistribute it and/or
       9                 :             :  * modify it under the terms of the GNU Lesser General Public
      10                 :             :  * License as published by the Free Software Foundation; either
      11                 :             :  * version 2.1 of the License, or (at your option) any later version.
      12                 :             :  *
      13                 :             :  * This library is distributed in the hope that it will be useful,
      14                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16                 :             :  * Lesser General Public License for more details.
      17                 :             :  *
      18                 :             :  * You should have received a copy of the GNU Lesser General Public License
      19                 :             :  * along with this library; if not, see <http://www.gnu.org/licenses/>.
      20                 :             :  */
      21                 :             : 
      22                 :             : /*
      23                 :             :  * Implementation details on Win32.
      24                 :             :  *
      25                 :             :  * - There is no way to set the no-inherit flag for
      26                 :             :  *   a "file descriptor" in the MS C runtime. The flag is there,
      27                 :             :  *   and the dospawn() function uses it, but unfortunately
      28                 :             :  *   this flag can only be set when opening the file.
      29                 :             :  * - As there is no fork(), we cannot reliably change directory
      30                 :             :  *   before starting the child process. (There might be several threads
      31                 :             :  *   running, and the current directory is common for all threads.)
      32                 :             :  *
      33                 :             :  * Thus, we must in many cases use a helper program to handle closing
      34                 :             :  * of (inherited) file descriptors and changing of directory. The
      35                 :             :  * helper process is also needed if the standard input, standard
      36                 :             :  * output, or standard error of the process to be run are supposed to
      37                 :             :  * be redirected somewhere.
      38                 :             :  *
      39                 :             :  * The structure of the source code in this file is a mess, I know.
      40                 :             :  */
      41                 :             : 
      42                 :             : /* Define this to get some logging all the time */
      43                 :             : /* #define G_SPAWN_WIN32_DEBUG */
      44                 :             : 
      45                 :             : #include "config.h"
      46                 :             : 
      47                 :             : #include "glib-init.h"
      48                 :             : #include "glib-private.h"
      49                 :             : #include "glib.h"
      50                 :             : #include "glibintl.h"
      51                 :             : #include "gprintfint.h"
      52                 :             : #include "gspawn-private.h"
      53                 :             : #include "gthread.h"
      54                 :             : 
      55                 :             : #include <string.h>
      56                 :             : #include <stdlib.h>
      57                 :             : #include <stdio.h>
      58                 :             : 
      59                 :             : #include <windows.h>
      60                 :             : #include <errno.h>
      61                 :             : #include <fcntl.h>
      62                 :             : #include <io.h>
      63                 :             : #include <process.h>
      64                 :             : #include <direct.h>
      65                 :             : #include <wchar.h>
      66                 :             : 
      67                 :             : #ifdef _MSC_VER
      68                 :             : #ifdef HAVE_VCRUNTIME_H
      69                 :             : #include <vcruntime.h> /* for _UCRT */
      70                 :             : #endif
      71                 :             : #endif
      72                 :             : 
      73                 :             : #ifndef GSPAWN_HELPER
      74                 :             : #ifdef G_SPAWN_WIN32_DEBUG
      75                 :             :   static int debug = 1;
      76                 :             :   #define SETUP_DEBUG() /* empty */
      77                 :             : #else
      78                 :             :   static int debug = -1;
      79                 :             :   #define SETUP_DEBUG()                                 \
      80                 :             :     G_STMT_START                                        \
      81                 :             :       {                                                 \
      82                 :             :         if (debug == -1)                                \
      83                 :             :           {                                             \
      84                 :             :             if (g_getenv ("G_SPAWN_WIN32_DEBUG") != NULL)     \
      85                 :             :               debug = 1;                                \
      86                 :             :             else                                        \
      87                 :             :               debug = 0;                                \
      88                 :             :           }                                             \
      89                 :             :       }                                                 \
      90                 :             :     G_STMT_END
      91                 :             : #endif
      92                 :             : #endif
      93                 :             : 
      94                 :             : enum
      95                 :             : {
      96                 :             :   CHILD_NO_ERROR,
      97                 :             :   CHILD_CHDIR_FAILED,
      98                 :             :   CHILD_SPAWN_FAILED,
      99                 :             :   CHILD_SPAWN_NOENT,
     100                 :             :   CHILD_DUP_FAILED,
     101                 :             : };
     102                 :             : 
     103                 :             : enum {
     104                 :             :   ARG_CHILD_ERR_REPORT = 1,
     105                 :             :   ARG_HELPER_SYNC,
     106                 :             :   ARG_STDIN,
     107                 :             :   ARG_STDOUT,
     108                 :             :   ARG_STDERR,
     109                 :             :   ARG_WORKING_DIRECTORY,
     110                 :             :   ARG_CLOSE_DESCRIPTORS,
     111                 :             :   ARG_USE_PATH,
     112                 :             :   ARG_WAIT,
     113                 :             :   ARG_FDS,
     114                 :             :   ARG_PROGRAM,
     115                 :             :   ARG_COUNT = ARG_PROGRAM
     116                 :             : };
     117                 :             : 
     118                 :             : #ifndef GSPAWN_HELPER
     119                 :             : 
     120                 :             : #ifdef _WIN64
     121                 :             : #define HELPER_PROCESS "gspawn-win64-helper"
     122                 :             : #else
     123                 :             : #define HELPER_PROCESS "gspawn-win32-helper"
     124                 :             : #endif
     125                 :             : 
     126                 :             : #ifndef _UCRT
     127                 :             : 
     128                 :             : /* The wspawn*e functions are thread-safe only in the Universal
     129                 :             :  * CRT (UCRT). If we are linking against the MSVCRT.dll or the
     130                 :             :  * pre-2015 MSVC runtime (MSVCRXXX.dll), then we have to use a
     131                 :             :  * mutex.
     132                 :             :  */
     133                 :             : 
     134                 :             : static GMutex safe_wspawn_e_mutex;
     135                 :             : 
     136                 :             : static intptr_t
     137                 :             : safe_wspawnve (int _Mode,
     138                 :             :                const wchar_t *_Filename,
     139                 :             :                const wchar_t *const *_ArgList,
     140                 :             :                const wchar_t *const *_Env)
     141                 :             : {
     142                 :             :   intptr_t ret_val = -1;
     143                 :             : 
     144                 :             :   g_mutex_lock (&safe_wspawn_e_mutex);
     145                 :             :   ret_val = _wspawnve (_Mode, _Filename, _ArgList, _Env);
     146                 :             :   g_mutex_unlock (&safe_wspawn_e_mutex);
     147                 :             : 
     148                 :             :   return ret_val;
     149                 :             : }
     150                 :             : 
     151                 :             : static intptr_t
     152                 :             : safe_wspawnvpe (int _Mode,
     153                 :             :                 const wchar_t *_Filename,
     154                 :             :                 const wchar_t *const *_ArgList,
     155                 :             :                 const wchar_t *const *_Env)
     156                 :             : {
     157                 :             :   intptr_t ret_val = -1;
     158                 :             : 
     159                 :             :   g_mutex_lock (&safe_wspawn_e_mutex);
     160                 :             :   ret_val = _wspawnvpe (_Mode, _Filename, _ArgList, _Env);
     161                 :             :   g_mutex_unlock (&safe_wspawn_e_mutex);
     162                 :             : 
     163                 :             :   return ret_val;
     164                 :             : }
     165                 :             : 
     166                 :             : #else
     167                 :             : 
     168                 :             : /**< private >
     169                 :             :  * ensure_cmd_environment:
     170                 :             :  *
     171                 :             :  * Workaround for an issue in the universal C Runtime library (UCRT). This adds
     172                 :             :  * a custom environment variable to this process's environment block that looks
     173                 :             :  * like the cmd.exe's shell-related environment variables, i.e the name starts
     174                 :             :  * with an equal sign character: '='. This is needed because the UCRT may crash
     175                 :             :  * if those environment variables are missing from the calling process's block.
     176                 :             :  *
     177                 :             :  * Reference:
     178                 :             :  *
     179                 :             :  * https://developercommunity.visualstudio.com/t/UCRT-Crash-in-_wspawne-functions/10262748
     180                 :             :  */
     181                 :             : static void
     182                 :          65 : ensure_cmd_environment (void)
     183                 :             : {
     184                 :             :   static gsize initialization_value = 0;
     185                 :             : 
     186                 :          65 :   if (g_once_init_enter (&initialization_value))
     187                 :             :     {
     188                 :          11 :       wchar_t *block = GetEnvironmentStringsW ();
     189                 :          11 :       gboolean have_cmd_environment = FALSE;
     190                 :             : 
     191                 :          11 :       if (block)
     192                 :             :         {
     193                 :          11 :           const wchar_t *p = block;
     194                 :             : 
     195                 :        2865 :           while (*p != L'\0')
     196                 :             :             {
     197                 :        2854 :               if (*p == L'=')
     198                 :             :                 {
     199                 :           0 :                   have_cmd_environment = TRUE;
     200                 :           0 :                   break;
     201                 :             :                 }
     202                 :             : 
     203                 :        2854 :               p += wcslen (p) + 1;
     204                 :             :             }
     205                 :             : 
     206                 :          11 :           if (!FreeEnvironmentStringsW (block))
     207                 :           0 :             g_warning ("%s failed with error code %u",
     208                 :             :                        "FreeEnvironmentStrings",
     209                 :           0 :                        (guint) GetLastError ());
     210                 :          11 :         }
     211                 :             : 
     212                 :          11 :       if (!have_cmd_environment)
     213                 :             :         {
     214                 :          11 :           if (!SetEnvironmentVariableW (L"=GLIB", L"GLIB"))
     215                 :             :             {
     216                 :           0 :               g_critical ("%s failed with error code %u",
     217                 :             :                           "SetEnvironmentVariable",
     218                 :           0 :                           (guint) GetLastError ());
     219                 :           0 :             }
     220                 :          11 :         }
     221                 :             : 
     222                 :          11 :       g_once_init_leave (&initialization_value, 1);
     223                 :          11 :     }
     224                 :          65 : }
     225                 :             : 
     226                 :             : static intptr_t
     227                 :           0 : safe_wspawnve (int                   _mode,
     228                 :             :                const wchar_t *       _filename,
     229                 :             :                const wchar_t *const *_args,
     230                 :             :                const wchar_t *const *_env)
     231                 :             : {
     232                 :           0 :   ensure_cmd_environment ();
     233                 :             : 
     234                 :           0 :   return _wspawnve (_mode, _filename, _args, _env);;
     235                 :             : }
     236                 :             : 
     237                 :             : static intptr_t
     238                 :          65 : safe_wspawnvpe (int                   _mode,
     239                 :             :                 const wchar_t *       _filename,
     240                 :             :                 const wchar_t *const *_args,
     241                 :             :                 const wchar_t *const *_env)
     242                 :             : {
     243                 :          65 :   ensure_cmd_environment ();
     244                 :             : 
     245                 :          65 :   return _wspawnvpe (_mode, _filename, _args, _env);
     246                 :             : }
     247                 :             : 
     248                 :             : #endif /* _UCRT */
     249                 :             : 
     250                 :             : /* This logic has a copy for wchar_t in gspawn-win32-helper.c, protect_wargv() */
     251                 :             : static gchar *
     252                 :        2534 : protect_argv_string (const gchar *string)
     253                 :             : {
     254                 :        2534 :   const gchar *p = string;
     255                 :             :   gchar *retval, *q;
     256                 :        2534 :   size_t len = 0;
     257                 :        2534 :   size_t pre_bslash = 0;
     258                 :        2534 :   gboolean need_dblquotes = FALSE;
     259                 :       95656 :   while (*p)
     260                 :             :     {
     261                 :       93122 :       if (*p == ' ' || *p == '\t')
     262                 :          42 :         need_dblquotes = TRUE;
     263                 :             :       /* estimate max len, assuming that all escapable characters will be escaped */
     264                 :       93122 :       if (*p == '"' || *p == '\\')
     265                 :        5829 :         len += 2;
     266                 :             :       else
     267                 :       87293 :         len += 1;
     268                 :       93122 :       p++;
     269                 :             :     }
     270                 :             :   
     271                 :        2534 :   q = retval = g_malloc (len + need_dblquotes*2 + 1);
     272                 :        2534 :   p = string;
     273                 :             : 
     274                 :        2534 :   if (need_dblquotes)
     275                 :          34 :     *q++ = '"';
     276                 :             :   /* Only quotes and backslashes preceding quotes are escaped:
     277                 :             :    * see "Parsing C Command-Line Arguments" at
     278                 :             :    * https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments
     279                 :             :    */
     280                 :       95656 :   while (*p)
     281                 :             :     {
     282                 :       93122 :       if (*p == '"')
     283                 :             :         {
     284                 :             :           /* Add backslash for escaping quote itself */
     285                 :          11 :           *q++ = '\\';
     286                 :             :           /* Add backslash for every preceding backslash for escaping it */
     287                 :          17 :           for (;pre_bslash > 0; --pre_bslash)
     288                 :           6 :             *q++ = '\\';
     289                 :          11 :         }
     290                 :             : 
     291                 :             :       /* Count length of continuous sequence of preceding backslashes. */
     292                 :       93122 :       if (*p == '\\')
     293                 :        5818 :         ++pre_bslash;
     294                 :             :       else
     295                 :       87304 :         pre_bslash = 0;
     296                 :             : 
     297                 :       93122 :       *q++ = *p;
     298                 :       93122 :       p++;
     299                 :             :     }
     300                 :             :   
     301                 :        2534 :   if (need_dblquotes)
     302                 :             :     {
     303                 :             :       /* Add backslash for every preceding backslash for escaping it,
     304                 :             :        * do NOT escape quote itself.
     305                 :             :        */
     306                 :          35 :       for (;pre_bslash > 0; --pre_bslash)
     307                 :           1 :         *q++ = '\\';
     308                 :          34 :       *q++ = '"';
     309                 :          34 :     }
     310                 :        2534 :   *q++ = '\0';
     311                 :             : 
     312                 :        2534 :   return retval;
     313                 :             : }
     314                 :             : 
     315                 :             : static gint
     316                 :         428 : protect_argv (const gchar * const   *argv,
     317                 :             :               gchar               ***new_argv)
     318                 :             : {
     319                 :             :   gint i;
     320                 :         428 :   gint argc = 0;
     321                 :             :   
     322                 :        2277 :   while (argv[argc])
     323                 :        1849 :     ++argc;
     324                 :         428 :   *new_argv = g_new (gchar *, argc+1);
     325                 :             : 
     326                 :             :   /* Quote each argv element if necessary, so that it will get
     327                 :             :    * reconstructed correctly in the C runtime startup code.  Note that
     328                 :             :    * the unquoting algorithm in the C runtime is really weird, and
     329                 :             :    * rather different than what Unix shells do. See stdargv.c in the C
     330                 :             :    * runtime sources (in the Platform SDK, in src/crt).
     331                 :             :    *
     332                 :             :    * Note that a new_argv[0] constructed by this function should
     333                 :             :    * *not* be passed as the filename argument to a spawn* or exec*
     334                 :             :    * family function. That argument should be the real file name
     335                 :             :    * without any quoting.
     336                 :             :    */
     337                 :        2277 :   for (i = 0; i < argc; i++)
     338                 :        1849 :     (*new_argv)[i] = protect_argv_string (argv[i]);
     339                 :             : 
     340                 :         428 :   (*new_argv)[argc] = NULL;
     341                 :             : 
     342                 :         428 :   return argc;
     343                 :             : }
     344                 :             : 
     345                 :          13 : G_DEFINE_QUARK (g-exec-error-quark, g_spawn_error)
     346                 :          41 : G_DEFINE_QUARK (g-spawn-exit-error-quark, g_spawn_exit_error)
     347                 :             : 
     348                 :             : /* Avoids a danger in threaded situations (calling close()
     349                 :             :  * on a file descriptor twice, and another thread has
     350                 :             :  * re-opened it since the first close)
     351                 :             :  */
     352                 :             : static void
     353                 :        3044 : close_and_invalidate (gint *fd)
     354                 :             : {
     355                 :        3044 :   if (*fd < 0)
     356                 :         580 :     return;
     357                 :             : 
     358                 :        2464 :   close (*fd);
     359                 :        2464 :   *fd = -1;
     360                 :        3044 : }
     361                 :             : 
     362                 :             : typedef enum
     363                 :             : {
     364                 :             :   READ_FAILED = 0, /* FALSE */
     365                 :             :   READ_OK,
     366                 :             :   READ_EOF
     367                 :             : } ReadResult;
     368                 :             : 
     369                 :             : static ReadResult
     370                 :         253 : read_data (GString     *str,
     371                 :             :            GIOChannel  *iochannel,
     372                 :             :            GError     **error)
     373                 :             : {
     374                 :             :   GIOStatus giostatus;
     375                 :             :   gsize bytes;
     376                 :         253 :   gchar buf[4096];
     377                 :             : 
     378                 :             :  again:
     379                 :             :   
     380                 :         253 :   giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
     381                 :             : 
     382                 :         253 :   if (bytes == 0)
     383                 :          64 :     return READ_EOF;
     384                 :         189 :   else if (bytes > 0)
     385                 :             :     {
     386                 :         189 :       g_string_append_len (str, buf, bytes);
     387                 :         189 :       return READ_OK;
     388                 :             :     }
     389                 :           0 :   else if (giostatus == G_IO_STATUS_AGAIN)
     390                 :           0 :     goto again;
     391                 :           0 :   else if (giostatus == G_IO_STATUS_ERROR)
     392                 :             :     {
     393                 :           0 :       g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
     394                 :           0 :                            _("Failed to read data from child process"));
     395                 :             :       
     396                 :           0 :       return READ_FAILED;
     397                 :             :     }
     398                 :             :   else
     399                 :           0 :     return READ_OK;
     400                 :         253 : }
     401                 :             : 
     402                 :             : static gboolean
     403                 :        1547 : make_pipe (gint     p[2],
     404                 :             :            GError **error)
     405                 :             : {
     406                 :        1547 :   if (_pipe (p, 4096, _O_BINARY) < 0)
     407                 :             :     {
     408                 :           0 :       int errsv = errno;
     409                 :             : 
     410                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     411                 :           0 :                    _("Failed to create pipe for communicating with child process (%s)"),
     412                 :           0 :                    g_strerror (errsv));
     413                 :           0 :       return FALSE;
     414                 :             :     }
     415                 :             :   else
     416                 :        1547 :     return TRUE;
     417                 :        1547 : }
     418                 :             : 
     419                 :             : /* The helper process writes a status report back to us, through a
     420                 :             :  * pipe, consisting of two ints.
     421                 :             :  */
     422                 :             : static gboolean
     423                 :         427 : read_helper_report (int      fd,
     424                 :             :                     gintptr  report[2],
     425                 :             :                     GError **error)
     426                 :             : {
     427                 :         427 :   gsize bytes = 0;
     428                 :             :   
     429                 :        1219 :   while (bytes < sizeof(gintptr)*2)
     430                 :             :     {
     431                 :             :       gint chunk;
     432                 :             :       int errsv;
     433                 :             : 
     434                 :         792 :       if (debug)
     435                 :           0 :         g_print ("%s:read_helper_report: read %" G_GSIZE_FORMAT "...\n",
     436                 :             :                  __FILE__,
     437                 :           0 :                  sizeof(gintptr)*2 - bytes);
     438                 :             : 
     439                 :        1584 :       chunk = read (fd, ((gchar*)report) + bytes,
     440                 :         792 :                     sizeof(gintptr)*2 - bytes);
     441                 :         792 :       errsv = errno;
     442                 :             : 
     443                 :         792 :       if (debug)
     444                 :           0 :         g_print ("...got %d bytes\n", chunk);
     445                 :             :           
     446                 :         792 :       if (chunk < 0)
     447                 :             :         {
     448                 :             :           /* Some weird shit happened, bail out */
     449                 :           0 :           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     450                 :           0 :                        _("Failed to read from child pipe (%s)"),
     451                 :           0 :                        g_strerror (errsv));
     452                 :             : 
     453                 :           0 :           return FALSE;
     454                 :             :         }
     455                 :         792 :       else if (chunk == 0)
     456                 :             :         {
     457                 :           0 :           g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     458                 :           0 :                        _("Failed to read from child pipe (%s)"),
     459                 :             :                        "EOF");
     460                 :           0 :           break; /* EOF */
     461                 :             :         }
     462                 :             :       else
     463                 :         792 :         bytes += chunk;
     464                 :             :     }
     465                 :             : 
     466                 :         427 :   if (bytes < sizeof(gintptr)*2)
     467                 :           0 :     return FALSE;
     468                 :             : 
     469                 :         427 :   return TRUE;
     470                 :         427 : }
     471                 :             : 
     472                 :             : static void
     473                 :           5 : set_child_error (gintptr      report[2],
     474                 :             :                  const gchar *working_directory,
     475                 :             :                  GError     **error)
     476                 :             : {
     477                 :           5 :   switch (report[0])
     478                 :             :     {
     479                 :             :     case CHILD_CHDIR_FAILED:
     480                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
     481                 :           0 :                    _("Failed to change to directory “%s” (%s)"),
     482                 :           0 :                    working_directory,
     483                 :           0 :                    g_strerror (report[1]));
     484                 :           0 :       break;
     485                 :             :     case CHILD_SPAWN_FAILED:
     486                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     487                 :           0 :                    _("Failed to execute child process (%s)"),
     488                 :           0 :                    g_strerror (report[1]));
     489                 :           0 :       break;
     490                 :             :     case CHILD_SPAWN_NOENT:
     491                 :          10 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT,
     492                 :           5 :                    _("Failed to execute child process (%s)"),
     493                 :           5 :                    g_strerror (report[1]));
     494                 :           5 :       break;
     495                 :             :     case CHILD_DUP_FAILED:
     496                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     497                 :           0 :                    _("Failed to dup() in child process (%s)"),
     498                 :           0 :                    g_strerror (report[1]));
     499                 :           0 :       break;
     500                 :             :     default:
     501                 :             :       g_assert_not_reached ();
     502                 :           0 :     }
     503                 :           5 : }
     504                 :             : 
     505                 :             : static gboolean
     506                 :         854 : utf8_charv_to_wcharv (const gchar * const   *utf8_charv,
     507                 :             :                       wchar_t             ***wcharv,
     508                 :             :                       int                   *error_index,
     509                 :             :                       GError               **error)
     510                 :             : {
     511                 :         854 :   wchar_t **retval = NULL;
     512                 :             : 
     513                 :         854 :   *wcharv = NULL;
     514                 :         854 :   if (utf8_charv != NULL)
     515                 :             :     {
     516                 :         492 :       int n = 0, i;
     517                 :             : 
     518                 :       23410 :       while (utf8_charv[n])
     519                 :       22918 :         n++;
     520                 :         492 :       retval = g_new (wchar_t *, n + 1);
     521                 :             : 
     522                 :       23410 :       for (i = 0; i < n; i++)
     523                 :             :         {
     524                 :       22918 :           retval[i] = g_utf8_to_utf16 (utf8_charv[i], -1, NULL, NULL, error);
     525                 :       22918 :           if (retval[i] == NULL)
     526                 :             :             {
     527                 :           0 :               if (error_index)
     528                 :           0 :                 *error_index = i;
     529                 :           0 :               while (i)
     530                 :           0 :                 g_free (retval[--i]);
     531                 :           0 :               g_free (retval);
     532                 :           0 :               return FALSE;
     533                 :             :             }
     534                 :       22918 :         }
     535                 :             :             
     536                 :         492 :       retval[n] = NULL;
     537                 :         492 :     }
     538                 :         854 :   *wcharv = retval;
     539                 :         854 :   return TRUE;
     540                 :         854 : }
     541                 :             : 
     542                 :             : static gboolean
     543                 :           0 : do_spawn_directly (gint                 *exit_status,
     544                 :             :                    gboolean              do_return_handle,
     545                 :             :                    GSpawnFlags           flags,
     546                 :             :                    const gchar * const  *argv,
     547                 :             :                    const gchar * const  *envp,
     548                 :             :                    const gchar * const  *protected_argv,
     549                 :             :                    GPid                 *child_pid,
     550                 :             :                    GError              **error)
     551                 :             : {
     552                 :           0 :   const int mode = (exit_status == NULL) ? P_NOWAIT : P_WAIT;
     553                 :             :   const gchar * const *new_argv;
     554                 :           0 :   gintptr rc = -1;
     555                 :             :   int errsv;
     556                 :           0 :   GError *conv_error = NULL;
     557                 :             :   gint conv_error_index;
     558                 :             :   wchar_t *wargv0, **wargv, **wenvp;
     559                 :             : 
     560                 :           0 :   g_assert (argv != NULL && argv[0] != NULL);
     561                 :             : 
     562                 :           0 :   new_argv = (flags & G_SPAWN_FILE_AND_ARGV_ZERO) ? protected_argv + 1 : protected_argv;
     563                 :             :       
     564                 :           0 :   wargv0 = g_utf8_to_utf16 (argv[0], -1, NULL, NULL, &conv_error);
     565                 :           0 :   if (wargv0 == NULL)
     566                 :             :     {
     567                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     568                 :           0 :                    _("Invalid program name: %s"),
     569                 :           0 :                    conv_error->message);
     570                 :           0 :       g_error_free (conv_error);
     571                 :             :       
     572                 :           0 :       return FALSE;
     573                 :             :     }
     574                 :             :   
     575                 :           0 :   if (!utf8_charv_to_wcharv (new_argv, &wargv, &conv_error_index, &conv_error))
     576                 :             :     {
     577                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     578                 :           0 :                    _("Invalid string in argument vector at %d: %s"),
     579                 :           0 :                    conv_error_index, conv_error->message);
     580                 :           0 :       g_error_free (conv_error);
     581                 :           0 :       g_free (wargv0);
     582                 :             : 
     583                 :           0 :       return FALSE;
     584                 :             :     }
     585                 :             : 
     586                 :           0 :   if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
     587                 :             :     {
     588                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     589                 :           0 :                    _("Invalid string in environment: %s"),
     590                 :           0 :                    conv_error->message);
     591                 :           0 :       g_error_free (conv_error);
     592                 :           0 :       g_free (wargv0);
     593                 :           0 :       g_strfreev ((gchar **) wargv);
     594                 :             : 
     595                 :           0 :       return FALSE;
     596                 :             :     }
     597                 :             : 
     598                 :           0 :   if (flags & G_SPAWN_SEARCH_PATH)
     599                 :           0 :     if (wenvp != NULL)
     600                 :           0 :       rc = safe_wspawnvpe (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
     601                 :             :     else
     602                 :           0 :       rc = _wspawnvp (mode, wargv0, (const wchar_t **) wargv);
     603                 :             :   else
     604                 :           0 :     if (wenvp != NULL)
     605                 :           0 :       rc = safe_wspawnve (mode, wargv0, (const wchar_t **) wargv, (const wchar_t **) wenvp);
     606                 :             :     else
     607                 :           0 :       rc = _wspawnv (mode, wargv0, (const wchar_t **) wargv);
     608                 :             : 
     609                 :           0 :   errsv = errno;
     610                 :             : 
     611                 :           0 :   g_free (wargv0);
     612                 :           0 :   g_strfreev ((gchar **) wargv);
     613                 :           0 :   g_strfreev ((gchar **) wenvp);
     614                 :             : 
     615                 :           0 :   if (rc == -1 && errsv != 0)
     616                 :             :     {
     617                 :           0 :       g_set_error (error, G_SPAWN_ERROR, _g_spawn_exec_err_to_g_error (errsv),
     618                 :           0 :                    _("Failed to execute child process (%s)"),
     619                 :           0 :                    g_strerror (errsv));
     620                 :           0 :       return FALSE;
     621                 :             :     }
     622                 :             : 
     623                 :           0 :   if (exit_status == NULL)
     624                 :             :     {
     625                 :           0 :       if (child_pid && do_return_handle)
     626                 :           0 :         *child_pid = (GPid) rc;
     627                 :             :       else
     628                 :             :         {
     629                 :           0 :           CloseHandle ((HANDLE) rc);
     630                 :           0 :           if (child_pid)
     631                 :           0 :             *child_pid = 0;
     632                 :             :         }
     633                 :           0 :     }
     634                 :             :   else
     635                 :           0 :     *exit_status = rc;
     636                 :             : 
     637                 :           0 :   return TRUE;
     638                 :           0 : }
     639                 :             : 
     640                 :             : static gboolean
     641                 :         427 : might_be_console_process (void)
     642                 :             : {
     643                 :             :   // we should always fail to attach ourself to a console (because we're
     644                 :             :   // either already attached, or we do not have a console)
     645                 :         427 :   gboolean attached_to_self = AttachConsole (GetCurrentProcessId ());
     646                 :         427 :   g_return_val_if_fail (!attached_to_self, TRUE);
     647                 :             : 
     648                 :         427 :   switch (GetLastError ())
     649                 :             :     {
     650                 :             :     // current process is already attached to a console
     651                 :             :     case ERROR_ACCESS_DENIED:
     652                 :         427 :       return TRUE;
     653                 :             :     // current process does not have a console
     654                 :             :     case ERROR_INVALID_HANDLE:
     655                 :           0 :       return FALSE;
     656                 :             :     // we should not get ERROR_INVALID_PARAMETER
     657                 :             :     }
     658                 :             : 
     659                 :             :   g_return_val_if_reached (FALSE);
     660                 :         427 : }
     661                 :             : 
     662                 :             : static gboolean
     663                 :         428 : fork_exec (gint                  *exit_status,
     664                 :             :            gboolean               do_return_handle,
     665                 :             :            const gchar           *working_directory,
     666                 :             :            const gchar * const   *argv,
     667                 :             :            const gchar * const   *envp,
     668                 :             :            GSpawnFlags            flags,
     669                 :             :            GSpawnChildSetupFunc   child_setup,
     670                 :             :            gpointer               user_data,
     671                 :             :            GPid                  *child_pid,
     672                 :             :            gint                  *stdin_pipe_out,
     673                 :             :            gint                  *stdout_pipe_out,
     674                 :             :            gint                  *stderr_pipe_out,
     675                 :             :            gint                   stdin_fd,
     676                 :             :            gint                   stdout_fd,
     677                 :             :            gint                   stderr_fd,
     678                 :             :            const gint            *source_fds,
     679                 :             :            const gint            *target_fds,
     680                 :             :            gsize                  n_fds,
     681                 :             :            gint                  *err_report,
     682                 :             :            GError               **error)
     683                 :             : {
     684                 :             :   char **protected_argv;
     685                 :             :   char args[ARG_COUNT][10];
     686                 :             :   char **new_argv;
     687                 :             :   int i;
     688                 :         428 :   gintptr rc = -1;
     689                 :             :   int errsv;
     690                 :             :   int argc;
     691                 :         428 :   int child_err_report_pipe[2] = { -1, -1 };
     692                 :         428 :   int helper_sync_pipe[2] = { -1, -1 };
     693                 :             :   gintptr helper_report[2];
     694                 :             :   static gboolean warned_about_child_setup = FALSE;
     695                 :         428 :   GError *conv_error = NULL;
     696                 :             :   gint conv_error_index;
     697                 :             :   gchar *helper_process;
     698                 :             :   wchar_t *whelper, **wargv, **wenvp;
     699                 :         428 :   int stdin_pipe[2] = { -1, -1 };
     700                 :         428 :   int stdout_pipe[2] = { -1, -1 };
     701                 :         428 :   int stderr_pipe[2] = { -1, -1 };
     702                 :             : 
     703                 :         428 :   g_assert (argv != NULL && argv[0] != NULL);
     704                 :         428 :   g_assert (stdin_pipe_out == NULL || stdin_fd < 0);
     705                 :         428 :   g_assert (stdout_pipe_out == NULL || stdout_fd < 0);
     706                 :         428 :   g_assert (stderr_pipe_out == NULL || stderr_fd < 0);
     707                 :             : 
     708                 :         428 :   if (child_setup && !warned_about_child_setup)
     709                 :             :     {
     710                 :           0 :       warned_about_child_setup = TRUE;
     711                 :           0 :       g_warning ("passing a child setup function to the g_spawn functions is pointless on Windows and it is ignored");
     712                 :           0 :     }
     713                 :             : 
     714                 :         428 :   if (stdin_pipe_out != NULL)
     715                 :             :     {
     716                 :          55 :       if (!make_pipe (stdin_pipe, error))
     717                 :           0 :         goto cleanup_and_fail;
     718                 :          55 :       if (_g_spawn_invalid_source_fd (stdin_pipe[0], source_fds, n_fds, error) ||
     719                 :          55 :           _g_spawn_invalid_source_fd (stdin_pipe[1], source_fds, n_fds, error))
     720                 :           0 :         goto cleanup_and_fail;
     721                 :          55 :       stdin_fd = stdin_pipe[0];
     722                 :          55 :     }
     723                 :             : 
     724                 :         428 :   if (stdout_pipe_out != NULL)
     725                 :             :     {
     726                 :         362 :       if (!make_pipe (stdout_pipe, error))
     727                 :           0 :         goto cleanup_and_fail;
     728                 :         362 :       if (_g_spawn_invalid_source_fd (stdout_pipe[0], source_fds, n_fds, error) ||
     729                 :         362 :           _g_spawn_invalid_source_fd (stdout_pipe[1], source_fds, n_fds, error))
     730                 :           0 :         goto cleanup_and_fail;
     731                 :         362 :       stdout_fd = stdout_pipe[1];
     732                 :         362 :     }
     733                 :             : 
     734                 :         428 :   if (stderr_pipe_out != NULL)
     735                 :             :     {
     736                 :         275 :       if (!make_pipe (stderr_pipe, error))
     737                 :           0 :         goto cleanup_and_fail;
     738                 :         275 :       if (_g_spawn_invalid_source_fd (stderr_pipe[0], source_fds, n_fds, error) ||
     739                 :         275 :           _g_spawn_invalid_source_fd (stderr_pipe[1], source_fds, n_fds, error))
     740                 :           0 :         goto cleanup_and_fail;
     741                 :         275 :       stderr_fd = stderr_pipe[1];
     742                 :         275 :     }
     743                 :             : 
     744                 :         428 :   argc = protect_argv (argv, &protected_argv);
     745                 :             : 
     746                 :         428 :   if (stdin_fd == -1 && stdout_fd == -1 && stderr_fd == -1 &&
     747                 :          38 :       (flags & G_SPAWN_CHILD_INHERITS_STDIN) &&
     748                 :           1 :       !(flags & G_SPAWN_STDOUT_TO_DEV_NULL) &&
     749                 :           1 :       !(flags & G_SPAWN_STDERR_TO_DEV_NULL) &&
     750                 :           1 :       (working_directory == NULL || !*working_directory) &&
     751                 :           1 :       (flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN) &&
     752                 :           0 :       n_fds == 0)
     753                 :             :     {
     754                 :             :       /* We can do without the helper process */
     755                 :           0 :       gboolean retval =
     756                 :           0 :         do_spawn_directly (exit_status, do_return_handle, flags,
     757                 :           0 :                            argv, envp, (const gchar * const *) protected_argv,
     758                 :           0 :                            child_pid, error);
     759                 :           0 :       g_strfreev (protected_argv);
     760                 :           0 :       return retval;
     761                 :             :     }
     762                 :             : 
     763                 :         428 :   if (!make_pipe (child_err_report_pipe, error))
     764                 :           0 :     goto cleanup_and_fail;
     765                 :         428 :   if (_g_spawn_invalid_source_fd (child_err_report_pipe[0], source_fds, n_fds, error) ||
     766                 :         427 :       _g_spawn_invalid_source_fd (child_err_report_pipe[1], source_fds, n_fds, error))
     767                 :           1 :     goto cleanup_and_fail;
     768                 :             :   
     769                 :         427 :   if (!make_pipe (helper_sync_pipe, error))
     770                 :           0 :     goto cleanup_and_fail;
     771                 :         427 :   if (_g_spawn_invalid_source_fd (helper_sync_pipe[0], source_fds, n_fds, error) ||
     772                 :         427 :       _g_spawn_invalid_source_fd (helper_sync_pipe[1], source_fds, n_fds, error))
     773                 :           0 :     goto cleanup_and_fail;
     774                 :             :   
     775                 :         427 :   new_argv = g_new (char *, argc + 1 + ARG_COUNT);
     776                 :         427 :   if (might_be_console_process ())
     777                 :         427 :     helper_process = HELPER_PROCESS "-console.exe";
     778                 :             :   else
     779                 :           0 :     helper_process = HELPER_PROCESS ".exe";
     780                 :             : 
     781                 :         427 :   helper_process = g_win32_find_helper_executable_path (helper_process, glib_dll);
     782                 :         427 :   new_argv[0] = protect_argv_string (helper_process);
     783                 :             : 
     784                 :         427 :   _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]);
     785                 :         427 :   new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
     786                 :             :   
     787                 :             :   /* Make the read end of the child error report pipe
     788                 :             :    * noninherited. Otherwise it will needlessly be inherited by the
     789                 :             :    * helper process, and the started actual user process. As such that
     790                 :             :    * shouldn't harm, but it is unnecessary.
     791                 :             :    */
     792                 :         427 :   child_err_report_pipe[0] = g_win32_reopen_noninherited (
     793                 :         427 :     child_err_report_pipe[0], _O_RDONLY, error);
     794                 :         427 :   if (child_err_report_pipe[0] == -1)
     795                 :           0 :       goto cleanup_and_fail;
     796                 :             : 
     797                 :         427 :   if (flags & G_SPAWN_FILE_AND_ARGV_ZERO)
     798                 :             :     {
     799                 :             :       /* Overload ARG_CHILD_ERR_REPORT to also encode the
     800                 :             :        * G_SPAWN_FILE_AND_ARGV_ZERO functionality.
     801                 :             :        */
     802                 :           1 :       strcat (args[ARG_CHILD_ERR_REPORT], "#");
     803                 :           1 :     }
     804                 :             :   
     805                 :         427 :   _g_sprintf (args[ARG_HELPER_SYNC], "%d", helper_sync_pipe[0]);
     806                 :         427 :   new_argv[ARG_HELPER_SYNC] = args[ARG_HELPER_SYNC];
     807                 :             :   
     808                 :             :   /* Make the write end of the sync pipe noninherited. Otherwise the
     809                 :             :    * helper process will inherit it, and thus if this process happens
     810                 :             :    * to crash before writing the sync byte to the pipe, the helper
     811                 :             :    * process won't read but won't get any EOF either, as it has the
     812                 :             :    * write end open itself.
     813                 :             :    */
     814                 :         427 :   helper_sync_pipe[1] = g_win32_reopen_noninherited (
     815                 :         427 :     helper_sync_pipe[1], _O_WRONLY, error);
     816                 :         427 :   if (helper_sync_pipe[1] == -1)
     817                 :           0 :       goto cleanup_and_fail;
     818                 :             : 
     819                 :         427 :   if (stdin_fd != -1)
     820                 :             :     {
     821                 :          56 :       _g_sprintf (args[ARG_STDIN], "%d", stdin_fd);
     822                 :          56 :       new_argv[ARG_STDIN] = args[ARG_STDIN];
     823                 :          56 :     }
     824                 :         371 :   else if (flags & G_SPAWN_CHILD_INHERITS_STDIN)
     825                 :             :     {
     826                 :             :       /* Let stdin be alone */
     827                 :           3 :       new_argv[ARG_STDIN] = "-";
     828                 :           3 :     }
     829                 :             :   else
     830                 :             :     {
     831                 :             :       /* Keep process from blocking on a read of stdin */
     832                 :         368 :       new_argv[ARG_STDIN] = "z";
     833                 :             :     }
     834                 :             :   
     835                 :         427 :   if (stdout_fd != -1)
     836                 :             :     {
     837                 :         365 :       _g_sprintf (args[ARG_STDOUT], "%d", stdout_fd);
     838                 :         365 :       new_argv[ARG_STDOUT] = args[ARG_STDOUT];
     839                 :         365 :     }
     840                 :          62 :   else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
     841                 :             :     {
     842                 :          28 :       new_argv[ARG_STDOUT] = "z";
     843                 :          28 :     }
     844                 :             :   else
     845                 :             :     {
     846                 :          34 :       new_argv[ARG_STDOUT] = "-";
     847                 :             :     }
     848                 :             :   
     849                 :         427 :   if (stderr_fd != -1)
     850                 :             :     {
     851                 :         277 :       _g_sprintf (args[ARG_STDERR], "%d", stderr_fd);
     852                 :         277 :       new_argv[ARG_STDERR] = args[ARG_STDERR];
     853                 :         277 :     }
     854                 :         150 :   else if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
     855                 :             :     {
     856                 :          65 :       new_argv[ARG_STDERR] = "z";
     857                 :          65 :     }
     858                 :             :   else
     859                 :             :     {
     860                 :          85 :       new_argv[ARG_STDERR] = "-";
     861                 :             :     }
     862                 :             :   
     863                 :         427 :   if (working_directory && *working_directory)
     864                 :         258 :     new_argv[ARG_WORKING_DIRECTORY] = protect_argv_string (working_directory);
     865                 :             :   else
     866                 :         169 :     new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
     867                 :             :   
     868                 :         427 :   if (!(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN))
     869                 :         420 :     new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
     870                 :             :   else
     871                 :           7 :     new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
     872                 :             : 
     873                 :         427 :   if (flags & G_SPAWN_SEARCH_PATH)
     874                 :           7 :     new_argv[ARG_USE_PATH] = "y";
     875                 :             :   else
     876                 :         420 :     new_argv[ARG_USE_PATH] = "-";
     877                 :             : 
     878                 :         427 :   if (exit_status == NULL)
     879                 :         349 :     new_argv[ARG_WAIT] = "-";
     880                 :             :   else
     881                 :          78 :     new_argv[ARG_WAIT] = "w";
     882                 :             : 
     883                 :         427 :   if (n_fds == 0)
     884                 :         426 :     new_argv[ARG_FDS] = g_strdup ("-");
     885                 :             :   else
     886                 :             :     {
     887                 :           1 :       GString *fds = g_string_new ("");
     888                 :             :       gsize n;
     889                 :             : 
     890                 :          11 :       for (n = 0; n < n_fds; n++)
     891                 :          10 :         g_string_append_printf (fds, "%d:%d,", source_fds[n], target_fds[n]);
     892                 :             : 
     893                 :             :       /* remove the trailing , */
     894                 :           1 :       g_string_truncate (fds, fds->len - 1);
     895                 :           1 :       new_argv[ARG_FDS] = g_string_free (fds, FALSE);
     896                 :             :     }
     897                 :             : 
     898                 :        2701 :   for (i = 0; i <= argc; i++)
     899                 :        2274 :     new_argv[ARG_PROGRAM + i] = protected_argv[i];
     900                 :             : 
     901                 :         427 :   SETUP_DEBUG();
     902                 :             : 
     903                 :         427 :   if (debug)
     904                 :             :     {
     905                 :           0 :       g_print ("calling %s with argv:\n", helper_process);
     906                 :           0 :       for (i = 0; i < argc + 1 + ARG_COUNT; i++)
     907                 :           0 :         g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
     908                 :           0 :     }
     909                 :             : 
     910                 :         427 :   if (!utf8_charv_to_wcharv ((const gchar * const *) new_argv, &wargv, &conv_error_index, &conv_error))
     911                 :             :     {
     912                 :           0 :       if (conv_error_index == ARG_WORKING_DIRECTORY)
     913                 :           0 :         g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_CHDIR,
     914                 :           0 :                      _("Invalid working directory: %s"),
     915                 :           0 :                      conv_error->message);
     916                 :             :       else
     917                 :           0 :         g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     918                 :           0 :                      _("Invalid string in argument vector at %d: %s"),
     919                 :           0 :                      conv_error_index - ARG_PROGRAM, conv_error->message);
     920                 :           0 :       g_error_free (conv_error);
     921                 :           0 :       g_strfreev (protected_argv);
     922                 :           0 :       g_free (new_argv[0]);
     923                 :           0 :       g_free (new_argv[ARG_WORKING_DIRECTORY]);
     924                 :           0 :       g_free (new_argv[ARG_FDS]);
     925                 :           0 :       g_free (new_argv);
     926                 :           0 :       g_free (helper_process);
     927                 :             : 
     928                 :           0 :       goto cleanup_and_fail;
     929                 :             :     }
     930                 :             : 
     931                 :         427 :   if (!utf8_charv_to_wcharv (envp, &wenvp, NULL, &conv_error))
     932                 :             :     {
     933                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     934                 :           0 :                    _("Invalid string in environment: %s"),
     935                 :           0 :                    conv_error->message);
     936                 :           0 :       g_error_free (conv_error);
     937                 :           0 :       g_strfreev (protected_argv);
     938                 :           0 :       g_free (new_argv[0]);
     939                 :           0 :       g_free (new_argv[ARG_WORKING_DIRECTORY]);
     940                 :           0 :       g_free (new_argv[ARG_FDS]);
     941                 :           0 :       g_free (new_argv);
     942                 :           0 :       g_free (helper_process);
     943                 :           0 :       g_strfreev ((gchar **) wargv);
     944                 :             :  
     945                 :           0 :       goto cleanup_and_fail;
     946                 :             :     }
     947                 :             : 
     948                 :         427 :   whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL);
     949                 :         427 :   g_free (helper_process);
     950                 :             : 
     951                 :         427 :   if (wenvp != NULL)
     952                 :          65 :     rc = safe_wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp);
     953                 :             :   else
     954                 :         362 :     rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv);
     955                 :             : 
     956                 :         427 :   errsv = errno;
     957                 :             : 
     958                 :         427 :   g_free (whelper);
     959                 :         427 :   g_strfreev ((gchar **) wargv);
     960                 :         427 :   g_strfreev ((gchar **) wenvp);
     961                 :             : 
     962                 :             :   /* Close the other process's ends of the pipes in this process,
     963                 :             :    * otherwise the reader will never get EOF.
     964                 :             :    */
     965                 :         427 :   close_and_invalidate (&child_err_report_pipe[1]);
     966                 :         427 :   close_and_invalidate (&helper_sync_pipe[0]);
     967                 :             : 
     968                 :         427 :   g_strfreev (protected_argv);
     969                 :             : 
     970                 :         427 :   g_free (new_argv[0]);
     971                 :         427 :   g_free (new_argv[ARG_WORKING_DIRECTORY]);
     972                 :         427 :   g_free (new_argv[ARG_FDS]);
     973                 :         427 :   g_free (new_argv);
     974                 :             : 
     975                 :             :   /* Check if gspawn-win32-helper couldn't be run */
     976                 :         427 :   if (rc == -1 && errsv != 0)
     977                 :             :     {
     978                 :           0 :       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
     979                 :           0 :                    _("Failed to execute helper program (%s)"),
     980                 :           0 :                    g_strerror (errsv));
     981                 :           0 :       goto cleanup_and_fail;
     982                 :             :     }
     983                 :             : 
     984                 :         427 :   if (exit_status != NULL)
     985                 :             :     {
     986                 :             :       /* Synchronous case. Pass helper's report pipe back to caller,
     987                 :             :        * which takes care of reading it after the grandchild has
     988                 :             :        * finished.
     989                 :             :        */
     990                 :          78 :       g_assert (err_report != NULL);
     991                 :          78 :       *err_report = child_err_report_pipe[0];
     992                 :          78 :       write (helper_sync_pipe[1], " ", 1);
     993                 :          78 :       close_and_invalidate (&helper_sync_pipe[1]);
     994                 :          78 :     }
     995                 :             :   else
     996                 :             :     {
     997                 :             :       /* Asynchronous case. We read the helper's report right away. */
     998                 :         349 :       if (!read_helper_report (child_err_report_pipe[0], helper_report, error))
     999                 :           0 :         goto cleanup_and_fail;
    1000                 :             :         
    1001                 :         349 :       close_and_invalidate (&child_err_report_pipe[0]);
    1002                 :             : 
    1003                 :         349 :       switch (helper_report[0])
    1004                 :             :         {
    1005                 :             :         case CHILD_NO_ERROR:
    1006                 :         346 :           if (child_pid && do_return_handle)
    1007                 :             :             {
    1008                 :             :               /* rc is our HANDLE for gspawn-win32-helper. It has
    1009                 :             :                * told us the HANDLE of its child. Duplicate that into
    1010                 :             :                * a HANDLE valid in this process.
    1011                 :             :                */
    1012                 :         686 :               if (!DuplicateHandle ((HANDLE) rc, (HANDLE) helper_report[1],
    1013                 :         343 :                                     GetCurrentProcess (), (LPHANDLE) child_pid,
    1014                 :             :                                     0, TRUE, DUPLICATE_SAME_ACCESS))
    1015                 :             :                 {
    1016                 :           0 :                   char *emsg = g_win32_error_message (GetLastError ());
    1017                 :           0 :                   g_print ("%s\n", emsg);
    1018                 :           0 :                   g_free (emsg);
    1019                 :           0 :                   *child_pid = 0;
    1020                 :           0 :                 }
    1021                 :         343 :             }
    1022                 :           3 :           else if (child_pid)
    1023                 :           1 :             *child_pid = 0;
    1024                 :         346 :           write (helper_sync_pipe[1], " ", 1);
    1025                 :         346 :           close_and_invalidate (&helper_sync_pipe[1]);
    1026                 :         346 :           break;
    1027                 :             :           
    1028                 :             :         default:
    1029                 :           3 :           write (helper_sync_pipe[1], " ", 1);
    1030                 :           3 :           close_and_invalidate (&helper_sync_pipe[1]);
    1031                 :           3 :           set_child_error (helper_report, working_directory, error);
    1032                 :           3 :           goto cleanup_and_fail;
    1033                 :             :         }
    1034                 :             :     }
    1035                 :             : 
    1036                 :             :   /* Success against all odds! return the information */
    1037                 :             :       
    1038                 :         424 :   if (rc != -1)
    1039                 :         424 :     CloseHandle ((HANDLE) rc);
    1040                 :             : 
    1041                 :             :   /* Close the other process's ends of the pipes in this process,
    1042                 :             :    * otherwise the reader will never get EOF.
    1043                 :             :    */
    1044                 :         424 :   close_and_invalidate (&stdin_pipe[0]);
    1045                 :         424 :   close_and_invalidate (&stdout_pipe[1]);
    1046                 :         424 :   close_and_invalidate (&stderr_pipe[1]);
    1047                 :             : 
    1048                 :         424 :   if (stdin_pipe_out != NULL)
    1049                 :          55 :     *stdin_pipe_out = stdin_pipe[1];
    1050                 :         424 :   if (stdout_pipe_out != NULL)
    1051                 :         362 :     *stdout_pipe_out = stdout_pipe[0];
    1052                 :         424 :   if (stderr_pipe_out != NULL)
    1053                 :         275 :     *stderr_pipe_out = stderr_pipe[0];
    1054                 :             : 
    1055                 :         424 :   return TRUE;
    1056                 :             : 
    1057                 :             :  cleanup_and_fail:
    1058                 :             : 
    1059                 :           4 :   if (rc != -1)
    1060                 :           3 :     CloseHandle ((HANDLE) rc);
    1061                 :           4 :   if (child_err_report_pipe[0] != -1)
    1062                 :           1 :     close (child_err_report_pipe[0]);
    1063                 :           4 :   if (child_err_report_pipe[1] != -1)
    1064                 :           1 :     close (child_err_report_pipe[1]);
    1065                 :           4 :   if (helper_sync_pipe[0] != -1)
    1066                 :           0 :     close (helper_sync_pipe[0]);
    1067                 :           4 :   if (helper_sync_pipe[1] != -1)
    1068                 :           0 :     close (helper_sync_pipe[1]);
    1069                 :             : 
    1070                 :           4 :   if (stdin_pipe[0] != -1)
    1071                 :           0 :     close (stdin_pipe[0]);
    1072                 :           4 :   if (stdin_pipe[1] != -1)
    1073                 :           0 :     close (stdin_pipe[1]);
    1074                 :           4 :   if (stdout_pipe[0] != -1)
    1075                 :           0 :     close (stdout_pipe[0]);
    1076                 :           4 :   if (stdout_pipe[1] != -1)
    1077                 :           0 :     close (stdout_pipe[1]);
    1078                 :           4 :   if (stderr_pipe[0] != -1)
    1079                 :           0 :     close (stderr_pipe[0]);
    1080                 :           4 :   if (stderr_pipe[1] != -1)
    1081                 :           0 :     close (stderr_pipe[1]);
    1082                 :             : 
    1083                 :           4 :   return FALSE;
    1084                 :         428 : }
    1085                 :             : 
    1086                 :             : gboolean
    1087                 :          78 : g_spawn_sync_impl (const gchar           *working_directory,
    1088                 :             :                    gchar                **argv,
    1089                 :             :                    gchar                **envp,
    1090                 :             :                    GSpawnFlags            flags,
    1091                 :             :                    GSpawnChildSetupFunc   child_setup,
    1092                 :             :                    gpointer               user_data,
    1093                 :             :                    gchar                **standard_output,
    1094                 :             :                    gchar                **standard_error,
    1095                 :             :                    gint                  *wait_status,
    1096                 :             :                    GError               **error)
    1097                 :             : {
    1098                 :          78 :   gint outpipe = -1;
    1099                 :          78 :   gint errpipe = -1;
    1100                 :          78 :   gint reportpipe = -1;
    1101                 :          78 :   GIOChannel *outchannel = NULL;
    1102                 :          78 :   GIOChannel *errchannel = NULL;
    1103                 :          78 :   GPollFD outfd = { -1, 0, 0 }, errfd = { -1, 0, 0 };
    1104                 :             :   GPollFD fds[2];
    1105                 :             :   gint nfds;
    1106                 :          78 :   gint outindex = -1;
    1107                 :          78 :   gint errindex = -1;
    1108                 :             :   gint ret;
    1109                 :          78 :   GString *outstr = NULL;
    1110                 :          78 :   GString *errstr = NULL;
    1111                 :             :   gboolean failed;
    1112                 :             :   gint status;
    1113                 :             :   
    1114                 :          78 :   g_return_val_if_fail (argv != NULL && argv[0] != NULL, FALSE);
    1115                 :          78 :   g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
    1116                 :          78 :   g_return_val_if_fail (standard_output == NULL ||
    1117                 :          61 :                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
    1118                 :          78 :   g_return_val_if_fail (standard_error == NULL ||
    1119                 :           3 :                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
    1120                 :             :   
    1121                 :             :   /* Just to ensure segfaults if callers try to use
    1122                 :             :    * these when an error is reported.
    1123                 :             :    */
    1124                 :          78 :   if (standard_output)
    1125                 :          61 :     *standard_output = NULL;
    1126                 :             : 
    1127                 :          78 :   if (standard_error)
    1128                 :           3 :     *standard_error = NULL;
    1129                 :             : 
    1130                 :          78 :   if (!fork_exec (&status,
    1131                 :             :                   FALSE,
    1132                 :          78 :                   working_directory,
    1133                 :          78 :                   (const gchar * const *) argv,
    1134                 :          78 :                   (const gchar * const *) envp,
    1135                 :          78 :                   flags,
    1136                 :          78 :                   child_setup,
    1137                 :          78 :                   user_data,
    1138                 :             :                   NULL,
    1139                 :             :                   NULL,
    1140                 :          78 :                   standard_output ? &outpipe : NULL,
    1141                 :          78 :                   standard_error ? &errpipe : NULL,
    1142                 :             :                   -1,
    1143                 :             :                   -1,
    1144                 :             :                   -1,
    1145                 :             :                   NULL, NULL, 0,
    1146                 :             :                   &reportpipe,
    1147                 :          78 :                   error))
    1148                 :           0 :     return FALSE;
    1149                 :             : 
    1150                 :             :   /* Read data from child. */
    1151                 :             :   
    1152                 :          78 :   failed = FALSE;
    1153                 :             : 
    1154                 :          78 :   if (outpipe >= 0)
    1155                 :             :     {
    1156                 :          61 :       outstr = g_string_new (NULL);
    1157                 :          61 :       outchannel = g_io_channel_win32_new_fd (outpipe);
    1158                 :          61 :       g_io_channel_set_encoding (outchannel, NULL, NULL);
    1159                 :          61 :       g_io_channel_set_buffered (outchannel, FALSE);
    1160                 :          61 :       g_io_channel_win32_make_pollfd (outchannel,
    1161                 :             :                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
    1162                 :             :                                       &outfd);
    1163                 :          61 :       if (debug)
    1164                 :           0 :         g_print ("outfd=%p\n", (HANDLE) outfd.fd);
    1165                 :          61 :     }
    1166                 :             :       
    1167                 :          78 :   if (errpipe >= 0)
    1168                 :             :     {
    1169                 :           3 :       errstr = g_string_new (NULL);
    1170                 :           3 :       errchannel = g_io_channel_win32_new_fd (errpipe);
    1171                 :           3 :       g_io_channel_set_encoding (errchannel, NULL, NULL);
    1172                 :           3 :       g_io_channel_set_buffered (errchannel, FALSE);
    1173                 :           3 :       g_io_channel_win32_make_pollfd (errchannel,
    1174                 :             :                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
    1175                 :             :                                       &errfd);
    1176                 :           3 :       if (debug)
    1177                 :           0 :         g_print ("errfd=%p\n", (HANDLE) errfd.fd);
    1178                 :           3 :     }
    1179                 :             : 
    1180                 :             :   /* Read data until we get EOF on all pipes. */
    1181                 :         662 :   while (!failed && (outpipe >= 0 || errpipe >= 0))
    1182                 :             :     {
    1183                 :         253 :       nfds = 0;
    1184                 :         253 :       if (outpipe >= 0)
    1185                 :             :         {
    1186                 :         251 :           fds[nfds] = outfd;
    1187                 :         251 :           outindex = nfds;
    1188                 :         251 :           nfds++;
    1189                 :         251 :         }
    1190                 :         253 :       if (errpipe >= 0)
    1191                 :             :         {
    1192                 :           7 :           fds[nfds] = errfd;
    1193                 :           7 :           errindex = nfds;
    1194                 :           7 :           nfds++;
    1195                 :           7 :         }
    1196                 :             : 
    1197                 :         253 :       if (debug)
    1198                 :           0 :         g_print ("g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
    1199                 :           0 :                  nfds);
    1200                 :             : 
    1201                 :         253 :       ret = g_io_channel_win32_poll (fds, nfds, -1);
    1202                 :             : 
    1203                 :         253 :       if (ret < 0)
    1204                 :             :         {
    1205                 :           0 :           failed = TRUE;
    1206                 :             : 
    1207                 :           0 :           g_set_error_literal (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ,
    1208                 :           0 :                                _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
    1209                 :             :           
    1210                 :           0 :           break;
    1211                 :             :         }
    1212                 :             : 
    1213                 :         253 :       if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
    1214                 :             :         {
    1215                 :         248 :           switch (read_data (outstr, outchannel, error))
    1216                 :             :             {
    1217                 :             :             case READ_FAILED:
    1218                 :           0 :               if (debug)
    1219                 :           0 :                 g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
    1220                 :           0 :               failed = TRUE;
    1221                 :           0 :               break;
    1222                 :             :             case READ_EOF:
    1223                 :          61 :               if (debug)
    1224                 :           0 :                 g_print ("g_spawn_sync: outchannel: READ_EOF\n");
    1225                 :          61 :               g_io_channel_unref (outchannel);
    1226                 :          61 :               outchannel = NULL;
    1227                 :          61 :               close_and_invalidate (&outpipe);
    1228                 :          61 :               break;
    1229                 :             :             default:
    1230                 :         187 :               if (debug)
    1231                 :           0 :                 g_print ("g_spawn_sync: outchannel: OK\n");
    1232                 :         187 :               break;
    1233                 :             :             }
    1234                 :             : 
    1235                 :         248 :           if (failed)
    1236                 :           0 :             break;
    1237                 :         248 :         }
    1238                 :             : 
    1239                 :         253 :       if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
    1240                 :             :         {
    1241                 :           5 :           switch (read_data (errstr, errchannel, error))
    1242                 :             :             {
    1243                 :             :             case READ_FAILED:
    1244                 :           0 :               if (debug)
    1245                 :           0 :                 g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
    1246                 :           0 :               failed = TRUE;
    1247                 :           0 :               break;
    1248                 :             :             case READ_EOF:
    1249                 :           3 :               if (debug)
    1250                 :           0 :                 g_print ("g_spawn_sync: errchannel: READ_EOF\n");
    1251                 :           3 :               g_io_channel_unref (errchannel);
    1252                 :           3 :               errchannel = NULL;
    1253                 :           3 :               close_and_invalidate (&errpipe);
    1254                 :           3 :               break;
    1255                 :             :             default:
    1256                 :           2 :               if (debug)
    1257                 :           0 :                 g_print ("g_spawn_sync: errchannel: OK\n");
    1258                 :           2 :               break;
    1259                 :             :             }
    1260                 :             : 
    1261                 :           5 :           if (failed)
    1262                 :           0 :             break;
    1263                 :           5 :         }
    1264                 :             :     }
    1265                 :             : 
    1266                 :          78 :   if (reportpipe == -1)
    1267                 :             :     {
    1268                 :             :       /* No helper process, exit status of actual spawned process
    1269                 :             :        * already available.
    1270                 :             :        */
    1271                 :           0 :       if (wait_status)
    1272                 :           0 :         *wait_status = status;
    1273                 :           0 :     }
    1274                 :             :   else
    1275                 :             :     {
    1276                 :             :       /* Helper process was involved. Read its report now after the
    1277                 :             :        * grandchild has finished.
    1278                 :             :        */
    1279                 :             :       gintptr helper_report[2];
    1280                 :             : 
    1281                 :          78 :       if (!read_helper_report (reportpipe, helper_report, error))
    1282                 :           0 :         failed = TRUE;
    1283                 :             :       else
    1284                 :             :         {
    1285                 :          78 :           switch (helper_report[0])
    1286                 :             :             {
    1287                 :             :             case CHILD_NO_ERROR:
    1288                 :          76 :               if (wait_status)
    1289                 :          70 :                 *wait_status = helper_report[1];
    1290                 :          76 :               break;
    1291                 :             :             default:
    1292                 :           2 :               set_child_error (helper_report, working_directory, error);
    1293                 :           2 :               failed = TRUE;
    1294                 :           2 :               break;
    1295                 :             :             }
    1296                 :             :         }
    1297                 :          78 :       close_and_invalidate (&reportpipe);
    1298                 :             :     }
    1299                 :             : 
    1300                 :             : 
    1301                 :             :   /* These should only be open still if we had an error.  */
    1302                 :             :   
    1303                 :          78 :   if (outchannel != NULL)
    1304                 :           0 :     g_io_channel_unref (outchannel);
    1305                 :          78 :   if (errchannel != NULL)
    1306                 :           0 :     g_io_channel_unref (errchannel);
    1307                 :          78 :   if (outpipe >= 0)
    1308                 :           0 :     close_and_invalidate (&outpipe);
    1309                 :          78 :   if (errpipe >= 0)
    1310                 :           0 :     close_and_invalidate (&errpipe);
    1311                 :             :   
    1312                 :          78 :   if (failed)
    1313                 :             :     {
    1314                 :           2 :       if (outstr)
    1315                 :           1 :         g_string_free (outstr, TRUE);
    1316                 :           2 :       if (errstr)
    1317                 :           0 :         g_string_free (errstr, TRUE);
    1318                 :             : 
    1319                 :           2 :       return FALSE;
    1320                 :             :     }
    1321                 :             :   else
    1322                 :             :     {
    1323                 :          76 :       if (standard_output)        
    1324                 :          60 :         *standard_output = g_string_free (outstr, FALSE);
    1325                 :             : 
    1326                 :          76 :       if (standard_error)
    1327                 :           3 :         *standard_error = g_string_free (errstr, FALSE);
    1328                 :             : 
    1329                 :          76 :       return TRUE;
    1330                 :             :     }
    1331                 :          78 : }
    1332                 :             : 
    1333                 :             : gboolean
    1334                 :         350 : g_spawn_async_with_pipes_and_fds_impl (const gchar           *working_directory,
    1335                 :             :                                        const gchar * const   *argv,
    1336                 :             :                                        const gchar * const   *envp,
    1337                 :             :                                        GSpawnFlags            flags,
    1338                 :             :                                        GSpawnChildSetupFunc   child_setup,
    1339                 :             :                                        gpointer               user_data,
    1340                 :             :                                        gint                   stdin_fd,
    1341                 :             :                                        gint                   stdout_fd,
    1342                 :             :                                        gint                   stderr_fd,
    1343                 :             :                                        const gint            *source_fds,
    1344                 :             :                                        const gint            *target_fds,
    1345                 :             :                                        gsize                  n_fds,
    1346                 :             :                                        GPid                  *child_pid_out,
    1347                 :             :                                        gint                  *stdin_pipe_out,
    1348                 :             :                                        gint                  *stdout_pipe_out,
    1349                 :             :                                        gint                  *stderr_pipe_out,
    1350                 :             :                                        GError               **error)
    1351                 :             : {
    1352                 :         350 :   g_return_val_if_fail (argv != NULL && argv[0] != NULL, FALSE);
    1353                 :         350 :   g_return_val_if_fail (stdout_pipe_out == NULL ||
    1354                 :         301 :                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
    1355                 :         350 :   g_return_val_if_fail (stderr_pipe_out == NULL ||
    1356                 :         272 :                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
    1357                 :             :   /* can't inherit stdin if we have an input pipe. */
    1358                 :         350 :   g_return_val_if_fail (stdin_pipe_out == NULL ||
    1359                 :          55 :                         !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
    1360                 :             :   /* can’t use pipes and stdin/stdout/stderr FDs */
    1361                 :         350 :   g_return_val_if_fail (stdin_pipe_out == NULL || stdin_fd < 0, FALSE);
    1362                 :         350 :   g_return_val_if_fail (stdout_pipe_out == NULL || stdout_fd < 0, FALSE);
    1363                 :         350 :   g_return_val_if_fail (stderr_pipe_out == NULL || stderr_fd < 0, FALSE);
    1364                 :             : 
    1365                 :         350 :   return fork_exec (NULL,
    1366                 :         350 :                     (flags & G_SPAWN_DO_NOT_REAP_CHILD),
    1367                 :         350 :                     working_directory,
    1368                 :         350 :                     argv,
    1369                 :         350 :                     envp,
    1370                 :         350 :                     flags,
    1371                 :         350 :                     child_setup,
    1372                 :         350 :                     user_data,
    1373                 :         350 :                     child_pid_out,
    1374                 :         350 :                     stdin_pipe_out,
    1375                 :         350 :                     stdout_pipe_out,
    1376                 :         350 :                     stderr_pipe_out,
    1377                 :         350 :                     stdin_fd,
    1378                 :         350 :                     stdout_fd,
    1379                 :         350 :                     stderr_fd,
    1380                 :         350 :                     source_fds,
    1381                 :         350 :                     target_fds,
    1382                 :         350 :                     n_fds,
    1383                 :             :                     NULL,
    1384                 :         350 :                     error);
    1385                 :         350 : }
    1386                 :             : 
    1387                 :             : void
    1388                 :          77 : g_spawn_close_pid_impl (GPid pid)
    1389                 :             : {
    1390                 :             :   /* CRT functions such as _wspawn* return (HANDLE)-1
    1391                 :             :    * on failure, so check also for that value. */
    1392                 :          77 :   if (pid != NULL && pid != (HANDLE) -1)
    1393                 :          77 :     CloseHandle (pid);
    1394                 :          77 : }
    1395                 :             : 
    1396                 :             : gboolean
    1397                 :          72 : g_spawn_check_wait_status_impl (gint     wait_status,
    1398                 :             :                                 GError **error)
    1399                 :             : {
    1400                 :          72 :   gboolean ret = FALSE;
    1401                 :             : 
    1402                 :          72 :   if (wait_status != 0)
    1403                 :             :     {
    1404                 :             :       /* On Windows, the wait status is just the exit status: the
    1405                 :             :        * difference between the two that exists on Unix is not relevant */
    1406                 :          48 :       g_set_error (error, G_SPAWN_EXIT_ERROR, wait_status,
    1407                 :          24 :                    _("Child process exited with code %ld"),
    1408                 :          24 :                    (long) wait_status);
    1409                 :          24 :       goto out;
    1410                 :             :     }
    1411                 :             : 
    1412                 :          48 :   ret = TRUE;
    1413                 :             :  out:
    1414                 :          72 :   return ret;
    1415                 :             : }
    1416                 :             : 
    1417                 :             : #ifdef G_OS_WIN32
    1418                 :             : 
    1419                 :             : /* Binary compatibility versions. Not for newly compiled code. */
    1420                 :             : 
    1421                 :             : _GLIB_EXTERN gboolean g_spawn_async_utf8              (const gchar           *working_directory,
    1422                 :             :                                                        gchar                **argv,
    1423                 :             :                                                        gchar                **envp,
    1424                 :             :                                                        GSpawnFlags            flags,
    1425                 :             :                                                        GSpawnChildSetupFunc   child_setup,
    1426                 :             :                                                        gpointer               user_data,
    1427                 :             :                                                        GPid                  *child_pid,
    1428                 :             :                                                        GError               **error);
    1429                 :             : _GLIB_EXTERN gboolean g_spawn_async_with_pipes_utf8   (const gchar           *working_directory,
    1430                 :             :                                                        gchar                **argv,
    1431                 :             :                                                        gchar                **envp,
    1432                 :             :                                                        GSpawnFlags            flags,
    1433                 :             :                                                        GSpawnChildSetupFunc   child_setup,
    1434                 :             :                                                        gpointer               user_data,
    1435                 :             :                                                        GPid                  *child_pid,
    1436                 :             :                                                        gint                  *standard_input,
    1437                 :             :                                                        gint                  *standard_output,
    1438                 :             :                                                        gint                  *standard_error,
    1439                 :             :                                                        GError               **error);
    1440                 :             : _GLIB_EXTERN gboolean g_spawn_sync_utf8               (const gchar           *working_directory,
    1441                 :             :                                                        gchar                **argv,
    1442                 :             :                                                        gchar                **envp,
    1443                 :             :                                                        GSpawnFlags            flags,
    1444                 :             :                                                        GSpawnChildSetupFunc   child_setup,
    1445                 :             :                                                        gpointer               user_data,
    1446                 :             :                                                        gchar                **standard_output,
    1447                 :             :                                                        gchar                **standard_error,
    1448                 :             :                                                        gint                  *wait_status,
    1449                 :             :                                                        GError               **error);
    1450                 :             : _GLIB_EXTERN gboolean g_spawn_command_line_sync_utf8  (const gchar           *command_line,
    1451                 :             :                                                        gchar                **standard_output,
    1452                 :             :                                                        gchar                **standard_error,
    1453                 :             :                                                        gint                  *wait_status,
    1454                 :             :                                                        GError               **error);
    1455                 :             : _GLIB_EXTERN gboolean g_spawn_command_line_async_utf8 (const gchar           *command_line,
    1456                 :             :                                                        GError               **error);
    1457                 :             : 
    1458                 :             : gboolean
    1459                 :           0 : g_spawn_async_utf8 (const gchar          *working_directory,
    1460                 :             :                     gchar               **argv,
    1461                 :             :                     gchar               **envp,
    1462                 :             :                     GSpawnFlags           flags,
    1463                 :             :                     GSpawnChildSetupFunc  child_setup,
    1464                 :             :                     gpointer              user_data,
    1465                 :             :                     GPid                 *child_pid,
    1466                 :             :                     GError              **error)
    1467                 :             : {
    1468                 :           0 :   return g_spawn_async (working_directory,
    1469                 :           0 :                         argv,
    1470                 :           0 :                         envp,
    1471                 :           0 :                         flags,
    1472                 :           0 :                         child_setup,
    1473                 :           0 :                         user_data,
    1474                 :           0 :                         child_pid,
    1475                 :           0 :                         error);
    1476                 :             : }
    1477                 :             : 
    1478                 :             : gboolean
    1479                 :           0 : g_spawn_async_with_pipes_utf8 (const gchar          *working_directory,
    1480                 :             :                                gchar               **argv,
    1481                 :             :                                gchar               **envp,
    1482                 :             :                                GSpawnFlags           flags,
    1483                 :             :                                GSpawnChildSetupFunc  child_setup,
    1484                 :             :                                gpointer              user_data,
    1485                 :             :                                GPid                 *child_pid,
    1486                 :             :                                gint                 *standard_input,
    1487                 :             :                                gint                 *standard_output,
    1488                 :             :                                gint                 *standard_error,
    1489                 :             :                                GError              **error)
    1490                 :             : {
    1491                 :           0 :   return g_spawn_async_with_pipes (working_directory,
    1492                 :           0 :                                    argv,
    1493                 :           0 :                                    envp,
    1494                 :           0 :                                    flags,
    1495                 :           0 :                                    child_setup,
    1496                 :           0 :                                    user_data,
    1497                 :           0 :                                    child_pid,
    1498                 :           0 :                                    standard_input,
    1499                 :           0 :                                    standard_output,
    1500                 :           0 :                                    standard_error,
    1501                 :           0 :                                    error);
    1502                 :             : }
    1503                 :             : 
    1504                 :             : gboolean
    1505                 :           0 : g_spawn_sync_utf8 (const gchar          *working_directory,
    1506                 :             :                    gchar               **argv,
    1507                 :             :                    gchar               **envp,
    1508                 :             :                    GSpawnFlags           flags,
    1509                 :             :                    GSpawnChildSetupFunc  child_setup,
    1510                 :             :                    gpointer              user_data,
    1511                 :             :                    gchar               **standard_output,
    1512                 :             :                    gchar               **standard_error,
    1513                 :             :                    gint                 *wait_status,
    1514                 :             :                    GError              **error)
    1515                 :             : {
    1516                 :           0 :   return g_spawn_sync (working_directory,
    1517                 :           0 :                        argv,
    1518                 :           0 :                        envp,
    1519                 :           0 :                        flags,
    1520                 :           0 :                        child_setup,
    1521                 :           0 :                        user_data,
    1522                 :           0 :                        standard_output,
    1523                 :           0 :                        standard_error,
    1524                 :           0 :                        wait_status,
    1525                 :           0 :                        error);
    1526                 :             : }
    1527                 :             : 
    1528                 :             : gboolean
    1529                 :           0 : g_spawn_command_line_sync_utf8 (const gchar  *command_line,
    1530                 :             :                                 gchar       **standard_output,
    1531                 :             :                                 gchar       **standard_error,
    1532                 :             :                                 gint         *wait_status,
    1533                 :             :                                 GError      **error)
    1534                 :             : {
    1535                 :           0 :   return g_spawn_command_line_sync (command_line,
    1536                 :           0 :                                     standard_output,
    1537                 :           0 :                                     standard_error,
    1538                 :           0 :                                     wait_status,
    1539                 :           0 :                                     error);
    1540                 :             : }
    1541                 :             : 
    1542                 :             : gboolean
    1543                 :           0 : g_spawn_command_line_async_utf8 (const gchar *command_line,
    1544                 :             :                                  GError     **error)
    1545                 :             : {
    1546                 :           0 :   return g_spawn_command_line_async (command_line, error);
    1547                 :             : }
    1548                 :             : 
    1549                 :             : #endif /* G_OS_WIN32 */
    1550                 :             : 
    1551                 :             : #endif /* !GSPAWN_HELPER */
        

Generated by: LCOV version 2.0-1