diff --git a/TODO b/TODO new file mode 100644 index 00000000..59a6d8c8 --- /dev/null +++ b/TODO @@ -0,0 +1,10 @@ +* Implement posix-sema.c + +* Add gpgme_mime_xxx to make handling of MIME/PGP easier + +* Allow to use GTK's main loop instead of the select stuff in + wait.c + +* Remove all that funny exit code handling - we donn't need it. + + diff --git a/autogen.sh b/autogen.sh index 13e4b368..378fe594 100755 --- a/autogen.sh +++ b/autogen.sh @@ -62,7 +62,7 @@ if test "$1" = "--build-w32"; then ./configure --host=${host} --target=${target} ${disable_foo_tests} \ --bindir=${crossbindir} --libdir=${crosslibdir} \ - --includedir=${crossincdir} $* + --includedir=${crossincdir} --enable-maintainer-mode $* exit $? fi diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index fe88ebba..63e16155 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,18 @@ +2001-01-30 Werner Koch + + * w32-io.c: Does now use reader threads, so that we can use + WaitForMultipleObjects. + * sema.h, posix-sema.c, w32-sema.c: Support for Critcial sections. + Does currently only work for W32. + + * debug.c, util.h : New. Changed all fprintfs to use this new + set of debugging functions. + +2001-01-23 Werner Koch + + * data.c (_gpgme_data_release_and_return_string): Fixed string + termination. + 2001-01-22 Werner Koch * delete.c: New. diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index 74d5955d..20944ac8 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -13,7 +13,7 @@ libgpgme_la_LDFLAGS = -version-info \ libgpgme_la_INCLUDES = -I$(top_srcdir)/lib libgpgme_la_SOURCES = \ - gpgme.h types.h util.h util.c \ + gpgme.h types.h util.h util.c debug.c \ context.h ops.h \ data.c recipient.c signers.c \ wait.c wait.h \ @@ -29,6 +29,7 @@ libgpgme_la_SOURCES = \ genkey.c \ delete.c \ rungpg.c rungpg.h status-table.h \ + sema.h posix-sema.c w32-sema.c \ syshdr.h io.h posix-io.c w32-io.c \ gpgme.c version.c errors.c diff --git a/gpgme/data.c b/gpgme/data.c index 48a2eaeb..9d8b58ee 100644 --- a/gpgme/data.c +++ b/gpgme/data.c @@ -311,7 +311,7 @@ _gpgme_data_release_and_return_string ( GpgmeData dh ) char *val = NULL; if (dh) { - if ( _gpgme_data_append ( dh, "", 0 ) ) /* append EOS */ + if ( _gpgme_data_append ( dh, "", 1 ) ) /* append EOS */ xfree (dh->private_buffer ); else { val = dh->private_buffer; @@ -331,10 +331,11 @@ _gpgme_data_release_and_return_string ( GpgmeData dh ) * @dh: the data object * @r_len: returns the length of the memory * - * Release the data object @dh and return its content and the length of - * that content. The caller has to free this data. @dh maybe NULL in - * which case NULL is returned. I there is not enough memory for allocating - * the return value, NULL is returned and the object is released. + * Release the data object @dh and return its content and the length + * of that content. The caller has to free this data. @dh maybe NULL + * in which case NULL is returned. If there is not enough memory for + * allocating the return value, NULL is returned and the object is + * released. * * Return value: a pointer to an allocated buffer of length @r_len. **/ diff --git a/gpgme/debug.c b/gpgme/debug.c new file mode 100644 index 00000000..f41929b3 --- /dev/null +++ b/gpgme/debug.c @@ -0,0 +1,156 @@ +/* debug.c + * Copyright (C) 2001 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "sema.h" + +DEFINE_STATIC_LOCK (debug_lock); + +struct debug_control_s { + FILE *fp; + char fname[100]; +}; + +static int debug_level = 0; + +static void +debug_init (void) +{ + static volatile int initialized = 0; + + if (initialized) + return; + LOCK (debug_lock); + if (!initialized) { + const char *e = getenv ("GPGME_DEBUG"); + + debug_level = e? atoi (e): 0; + initialized = 1; + if (debug_level > 0) + fprintf (stderr,"gpgme_debug: level=%d\n", debug_level); + } + UNLOCK (debug_lock); +} + + +void +_gpgme_debug (int level, const char *format, ...) +{ + va_list arg_ptr ; + + debug_init (); + if ( debug_level < level ) + return; + + va_start ( arg_ptr, format ) ; + LOCK (debug_lock); + vfprintf (stderr, format, arg_ptr) ; + va_end ( arg_ptr ) ; + if( format && *format && format[strlen(format)-1] != '\n' ) + putc ('\n', stderr); + UNLOCK (debug_lock); + fflush (stderr); +} + + + +void +_gpgme_debug_begin ( void **helper, int level, const char *text) +{ + struct debug_control_s *ctl; + + debug_init (); + + *helper = NULL; + if ( debug_level < level ) + return; + ctl = xtrycalloc (1, sizeof *ctl ); + if (!ctl) { + _gpgme_debug (255, __FILE__ ":" STR2(__LINE__)": out of core"); + return; + } + + /* Oh what a pitty sthat we don't have a asprintf or snprintf under + * Windoze. We definitely should write our own clib for W32! */ + sprintf ( ctl->fname, "/tmp/gpgme_debug.%d.%p", getpid (), ctl ); + ctl->fp = fopen (ctl->fname, "w+"); + if (!ctl->fp) { + _gpgme_debug (255,__FILE__ ":" STR2(__LINE__)": failed to create `%s'", + ctl->fname ); + xfree (ctl); + return; + } + *helper = ctl; + _gpgme_debug_add (helper, "%s", text ); +} + +int +_gpgme_debug_enabled (void **helper) +{ + return helper && *helper; +} + + +void +_gpgme_debug_add (void **helper, const char *format, ...) +{ + struct debug_control_s *ctl = *helper; + va_list arg_ptr ; + + if ( !*helper ) + return; + + va_start ( arg_ptr, format ) ; + vfprintf (ctl->fp, format, arg_ptr) ; + va_end ( arg_ptr ) ; +} + +void +_gpgme_debug_end (void **helper, const char *text) +{ + struct debug_control_s *ctl = *helper; + int c, last_c=EOF; + + if ( !*helper ) + return; + + _gpgme_debug_add (helper, "%s", text ); + rewind (ctl->fp); + LOCK (debug_lock); + while ( (c=getc (ctl->fp)) != EOF ) { + putc (c, stderr); + last_c = c; + } + if (last_c != '\n') + putc ('\n', stderr); + UNLOCK (debug_lock); + + remove (ctl->fname); + xfree (ctl); + *helper = NULL; +} + diff --git a/gpgme/decrypt.c b/gpgme/decrypt.c index 083e5e82..75d4ac8b 100644 --- a/gpgme/decrypt.c +++ b/gpgme/decrypt.c @@ -102,7 +102,7 @@ decrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) break; case STATUS_MISSING_PASSPHRASE: - fprintf (stderr, "Missing passphrase - stop\n");; + DEBUG0 ("missing passphrase - stop\n");; ctx->result.decrypt->no_passphrase = 1; break; @@ -174,7 +174,7 @@ command_handler ( void *opaque, GpgStatusCode code, const char *key ) buf, &c->result.decrypt->last_pw_handle ); xfree (buf); return s; - } + } return NULL; } diff --git a/gpgme/encrypt.c b/gpgme/encrypt.c index 91520a89..e4bb38e2 100644 --- a/gpgme/encrypt.c +++ b/gpgme/encrypt.c @@ -31,8 +31,7 @@ static void encrypt_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) { - fprintf (stderr, "encrypt_status: code=%d args=`%s'\n", - code, args ); + DEBUG2 ("encrypt_status: code=%d args=`%s'\n", code, args ); } diff --git a/gpgme/export.c b/gpgme/export.c index 0265b46a..c46c3a97 100644 --- a/gpgme/export.c +++ b/gpgme/export.c @@ -31,8 +31,7 @@ static void export_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) { - fprintf (stderr, "export_status: code=%d args=`%s'\n", - code, args ); + DEBUG2 ("export_status: code=%d args=`%s'\n", code, args ); /* FIXME: Need to do more */ } diff --git a/gpgme/genkey.c b/gpgme/genkey.c index b002372c..c2bab3d6 100644 --- a/gpgme/genkey.c +++ b/gpgme/genkey.c @@ -59,8 +59,7 @@ genkey_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) return; } - fprintf (stderr, "genkey_status: code=%d args=`%s'\n", - code, args ); + DEBUG2 ("genkey_status: code=%d args=`%s'\n", code, args ); /* FIXME: Need to do more */ } diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index 54ec97fb..935e8e80 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -50,7 +50,6 @@ gpgme_new (GpgmeCtx *r_ctx) if (!c) return mk_error (Out_Of_Core); c->verbosity = 1; - c->use_armor = 1; /* fixme: reset this to 0 */ *r_ctx = c; return 0; diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 971101b9..73744922 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -22,7 +22,7 @@ #define GPGME_H #ifdef _MSC_VER - typedef long off_t + typedef long off_t; #else # include #endif @@ -126,7 +126,8 @@ typedef enum { GPGME_ATTR_COMMENT = 11, GPGME_ATTR_VALIDITY= 12, GPGME_ATTR_LEVEL = 13, - GPGME_ATTR_TYPE = 14 + GPGME_ATTR_TYPE = 14, + GPGME_ATTR_IS_SECRET= 15 } GpgmeAttr; typedef enum { diff --git a/gpgme/import.c b/gpgme/import.c index 368063ac..a05f60b3 100644 --- a/gpgme/import.c +++ b/gpgme/import.c @@ -31,8 +31,7 @@ static void import_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) { - fprintf (stderr, "import_status: code=%d args=`%s'\n", - code, args ); + DEBUG2 ("import_status: code=%d args=`%s'\n", code, args ); /* FIXME: We have to check here whether the import actually worked * and maybe it is a good idea to save some statistics and provide * a progress callback */ diff --git a/gpgme/key.c b/gpgme/key.c index 87a5602a..3ee49f7b 100644 --- a/gpgme/key.c +++ b/gpgme/key.c @@ -48,8 +48,8 @@ pkalgo_to_string ( int algo ) -GpgmeError -_gpgme_key_new( GpgmeKey *r_key ) +static GpgmeError +key_new ( GpgmeKey *r_key, int secret ) { GpgmeKey key; @@ -59,9 +59,23 @@ _gpgme_key_new( GpgmeKey *r_key ) return mk_error (Out_Of_Core); key->ref_count = 1; *r_key = key; + if (secret) + key->secret = 1; return 0; } +GpgmeError +_gpgme_key_new ( GpgmeKey *r_key ) +{ + return key_new ( r_key, 0 ); +} + +GpgmeError +_gpgme_key_new_secret ( GpgmeKey *r_key ) +{ + return key_new ( r_key, 1 ); +} + void gpgme_key_ref ( GpgmeKey key ) { @@ -70,8 +84,8 @@ gpgme_key_ref ( GpgmeKey key ) } -struct subkey_s * -_gpgme_key_add_subkey (GpgmeKey key) +static struct subkey_s * +add_subkey (GpgmeKey key, int secret) { struct subkey_s *k, *kk; @@ -86,9 +100,22 @@ _gpgme_key_add_subkey (GpgmeKey key) kk = kk->next; kk->next = k; } + if (secret) + k->secret = 1; return k; } +struct subkey_s * +_gpgme_key_add_subkey (GpgmeKey key) +{ + return add_subkey (key, 0); +} + +struct subkey_s * +_gpgme_key_add_secret_subkey (GpgmeKey key) +{ + return add_subkey (key, 1); +} void gpgme_key_release ( GpgmeKey key ) @@ -350,6 +377,8 @@ gpgme_key_get_as_xml ( GpgmeKey key ) _gpgme_data_append_string ( d, "\n" " \n" ); + if ( key->secret ) + _gpgme_data_append_string ( d, " \n"); add_tag_and_string (d, "keyid", key->keys.keyid ); if (key->keys.fingerprint) add_tag_and_string (d, "fpr", key->keys.fingerprint ); @@ -374,6 +403,8 @@ gpgme_key_get_as_xml ( GpgmeKey key ) for (k=key->keys.next; k; k = k->next ) { _gpgme_data_append_string (d, " \n"); + if ( k->secret ) + _gpgme_data_append_string ( d, " \n"); add_tag_and_string (d, "keyid", k->keyid ); if (k->fingerprint) add_tag_and_string (d, "fpr", k->fingerprint ); @@ -456,6 +487,10 @@ gpgme_key_get_string_attr ( GpgmeKey key, GpgmeAttr what, case GPGME_ATTR_LEVEL: /* not used here */ case GPGME_ATTR_TYPE: break; + case GPGME_ATTR_IS_SECRET: + if (key->secret) + val = "1"; + break; } return val; } @@ -491,6 +526,9 @@ gpgme_key_get_ulong_attr ( GpgmeKey key, GpgmeAttr what, if (u) val = u->validity; break; + case GPGME_ATTR_IS_SECRET: + val = !!key->secret; + break; default: break; } diff --git a/gpgme/key.h b/gpgme/key.h index c9be9b0a..91a4c846 100644 --- a/gpgme/key.h +++ b/gpgme/key.h @@ -27,6 +27,7 @@ struct subkey_s { struct subkey_s *next; + unsigned int secret:1; struct { unsigned int revoked:1 ; unsigned int expired:1 ; @@ -46,11 +47,13 @@ struct gpgme_key_s { unsigned int disabled:1 ; } gloflags; unsigned int ref_count; + unsigned int secret:1; struct subkey_s keys; struct user_id_s *uids; }; struct subkey_s *_gpgme_key_add_subkey (GpgmeKey key); +struct subkey_s *_gpgme_key_add_secret_subkey (GpgmeKey key); GpgmeError _gpgme_key_append_name ( GpgmeKey key, const char *s ); diff --git a/gpgme/keylist.c b/gpgme/keylist.c index a1c356fc..9fea4257 100644 --- a/gpgme/keylist.c +++ b/gpgme/keylist.c @@ -49,7 +49,6 @@ keylist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) default: /* ignore all other codes */ - fprintf (stderr, "keylist_status: code=%d not handled\n", code ); break; } } @@ -153,7 +152,7 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) rectype = RT_UID; key = ctx->tmp_key; } - else if ( !strcmp ( p, "sub" ) && key ) { + else if ( !strcmp (p, "sub") && key ) { /* start a new subkey */ rectype = RT_SUB; if ( !(sk = _gpgme_key_add_subkey (key)) ) { @@ -161,10 +160,18 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) return; } } - else if ( !strcmp ( p, "pub" ) ) { + else if ( !strcmp (p, "ssb") && key ) { + /* start a new secret subkey */ + rectype = RT_SSB; + if ( !(sk = _gpgme_key_add_secret_subkey (key)) ) { + ctx->out_of_core=1; + return; + } + } + else if ( !strcmp (p, "pub") ) { /* start a new keyblock */ if ( _gpgme_key_new ( &key ) ) { - ctx->out_of_core=1; /* the only kind of error we can get */ + ctx->out_of_core=1; /* the only kind of error we can get*/ return; } rectype = RT_PUB; @@ -173,17 +180,25 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) assert ( !ctx->tmp_key ); ctx->tmp_key = key; } + else if ( !strcmp (p, "sec") ) { + /* start a new keyblock */ + if ( _gpgme_key_new_secret ( &key ) ) { + ctx->out_of_core=1; /*the only kind of error we can get*/ + return; + } + rectype = RT_SEC; + if ( ctx->tmp_key ) + finish_key ( ctx ); + assert ( !ctx->tmp_key ); + ctx->tmp_key = key; + } else if ( !strcmp ( p, "fpr" ) && key ) rectype = RT_FPR; - else if ( !strcmp ( p, "ssb" ) ) - rectype = RT_SSB; - else if ( !strcmp ( p, "sec" ) ) - rectype = RT_SEC; else rectype = RT_NONE; } - else if ( rectype == RT_PUB ) { + else if ( rectype == RT_PUB || rectype == RT_SEC ) { switch (field) { case 2: /* trust info */ trust_info = p; /*save for later */ @@ -226,7 +241,7 @@ keylist_colon_handler ( GpgmeCtx ctx, char *line ) break; } } - else if ( rectype == RT_SUB && sk ) { + else if ( (rectype == RT_SUB || rectype== RT_SSB) && sk ) { switch (field) { case 2: /* trust info */ set_subkey_trust_info ( sk, p); @@ -344,6 +359,7 @@ gpgme_op_keylist_start ( GpgmeCtx c, const char *pattern, int secret_only ) _gpgme_release_result (c); c->out_of_core = 0; +#warning This context still keeps a gpg Zombie in some cases. if ( c->gpg ) { _gpgme_gpg_release ( c->gpg ); c->gpg = NULL; diff --git a/gpgme/ops.h b/gpgme/ops.h index 43001f2c..cbf35299 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -61,7 +61,8 @@ GpgmeError _gpgme_data_unread (GpgmeData dh, /*-- key.c --*/ -GpgmeError _gpgme_key_new( GpgmeKey *r_key ); +GpgmeError _gpgme_key_new ( GpgmeKey *r_key ); +GpgmeError _gpgme_key_new_secret ( GpgmeKey *r_key ); /*-- verify.c --*/ diff --git a/gpgme/posix-io.c b/gpgme/posix-io.c index ec242d31..e46c70b7 100644 --- a/gpgme/posix-io.c +++ b/gpgme/posix-io.c @@ -33,17 +33,9 @@ #include #include "syshdr.h" +#include "util.h" #include "io.h" -#define DEBUG_SELECT_ENABLED 0 - -#if DEBUG_SELECT_ENABLED -# define DEBUG_SELECT(a) fprintf a -#else -# define DEBUG_SELECT(a) do { } while(0) -#endif - - int _gpgme_io_read ( int fd, void *buffer, size_t count ) { @@ -137,8 +129,7 @@ _gpgme_io_spawn ( const char *path, char **argv, if (fd_child_list[i].dup_to != -1 ) { if ( dup2 (fd_child_list[i].fd, fd_child_list[i].dup_to ) == -1 ) { - fprintf (stderr, "dup2 failed in child: %s\n", - strerror (errno)); + DEBUG1 ("dup2 failed in child: %s\n", strerror (errno)); _exit (8); } if ( fd_child_list[i].dup_to == 0 ) @@ -152,26 +143,21 @@ _gpgme_io_spawn ( const char *path, char **argv, if( !duped_stdin || !duped_stderr ) { int fd = open ( "/dev/null", O_RDWR ); if ( fd == -1 ) { - fprintf (stderr,"can't open `/dev/null': %s\n", - strerror (errno) ); + DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno) ); _exit (8); } /* Make sure that the process has a connected stdin */ if ( !duped_stdin ) { if ( dup2 ( fd, 0 ) == -1 ) { - fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n", + DEBUG1("dup2(/dev/null, 0) failed: %s\n", strerror (errno) ); _exit (8); } } - /* We normally don't want all the normal output */ if ( !duped_stderr ) { - if (!getenv ("GPGME_DEBUG") ) { - if ( dup2 ( fd, 2 ) == -1 ) { - fprintf (stderr,"dup2(dev/null, 2) failed: %s\n", - strerror (errno) ); - _exit (8); - } + if ( dup2 ( fd, 2 ) == -1 ) { + DEBUG1 ("dup2(dev/null, 2) failed: %s\n", strerror (errno)); + _exit (8); } } close (fd); @@ -180,7 +166,7 @@ _gpgme_io_spawn ( const char *path, char **argv, execv ( path, argv ); /* Hmm: in that case we could write a special status code to the * status-pipe */ - fprintf (stderr,"exec of `%s' failed\n", path ); + DEBUG1 ("exec of `%s' failed\n", path ); _exit (8); } /* end child */ @@ -230,12 +216,13 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) static fd_set writefds; int any, i, max_fd, n, count; struct timeval timeout = { 0, 50 }; /* Use a 50ms timeout */ + void *dbg_help; FD_ZERO ( &readfds ); FD_ZERO ( &writefds ); max_fd = 0; - DEBUG_SELECT ((stderr, "gpgme:select on [ ")); + DEBUG_BEGIN (dbg_help, "gpgme:select on [ "); any = 0; for ( i=0; i < nfds; i++ ) { if ( fds[i].fd == -1 ) @@ -245,7 +232,7 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) FD_SET ( fds[i].fd, &readfds ); if ( fds[i].fd > max_fd ) max_fd = fds[i].fd; - DEBUG_SELECT ((stderr, "r%d ", fds[i].fd )); + DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd ); any = 1; } else if ( fds[i].for_write ) { @@ -253,12 +240,12 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) FD_SET ( fds[i].fd, &writefds ); if ( fds[i].fd > max_fd ) max_fd = fds[i].fd; - DEBUG_SELECT ((stderr, "w%d ", fds[i].fd )); + DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd ); any = 1; } fds[i].signaled = 0; } - DEBUG_SELECT ((stderr, "]\n" )); + DEBUG_END (dbg_help, "]" ); if ( !any ) return 0; @@ -266,20 +253,20 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) count = select ( max_fd+1, &readfds, &writefds, NULL, &timeout ); } while ( count < 0 && errno == EINTR); if ( count < 0 ) { - fprintf (stderr, "_gpgme_io_select failed: %s\n", strerror (errno) ); + DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno) ); return -1; /* error */ } -#if DEBUG_SELECT_ENABLED - fprintf (stderr, "gpgme:select OK [ " ); - for (i=0; i <= max_fd; i++ ) { - if (FD_ISSET (i, &readfds) ) - fprintf (stderr, "r%d ", i ); - if (FD_ISSET (i, &writefds) ) - fprintf (stderr, "w%d ", i ); + DEBUG_BEGIN (dbg_help, "select OK [ " ); + if (DEBUG_ENABLED(dbg_help)) { + for (i=0; i <= max_fd; i++ ) { + if (FD_ISSET (i, &readfds) ) + DEBUG_ADD1 (dbg_help, "r%d ", i ); + if (FD_ISSET (i, &writefds) ) + DEBUG_ADD1 (dbg_help, "w%d ", i ); + } + DEBUG_END (dbg_help, "]" ); } - fprintf (stderr, "]\n" ); -#endif /* n is used to optimize it a little bit */ for ( n=count, i=0; i < nfds && n ; i++ ) { diff --git a/gpgme/posix-sema.c b/gpgme/posix-sema.c new file mode 100644 index 00000000..82f9b8c3 --- /dev/null +++ b/gpgme/posix-sema.c @@ -0,0 +1,70 @@ +/* posix-sema.c + * Copyright (C) 2001 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include +#ifndef HAVE_DOSISH_SYSTEM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "syshdr.h" + +#include "util.h" +#include "sema.h" + + + +void +_gpgme_sema_subsystem_init () +{ +#warning Posix semaphore support has not yet been implemented +} + + +void +_gpgme_sema_cs_enter ( struct critsect_s *s ) +{ +} + +void +_gpgme_sema_cs_leave (struct critsect_s *s) +{ +} + +void +_gpgme_sema_cs_destroy ( struct critsect_s *s ) +{ +} + + + +#endif /*!HAVE_DOSISH_SYSTEM*/ + + + + + diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 76313584..101d9a9f 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -789,7 +789,7 @@ gpg_inbound_handler ( void *opaque, int pid, int fd ) nread = _gpgme_io_read (fd, buf, 200 ); if ( nread < 0 ) { - fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n", + DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s", fd, nread, strerror (errno) ); return 1; } @@ -802,7 +802,7 @@ gpg_inbound_handler ( void *opaque, int pid, int fd ) err = _gpgme_data_append ( dh, buf, nread ); if ( err ) { - fprintf (stderr, "_gpgme_append_data failed: %s\n", + DEBUG1 ("_gpgme_append_data failed: %s\n", gpgme_strerror(err)); /* Fixme: we should close the pipe or read it to /dev/null in * this case. Returnin EOF is not sufficient */ @@ -836,8 +836,8 @@ write_mem_data ( GpgmeData dh, int fd ) if (nwritten == -1 && errno == EAGAIN ) return 0; if ( nwritten < 1 ) { - fprintf (stderr, "write_mem_data(%d): write failed (n=%d): %s\n", - fd, nwritten, strerror (errno) ); + DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s", + fd, nwritten, strerror (errno) ); _gpgme_io_close (fd); return 1; } @@ -863,8 +863,8 @@ write_cb_data ( GpgmeData dh, int fd ) if (nwritten == -1 && errno == EAGAIN ) return 0; if ( nwritten < 1 ) { - fprintf (stderr, "write_cb_data(%d): write failed (n=%d): %s\n", - fd, nwritten, strerror (errno) ); + DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s", + fd, nwritten, strerror (errno) ); _gpgme_io_close (fd); return 1; } @@ -872,7 +872,7 @@ write_cb_data ( GpgmeData dh, int fd ) if ( nwritten < nbytes ) { /* ugly, ugly: It does currently only for for MEM type data */ if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) ) - fprintf (stderr, "wite_cb_data: unread of %d bytes failed\n", + DEBUG1 ("wite_cb_data: unread of %d bytes failed\n", nbytes - nwritten ); _gpgme_io_close (fd); return 1; @@ -915,7 +915,7 @@ gpg_status_handler ( void *opaque, int pid, int fd ) assert ( fd == gpg->status.fd[0] ); rc = read_status ( gpg ); if ( rc ) { - fprintf (stderr, "gpg_handler: read_status problem %d\n - stop", rc); + DEBUG1 ("gpg_handler: read_status problem %d\n - stop", rc); return 1; } @@ -1006,10 +1006,9 @@ read_status ( GpgObject gpg ) return mk_error (Out_Of_Core); /* this should be the last thing we have received * and the next thing will be that the command - * handler does it action */ + * handler does its action */ if ( nread > 1 ) - fprintf (stderr, "** ERROR, unxpected data in" - " read_status\n" ); + DEBUG0 ("ERROR, unexpected data in read_status"); _gpgme_thaw_fd (gpg->cmd.fd); } else if ( gpg->status.fnc ) { @@ -1061,7 +1060,7 @@ gpg_colon_line_handler ( void *opaque, int pid, int fd ) assert ( fd == gpg->colon.fd[0] ); rc = read_colon_line ( gpg ); if ( rc ) { - fprintf (stderr, "gpg_colon_line_handler: " + DEBUG1 ("gpg_colon_line_handler: " "read problem %d\n - stop", rc); return 1; } @@ -1191,7 +1190,7 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) *nread = 2; } else if (err) { - fprintf (stderr, "** pipemode_cb: copy sig failed: %s\n", + DEBUG1 ("pipemode_cb: copy sig failed: %s\n", gpgme_strerror (err) ); return -1; } @@ -1205,7 +1204,7 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) *nread = 4; } else if (err) { - fprintf (stderr, "** pipemode_cb: copy data failed: %s\n", + DEBUG1 ("pipemode_cb: copy data failed: %s\n", gpgme_strerror (err) ); return -1; } @@ -1230,32 +1229,32 @@ command_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) const char *value; int value_len; - fprintf (stderr, "** command_cb: enter\n"); + DEBUG0 ("command_cb: enter\n"); assert (gpg->cmd.used); if ( !buffer || !length || !nread ) return 0; /* those values are reserved for extensions */ *nread =0; if ( !gpg->cmd.code ) { - fprintf (stderr, "** command_cb: no code\n"); + DEBUG0 ("command_cb: no code\n"); return -1; } if ( !gpg->cmd.fnc ) { - fprintf (stderr, "** command_cb: no user cb\n"); + DEBUG0 ("command_cb: no user cb\n"); return -1; } value = gpg->cmd.fnc ( gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword ); if ( !value ) { - fprintf (stderr, "** command_cb: no data from user cb\n"); + DEBUG0 ("command_cb: no data from user cb\n"); gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); return -1; } value_len = strlen (value); if ( value_len+1 > length ) { - fprintf (stderr, "** command_cb: too much data from user cb\n"); + DEBUG0 ("command_cb: too much data from user cb\n"); gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); return -1; } @@ -1265,8 +1264,6 @@ command_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) buffer[value_len++] = '\n'; *nread = value_len; - fprintf (stderr, "** command_cb: leave (wrote `%.*s')\n", - (int)*nread-1, buffer); gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); gpg->cmd.code = 0; /* and sleep again until read_status will wake us up again */ diff --git a/gpgme/sema.h b/gpgme/sema.h new file mode 100644 index 00000000..db28a714 --- /dev/null +++ b/gpgme/sema.h @@ -0,0 +1,62 @@ +/* sema.h - definitions for semaphores + * Copyright (C) 2001 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef SEMA_H +#define SEMA_H + +struct critsect_s { + const char *name; + void *private; +}; + +#define DEFINE_GLOBAL_LOCK(name) \ + struct critsect_s name = { #name, NULL } +#define DEFINE_STATIC_LOCK(name) \ + static struct critsect_s name = { #name, NULL } + +#define DECLARE_LOCK(name) struct critsect_s name +#define INIT_LOCK(a) do { \ + (a).name = #a; \ + (a).private = NULL; \ + } while (0) +#define DESTROY_LOCK(name) _gpgme_sema_cs_destroy (&(name)) + + +#define LOCK(name) do { \ + _gpgme_sema_cs_enter ( &(name) );\ + } while (0) + +#define UNLOCK(name) do { \ + _gpgme_sema_cs_leave ( &(name) );\ + } while (0) + + +void _gpgme_sema_subsystem_init (void); +void _gpgme_sema_cs_enter ( struct critsect_s *s ); +void _gpgme_sema_cs_leave ( struct critsect_s *s ); +void _gpgme_sema_cs_destroy ( struct critsect_s *s ); + + +#endif /* SEMA_H */ + + + + + diff --git a/gpgme/sign.c b/gpgme/sign.c index cef099bb..5b6c61e8 100644 --- a/gpgme/sign.c +++ b/gpgme/sign.c @@ -33,12 +33,17 @@ struct sign_result_s { int no_passphrase; int okay; void *last_pw_handle; + char *userid_hint; + char *passphrase_info; + int bad_passphrase; }; void _gpgme_release_sign_result ( SignResult res ) { + xfree (res->userid_hint); + xfree (res->passphrase_info); xfree (res); } @@ -64,23 +69,41 @@ sign_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) case STATUS_EOF: break; + case STATUS_USERID_HINT: + xfree (ctx->result.sign->userid_hint); + if (!(ctx->result.sign->userid_hint = xtrystrdup (args)) ) + ctx->out_of_core = 1; + break; + + case STATUS_BAD_PASSPHRASE: + ctx->result.sign->bad_passphrase++; + break; + + case STATUS_GOOD_PASSPHRASE: + ctx->result.sign->bad_passphrase = 0; + break; + case STATUS_NEED_PASSPHRASE: case STATUS_NEED_PASSPHRASE_SYM: - fprintf (stderr, "Ooops: Need a passphrase - use the agent\n"); + xfree (ctx->result.sign->passphrase_info); + if (!(ctx->result.sign->passphrase_info = xtrystrdup (args)) ) + ctx->out_of_core = 1; break; case STATUS_MISSING_PASSPHRASE: - fprintf (stderr, "Missing passphrase - stop\n");; + DEBUG0 ("missing passphrase - stop\n"); ctx->result.sign->no_passphrase = 1; break; - case STATUS_SIG_CREATED: - /* fixme: we have no error return for multible signatures */ + case STATUS_SIG_CREATED: + /* fixme: we have no error return for multiple signatures */ ctx->result.sign->okay =1; + /* parse the line and save the information + * + */ break; default: - fprintf (stderr, "sign_status: code=%d not handled\n", code ); break; } } @@ -115,10 +138,32 @@ command_handler ( void *opaque, GpgStatusCode code, const char *key ) return NULL; if ( code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter") ) { - return c->passphrase_cb (c->passphrase_cb_value, - "Please enter your Friedrich Willem!", - &c->result.sign->last_pw_handle ); - } + const char *userid_hint = c->result.sign->userid_hint; + const char *passphrase_info = c->result.sign->passphrase_info; + int bad_passphrase = c->result.sign->bad_passphrase; + char *buf; + const char *s; + + c->result.sign->bad_passphrase = 0; + if (!userid_hint) + userid_hint = "[User ID hint missing]"; + if (!passphrase_info) + passphrase_info = "[passphrase info missing]"; + buf = xtrymalloc ( 20 + strlen (userid_hint) + + strlen (passphrase_info) + 3); + if (!buf) { + c->out_of_core = 1; + return NULL; + } + sprintf (buf, "%s\n%s\n%s", + bad_passphrase? "TRY_AGAIN":"ENTER", + userid_hint, passphrase_info ); + + s = c->passphrase_cb (c->passphrase_cb_value, + buf, &c->result.sign->last_pw_handle ); + xfree (buf); + return s; + } return NULL; } diff --git a/gpgme/signers.c b/gpgme/signers.c index a9da7da6..70c3a004 100644 --- a/gpgme/signers.c +++ b/gpgme/signers.c @@ -87,7 +87,7 @@ gpgme_signers_enum (const GpgmeCtx c, int seq ) int i; return_null_if_fail (c); - return_null_if_fail (seq<0); + return_null_if_fail (seq>=0); if (!c->signers) c->signers_size = 0; diff --git a/gpgme/util.h b/gpgme/util.h index 39e18e83..65bfa2b4 100644 --- a/gpgme/util.h +++ b/gpgme/util.h @@ -40,6 +40,57 @@ void _gpgme_free ( void *a ); #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) +#ifndef STR + #define STR(v) #v +#endif +#define STR2(v) STR(v) + + +void _gpgme_debug (int level, const char *format, ...); +void _gpgme_debug_begin ( void **helper, int level, const char *text); +int _gpgme_debug_enabled ( void **helper ); +void _gpgme_debug_add (void **helper, const char *format, ...); +void _gpgme_debug_end (void **helper, const char *text); + +#define DEBUG0(x) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x ) +#define DEBUG1(x,a) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__)": " x, (a) ) +#define DEBUG2(x,a,b) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b) ) +#define DEBUG3(x,a,b,c) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c) ) +#define DEBUG4(x,a,b,c,d) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c), (d) ) +#define DEBUG5(x,a,b,c,d,e) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e) ) +#define DEBUG6(x,a,b,c,d,e,f) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f) ) +#define DEBUG7(x,a,b,c,d,e,f,g) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g) ) +#define DEBUG8(x,a,b,c,d,e,f,g,h) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g), (h) ) +#define DEBUG9(x,a,b,c,d,e,f,g,h,i) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g), (h), (i) ) +#define DEBUG10(x,a,b,c,d,e,f,g,h,i,j) _gpgme_debug (1, __FILE__ ":" \ + STR2 (__LINE__) ": " x, (a), (b), (c), (d), (e), (f), (g), (h), (i), (j) ) + +#define DEBUG_BEGIN(y,x) _gpgme_debug_begin (&(y), 1, __FILE__ ":" \ + STR2 (__LINE__) ": " x ) +#define DEBUG_ENABLED(y) _gpgme_debug_enabled(&(y)) +#define DEBUG_ADD0(y,x) _gpgme_debug_add (&(y), (x), \ + ) +#define DEBUG_ADD1(y,x,a) _gpgme_debug_add (&(y), (x), \ + (a) ) +#define DEBUG_ADD2(y,x,a,b) _gpgme_debug_add (&(y), (x), \ + (a), (b) ) +#define DEBUG_ADD3(y,x,a,b,c) _gpgme_debug_add (&(y), (x), \ + (a), (b), (c) ) +#define DEBUG_ADD4(y,x,a,b,c,d) _gpgme_debug_add (&(y), (x), \ + (a), (b), (c), (d) ) +#define DEBUG_ADD5(y,x,a,b,c,d,e) _gpgme_debug_add (&(y), (x), \ + (a), (b), (c), (d), (e) ) +#define DEBUG_END(y,x) _gpgme_debug_end (&(y), (x) ) diff --git a/gpgme/verify.c b/gpgme/verify.c index fad5cd9b..cc203959 100644 --- a/gpgme/verify.c +++ b/gpgme/verify.c @@ -129,7 +129,6 @@ verify_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args ) default: /* ignore all other codes */ - fprintf (stderr, "verify_status: code=%d not handled\n", code ); break; } } diff --git a/gpgme/version.c b/gpgme/version.c index 0dfe4a36..f1c83970 100644 --- a/gpgme/version.c +++ b/gpgme/version.c @@ -27,6 +27,7 @@ #include "gpgme.h" #include "context.h" #include "rungpg.h" +#include "sema.h" #include "util.h" @@ -36,6 +37,18 @@ static char *tmp_engine_version; static const char *get_engine_info (void); +static void +do_subsystem_inits (void) +{ + static int done = 0; + + if (done) + return; + _gpgme_sema_subsystem_init (); +} + + + static const char* parse_version_number ( const char *s, int *number ) { @@ -108,13 +121,17 @@ compare_versions ( const char *my_version, const char *req_version ) * Check that the the version of the library is at minimum the requested one * and return the version string; return NULL if the condition is not * met. If a NULL is passed to this function, no check is done and - * the version string is simply returned. + * the version string is simply returned. It is a pretty good idea to + * run this function as soon as poossible, becuase it also intializes + * some subsystems. In a multithreaded environment if should be called + * before the first thread is created. * * Return value: The version string or NULL **/ const char * gpgme_check_version ( const char *req_version ) { + do_subsystem_inits (); return compare_versions ( VERSION, req_version ); } @@ -134,6 +151,7 @@ gpgme_check_version ( const char *req_version ) const char * gpgme_get_engine_info () { + do_subsystem_inits (); return get_engine_info (); } diff --git a/gpgme/w32-io.c b/gpgme/w32-io.c index 9df6c981..c16e4415 100644 --- a/gpgme/w32-io.c +++ b/gpgme/w32-io.c @@ -34,17 +34,9 @@ #include "syshdr.h" #include "util.h" +#include "sema.h" #include "io.h" -#define DEBUG_SELECT_ENABLED 1 - -#if DEBUG_SELECT_ENABLED -# define DEBUG_SELECT(a) fprintf a -#else -# define DEBUG_SELECT(a) do { } while(0) -#endif - - /* * We assume that a HANDLE can be represented by an int which should be true @@ -58,19 +50,232 @@ #define pid_to_handle(a) ((HANDLE)(a)) #define handle_to_pid(a) ((int)(a)) +#define READBUF_SIZE 4096 + +struct reader_context_s { + HANDLE file_hd; + HANDLE thread_hd; + DECLARE_LOCK (mutex); + + int eof; + int error; + int error_code; + + HANDLE have_data_ev; /* manually reset */ + int have_data_flag; /* FIXME: is there another way to check whether + it has been signaled? */ + HANDLE have_space_ev; /* auto reset */ + size_t readpos, writepos; + char buffer[READBUF_SIZE]; +}; + + +#define MAX_READERS 20 +static struct { + volatile int used; + int fd; + struct reader_context_s *context; +} reader_table[MAX_READERS]; +static int reader_table_size= MAX_READERS; +DEFINE_STATIC_LOCK (reader_table_lock); + +static HANDLE +set_synchronize (HANDLE h) +{ + HANDLE tmp; + + /* For NT we have to set the sync flag. It seems that the only + * way to do it is by duplicating the handle. Tsss.. */ + if (!DuplicateHandle( GetCurrentProcess(), h, + GetCurrentProcess(), &tmp, + SYNCHRONIZE, FALSE, 0 ) ) { + DEBUG1 ("** Set SYNCRONIZE failed: ec=%d\n", (int)GetLastError()); + } + else { + CloseHandle (h); + h = tmp; + } + return h; +} + + + +static DWORD CALLBACK +reader (void *arg) +{ + struct reader_context_s *c = arg; + int nbytes; + DWORD nread; + + DEBUG2 ("reader thread %p for file %p started", c->thread_hd, c->file_hd ); + for (;;) { + LOCK (c->mutex); + /* leave a one byte gap so that we can see wheter it is empty or full*/ + if ((c->writepos + 1) % READBUF_SIZE == c->readpos) { + /* wait for space */ + ResetEvent (c->have_space_ev); + UNLOCK (c->mutex); + DEBUG1 ("reader thread %p: waiting for space ...", c->thread_hd ); + WaitForSingleObject (c->have_space_ev, INFINITE); + DEBUG1 ("reader thread %p: got space", c->thread_hd ); + LOCK (c->mutex); + } + nbytes = (c->readpos + READBUF_SIZE - c->writepos-1) % READBUF_SIZE; + if ( nbytes > READBUF_SIZE - c->writepos ) + nbytes = READBUF_SIZE - c->writepos; + UNLOCK (c->mutex); + + DEBUG2 ("reader thread %p: reading %d bytes", c->thread_hd, nbytes ); + if ( !ReadFile ( c->file_hd, + c->buffer+c->writepos, nbytes, &nread, NULL) ) { + c->error = 1; + c->error_code = (int)GetLastError (); + DEBUG2 ("reader thread %p: read error: ec=%d", + c->thread_hd, c->error_code ); + break; + } + if ( !nread ) { + c->eof = 1; + DEBUG1 ("reader thread %p: got eof", c->thread_hd ); + break; + } + DEBUG2 ("reader thread %p: got %d bytes", c->thread_hd, (int)nread ); + + LOCK (c->mutex); + c->writepos = (c->writepos + nread) % READBUF_SIZE; + c->have_data_flag = 1; + SetEvent (c->have_data_ev); + UNLOCK (c->mutex); + } + DEBUG1 ("reader thread %p ended", c->thread_hd ); + + return 0; +} + + +static struct reader_context_s * +create_reader (HANDLE fd) +{ + struct reader_context_s *c; + SECURITY_ATTRIBUTES sec_attr; + DWORD tid; + + DEBUG1 ("creating new read thread for file handle %p", fd ); + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + c = xtrycalloc (1, sizeof *c ); + if (!c) + return NULL; + + c->file_hd = fd; + c->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + c->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL); + if (!c->have_data_ev || !c->have_space_ev) { + DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ()); + if (c->have_data_ev) + CloseHandle (c->have_data_ev); + if (c->have_space_ev) + CloseHandle (c->have_space_ev); + xfree (c); + return NULL; + } + + c->have_data_ev = set_synchronize (c->have_data_ev); + INIT_LOCK (c->mutex); + + c->thread_hd = CreateThread (&sec_attr, 0, reader, c, 0, &tid ); + if (!c->thread_hd) { + DEBUG1 ("** failed to create reader thread: ec=%d\n", + (int)GetLastError ()); + DESTROY_LOCK (c->mutex); + if (c->have_data_ev) + CloseHandle (c->have_data_ev); + if (c->have_space_ev) + CloseHandle (c->have_space_ev); + xfree (c); + return NULL; + } + + return c; +} + + +/* + * Find a reader context or create a new one + * Note that the reader context will last until a io_close. + */ +static struct reader_context_s * +find_reader (int fd, int start_it) +{ + int i; + + for (i=0; i < reader_table_size ; i++ ) { + if ( reader_table[i].used && reader_table[i].fd == fd ) + return reader_table[i].context; + } + if (!start_it) + return NULL; + + LOCK (reader_table_lock); + for (i=0; i < reader_table_size; i++ ) { + if (!reader_table[i].used) { + reader_table[i].fd = fd; + reader_table[i].context = create_reader (fd_to_handle (fd)); + reader_table[i].used = 1; + UNLOCK (reader_table_lock); + return reader_table[i].context; + } + } + UNLOCK (reader_table_lock); + return NULL; +} + + int _gpgme_io_read ( int fd, void *buffer, size_t count ) { - int nread = 0; - HANDLE h = fd_to_handle (fd); + int nread; + struct reader_context_s *c = find_reader (fd,1); - DEBUG_SELECT ((stderr,"** fd %d: about to read %d bytes\n", fd, (int)count )); - if ( !ReadFile ( h, buffer, count, &nread, NULL) ) { - fprintf (stderr, "** ReadFile failed: ec=%d\n", (int)GetLastError ()); + DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count ); + if ( !c ) { + DEBUG0 ( "no reader thread\n"); return -1; } - DEBUG_SELECT ((stderr,"** fd %d: got %d bytes\n", fd, nread )); + + LOCK (c->mutex); + if (c->readpos == c->writepos) { /* no data avail */ + UNLOCK (c->mutex); + DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd); + WaitForSingleObject (c->have_data_ev, INFINITE); + DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd); + LOCK (c->mutex); + if (c->readpos == c->writepos && !c->eof && !c->error) { + UNLOCK (c->mutex); + if (c->eof) + return 0; + return -1; + } + } + + nread = c->readpos < c->writepos? c->writepos - c->readpos + : READBUF_SIZE - c->readpos; + if (nread > count) + nread = count; + memcpy (buffer, c->buffer+c->readpos, nread); + c->readpos = (c->readpos + nread) % READBUF_SIZE; + if (c->readpos == c->writepos) { + c->have_data_flag = 0; + ResetEvent (c->have_data_ev); + } + if (nread) + SetEvent (c->have_space_ev); + UNLOCK (c->mutex); + + DEBUG2 ("fd %d: got %d bytes\n", fd, nread ); return nread; } @@ -79,17 +284,18 @@ _gpgme_io_read ( int fd, void *buffer, size_t count ) int _gpgme_io_write ( int fd, const void *buffer, size_t count ) { - int nwritten; + DWORD nwritten; HANDLE h = fd_to_handle (fd); - DEBUG_SELECT ((stderr,"** fd %d: about to write %d bytes\n", fd, (int)count )); + DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count ); if ( !WriteFile ( h, buffer, count, &nwritten, NULL) ) { - fprintf (stderr, "** WriteFile failed: ec=%d\n", (int)GetLastError ()); + DEBUG1 ("WriteFile failed: ec=%d\n", (int)GetLastError ()); return -1; } - DEBUG_SELECT ((stderr,"** fd %d: wrote %d bytes\n", fd, nwritten )); + DEBUG2 ("fd %d: wrote %d bytes\n", + fd, (int)nwritten ); - return nwritten; + return (int)nwritten; } int @@ -110,8 +316,7 @@ _gpgme_io_pipe ( int filedes[2], int inherit_idx ) if (!DuplicateHandle( GetCurrentProcess(), r, GetCurrentProcess(), &h, 0, TRUE, DUPLICATE_SAME_ACCESS ) ) { - fprintf (stderr, "** DuplicateHandle failed: ec=%d\n", - (int)GetLastError()); + DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError()); CloseHandle (r); CloseHandle (w); return -1; @@ -124,8 +329,7 @@ _gpgme_io_pipe ( int filedes[2], int inherit_idx ) if (!DuplicateHandle( GetCurrentProcess(), w, GetCurrentProcess(), &h, 0, TRUE, DUPLICATE_SAME_ACCESS ) ) { - fprintf (stderr, "** DuplicateHandle failed: ec=%d\n", - (int)GetLastError()); + DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError()); CloseHandle (r); CloseHandle (w); return -1; @@ -136,8 +340,8 @@ _gpgme_io_pipe ( int filedes[2], int inherit_idx ) filedes[0] = handle_to_fd (r); filedes[1] = handle_to_fd (w); - DEBUG_SELECT ((stderr,"** create pipe %p %p %d %d inherit=%d\n", r, w, - filedes[0], filedes[1], inherit_idx )); + DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w, + filedes[0], filedes[1], inherit_idx ); return 0; } @@ -147,9 +351,11 @@ _gpgme_io_close ( int fd ) if ( fd == -1 ) return -1; - DEBUG_SELECT ((stderr,"** closing handle for fd %d\n", fd)); + DEBUG1 ("** closing handle for fd %d\n", fd); + /* fixme: destroy thread */ + if ( !CloseHandle (fd_to_handle (fd)) ) { - fprintf (stderr, "** CloseHandle for fd %d failed: ec=%d\n", + DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n", fd, (int)GetLastError ()); return -1; } @@ -230,16 +436,16 @@ _gpgme_io_spawn ( const char *path, char **argv, for (i=0; fd_child_list[i].fd != -1; i++ ) { if (fd_child_list[i].dup_to == 0 ) { si.hStdInput = fd_to_handle (fd_child_list[i].fd); - DEBUG_SELECT ((stderr,"** using %d for stdin\n", fd_child_list[i].fd )); + DEBUG1 ("using %d for stdin", fd_child_list[i].fd ); duped_stdin=1; } else if (fd_child_list[i].dup_to == 1 ) { si.hStdOutput = fd_to_handle (fd_child_list[i].fd); - DEBUG_SELECT ((stderr,"** using %d for stdout\n", fd_child_list[i].fd )); + DEBUG1 ("using %d for stdout", fd_child_list[i].fd ); } else if (fd_child_list[i].dup_to == 2 ) { si.hStdError = fd_to_handle (fd_child_list[i].fd); - DEBUG_SELECT ((stderr,"** using %d for stderr\n", fd_child_list[i].fd )); + DEBUG1 ("using %d for stderr", fd_child_list[i].fd ); duped_stderr = 1; } } @@ -250,7 +456,7 @@ _gpgme_io_spawn ( const char *path, char **argv, memset (&sa, 0, sizeof sa ); sa.nLength = sizeof sa; sa.bInheritHandle = TRUE; - hnul = CreateFile ( "/dev/nul", + hnul = CreateFile ( "nul", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sa, @@ -258,27 +464,23 @@ _gpgme_io_spawn ( const char *path, char **argv, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hnul == INVALID_HANDLE_VALUE ) { - fprintf (stderr,"can't open `/dev/nul': ec=%d\n", - (int)GetLastError () ); + DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ()); xfree (arg_string); return -1; } /* Make sure that the process has a connected stdin */ if ( !duped_stdin ) { si.hStdInput = hnul; - DEBUG_SELECT ((stderr,"** using %d for stdin\n", (int)hnul )); + DEBUG1 ("using %d for dummy stdin", (int)hnul ); } /* We normally don't want all the normal output */ if ( !duped_stderr ) { - if (!debug_me) { - si.hStdError = hnul; - DEBUG_SELECT ((stderr,"** using %d for stderr\n", (int)hnul )); - } + si.hStdError = hnul; + DEBUG1 ("using %d for dummy stderr", (int)hnul ); } } - DEBUG_SELECT ((stderr,"** CreateProcess ...\n")); - DEBUG_SELECT ((stderr,"** args=`%s'\n", arg_string)); + DEBUG1 ("CreateProcess, args=`%s'", arg_string); cr_flags |= CREATE_SUSPENDED; if ( !CreateProcessA (GPG_PATH, arg_string, @@ -291,8 +493,7 @@ _gpgme_io_spawn ( const char *path, char **argv, &si, /* startup information */ &pi /* returns process information */ ) ) { - fprintf (stderr, "** CreateProcess failed: ec=%d\n", - (int) GetLastError ()); + DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ()); xfree (arg_string); return -1; } @@ -300,31 +501,28 @@ _gpgme_io_spawn ( const char *path, char **argv, /* close the /dev/nul handle if used */ if (hnul != INVALID_HANDLE_VALUE ) { if ( !CloseHandle ( hnul ) ) - fprintf (stderr, "** CloseHandle(hnul) failed: ec=%d\n", - (int)GetLastError()); + DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError()); } /* Close the other ends of the pipes */ for (i=0; fd_parent_list[i].fd != -1; i++ ) { - DEBUG_SELECT ((stderr,"** Closing fd %d\n", fd_parent_list[i].fd )); + DEBUG1 ("Closing fd %d\n", fd_parent_list[i].fd ); if ( !CloseHandle ( fd_to_handle (fd_parent_list[i].fd) ) ) - fprintf (stderr, "** CloseHandle failed: ec=%d\n", - (int)GetLastError()); + DEBUG1 ("CloseHandle failed: ec=%d", (int)GetLastError()); } - DEBUG_SELECT ((stderr,"** CreateProcess ready\n" - "** hProcess=%p hThread=%p\n" - "** dwProcessID=%d dwThreadId=%d\n", - pi.hProcess, pi.hThread, - (int) pi.dwProcessId, (int) pi.dwThreadId)); + DEBUG4 ("CreateProcess ready\n" + "- hProcess=%p hThread=%p\n" + "- dwProcessID=%d dwThreadId=%d\n", + pi.hProcess, pi.hThread, + (int) pi.dwProcessId, (int) pi.dwThreadId); if ( ResumeThread ( pi.hThread ) < 0 ) { - fprintf (stderr, "** ResumeThread failed: ec=%d\n", - (int)GetLastError ()); + DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ()); } if ( !CloseHandle (pi.hThread) ) { - fprintf (stderr, "** CloseHandle of thread failed: ec=%d\n", + DEBUG1 ("CloseHandle of thread failed: ec=%d\n", (int)GetLastError ()); } @@ -345,30 +543,29 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal ) code = WaitForSingleObject ( proc, hang? INFINITE : 0 ); switch (code) { case WAIT_FAILED: - fprintf (stderr, "** WFSO pid=%d failed: %d\n", - (int)pid, (int)GetLastError () ); + DEBUG2 ("WFSO pid=%d failed: %d\n", (int)pid, (int)GetLastError () ); break; case WAIT_OBJECT_0: if (!GetExitCodeProcess (proc, &exc)) { - fprintf (stderr, "** GECP pid=%d failed: ec=%d\n", - (int)pid, (int)GetLastError () ); + DEBUG2 ("** GECP pid=%d failed: ec=%d\n", + (int)pid, (int)GetLastError () ); *r_status = 4; } else { - DEBUG_SELECT ((stderr,"** GECP pid=%d exit code=%d\n", - (int)pid, exc)); + DEBUG2 ("GECP pid=%d exit code=%d\n", (int)pid, exc); *r_status = exc; } ret = 1; break; case WAIT_TIMEOUT: - DEBUG_SELECT ((stderr,"** WFSO pid=%d timed out\n", (int)pid)); + if (hang) + DEBUG1 ("WFSO pid=%d timed out\n", (int)pid); break; default: - fprintf (stderr, "** WFSO pid=%d returned %d\n", (int)pid, code ); + DEBUG2 ("WFSO pid=%d returned %d\n", (int)pid, code ); break; } return ret; @@ -384,40 +581,50 @@ _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal ) int _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) { -#if 0 /* We can't use WFMO becaus a pipe handle is not a suitable object */ +#if 1 HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; int code, nwait; int i, any, any_write; int count; + void *dbg_help; restart: - DEBUG_SELECT ((stderr, "gpgme:select on [ ")); + DEBUG_BEGIN (dbg_help, "select on [ "); any = any_write = 0; nwait = 0; for ( i=0; i < nfds; i++ ) { if ( fds[i].fd == -1 ) continue; - if ( fds[i].for_read || fds[i].for_write ) { + if ( fds[i].for_read ) { if ( nwait >= DIM (waitbuf) ) { - DEBUG_SELECT ((stderr,stderr, "oops ]\n" )); - fprintf (stderr, "** Too many objects for WFMO!\n" ); + DEBUG_END (dbg_help, "oops ]"); + DEBUG0 ("Too many objects for WFMO!" ); return -1; } else { - if ( fds[i].for_read ) - waitbuf[nwait++] = fd_to_handle (fds[i].fd); - DEBUG_SELECT ((stderr, "%c%d ", - fds[i].for_read? 'r':'w',fds[i].fd )); + if ( fds[i].for_read ) { + struct reader_context_s *c = find_reader (fds[i].fd,1); + + if (!c) { + DEBUG1 ("no reader thread for fd %d", fds[i].fd); + } + else { + waitbuf[nwait++] = c->have_data_ev; + } + } + DEBUG_ADD2 (dbg_help, "%c%d ", + fds[i].for_read? 'r':'w',fds[i].fd ); any = 1; } } fds[i].signaled = 0; } - DEBUG_SELECT ((stderr, "]\n" )); + DEBUG_END (dbg_help, "]"); if (!any) return 0; count = 0; + /* no way to see whether a handle is ready for writing, signal all */ for ( i=0; i < nfds; i++ ) { if ( fds[i].fd == -1 ) continue; @@ -428,64 +635,7 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) } } code = WaitForMultipleObjects ( nwait, waitbuf, 0, any_write? 0:1000); - if (code == WAIT_FAILED ) { - int le = (int)GetLastError (); - if ( le == ERROR_INVALID_HANDLE || le == ERROR_INVALID_EVENT_COUNT ) { - any = 0; - for ( i=0; i < nfds; i++ ) { - if ( fds[i].fd == -1 ) - continue; - if ( fds[i].for_read /*|| fds[i].for_write*/ ) { - int navail; - if (PeekNamedPipe (fd_to_handle (fds[i].fd), - NULL, 0, NULL, - &navail, NULL) && navail ) { - fds[i].signaled = 1; - any = 1; - count++; - } - } - } - if (any) - return count; - /* find that handle and remove it from the list*/ - for (i=0; i < nwait; i++ ) { - code = WaitForSingleObject ( waitbuf[i], NULL ); - if (!code) { - int k, j = handle_to_fd (waitbuf[i]); - - fprintf (stderr, "** handle meanwhile signaled %d\n", j); - for (k=0 ; k < nfds; k++ ) { - if ( fds[k].fd == j ) { - fds[k].signaled = 1; - count++; - return count; - } - } - fprintf (stderr, "** oops, or not???\n"); - } - if ( GetLastError () == ERROR_INVALID_HANDLE) { - int k, j = handle_to_fd (waitbuf[i]); - - fprintf (stderr, "** WFMO invalid handle %d removed\n", j); - for (k=0 ; k < nfds; i++ ) { - if ( fds[k].fd == j ) { - fds[k].for_read = fds[k].for_write = 0; - goto restart; - } - } - fprintf (stderr, "** oops, or not???\n"); - } - } - } - - fprintf (stderr, "** WFMO failed: %d\n", le ); - count = -1; - } - else if ( code == WAIT_TIMEOUT ) { - fprintf (stderr, "** WFMO timed out\n" ); - } - else if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) { + if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) { /* This WFMO is a really silly function: It does return either * the index of the signaled object or if 2 objects have been * signalled at the same time, the index of the object with the @@ -503,13 +653,32 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) } } if (!any) { - fprintf (stderr, - "** Oops: No signaled objects found after WFMO\n"); + DEBUG0 ("Oops: No signaled objects found after WFMO"); count = -1; } } + else if ( code == WAIT_TIMEOUT ) { + DEBUG0 ("WFMO timed out\n" ); + } + else if (code == WAIT_FAILED ) { + int le = (int)GetLastError (); + if ( le == ERROR_INVALID_HANDLE ) { + int k, j = handle_to_fd (waitbuf[i]); + + DEBUG1 ("WFMO invalid handle %d removed\n", j); + for (k=0 ; k < nfds; i++ ) { + if ( fds[k].fd == j ) { + fds[k].for_read = fds[k].for_write = 0; + goto restart; + } + } + DEBUG0 (" oops, or not???\n"); + } + DEBUG1 ("WFMO failed: %d\n", le ); + count = -1; + } else { - fprintf (stderr, "** WFMO returned %d\n", code ); + DEBUG1 ("WFMO returned %d\n", code ); count = -1; } @@ -552,15 +721,14 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) continue; if ( fds[i].for_read ) { int navail; - + if ( !PeekNamedPipe (fd_to_handle (fds[i].fd), NULL, 0, NULL, &navail, NULL) ) { - fprintf (stderr, "** select: PeekFile failed: ec=%d\n", - (int)GetLastError ()); + DEBUG1 ("select: PeekFile failed: ec=%d\n", + (int)GetLastError ()); } else if ( navail ) { - /*fprintf (stderr, "** fd %d has %d bytes to read\n", - fds[i].fd, navail );*/ + DEBUG2 ("fd %d has %d bytes to read\n", fds[i].fd, navail ); fds[i].signaled = 1; count++; } diff --git a/gpgme/w32-sema.c b/gpgme/w32-sema.c new file mode 100644 index 00000000..3b905c91 --- /dev/null +++ b/gpgme/w32-sema.c @@ -0,0 +1,123 @@ +/* w32-sema.c + * Copyright (C) 2001 Werner Koch (dd9jn) + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include +#ifdef HAVE_DOSISH_SYSTEM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "syshdr.h" + +#include "util.h" +#include "sema.h" + +static void +sema_fatal (const char *text) +{ + fprintf (stderr, "sema.c: %s\n", text); + abort (); +} + + +static void +critsect_init (struct critsect_s *s) +{ + CRITICAL_SECTION *mp; + static CRITICAL_SECTION init_lock; + static int initialized; + + if (!initialized) { + /* the very first time we call this function, we assume that only + * one thread is running, so that we can bootstrap the semaphore code + */ + InitializeCriticalSection (&init_lock); + initialized = 1; + } + if (!s) + return; /* we just want to initialize ourself */ + + /* first test whether it is really not initialized */ + EnterCriticalSection (&init_lock); + if ( s->private ) { + LeaveCriticalSection (&init_lock); + return; + } + /* now init it */ + mp = xtrymalloc ( sizeof *mp ); + if (!mp) { + LeaveCriticalSection (&init_lock); + sema_fatal ("out of core while creating critical section lock"); + } + InitializeCriticalSection (mp); + s->private = mp; + LeaveCriticalSection (&init_lock); +} + +void +_gpgme_sema_subsystem_init () +{ + /* fixme: we should check that there is only one thread running */ + critsect_init (NULL); +} + + +void +_gpgme_sema_cs_enter ( struct critsect_s *s ) +{ + if (!s->private) + critsect_init (s); + EnterCriticalSection ( (CRITICAL_SECTION*)s->private ); +} + +void +_gpgme_sema_cs_leave (struct critsect_s *s) +{ + if (!s->private) + critsect_init (s); + LeaveCriticalSection ( (CRITICAL_SECTION*)s->private ); +} + +void +_gpgme_sema_cs_destroy ( struct critsect_s *s ) +{ + if (s && s->private) { + DeleteCriticalSection ((CRITICAL_SECTION*)s->private); + xfree (s->private); + s->private = NULL; + } +} + + + +#endif /*HAVE_DOSISH_SYSTEM*/ + + + + + diff --git a/tests/t-keylist.c b/tests/t-keylist.c index 978174f3..fb7b79d5 100644 --- a/tests/t-keylist.c +++ b/tests/t-keylist.c @@ -68,6 +68,7 @@ doit ( GpgmeCtx ctx, const char *pattern ) s = gpgme_key_get_string_attr (key, GPGME_ATTR_COMMENT, NULL, i ); printf ("\n", i, s ); } + printf ("\n", key ); gpgme_key_release (key); }