1 /* w32-io.c - W32 API I/O functions.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
5 This file is part of GPGME.
7 GPGME is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
12 GPGME is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
33 #include <sys/types.h>
43 /* We assume that a HANDLE can be represented by an int which should
44 be true for all i386 systems (HANDLE is defined as void *) and
45 these are the only systems for which Windows is available. Further
46 we assume that -1 denotes an invalid handle. */
48 #define fd_to_handle(a) ((HANDLE)(a))
49 #define handle_to_fd(a) ((int)(a))
50 #define pid_to_handle(a) ((HANDLE)(a))
51 #define handle_to_pid(a) ((int)(a))
53 #define READBUF_SIZE 4096
54 #define WRITEBUF_SIZE 4096
55 #define PIPEBUF_SIZE 4096
56 #define MAX_READERS 40
57 #define MAX_WRITERS 40
63 _gpgme_close_notify_handler_t handler;
66 DEFINE_STATIC_LOCK (notify_table_lock);
69 struct reader_context_s
83 /* This is manually reset. */
85 /* This is automatically reset. */
88 size_t readpos, writepos;
89 char buffer[READBUF_SIZE];
97 struct reader_context_s *context;
98 } reader_table[MAX_READERS];
99 static int reader_table_size= MAX_READERS;
100 DEFINE_STATIC_LOCK (reader_table_lock);
103 struct writer_context_s
109 DECLARE_LOCK (mutex);
115 /* This is manually reset. */
120 char buffer[WRITEBUF_SIZE];
128 struct writer_context_s *context;
129 } writer_table[MAX_WRITERS];
130 static int writer_table_size= MAX_WRITERS;
131 DEFINE_STATIC_LOCK (writer_table_lock);
135 get_desired_thread_priority (void)
139 if (!_gpgme_get_conf_int ("IOThreadPriority", &value))
141 value = THREAD_PRIORITY_HIGHEST;
142 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
143 "%d (default)", value);
147 TRACE1 (DEBUG_SYSIO, "gpgme:get_desired_thread_priority", 0,
148 "%d (configured)", value);
155 set_synchronize (HANDLE hd)
159 /* For NT we have to set the sync flag. It seems that the only way
160 to do it is by duplicating the handle. Tsss... */
161 if (!DuplicateHandle (GetCurrentProcess (), hd,
162 GetCurrentProcess (), &new_hd,
163 EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0))
165 TRACE1 (DEBUG_SYSIO, "gpgme:set_synchronize", hd,
166 "DuplicateHandle failed: ec=%d", (int) GetLastError ());
167 /* FIXME: Should translate the error code. */
169 return INVALID_HANDLE_VALUE;
177 static DWORD CALLBACK
180 struct reader_context_s *ctx = arg;
183 TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd,
184 "thread=%p", ctx->thread_hd);
189 /* Leave a 1 byte gap so that we can see whether it is empty or
191 if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos)
193 /* Wait for space. */
194 if (!ResetEvent (ctx->have_space_ev))
195 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
197 TRACE_LOG ("waiting for space");
198 WaitForSingleObject (ctx->have_space_ev, INFINITE);
199 TRACE_LOG ("got space");
207 nbytes = (ctx->readpos + READBUF_SIZE
208 - ctx->writepos - 1) % READBUF_SIZE;
209 if (nbytes > READBUF_SIZE - ctx->writepos)
210 nbytes = READBUF_SIZE - ctx->writepos;
213 TRACE_LOG1 ("reading %d bytes", nbytes);
214 if (!ReadFile (ctx->file_hd,
215 ctx->buffer + ctx->writepos, nbytes, &nread, NULL))
217 ctx->error_code = (int) GetLastError ();
218 if (ctx->error_code == ERROR_BROKEN_PIPE)
221 TRACE_LOG ("got EOF (broken pipe)");
226 TRACE_LOG1 ("read error: ec=%d", ctx->error_code);
233 TRACE_LOG ("got eof");
236 TRACE_LOG1 ("got %u bytes", nread);
244 ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;
245 if (!SetEvent (ctx->have_data_ev))
246 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
247 (int) GetLastError ());
250 /* Indicate that we have an error or EOF. */
251 if (!SetEvent (ctx->have_data_ev))
252 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev,
253 (int) GetLastError ());
254 SetEvent (ctx->stopped);
260 static struct reader_context_s *
261 create_reader (HANDLE fd)
263 struct reader_context_s *ctx;
264 SECURITY_ATTRIBUTES sec_attr;
267 TRACE_BEG (DEBUG_SYSIO, "gpgme:create_reader", fd);
269 memset (&sec_attr, 0, sizeof sec_attr);
270 sec_attr.nLength = sizeof sec_attr;
271 sec_attr.bInheritHandle = FALSE;
273 ctx = calloc (1, sizeof *ctx);
276 TRACE_SYSERR (errno);
282 ctx->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
283 if (ctx->have_data_ev)
284 ctx->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
285 if (ctx->have_space_ev)
286 ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
287 if (!ctx->have_data_ev || !ctx->have_space_ev || !ctx->stopped)
289 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
290 if (ctx->have_data_ev)
291 CloseHandle (ctx->have_data_ev);
292 if (ctx->have_space_ev)
293 CloseHandle (ctx->have_space_ev);
295 CloseHandle (ctx->stopped);
297 /* FIXME: Translate the error code. */
302 ctx->have_data_ev = set_synchronize (ctx->have_data_ev);
303 INIT_LOCK (ctx->mutex);
305 ctx->thread_hd = CreateThread (&sec_attr, 0, reader, ctx, 0, &tid);
308 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
309 DESTROY_LOCK (ctx->mutex);
310 if (ctx->have_data_ev)
311 CloseHandle (ctx->have_data_ev);
312 if (ctx->have_space_ev)
313 CloseHandle (ctx->have_space_ev);
315 CloseHandle (ctx->stopped);
322 /* We set the priority of the thread higher because we know that
323 it only runs for a short time. This greatly helps to
324 increase the performance of the I/O. */
325 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
334 destroy_reader (struct reader_context_s *ctx)
338 if (ctx->refcount != 0)
344 if (ctx->have_space_ev)
345 SetEvent (ctx->have_space_ev);
348 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
349 "waiting for termination of thread %p", ctx->thread_hd);
350 WaitForSingleObject (ctx->stopped, INFINITE);
351 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_reader", ctx->file_hd,
352 "thread %p has terminated", ctx->thread_hd);
355 CloseHandle (ctx->stopped);
356 if (ctx->have_data_ev)
357 CloseHandle (ctx->have_data_ev);
358 if (ctx->have_space_ev)
359 CloseHandle (ctx->have_space_ev);
360 CloseHandle (ctx->thread_hd);
361 DESTROY_LOCK (ctx->mutex);
366 /* Find a reader context or create a new one. Note that the reader
367 context will last until a _gpgme_io_close. */
368 static struct reader_context_s *
369 find_reader (int fd, int start_it)
371 struct reader_context_s *rd = NULL;
374 LOCK (reader_table_lock);
375 for (i = 0; i < reader_table_size; i++)
376 if (reader_table[i].used && reader_table[i].fd == fd)
377 rd = reader_table[i].context;
381 UNLOCK (reader_table_lock);
385 for (i = 0; i < reader_table_size; i++)
386 if (!reader_table[i].used)
389 if (i != reader_table_size)
391 rd = create_reader (fd_to_handle (fd));
392 reader_table[i].fd = fd;
393 reader_table[i].context = rd;
394 reader_table[i].used = 1;
397 UNLOCK (reader_table_lock);
407 LOCK (reader_table_lock);
408 for (i = 0; i < reader_table_size; i++)
410 if (reader_table[i].used && reader_table[i].fd == fd)
412 destroy_reader (reader_table[i].context);
413 reader_table[i].context = NULL;
414 reader_table[i].used = 0;
418 UNLOCK (reader_table_lock);
423 _gpgme_io_read (int fd, void *buffer, size_t count)
426 struct reader_context_s *ctx;
427 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
428 "buffer=%p, count=%u", buffer, count);
430 ctx = find_reader (fd, 1);
434 return TRACE_SYSRES (-1);
436 if (ctx->eof_shortcut)
437 return TRACE_SYSRES (0);
440 if (ctx->readpos == ctx->writepos && !ctx->error)
442 /* No data available. */
444 TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd);
445 WaitForSingleObject (ctx->have_data_ev, INFINITE);
446 TRACE_LOG1 ("data from thread %p available", ctx->thread_hd);
450 if (ctx->readpos == ctx->writepos || ctx->error)
453 ctx->eof_shortcut = 1;
455 return TRACE_SYSRES (0);
458 TRACE_LOG ("EOF but ctx->eof flag not set");
461 errno = ctx->error_code;
462 return TRACE_SYSRES (-1);
465 nread = ctx->readpos < ctx->writepos
466 ? ctx->writepos - ctx->readpos
467 : READBUF_SIZE - ctx->readpos;
470 memcpy (buffer, ctx->buffer + ctx->readpos, nread);
471 ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE;
472 if (ctx->readpos == ctx->writepos && !ctx->eof)
474 if (!ResetEvent (ctx->have_data_ev))
476 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
478 /* FIXME: Should translate the error code. */
480 return TRACE_SYSRES (-1);
483 if (!SetEvent (ctx->have_space_ev))
485 TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d",
486 ctx->have_space_ev, (int) GetLastError ());
488 /* FIXME: Should translate the error code. */
490 return TRACE_SYSRES (-1);
494 TRACE_LOGBUF (buffer, nread);
495 return TRACE_SYSRES (nread);
499 /* The writer does use a simple buffering strategy so that we are
500 informed about write errors as soon as possible (i. e. with the the
501 next call to the write function. */
502 static DWORD CALLBACK
505 struct writer_context_s *ctx = arg;
507 TRACE_BEG1 (DEBUG_SYSIO, "gpgme:writer", ctx->file_hd,
508 "thread=%p", ctx->thread_hd);
520 if (!SetEvent (ctx->is_empty))
521 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
522 if (!ResetEvent (ctx->have_data))
523 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
526 WaitForSingleObject (ctx->have_data, INFINITE);
527 TRACE_LOG ("got data to send");
537 TRACE_LOG1 ("writing %d bytes", ctx->nbytes);
538 /* Note that CTX->nbytes is not zero at this point, because
539 _gpgme_io_write always writes at least 1 byte before waking
540 us up, unless CTX->stop_me is true, which we catch above. */
541 if (!WriteFile (ctx->file_hd, ctx->buffer,
542 ctx->nbytes, &nwritten, NULL))
544 ctx->error_code = (int) GetLastError ();
546 TRACE_LOG1 ("write error: ec=%d", ctx->error_code);
549 TRACE_LOG1 ("wrote %d bytes", (int) nwritten);
552 ctx->nbytes -= nwritten;
555 /* Indicate that we have an error. */
556 if (!SetEvent (ctx->is_empty))
557 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
558 SetEvent (ctx->stopped);
564 static struct writer_context_s *
565 create_writer (HANDLE fd)
567 struct writer_context_s *ctx;
568 SECURITY_ATTRIBUTES sec_attr;
571 TRACE_BEG (DEBUG_SYSIO, "gpgme:create_writer", fd);
573 memset (&sec_attr, 0, sizeof sec_attr);
574 sec_attr.nLength = sizeof sec_attr;
575 sec_attr.bInheritHandle = FALSE;
577 ctx = calloc (1, sizeof *ctx);
580 TRACE_SYSERR (errno);
586 ctx->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
588 ctx->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
590 ctx->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
591 if (!ctx->have_data || !ctx->is_empty || !ctx->stopped)
593 TRACE_LOG1 ("CreateEvent failed: ec=%d", (int) GetLastError ());
595 CloseHandle (ctx->have_data);
597 CloseHandle (ctx->is_empty);
599 CloseHandle (ctx->stopped);
601 /* FIXME: Translate the error code. */
606 ctx->is_empty = set_synchronize (ctx->is_empty);
607 INIT_LOCK (ctx->mutex);
609 ctx->thread_hd = CreateThread (&sec_attr, 0, writer, ctx, 0, &tid );
612 TRACE_LOG1 ("CreateThread failed: ec=%d", (int) GetLastError ());
613 DESTROY_LOCK (ctx->mutex);
615 CloseHandle (ctx->have_data);
617 CloseHandle (ctx->is_empty);
619 CloseHandle (ctx->stopped);
626 /* We set the priority of the thread higher because we know
627 that it only runs for a short time. This greatly helps to
628 increase the performance of the I/O. */
629 SetThreadPriority (ctx->thread_hd, get_desired_thread_priority ());
637 destroy_writer (struct writer_context_s *ctx)
641 if (ctx->refcount != 0)
648 SetEvent (ctx->have_data);
651 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
652 "waiting for termination of thread %p", ctx->thread_hd);
653 WaitForSingleObject (ctx->stopped, INFINITE);
654 TRACE1 (DEBUG_SYSIO, "gpgme:destroy_writer", ctx->file_hd,
655 "thread %p has terminated", ctx->thread_hd);
658 CloseHandle (ctx->stopped);
660 CloseHandle (ctx->have_data);
662 CloseHandle (ctx->is_empty);
663 CloseHandle (ctx->thread_hd);
664 DESTROY_LOCK (ctx->mutex);
669 /* Find a writer context or create a new one. Note that the writer
670 context will last until a _gpgme_io_close. */
671 static struct writer_context_s *
672 find_writer (int fd, int start_it)
674 struct writer_context_s *wt = NULL;
677 LOCK (writer_table_lock);
678 for (i = 0; i < writer_table_size; i++)
679 if (writer_table[i].used && writer_table[i].fd == fd)
680 wt = writer_table[i].context;
684 UNLOCK (writer_table_lock);
688 for (i = 0; i < writer_table_size; i++)
689 if (!writer_table[i].used)
692 if (i != writer_table_size)
694 wt = create_writer (fd_to_handle (fd));
695 writer_table[i].fd = fd;
696 writer_table[i].context = wt;
697 writer_table[i].used = 1;
700 UNLOCK (writer_table_lock);
710 LOCK (writer_table_lock);
711 for (i = 0; i < writer_table_size; i++)
713 if (writer_table[i].used && writer_table[i].fd == fd)
715 destroy_writer (writer_table[i].context);
716 writer_table[i].context = NULL;
717 writer_table[i].used = 0;
721 UNLOCK (writer_table_lock);
726 _gpgme_io_write (int fd, const void *buffer, size_t count)
728 struct writer_context_s *ctx;
729 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
730 "buffer=%p, count=%u", buffer, count);
731 TRACE_LOGBUF (buffer, count);
734 return TRACE_SYSRES (0);
736 ctx = find_writer (fd, 1);
738 return TRACE_SYSRES (-1);
741 if (!ctx->error && ctx->nbytes)
743 /* Bytes are pending for send. */
745 /* Reset the is_empty event. Better safe than sorry. */
746 if (!ResetEvent (ctx->is_empty))
748 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
750 /* FIXME: Should translate the error code. */
752 return TRACE_SYSRES (-1);
755 TRACE_LOG1 ("waiting for empty buffer in thread %p", ctx->thread_hd);
756 WaitForSingleObject (ctx->is_empty, INFINITE);
757 TRACE_LOG1 ("thread %p buffer is empty", ctx->thread_hd);
764 if (ctx->error_code == ERROR_NO_DATA)
768 return TRACE_SYSRES (-1);
771 /* If no error occured, the number of bytes in the buffer must be
773 assert (!ctx->nbytes);
775 if (count > WRITEBUF_SIZE)
776 count = WRITEBUF_SIZE;
777 memcpy (ctx->buffer, buffer, count);
780 /* We have to reset the is_empty event early, because it is also
781 used by the select() implementation to probe the channel. */
782 if (!ResetEvent (ctx->is_empty))
784 TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ());
786 /* FIXME: Should translate the error code. */
788 return TRACE_SYSRES (-1);
790 if (!SetEvent (ctx->have_data))
792 TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ());
794 /* FIXME: Should translate the error code. */
796 return TRACE_SYSRES (-1);
800 return TRACE_SYSRES ((int) count);
805 _gpgme_io_pipe (int filedes[2], int inherit_idx)
809 SECURITY_ATTRIBUTES sec_attr;
810 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
811 "inherit_idx=%i (GPGME uses it for %s)",
812 inherit_idx, inherit_idx ? "reading" : "writing");
814 memset (&sec_attr, 0, sizeof (sec_attr));
815 sec_attr.nLength = sizeof (sec_attr);
816 sec_attr.bInheritHandle = FALSE;
818 if (!CreatePipe (&rh, &wh, &sec_attr, PIPEBUF_SIZE))
820 TRACE_LOG1 ("CreatePipe failed: ec=%d", (int) GetLastError ());
821 /* FIXME: Should translate the error code. */
823 return TRACE_SYSRES (-1);
826 /* Make one end inheritable. */
827 if (inherit_idx == 0)
830 if (!DuplicateHandle (GetCurrentProcess(), rh,
831 GetCurrentProcess(), &hd, 0,
832 TRUE, DUPLICATE_SAME_ACCESS))
834 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
835 (int) GetLastError ());
838 /* FIXME: Should translate the error code. */
840 return TRACE_SYSRES (-1);
845 else if (inherit_idx == 1)
848 if (!DuplicateHandle( GetCurrentProcess(), wh,
849 GetCurrentProcess(), &hd, 0,
850 TRUE, DUPLICATE_SAME_ACCESS))
852 TRACE_LOG1 ("DuplicateHandle failed: ec=%d",
853 (int) GetLastError ());
856 /* FIXME: Should translate the error code. */
858 return TRACE_SYSRES (-1);
864 filedes[0] = handle_to_fd (rh);
865 filedes[1] = handle_to_fd (wh);
866 return TRACE_SUC2 ("read=%p, write=%p", rh, wh);
871 _gpgme_io_close (int fd)
874 _gpgme_close_notify_handler_t handler = NULL;
876 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
881 return TRACE_SYSRES (-1);
886 LOCK (notify_table_lock);
887 for (i = 0; i < DIM (notify_table); i++)
889 if (notify_table[i].inuse && notify_table[i].fd == fd)
891 handler = notify_table[i].handler;
892 value = notify_table[i].value;
893 notify_table[i].handler = NULL;
894 notify_table[i].value = NULL;
895 notify_table[i].inuse = 0;
899 UNLOCK (notify_table_lock);
903 if (!CloseHandle (fd_to_handle (fd)))
905 TRACE_LOG1 ("CloseHandle failed: ec=%d", (int) GetLastError ());
906 /* FIXME: Should translate the error code. */
908 return TRACE_SYSRES (-1);
911 return TRACE_SYSRES (0);
916 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
920 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
921 "close_handler=%p/%p", handler, value);
925 LOCK (notify_table_lock);
926 for (i=0; i < DIM (notify_table); i++)
927 if (notify_table[i].inuse && notify_table[i].fd == fd)
929 if (i == DIM (notify_table))
930 for (i = 0; i < DIM (notify_table); i++)
931 if (!notify_table[i].inuse)
933 if (i == DIM (notify_table))
935 UNLOCK (notify_table_lock);
937 return TRACE_SYSRES (-1);
939 notify_table[i].fd = fd;
940 notify_table[i].handler = handler;
941 notify_table[i].value = value;
942 notify_table[i].inuse = 1;
943 UNLOCK (notify_table_lock);
944 return TRACE_SYSRES (0);
949 _gpgme_io_set_nonblocking (int fd)
951 TRACE (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
957 build_commandline (char **argv)
964 /* We have to quote some things because under Windows the program
965 parses the commandline and does some unquoting. We enclose the
966 whole argument in double-quotes, and escape literal double-quotes
967 as well as backslashes with a backslash. We end up with a
968 trailing space at the end of the line, but that is harmless. */
969 for (i = 0; argv[i]; i++)
972 /* The leading double-quote. */
976 /* An extra one for each literal that must be escaped. */
977 if (*p == '\\' || *p == '"')
982 /* The trailing double-quote and the delimiter. */
985 /* And a trailing zero. */
988 buf = p = malloc (n);
991 for (i = 0; argv[i]; i++)
993 char *argvp = argv[i];
998 if (*argvp == '\\' || *argvp == '"')
1000 *(p++) = *(argvp++);
1012 _gpgme_io_spawn (const char *path, char *const argv[],
1013 struct spawn_fd_item_s *fd_list, pid_t *r_pid)
1015 SECURITY_ATTRIBUTES sec_attr;
1016 PROCESS_INFORMATION pi =
1018 NULL, /* returns process handle */
1019 0, /* returns primary thread handle */
1020 0, /* returns pid */
1024 int cr_flags = CREATE_DEFAULT_ERROR_MODE
1025 | GetPriorityClass (GetCurrentProcess ());
1034 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
1039 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
1043 /* We do not inherit any handles by default, and just insert those
1044 handles we want the child to have afterwards. But some handle
1045 values occur on the command line, and we need to move
1046 stdin/out/err to the right location. So we use a wrapper program
1047 which gets the information from a temporary file. */
1048 if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0)
1050 TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno));
1051 return TRACE_SYSRES (-1);
1053 TRACE_LOG1 ("tmp_name = %s", tmp_name);
1055 args = calloc (2 + i + 1, sizeof (*args));
1056 args[0] = (char *) _gpgme_get_w32spawn_path ();
1059 memcpy (&args[3], &argv[1], i * sizeof (*args));
1061 memset (&sec_attr, 0, sizeof sec_attr);
1062 sec_attr.nLength = sizeof sec_attr;
1063 sec_attr.bInheritHandle = FALSE;
1065 arg_string = build_commandline (args);
1070 DeleteFile (tmp_name);
1071 return TRACE_SYSRES (-1);
1074 memset (&si, 0, sizeof si);
1075 si.cb = sizeof (si);
1076 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1077 si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
1078 si.hStdInput = INVALID_HANDLE_VALUE;
1079 si.hStdOutput = INVALID_HANDLE_VALUE;
1080 si.hStdError = INVALID_HANDLE_VALUE;
1082 cr_flags |= CREATE_SUSPENDED;
1083 cr_flags |= DETACHED_PROCESS;
1084 if (!CreateProcessA (_gpgme_get_w32spawn_path (),
1086 &sec_attr, /* process security attributes */
1087 &sec_attr, /* thread security attributes */
1088 FALSE, /* inherit handles */
1089 cr_flags, /* creation flags */
1090 NULL, /* environment */
1091 NULL, /* use current drive/directory */
1092 &si, /* startup information */
1093 &pi)) /* returns process information */
1095 TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());
1098 DeleteFile (tmp_name);
1100 /* FIXME: Should translate the error code. */
1102 return TRACE_SYSRES (-1);
1107 /* Insert the inherited handles. */
1108 for (i = 0; fd_list[i].fd != -1; i++)
1112 /* Make it inheritable for the wrapper process. */
1113 if (!DuplicateHandle (GetCurrentProcess(), fd_to_handle (fd_list[i].fd),
1114 pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS))
1116 TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ());
1117 TerminateProcess (pi.hProcess, 0);
1118 /* Just in case TerminateProcess didn't work, let the
1119 process fail on its own. */
1120 ResumeThread (pi.hThread);
1121 CloseHandle (pi.hThread);
1122 CloseHandle (pi.hProcess);
1125 DeleteFile (tmp_name);
1127 /* FIXME: Should translate the error code. */
1129 return TRACE_SYSRES (-1);
1131 /* Return the child name of this handle. */
1132 fd_list[i].peer_name = handle_to_fd (hd);
1135 /* Write the handle translation information to the temporary
1138 /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex
1139 notation: "0xFEDCBA9876543210" with an extra white space after
1140 every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead
1141 for a time when a HANDLE is 64 bit. */
1142 #define BUFFER_MAX 800
1143 char line[BUFFER_MAX + 1];
1150 for (i = 0; fd_list[i].fd != -1; i++)
1152 /* Strip the newline. */
1153 len = strlen (line) - 1;
1155 /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */
1156 snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n",
1157 fd_list[i].fd, fd_list[i].dup_to,
1158 fd_list[i].peer_name, fd_list[i].arg_loc);
1159 /* Rather safe than sorry. */
1160 line[BUFFER_MAX - 1] = '\n';
1161 line[BUFFER_MAX] = '\0';
1163 len = strlen (line);
1167 res = write (tmp_fd, &line[written], len - written);
1171 while (res > 0 || (res < 0 && errno == EAGAIN));
1174 /* The temporary file is deleted by the gpgme-w32spawn process
1177 TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "
1178 "dwProcessID=%d, dwThreadId=%d",
1179 pi.hProcess, pi.hThread,
1180 (int) pi.dwProcessId, (int) pi.dwThreadId);
1183 *r_pid = (pid_t)pi.dwProcessId;
1185 if (ResumeThread (pi.hThread) < 0)
1186 TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
1188 if (!CloseHandle (pi.hThread))
1189 TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",
1190 (int) GetLastError ());
1192 TRACE_LOG1 ("process=%p", pi.hProcess);
1194 /* We don't need to wait for the process. */
1195 if (!CloseHandle (pi.hProcess))
1196 TRACE_LOG1 ("CloseHandle of process failed: ec=%d",
1197 (int) GetLastError ());
1199 for (i = 0; fd_list[i].fd != -1; i++)
1200 _gpgme_io_close (fd_list[i].fd);
1202 for (i = 0; fd_list[i].fd != -1; i++)
1203 if (fd_list[i].dup_to == -1)
1204 TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd,
1205 fd_list[i].peer_name);
1207 TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd,
1208 fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" :
1209 ((fd_list[i].dup_to == 1) ? "out" : "err"));
1211 return TRACE_SYSRES (0);
1215 /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
1216 nothing to select, > 0 = number of signaled fds. */
1218 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
1220 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
1221 int waitidx[MAXIMUM_WAIT_OBJECTS];
1228 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
1229 "nfds=%u, nonblock=%u", nfds, nonblock);
1232 TRACE_SEQ (dbg_help, "select on [ ");
1236 for (i=0; i < nfds; i++)
1238 if (fds[i].fd == -1)
1240 fds[i].signaled = 0;
1241 if (fds[i].for_read || fds[i].for_write)
1243 if (fds[i].for_read)
1245 struct reader_context_s *ctx = find_reader (fds[i].fd,1);
1248 TRACE_LOG1 ("error: no reader for FD 0x%x (ignored)",
1252 if (nwait >= DIM (waitbuf))
1254 TRACE_END (dbg_help, "oops ]");
1255 TRACE_LOG ("Too many objects for WFMO!");
1256 /* FIXME: Should translate the error code. */
1258 return TRACE_SYSRES (-1);
1261 waitbuf[nwait++] = ctx->have_data_ev;
1263 TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
1266 else if (fds[i].for_write)
1268 struct writer_context_s *ctx = find_writer (fds[i].fd,1);
1271 TRACE_LOG1 ("error: no writer for FD 0x%x (ignored)",
1275 if (nwait >= DIM (waitbuf))
1277 TRACE_END (dbg_help, "oops ]");
1278 TRACE_LOG ("Too many objects for WFMO!");
1279 /* FIXME: Should translate the error code. */
1281 return TRACE_SYSRES (-1);
1284 waitbuf[nwait++] = ctx->is_empty;
1286 TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
1291 TRACE_END (dbg_help, "]");
1293 return TRACE_SYSRES (0);
1295 code = WaitForMultipleObjects (nwait, waitbuf, 0, nonblock ? 0 : 1000);
1296 if (code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait)
1298 /* This WFMO is a really silly function: It does return either
1299 the index of the signaled object or if 2 objects have been
1300 signalled at the same time, the index of the object with the
1301 lowest object is returned - so and how do we find out how
1302 many objects have been signaled???. The only solution I can
1303 imagine is to test each object starting with the returned
1304 index individually - how dull. */
1306 for (i = code - WAIT_OBJECT_0; i < nwait; i++)
1308 if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0)
1310 assert (waitidx[i] >=0 && waitidx[i] < nfds);
1311 fds[waitidx[i]].signaled = 1;
1318 TRACE_LOG ("no signaled objects found after WFMO");
1322 else if (code == WAIT_TIMEOUT)
1323 TRACE_LOG ("WFMO timed out");
1324 else if (code == WAIT_FAILED)
1326 int le = (int) GetLastError ();
1327 if (le == ERROR_INVALID_HANDLE)
1330 int j = handle_to_fd (waitbuf[i]);
1332 TRACE_LOG1 ("WFMO invalid handle %d removed", j);
1333 for (k = 0 ; k < nfds; k++)
1337 fds[k].for_read = fds[k].for_write = 0;
1341 TRACE_LOG (" oops, or not???");
1343 TRACE_LOG1 ("WFMO failed: %d", le);
1348 TRACE_LOG1 ("WFMO returned %d", code);
1354 TRACE_SEQ (dbg_help, "select OK [ ");
1355 for (i = 0; i < nfds; i++)
1357 if (fds[i].fd == -1)
1359 if ((fds[i].for_read || fds[i].for_write) && fds[i].signaled)
1360 TRACE_ADD2 (dbg_help, "%c0x%x ",
1361 fds[i].for_read ? 'r' : 'w', fds[i].fd);
1363 TRACE_END (dbg_help, "]");
1368 /* FIXME: Should determine a proper error code. */
1372 return TRACE_SYSRES (count);
1377 _gpgme_io_subsystem_init (void)
1379 /* Nothing to do. */
1383 /* Write the printable version of FD to the buffer BUF of length
1384 BUFLEN. The printable version is the representation on the command
1385 line that the child process expects. */
1387 _gpgme_io_fd2str (char *buf, int buflen, int fd)
1389 return snprintf (buf, buflen, "%d", fd);
1394 _gpgme_io_dup (int fd)
1396 HANDLE handle = fd_to_handle (fd);
1397 HANDLE new_handle = fd_to_handle (fd);
1399 struct reader_context_s *rd_ctx;
1400 struct writer_context_s *wt_ctx;
1402 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_dup", fd);
1404 if (!DuplicateHandle (GetCurrentProcess(), handle,
1405 GetCurrentProcess(), &new_handle,
1406 0, FALSE, DUPLICATE_SAME_ACCESS))
1408 TRACE_LOG1 ("DuplicateHandle failed: ec=%d\n", (int) GetLastError ());
1409 /* FIXME: Translate error code. */
1411 return TRACE_SYSRES (-1);
1414 rd_ctx = find_reader (fd, 1);
1417 /* No need for locking, as the only races are against the reader
1418 thread itself, which doesn't touch refcount. */
1421 LOCK (reader_table_lock);
1422 for (i = 0; i < reader_table_size; i++)
1423 if (!reader_table[i].used)
1426 assert (i != reader_table_size);
1427 reader_table[i].fd = handle_to_fd (new_handle);
1428 reader_table[i].context = rd_ctx;
1429 reader_table[i].used = 1;
1430 UNLOCK (reader_table_lock);
1433 wt_ctx = find_writer (fd, 1);
1436 /* No need for locking, as the only races are against the writer
1437 thread itself, which doesn't touch refcount. */
1440 LOCK (writer_table_lock);
1441 for (i = 0; i < writer_table_size; i++)
1442 if (!writer_table[i].used)
1445 assert (i != writer_table_size);
1446 writer_table[i].fd = handle_to_fd (new_handle);
1447 writer_table[i].context = wt_ctx;
1448 writer_table[i].used = 1;
1449 UNLOCK (writer_table_lock);
1452 return TRACE_SYSRES (handle_to_fd (new_handle));
1456 /* The following interface is only useful for GPGME Glib and Qt. */
1458 /* Compatibility interface, obsolete. */
1460 gpgme_get_giochannel (int fd)
1466 /* Look up the giochannel or qiodevice for file descriptor FD. */
1468 gpgme_get_fdptr (int fd)
1481 case WSAEWOULDBLOCK:
1483 case ERROR_BROKEN_PIPE:
1485 case WSANOTINITIALISED:
1494 _gpgme_io_socket (int domain, int type, int proto)
1498 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
1499 "type=%i, protp=%i", type, proto);
1501 res = socket (domain, type, proto);
1502 if (res == INVALID_SOCKET)
1504 errno = wsa2errno (WSAGetLastError ());
1505 return TRACE_SYSRES (-1);
1508 TRACE_SUC1 ("socket=0x%x", res);
1515 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
1520 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
1521 "addr=%p, addrlen=%i", addr, addrlen);
1523 res = connect (sockfd, addr, addrlen);
1526 errno = wsa2errno (WSAGetLastError ());
1527 return TRACE_SYSRES (-1);
1530 return TRACE_SUC ();