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