Fix potential heap corruption. Sometimes called g_free() on string
[platform/upstream/glib.git] / glib / gspawn-win32.c
1 /* gspawn-win32.c - Process launching on Win32
2  *
3  *  Copyright 2000 Red Hat, Inc.
4  *
5  * GLib is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * GLib is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with GLib; see the file COPYING.LIB.  If not, write
17  * to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Implementation details on Win32.
23  *
24  * - There is no way to set the no-inherit flag for
25  *   a "file descriptor" in the MS C runtime. The flag is there,
26  *   and the dospawn() function uses it, but unfortunately
27  *   this flag can only be set when opening the file.
28  * - As there is no fork(), we cannot reliably change directory
29  *   before starting the child process. (There might be several threads
30  *   running, and the current directory is common for all threads.)
31  *
32  * Thus, we must in most cases use a helper program to handle closing
33  * of (inherited) file descriptors and changing of directory. In fact,
34  * we do it all the time.
35  */
36
37 /* Define this to get some logging all the time */
38 /* #define G_SPAWN_WIN32_DEBUG */
39
40 #include <config.h>
41
42 #include "config.h"
43
44 #include "glib.h"
45 #include "gprintfint.h"
46
47 #include <string.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50
51 #include <windows.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <io.h>
55 #include <process.h>
56 #include <direct.h>
57
58 #include "glibintl.h"
59
60 #ifdef G_SPAWN_WIN32_DEBUG
61   static int debug = 1;
62   #define SETUP_DEBUG() /* empty */
63
64 #else
65   static int debug = -1;
66   #define SETUP_DEBUG()                                 \
67     G_STMT_START                                        \
68       {                                                 \
69         if (debug == -1)                                \
70           {                                             \
71             if (getenv ("G_SPAWN_WIN32_DEBUG") != NULL) \
72               debug = 1;                                \
73             else                                        \
74               debug = 0;                                \
75           }                                             \
76       }                                                 \
77     G_STMT_END
78 #endif
79
80 enum
81 {
82   CHILD_NO_ERROR,
83   CHILD_CHDIR_FAILED,
84   CHILD_SPAWN_FAILED,
85 };
86
87 enum {
88   ARG_CHILD_ERR_REPORT = 1,
89   ARG_STDIN,
90   ARG_STDOUT,
91   ARG_STDERR,
92   ARG_WORKING_DIRECTORY,
93   ARG_CLOSE_DESCRIPTORS,
94   ARG_USE_PATH,
95   ARG_WAIT,
96   ARG_PROGRAM,
97   ARG_COUNT = ARG_PROGRAM
98 };
99
100 #ifndef GSPAWN_HELPER
101
102 static gboolean make_pipe            (gint                  p[2],
103                                       GError              **error);
104 static gboolean do_spawn_with_pipes  (gboolean              dont_wait,
105                                       gboolean              dont_return_handle,
106                                       const gchar          *working_directory,
107                                       gchar               **argv,
108                                       gchar               **envp,
109                                       gboolean              close_descriptors,
110                                       gboolean              search_path,
111                                       gboolean              stdout_to_null,
112                                       gboolean              stderr_to_null,
113                                       gboolean              child_inherits_stdin,
114                                       GSpawnChildSetupFunc  child_setup,
115                                       gpointer              user_data,
116                                       gint                 *child_pid,
117                                       gint                 *standard_input,
118                                       gint                 *standard_output,
119                                       gint                 *standard_error,
120                                       gint                 *exit_status,
121                                       GError              **error);
122
123 GQuark
124 g_spawn_error_quark (void)
125 {
126   static GQuark quark = 0;
127   if (quark == 0)
128     quark = g_quark_from_static_string ("g-exec-error-quark");
129   return quark;
130 }
131
132 gboolean
133 g_spawn_async (const gchar          *working_directory,
134                gchar               **argv,
135                gchar               **envp,
136                GSpawnFlags           flags,
137                GSpawnChildSetupFunc  child_setup,
138                gpointer              user_data,
139                gint                 *child_pid,
140                GError              **error)
141 {
142   g_return_val_if_fail (argv != NULL, FALSE);
143   
144   return g_spawn_async_with_pipes (working_directory,
145                                    argv, envp,
146                                    flags,
147                                    child_setup,
148                                    user_data,
149                                    child_pid,
150                                    NULL, NULL, NULL,
151                                    error);
152 }
153
154 /* Avoids a danger in threaded situations (calling close()
155  * on a file descriptor twice, and another thread has
156  * re-opened it since the first close)
157  */
158 static gint
159 close_and_invalidate (gint *fd)
160 {
161   gint ret;
162
163   if (*fd < 0)
164     return -1;
165   else
166     {
167       ret = close (*fd);
168       *fd = -1;
169     }
170
171   return ret;
172 }
173
174 typedef enum
175 {
176   READ_FAILED = 0, /* FALSE */
177   READ_OK,
178   READ_EOF
179 } ReadResult;
180
181 static ReadResult
182 read_data (GString     *str,
183            GIOChannel  *iochannel,
184            GError     **error)
185 {
186   GIOStatus giostatus;
187   gssize bytes;
188   gchar buf[4096];
189
190  again:
191   
192   giostatus = g_io_channel_read_chars (iochannel, buf, sizeof (buf), &bytes, NULL);
193
194   if (bytes == 0)
195     return READ_EOF;
196   else if (bytes > 0)
197     {
198       g_string_append_len (str, buf, bytes);
199       return READ_OK;
200     }
201   else if (giostatus == G_IO_STATUS_AGAIN)
202     goto again;
203   else if (giostatus == G_IO_STATUS_ERROR)
204     {
205       g_set_error (error,
206                    G_SPAWN_ERROR,
207                    G_SPAWN_ERROR_READ,
208                    _("Failed to read data from child process"));
209       
210       return READ_FAILED;
211     }
212   else
213     return READ_OK;
214 }
215
216 gboolean
217 g_spawn_sync (const gchar          *working_directory,
218               gchar               **argv,
219               gchar               **envp,
220               GSpawnFlags           flags,
221               GSpawnChildSetupFunc  child_setup,
222               gpointer              user_data,
223               gchar               **standard_output,
224               gchar               **standard_error,
225               gint                 *exit_status,
226               GError              **error)     
227 {
228   gint outpipe = -1;
229   gint errpipe = -1;
230   gint pid;
231   GIOChannel *outchannel = NULL;
232   GIOChannel *errchannel = NULL;
233   GPollFD outfd, errfd;
234   GPollFD fds[2];
235   gint nfds;
236   gint outindex = -1;
237   gint errindex = -1;
238   gint ret;
239   GString *outstr = NULL;
240   GString *errstr = NULL;
241   gboolean failed;
242   gint status;
243   
244   g_return_val_if_fail (argv != NULL, FALSE);
245   g_return_val_if_fail (!(flags & G_SPAWN_DO_NOT_REAP_CHILD), FALSE);
246   g_return_val_if_fail (standard_output == NULL ||
247                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
248   g_return_val_if_fail (standard_error == NULL ||
249                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
250   
251   /* Just to ensure segfaults if callers try to use
252    * these when an error is reported.
253    */
254   if (standard_output)
255     *standard_output = NULL;
256
257   if (standard_error)
258     *standard_error = NULL;
259   
260   if (!do_spawn_with_pipes (FALSE,
261                             TRUE,
262                             working_directory,
263                             argv,
264                             envp,
265                             !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
266                             (flags & G_SPAWN_SEARCH_PATH) != 0,
267                             (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
268                             (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
269                             (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
270                             child_setup,
271                             user_data,
272                             &pid,
273                             NULL,
274                             standard_output ? &outpipe : NULL,
275                             standard_error ? &errpipe : NULL,
276                             &status,
277                             error))
278     return FALSE;
279
280   /* Read data from child. */
281   
282   failed = FALSE;
283
284   if (outpipe >= 0)
285     {
286       outstr = g_string_new ("");
287       outchannel = g_io_channel_win32_new_fd (outpipe);
288       g_io_channel_set_encoding (outchannel, NULL, NULL);
289       g_io_channel_win32_make_pollfd (outchannel,
290                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
291                                       &outfd);
292     }
293       
294   if (errpipe >= 0)
295     {
296       errstr = g_string_new ("");
297       errchannel = g_io_channel_win32_new_fd (errpipe);
298       g_io_channel_set_encoding (errchannel, NULL, NULL);
299       g_io_channel_win32_make_pollfd (errchannel,
300                                       G_IO_IN | G_IO_ERR | G_IO_HUP,
301                                       &errfd);
302     }
303
304   /* Read data until we get EOF on both pipes. */
305   while (!failed &&
306          (outpipe >= 0 ||
307           errpipe >= 0))
308     {
309       nfds = 0;
310       if (outpipe >= 0)
311         {
312           fds[nfds] = outfd;
313           outindex = nfds;
314           nfds++;
315         }
316       if (errpipe >= 0)
317         {
318           fds[nfds] = errfd;
319           errindex = nfds;
320           nfds++;
321         }
322
323       if (debug)
324         g_print ("%s:g_spawn_sync: calling g_io_channel_win32_poll, nfds=%d\n",
325                  __FILE__, nfds);
326
327       ret = g_io_channel_win32_poll (fds, nfds, -1);
328
329       if (ret < 0)
330         {
331           failed = TRUE;
332
333           g_set_error (error,
334                        G_SPAWN_ERROR,
335                        G_SPAWN_ERROR_READ,
336                        _("Unexpected error in g_io_channel_win32_poll() reading data from a child process"));
337               
338           break;
339         }
340
341       if (outpipe >= 0 && (fds[outindex].revents & G_IO_IN))
342         {
343           switch (read_data (outstr, outchannel, error))
344             {
345             case READ_FAILED:
346               if (debug)
347                 g_print ("g_spawn_sync: outchannel: READ_FAILED\n");
348               failed = TRUE;
349               break;
350             case READ_EOF:
351               if (debug)
352                 g_print ("g_spawn_sync: outchannel: READ_EOF\n");
353               g_io_channel_unref (outchannel);
354               outchannel = NULL;
355               close_and_invalidate (&outpipe);
356               break;
357             default:
358               if (debug)
359                 g_print ("g_spawn_sync: outchannel: OK\n");
360               break;
361             }
362
363           if (failed)
364             break;
365         }
366
367       if (errpipe >= 0 && (fds[errindex].revents & G_IO_IN))
368         {
369           switch (read_data (errstr, errchannel, error))
370             {
371             case READ_FAILED:
372               if (debug)
373                 g_print ("g_spawn_sync: errchannel: READ_FAILED\n");
374               failed = TRUE;
375               break;
376             case READ_EOF:
377               if (debug)
378                 g_print ("g_spawn_sync: errchannel: READ_EOF\n");
379               g_io_channel_unref (errchannel);
380               errchannel = NULL;
381               close_and_invalidate (&errpipe);
382               break;
383             default:
384               if (debug)
385                 g_print ("g_spawn_sync: errchannel: OK\n");
386               break;
387             }
388
389           if (failed)
390             break;
391         }
392     }
393
394   /* These should only be open still if we had an error.  */
395   
396   if (outchannel != NULL)
397     g_io_channel_unref (outchannel);
398   if (errchannel != NULL)
399     g_io_channel_unref (errchannel);
400   if (outpipe >= 0)
401     close_and_invalidate (&outpipe);
402   if (errpipe >= 0)
403     close_and_invalidate (&errpipe);
404   
405   if (failed)
406     {
407       if (outstr)
408         g_string_free (outstr, TRUE);
409       if (errstr)
410         g_string_free (errstr, TRUE);
411
412       return FALSE;
413     }
414   else
415     {
416       if (exit_status)
417         *exit_status = status;
418       
419       if (standard_output)        
420         *standard_output = g_string_free (outstr, FALSE);
421
422       if (standard_error)
423         *standard_error = g_string_free (errstr, FALSE);
424
425       return TRUE;
426     }
427 }
428
429 gboolean
430 g_spawn_async_with_pipes (const gchar          *working_directory,
431                           gchar               **argv,
432                           gchar               **envp,
433                           GSpawnFlags           flags,
434                           GSpawnChildSetupFunc  child_setup,
435                           gpointer              user_data,
436                           gint                 *child_pid,
437                           gint                 *standard_input,
438                           gint                 *standard_output,
439                           gint                 *standard_error,
440                           GError              **error)
441 {
442   g_return_val_if_fail (argv != NULL, FALSE);
443   g_return_val_if_fail (standard_output == NULL ||
444                         !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), FALSE);
445   g_return_val_if_fail (standard_error == NULL ||
446                         !(flags & G_SPAWN_STDERR_TO_DEV_NULL), FALSE);
447   /* can't inherit stdin if we have an input pipe. */
448   g_return_val_if_fail (standard_input == NULL ||
449                         !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
450   
451   return do_spawn_with_pipes (TRUE,
452                               !(flags & G_SPAWN_DO_NOT_REAP_CHILD),
453                               working_directory,
454                               argv,
455                               envp,
456                               !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
457                               (flags & G_SPAWN_SEARCH_PATH) != 0,
458                               (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
459                               (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
460                               (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
461                               child_setup,
462                               user_data,
463                               child_pid,
464                               standard_input,
465                               standard_output,
466                               standard_error,
467                               NULL,
468                               error);
469 }
470
471 gboolean
472 g_spawn_command_line_sync (const gchar  *command_line,
473                            gchar       **standard_output,
474                            gchar       **standard_error,
475                            gint         *exit_status,
476                            GError      **error)
477 {
478   gboolean retval;
479   gchar **argv = 0;
480
481   g_return_val_if_fail (command_line != NULL, FALSE);
482   
483   if (!g_shell_parse_argv (command_line,
484                            NULL, &argv,
485                            error))
486     return FALSE;
487   
488   retval = g_spawn_sync (NULL,
489                          argv,
490                          NULL,
491                          G_SPAWN_SEARCH_PATH,
492                          NULL,
493                          NULL,
494                          standard_output,
495                          standard_error,
496                          exit_status,
497                          error);
498   g_strfreev (argv);
499
500   return retval;
501 }
502
503 gboolean
504 g_spawn_command_line_async (const gchar *command_line,
505                             GError     **error)
506 {
507   gboolean retval;
508   gchar **argv = 0;
509
510   g_return_val_if_fail (command_line != NULL, FALSE);
511
512   if (!g_shell_parse_argv (command_line,
513                            NULL, &argv,
514                            error))
515     return FALSE;
516   
517   retval = g_spawn_async (NULL,
518                           argv,
519                           NULL,
520                           G_SPAWN_SEARCH_PATH,
521                           NULL,
522                           NULL,
523                           NULL,
524                           error);
525   g_strfreev (argv);
526
527   return retval;
528 }
529
530 static gint
531 do_spawn (gboolean              dont_wait,
532           gint                  child_err_report_fd,
533           gint                  stdin_fd,
534           gint                  stdout_fd,
535           gint                  stderr_fd,
536           const gchar          *working_directory,
537           gchar               **argv,
538           gchar               **envp,
539           gboolean              close_descriptors,
540           gboolean              search_path,
541           gboolean              stdout_to_null,
542           gboolean              stderr_to_null,
543           gboolean              child_inherits_stdin,
544           GSpawnChildSetupFunc  child_setup,
545           gpointer              user_data)
546 {
547   gchar **new_argv;
548   gchar args[ARG_COUNT][10];
549   gint i;
550   int rc;
551   int argc = 0;
552
553   SETUP_DEBUG();
554
555   while (argv[argc])
556     ++argc;
557
558   new_argv = g_new (gchar *, argc + 1 + ARG_COUNT);
559
560   new_argv[0] = "gspawn-win32-helper";
561   _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_fd);
562   new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
563
564   if (stdin_fd >= 0)
565     {
566       _g_sprintf (args[ARG_STDIN], "%d", stdin_fd);
567       new_argv[ARG_STDIN] = args[ARG_STDIN];
568     }
569   else if (child_inherits_stdin)
570     {
571       /* Let stdin be alone */
572       new_argv[ARG_STDIN] = "-";
573     }
574   else
575     {
576       /* Keep process from blocking on a read of stdin */
577       new_argv[ARG_STDIN] = "z";
578     }
579
580   if (stdout_fd >= 0)
581     {
582       _g_sprintf (args[ARG_STDOUT], "%d", stdout_fd);
583       new_argv[ARG_STDOUT] = args[ARG_STDOUT];
584     }
585   else if (stdout_to_null)
586     {
587       new_argv[ARG_STDOUT] = "z";
588     }
589   else
590     {
591       new_argv[ARG_STDOUT] = "-";
592     }
593
594   if (stderr_fd >= 0)
595     {
596       _g_sprintf (args[ARG_STDERR], "%d", stderr_fd);
597       new_argv[ARG_STDERR] = args[ARG_STDERR];
598     }
599   else if (stderr_to_null)
600     {
601       new_argv[ARG_STDERR] = "z";
602     }
603   else
604     {
605       new_argv[ARG_STDERR] = "-";
606     }
607
608   if (working_directory && *working_directory)
609     /* The g_strdup() to lose the constness */
610     new_argv[ARG_WORKING_DIRECTORY] = g_strdup (working_directory);
611   else
612     new_argv[ARG_WORKING_DIRECTORY] = g_strdup ("-");
613
614   if (close_descriptors)
615     new_argv[ARG_CLOSE_DESCRIPTORS] = "y";
616   else
617     new_argv[ARG_CLOSE_DESCRIPTORS] = "-";
618
619   if (search_path)
620     new_argv[ARG_USE_PATH] = "y";
621   else
622     new_argv[ARG_USE_PATH] = "-";
623
624   if (dont_wait)
625     new_argv[ARG_WAIT] = "-";
626   else
627     new_argv[ARG_WAIT] = "w";
628
629   for (i = 0; i <= argc; i++)
630     new_argv[ARG_PROGRAM + i] = argv[i];
631
632   /* Call user function just before we execute the helper program,
633    * which executes the program. Dunno what's the usefulness of this.
634    * A child setup function used on Unix probably isn't of much use
635    * as such on Win32, anyhow
636    */
637   if (child_setup)
638     {
639       (* child_setup) (user_data);
640     }
641
642   if (debug)
643     {
644       g_print ("calling gspawn-win32-helper with argv:\n");
645       for (i = 0; i < argc + 1 + ARG_COUNT; i++)
646         g_print ("argv[%d]: %s\n", i, (new_argv[i] ? new_argv[i] : "NULL"));
647     }
648   
649   if (envp != NULL)
650     /* Let's hope envp hasn't mucked with PATH so that
651      * gspawn-win32-helper.exe isn't found.
652      */
653     rc = spawnvpe (P_NOWAIT, "gspawn-win32-helper", new_argv, envp);
654   else
655     rc = spawnvp (P_NOWAIT, "gspawn-win32-helper", new_argv);
656
657   /* Close the child_err_report_fd and the other process's ends of the
658    * pipes in this process, otherwise the reader will never get
659    * EOF.
660    */
661   close (child_err_report_fd);
662   if (stdin_fd >= 0)
663     close (stdin_fd);
664   if (stdout_fd >= 0)
665     close (stdout_fd);
666   if (stderr_fd >= 0)
667     close (stderr_fd);
668
669   g_free (new_argv[ARG_WORKING_DIRECTORY]);
670   g_free (new_argv);
671
672   return rc;
673 }
674
675 static gboolean
676 read_ints (int      fd,
677            gint*    buf,
678            gint     n_ints_in_buf,
679            gint    *n_ints_read,
680            GError **error)
681 {
682   gint bytes = 0;
683   
684   while (bytes < sizeof(gint)*n_ints_in_buf)
685     {
686       gint chunk;
687
688       if (debug)
689         g_print ("%s:read_ints: trying to read %d bytes from pipe...\n",
690                  __FILE__,
691                  sizeof(gint)*n_ints_in_buf - bytes);
692
693       chunk = read (fd, ((gchar*)buf) + bytes,
694                     sizeof(gint)*n_ints_in_buf - bytes);
695
696       if (debug)
697         g_print ("... got %d bytes\n", chunk);
698           
699       if (chunk < 0)
700         {
701           /* Some weird shit happened, bail out */
702               
703           g_set_error (error,
704                        G_SPAWN_ERROR,
705                        G_SPAWN_ERROR_FAILED,
706                        _("Failed to read from child pipe (%s)"),
707                        g_strerror (errno));
708
709           return FALSE;
710         }
711       else if (chunk == 0)
712         break; /* EOF */
713       else
714         bytes += chunk;
715     }
716
717   *n_ints_read = bytes/sizeof(gint);
718
719   return TRUE;
720 }
721
722 static gboolean
723 do_spawn_with_pipes (gboolean              dont_wait,
724                      gboolean              dont_return_handle,
725                      const gchar          *working_directory,
726                      gchar               **argv,
727                      gchar               **envp,
728                      gboolean              close_descriptors,
729                      gboolean              search_path,
730                      gboolean              stdout_to_null,
731                      gboolean              stderr_to_null,
732                      gboolean              child_inherits_stdin,
733                      GSpawnChildSetupFunc  child_setup,
734                      gpointer              user_data,
735                      gint                 *child_pid,
736                      gint                 *standard_input,
737                      gint                 *standard_output,
738                      gint                 *standard_error,
739                      gint                 *exit_status,
740                      GError              **error)     
741 {
742   gint stdin_pipe[2] = { -1, -1 };
743   gint stdout_pipe[2] = { -1, -1 };
744   gint stderr_pipe[2] = { -1, -1 };
745   gint child_err_report_pipe[2] = { -1, -1 };
746   gint helper = -1;
747   gint buf[2];
748   gint n_ints = 0;
749   
750   if (!make_pipe (child_err_report_pipe, error))
751     return FALSE;
752
753   if (standard_input && !make_pipe (stdin_pipe, error))
754     goto cleanup_and_fail;
755   
756   if (standard_output && !make_pipe (stdout_pipe, error))
757     goto cleanup_and_fail;
758
759   if (standard_error && !make_pipe (stderr_pipe, error))
760     goto cleanup_and_fail;
761
762   helper = do_spawn (dont_wait,
763                      child_err_report_pipe[1],
764                      stdin_pipe[0],
765                      stdout_pipe[1],
766                      stderr_pipe[1],
767                      working_directory,
768                      argv,
769                      envp,
770                      close_descriptors,
771                      search_path,
772                      stdout_to_null,
773                      stderr_to_null,
774                      child_inherits_stdin,
775                      child_setup,
776                      user_data);
777       
778   /* do_spawn() returns -1 if gspawn-win32-helper couldn't be run */
779   if (helper == -1)
780     {
781       g_set_error (error,
782                    G_SPAWN_ERROR,
783                    G_SPAWN_ERROR_FAILED,
784                    _("Failed to execute helper program"));
785       goto cleanup_and_fail;
786     }
787
788   if (!read_ints (child_err_report_pipe[0],
789                   buf, 2, &n_ints,
790                   error) ||
791       n_ints != 2)
792     goto cleanup_and_fail;
793         
794   /* Error code from gspawn-win32-helper. */
795   switch (buf[0])
796     {
797     case CHILD_NO_ERROR:
798       if (child_pid && dont_wait && !dont_return_handle)
799         {
800           /* helper is our HANDLE for gspawn-win32-helper. It has
801            * told us the HANDLE of its child. Duplicate that into
802            * a HANDLE valid in this process.
803            */
804           if (!DuplicateHandle ((HANDLE) helper, (HANDLE) buf[1],
805                                 GetCurrentProcess (), (LPHANDLE) child_pid,
806                                 0, TRUE, DUPLICATE_SAME_ACCESS))
807             *child_pid = 0;
808         }
809       else if (child_pid)
810         *child_pid = 0;
811       break;
812       
813     case CHILD_CHDIR_FAILED:
814       g_set_error (error,
815                    G_SPAWN_ERROR,
816                    G_SPAWN_ERROR_CHDIR,
817                    _("Failed to change to directory '%s' (%s)"),
818                    working_directory,
819                    g_strerror (buf[1]));
820       goto cleanup_and_fail;
821       
822     case CHILD_SPAWN_FAILED:
823       g_set_error (error,
824                    G_SPAWN_ERROR,
825                    G_SPAWN_ERROR_FAILED,
826                    _("Failed to execute child process (%s)"),
827                    g_strerror (buf[1]));
828       goto cleanup_and_fail;
829     }
830
831   /* Success against all odds! return the information */
832       
833   if (standard_input)
834     *standard_input = stdin_pipe[1];
835   if (standard_output)
836     *standard_output = stdout_pipe[0];
837   if (standard_error)
838     *standard_error = stderr_pipe[0];
839   if (exit_status)
840     *exit_status = buf[1];
841   CloseHandle ((HANDLE) helper);
842   
843   return TRUE;
844
845  cleanup_and_fail:
846   if (helper != -1)
847     CloseHandle ((HANDLE) helper);
848   close_and_invalidate (&child_err_report_pipe[0]);
849   close_and_invalidate (&child_err_report_pipe[1]);
850   close_and_invalidate (&stdin_pipe[0]);
851   close_and_invalidate (&stdin_pipe[1]);
852   close_and_invalidate (&stdout_pipe[0]);
853   close_and_invalidate (&stdout_pipe[1]);
854   close_and_invalidate (&stderr_pipe[0]);
855   close_and_invalidate (&stderr_pipe[1]);
856
857   return FALSE;
858 }
859
860 static gboolean
861 make_pipe (gint     p[2],
862            GError **error)
863 {
864   if (pipe (p) < 0)
865     {
866       g_set_error (error,
867                    G_SPAWN_ERROR,
868                    G_SPAWN_ERROR_FAILED,
869                    _("Failed to create pipe for communicating with child process (%s)"),
870                    g_strerror (errno));
871       return FALSE;
872     }
873   else
874     return TRUE;
875 }
876
877 #endif /* !GSPAWN_HELPER */