Add better debug printing. Use reader threads for W32

This commit is contained in:
Werner Koch 2001-01-30 11:01:41 +00:00
parent f2be414251
commit e318473836
29 changed files with 1002 additions and 244 deletions

10
TODO Normal file
View File

@ -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.

View File

@ -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

View File

@ -1,3 +1,18 @@
2001-01-30 Werner Koch <wk@gnupg.org>
* 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 <wk@gnupg.org>
* data.c (_gpgme_data_release_and_return_string): Fixed string
termination.
2001-01-22 Werner Koch <wk@gnupg.org>
* delete.c: New.

View File

@ -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

View File

@ -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.
**/

156
gpgme/debug.c Normal file
View File

@ -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 <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#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;
}

View File

@ -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;
}

View File

@ -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 );
}

View File

@ -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 */
}

View File

@ -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 */
}

View File

@ -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;

View File

@ -22,7 +22,7 @@
#define GPGME_H
#ifdef _MSC_VER
typedef long off_t
typedef long off_t;
#else
# include <sys/types.h>
#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 {

View File

@ -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 */

View File

@ -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, "<GnupgKeyblock>\n"
" <mainkey>\n" );
if ( key->secret )
_gpgme_data_append_string ( d, " <secret/>\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, " <subkey>\n");
if ( k->secret )
_gpgme_data_append_string ( d, " <secret/>\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;
}

View File

@ -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 );

View File

@ -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;

View File

@ -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 --*/

View File

@ -33,17 +33,9 @@
#include <fcntl.h>
#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++ ) {

70
gpgme/posix-sema.c Normal file
View File

@ -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 <config.h>
#ifndef HAVE_DOSISH_SYSTEM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#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*/

View File

@ -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 */

62
gpgme/sema.h Normal file
View File

@ -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 */

View File

@ -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
* <type> <pubkey algo> <hash algo> <class> <timestamp> <key fpr>
*/
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;
}

View File

@ -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;

View File

@ -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) )

View File

@ -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;
}
}

View File

@ -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 ();
}

View File

@ -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++;
}

123
gpgme/w32-sema.c Normal file
View File

@ -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 <config.h>
#ifdef HAVE_DOSISH_SYSTEM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <windows.h>
#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*/

View File

@ -68,6 +68,7 @@ doit ( GpgmeCtx ctx, const char *pattern )
s = gpgme_key_get_string_attr (key, GPGME_ATTR_COMMENT, NULL, i );
printf ("<!-- comment.%d=%s -->\n", i, s );
}
printf ("<!-- End key object (%p) -->\n", key );
gpgme_key_release (key);
}