dnl
dnl Checks for library functions
dnl
+AC_CHECK_FUNCS(stpcpy)
dnl
key.c key.h \
keylist.c \
rungpg.c rungpg.h status-table.h \
+ io.h posix-io.c w32-io.c \
gpgme.c version.c errors.c
+
+
+
|| ((a) >= 'f' && (a) <= 'f') )
+/**
+ * gpgme_data_new:
+ * @r_dh: returns the new data object
+ *
+ * Create a new data object without any content.
+ *
+ * Return value: An error value or 0 on success
+ **/
GpgmeError
gpgme_data_new ( GpgmeData *r_dh )
{
return 0;
}
+/**
+ * gpgme_data_new_from_file:
+ * @r_dh: returns the new data object
+ * @fname: filename
+ * @copy: Flag, whether the file should be copied.
+ *
+ * Create a new data object and initialize it with the content of
+ * the file @file. If @copy is %True the file is immediately read in
+ * adn closed. @copy of %False is not yet supportted.
+ *
+ * Return value: An error code or 0 on success. If the error code is
+ * %GPGME_File_Error, the OS error code is held in %errno.
+ **/
GpgmeError
gpgme_data_new_from_file ( GpgmeData *r_dh, const char *fname, int copy )
{
return val;
}
+/**
+ * gpgme_data_release_and_get_mem:
+ * @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.
+ *
+ * Return value: a pointer to an allocated buffer of length @r_len.
+ **/
char *
gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len )
{
}
+/**
+ * gpgme_data_get_type:
+ * @dh: the data object
+ *
+ * Get the type of the data object.
+ * Data types are prefixed with %GPGME_DATA_TYPE_
+ *
+ * Return value: the data type
+ **/
GpgmeDataType
gpgme_data_get_type ( GpgmeData dh )
{
return dh->mode;
}
+/**
+ * gpgme_data_rewind:
+ * @dh: the data object
+ *
+ * Prepare the data object in a way, that a gpgme_data_read() does start
+ * at the beginning of the data. This has to be done for all types
+ * of data objects.
+ *
+ * Return value: An error code or 0 on success
+ **/
GpgmeError
gpgme_data_rewind ( GpgmeData dh )
{
return 0;
}
+/**
+ * gpgme_data_read:
+ * @dh: the data object
+ * @buffer: A buffer
+ * @length: The length of that bufer
+ * @nread: Returns the number of bytes actually read.
+ *
+ * Copy data from the current read position (which may be set by
+ * gpgme_data_rewind()) to the supplied @buffer, max. @length bytes
+ * are copied and the actual number of bytes are returned in @nread.
+ * If there are no more bytes available %GPGME_EOF is returned and @nread
+ * is set to 0.
+ *
+ * Return value: An errocodee or 0 on success, EOF is indcated by the
+ * error code GPGME_EOF.
+ **/
GpgmeError
gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
{
}
+/**
+ * gpgme_get_notation:
+ * @c: the context
+ *
+ * If there is notation data available from the last signature check, this
+ * function may be used to return this notation data as a string. The string
+ * is an XML represantaton of that data embedded in a %<notation> container.
+ *
+ * Return value: An XML string or NULL if no notation data is available.
+ **/
char *
gpgme_get_notation ( GpgmeCtx c )
{
}
+/**
+ * gpgme_set_armor:
+ * @c: the contect
+ * @yes: boolean value to set or clear that flag
+ *
+ * Enable or disable the use of an ascii armor for all output.
+ **/
void
gpgme_set_armor ( GpgmeCtx c, int yes )
{
c->use_armor = yes;
}
+/**
+ * gpgme_set_textmode:
+ * @c: the context
+ * @yes: boolean flag whether textmode should be enabled
+ *
+ * Enable or disable the use of the special textmode. Textmode is for example
+ * used for MIME (RFC2015) signatures
+ **/
void
gpgme_set_textmode ( GpgmeCtx c, int yes )
{
+
+
--- /dev/null
+/* io.h - I/O functions
+ * Copyright (C) 2000 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 IO_H
+#define IO_H
+
+#include "types.h"
+
+struct spawn_fd_item_s {
+ int fd;
+ int dup_to;
+};
+
+
+struct io_select_fd_s {
+ int fd;
+ int for_read;
+ int for_write;
+ int signaled;
+ void *opaque;
+};
+
+
+/* These function are either defined in posix-io.c or w32-io.c */
+
+int _gpgme_io_read ( int fd, void *buffer, size_t count );
+int _gpgme_io_write ( int fd, const void *buffer, size_t count );
+int _gpgme_io_pipe ( int filedes[2] );
+int _gpgme_io_set_nonblocking ( int fd );
+pid_t _gpgme_io_spawn ( const char *path, char **argv,
+ struct spawn_fd_item_s *fd_child_list,
+ struct spawn_fd_item_s *fd_parent_list );
+int _gpgme_io_waitpid ( pid_t pid, int hang, int *r_status, int *r_signal );
+int _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds);
+
+
+
+
+
+
+
+#endif /* IO_H */
+
+
+
+
+
--- /dev/null
+/* posix-io.c - Posix I/O functions
+ * Copyright (C) 2000 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 <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.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 )
+{
+ int nread;
+
+ do {
+ nread = read (fd, buffer, count);
+ } while (nread == -1 && errno == EINTR );
+ return nread;
+}
+
+
+int
+_gpgme_io_write ( int fd, const void *buffer, size_t count )
+{
+ int nwritten;
+
+ do {
+ nwritten = write (fd, buffer, count);
+ } while (nwritten == -1 && errno == EINTR );
+ return nwritten;
+}
+
+int
+_gpgme_io_pipe ( int filedes[2] )
+{
+ return pipe ( filedes );
+}
+
+
+int
+_gpgme_io_set_nonblocking ( int fd )
+{
+ int flags;
+
+ flags = fcntl (fd, F_GETFL, 0);
+ if (flags == -1)
+ return -1;
+ flags |= O_NONBLOCK;
+ return fcntl (fd, F_SETFL, flags);
+}
+
+
+pid_t
+_gpgme_io_spawn ( const char *path, char **argv,
+ struct spawn_fd_item_s *fd_child_list,
+ struct spawn_fd_item_s *fd_parent_list )
+{
+ pid_t pid;
+ int i;
+
+ pid = fork ();
+ if (pid == -1)
+ return -1;
+
+ if ( !pid ) { /* child */
+ int duped_stdin = 0;
+ int duped_stderr = 0;
+
+ /* first close all fds which will not be duped */
+ for (i=0; fd_child_list[i].fd != -1; i++ ) {
+ if (fd_child_list[i].dup_to == -1 )
+ close (fd_child_list[i].fd);
+ }
+ /* and now dup and close the rest */
+ for (i=0; fd_child_list[i].fd != -1; i++ ) {
+ 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));
+ _exit (8);
+ }
+ if ( fd_child_list[i].dup_to == 0 )
+ duped_stdin=1;
+ if ( fd_child_list[i].dup_to == 2 )
+ duped_stderr=1;
+ close (fd_child_list[i].fd);
+ }
+ }
+
+ if( !duped_stdin || !duped_stderr ) {
+ int fd = open ( "/dev/null", O_RDONLY );
+ if ( fd == -1 ) {
+ fprintf (stderr,"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",
+ 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);
+ }
+ }
+ }
+ close (fd);
+ }
+
+ 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 );
+ _exit (8);
+ } /* end child */
+
+ /* .dup_to is not used in the parent list */
+ for (i=0; fd_parent_list[i].fd != -1; i++ ) {
+ close (fd_parent_list[i].fd);
+ }
+
+ return pid;
+}
+
+
+int
+_gpgme_io_waitpid ( pid_t pid, int hang, int *r_status, int *r_signal )
+{
+ int status;
+
+ *r_status = 0;
+ *r_signal = 0;
+ if ( waitpid ( pid, &status, hang? 0 : WNOHANG ) == pid ) {
+ if ( WIFSIGNALED (status) ) {
+ *r_status = 4; /* Need some value here */
+ *r_signal = WTERMSIG (status);
+ }
+ else if ( WIFEXITED (status) ) {
+ *r_status = WEXITSTATUS (status);
+ }
+ else {
+ *r_status = 4; /* oops */
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Select on the list of fds.
+ * Returns: -1 = error
+ * 0 = timeout or nothing to select
+ * >0 = number of signaled fds
+ */
+int
+_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
+{
+ static fd_set readfds;
+ static fd_set writefds;
+ int any, i, max_fd, n, count;
+ struct timeval timeout = { 1, 0 }; /* Use a one second timeout */
+
+ FD_ZERO ( &readfds );
+ FD_ZERO ( &writefds );
+ max_fd = 0;
+
+ DEBUG_SELECT ((stderr, "gpgme:select on [ "));
+ any = 0;
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( fds[i].for_read ) {
+ assert ( !FD_ISSET ( fds[i].fd, &readfds ) );
+ 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 ));
+ any = 1;
+ }
+ else if ( fds[i].for_write ) {
+ assert ( !FD_ISSET ( fds[i].fd, &writefds ) );
+ 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 ));
+ any = 1;
+ }
+ fds[i].signaled = 0;
+ }
+ DEBUG_SELECT ((stderr, "]\n" ));
+ if ( !any )
+ return 0;
+
+ do {
+ 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) );
+ 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 );
+ }
+ fprintf (stderr, "]\n" );
+#endif
+
+ /* n is used to optimize it a little bit */
+ for ( n=count, i=0; i < nfds && n ; i++ ) {
+ if ( fds[i].fd == -1 )
+ ;
+ else if ( fds[i].for_read ) {
+ if ( FD_ISSET ( fds[i].fd, &readfds ) ) {
+ fds[i].signaled = 1;
+ n--;
+ }
+ }
+ else if ( fds[i].for_write ) {
+ if ( FD_ISSET ( fds[i].fd, &writefds ) ) {
+ fds[i].signaled = 1;
+ n--;
+ }
+ }
+ }
+ return count;
+}
+
+
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+
+
#include "wait.h"
#include "rungpg.h"
#include "context.h" /*temp hack until we have GpmeData methods to do I/O */
+#include "io.h"
#include "status-table.h"
}
/* In any case we need a status pipe - create it right here and
* don't handle it with our generic GpgmeData mechanism */
- if (pipe (gpg->status.fd) == -1) {
+ if (_gpgme_io_pipe (gpg->status.fd) == -1) {
rc = mk_error (Pipe_Error);
goto leave;
}
-static int
-set_nonblocking ( int fd )
-{
- int flags;
-
- flags = fcntl (fd, F_GETFL, 0);
- if (flags == -1)
- return -1;
- flags |= O_NONBLOCK;
- return fcntl (fd, F_SETFL, flags);
-}
-
-
GpgmeError
_gpgme_gpg_add_arg ( GpgObject gpg, const char *arg )
{
if (!gpg->colon.buffer) {
return mk_error (Out_Of_Core);
}
- if (pipe (gpg->colon.fd) == -1) {
+ if (_gpgme_io_pipe (gpg->colon.fd) == -1) {
xfree (gpg->colon.buffer); gpg->colon.buffer = NULL;
return mk_error (Pipe_Error);
}
{
int fds[2];
- if (pipe (fds) == -1) {
+ if (_gpgme_io_pipe (fds) == -1) {
xfree (fd_data_map);
free_argv (argv);
return mk_error (Pipe_Error);
_gpgme_gpg_spawn( GpgObject gpg, void *opaque )
{
int rc;
- int i;
+ int i, n;
pid_t pid;
+ struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
if ( !gpg )
return mk_error (Invalid_Value);
if ( rc )
return rc;
- fflush (stderr);
- pid = fork ();
- if (pid == -1) {
- return mk_error (Exec_Error);
+ n = 4; /* status fd, 2*colon_fd and end of list */
+ for (i=0; gpg->fd_data_map[i].data; i++ )
+ n += 2;
+ fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list );
+ if (!fd_child_list)
+ return mk_error (Out_Of_Core);
+ fd_parent_list = fd_child_list + n;
+
+ /* build the fd list for the child */
+ n=0;
+ fd_child_list[n].fd = gpg->status.fd[0];
+ fd_child_list[n].dup_to = -1;
+ n++;
+ if ( gpg->colon.fnc ) {
+ fd_child_list[n].fd = gpg->colon.fd[0];
+ fd_child_list[n].dup_to = -1;
+ n++;
+ fd_child_list[n].fd = gpg->colon.fd[1];
+ fd_child_list[n].dup_to = 1; /* dup to stdout */
+ n++;
}
-
- if ( !pid ) { /* child */
- int duped_stdin = 0;
- int duped_stderr = 0;
-
- close (gpg->status.fd[0]);
-
- if (gpg->colon.fnc) {
- /* dup it to stdout */
- if ( dup2 ( gpg->colon.fd[1], 1 ) == -1 ) {
- fprintf (stderr,"dup2(colon, 1) failed: %s\n",
- strerror (errno) );
- _exit (8);
- }
- close (gpg->colon.fd[0]);
- close (gpg->colon.fd[1]);
- }
-
- for (i=0; gpg->fd_data_map[i].data; i++ ) {
- close (gpg->fd_data_map[i].fd);
- gpg->fd_data_map[i].fd = -1;
- if ( gpg->fd_data_map[i].dup_to != -1 ) {
- if ( dup2 (gpg->fd_data_map[i].peer_fd,
- gpg->fd_data_map[i].dup_to ) == -1 ) {
- fprintf (stderr, "dup2 failed in child: %s\n",
- strerror (errno));
- _exit (8);
- }
- if ( gpg->fd_data_map[i].dup_to == 0 )
- duped_stdin=1;
- if ( gpg->fd_data_map[i].dup_to == 2 )
- duped_stderr=1;
- close ( gpg->fd_data_map[i].peer_fd );
- }
+ for (i=0; gpg->fd_data_map[i].data; i++ ) {
+ fd_child_list[n].fd = gpg->fd_data_map[i].fd;
+ fd_child_list[n].dup_to = -1;
+ n++;
+ if (gpg->fd_data_map[i].dup_to != -1) {
+ fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
+ fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
+ n++;
}
+ }
+ fd_child_list[n].fd = -1;
+ fd_child_list[n].dup_to = -1;
- if( !duped_stdin || !duped_stderr ) {
- int fd = open ( "/dev/null", O_RDONLY );
- if ( fd == -1 ) {
- fprintf (stderr,"can't open `/dev/null': %s\n",
- strerror (errno) );
- _exit (8);
- }
- /* Make sure that gpg has a connected stdin */
- if ( !duped_stdin ) {
- if ( dup2 ( fd, 0 ) == -1 ) {
- fprintf (stderr,"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);
- }
- }
- }
- close (fd);
- }
+ /* build the fd list for the parent */
+ n=0;
+ if ( gpg->status.fd[1] != -1 ) {
+ fd_parent_list[n].fd = gpg->status.fd[1];
+ fd_parent_list[n].dup_to = -1;
+ n++;
+ gpg->status.fd[1] = -1;
+ }
+ if ( gpg->colon.fd[1] != -1 ) {
+ fd_parent_list[n].fd = gpg->colon.fd[1];
+ fd_parent_list[n].dup_to = -1;
+ n++;
+ gpg->colon.fd[1] = -1;
+ }
+ for (i=0; gpg->fd_data_map[i].data; i++ ) {
+ fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
+ fd_parent_list[n].dup_to = -1;
+ n++;
+ gpg->fd_data_map[i].peer_fd = -1;
+ }
+ fd_parent_list[n].fd = -1;
+ fd_parent_list[n].dup_to = -1;
- execv ( GPG_PATH, gpg->argv );
- fprintf (stderr,"exec of gpg failed\n");
- _exit (8);
+
+ fflush (stderr);
+ pid = _gpgme_io_spawn (GPG_PATH, gpg->argv, fd_child_list, fd_parent_list);
+ xfree (fd_child_list);
+ if (pid == -1) {
+ return mk_error (Exec_Error);
}
- /* parent */
+
gpg->pid = pid;
/*_gpgme_register_term_handler ( closure, closure_value, pid );*/
- if ( gpg->status.fd[1] != -1 ) {
- close (gpg->status.fd[1]);
- gpg->status.fd[1] = -1;
- }
if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
gpg, pid, gpg->status.fd[0], 1 ) ) {
/* FIXME: kill the child */
}
- if ( gpg->colon.fd[1] != -1 ) {
- close (gpg->colon.fd[1]);
- gpg->colon.fd[1] = -1;
+ if ( gpg->colon.fnc ) {
assert ( gpg->colon.fd[0] != -1 );
if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler,
gpg, pid, gpg->colon.fd[0], 1 ) ) {
}
for (i=0; gpg->fd_data_map[i].data; i++ ) {
- close (gpg->fd_data_map[i].peer_fd);
- gpg->fd_data_map[i].peer_fd = -1;
-
/* Due to problems with select and write we set outbound pipes
* to non-blocking */
if (!gpg->fd_data_map[i].inbound) {
- set_nonblocking (gpg->fd_data_map[i].fd);
+ _gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd);
}
if ( _gpgme_register_pipe_handler (
assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
- do {
- nread = read (fd, buf, 200 );
- } while ( nread == -1 && errno == EINTR);
+ nread = _gpgme_io_read (fd, buf, 200 );
fprintf(stderr, "inbound on fd %d: nread=%d\n", fd, nread );
if ( nread < 0 ) {
fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n",
*/
- do {
- fprintf (stderr, "write_mem_data(%d): about to write %d bytes len=%d rpos=%d\n",
+ fprintf (stderr, "write_mem_data(%d): about to write %d bytes len=%d rpos=%d\n",
fd, (int)nbytes, (int)dh->len, dh->readpos );
- nwritten = write ( fd, dh->data+dh->readpos, nbytes );
- fprintf (stderr, "write_mem_data(%d): wrote %d bytes\n", fd, nwritten );
- } while ( nwritten == -1 && errno == EINTR );
+ nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
+ fprintf (stderr, "write_mem_data(%d): wrote %d bytes\n", fd, nwritten );
if (nwritten == -1 && errno == EAGAIN )
return 0;
if ( nwritten < 1 ) {
}
- do {
- nread = read ( gpg->status.fd[0], buffer+readpos, bufsize-readpos );
- } while (nread == -1 && errno == EINTR);
-
+ nread = _gpgme_io_read ( gpg->status.fd[0],
+ buffer+readpos, bufsize-readpos );
if (nread == -1)
return mk_error(Read_Error);
}
- do {
- nread = read ( gpg->colon.fd[0], buffer+readpos, bufsize-readpos );
- } while (nread == -1 && errno == EINTR);
-
+ nread = _gpgme_io_read ( gpg->colon.fd[0],
+ buffer+readpos, bufsize-readpos );
if (nread == -1)
return mk_error(Read_Error);
+/*********************************************
+ ********** missing string functions *********
+ *********************************************/
+
+#ifndef HAVE_STPCPY
+char *
+stpcpy (char *a, const char *b)
+{
+ while( *b )
+ *a++ = *b++;
+ *a = 0;
+
+ return a;
+}
+#endif
+
#define DIMof(type,member) DIM(((type *)0)->member)
+
+#ifndef HAVE_STPCPY
+char *stpcpy (char *a, const char *b);
+#endif
+
+
+
#endif /* UTIL_H */
}
+/**
+ * gpgme_op_verify:
+ * @c: the context
+ * @sig: the signature data
+ * @text: the signed text
+ * @r_stat: returns the status of the signature
+ *
+ * Perform a signature check on the signature given in @sig. Currently it is
+ * assumed that this is a detached signature for the material given in @text.
+ * The result of this operation is returned in @r_stat which can take these
+ * values:
+ * GPGME_SIG_STAT_NONE: No status - should not happen
+ * GPGME_SIG_STAT_GOOD: The signature is valid
+ * GPGME_SIG_STAT_BAD: The signature is not valid
+ * GPGME_SIG_STAT_NOKEY: The signature could not be checked due to a
+ * missing key
+ * GPGME_SIG_STAT_NOSIG: This is not a signature
+ * GPGME_SIG_STAT_ERROR: Due to some other error the check could not be done.
+ *
+ * Return value: 0 on success or an errorcode if something not related to
+ * the signature itself did go wrong.
+ **/
GpgmeError
gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
GpgmeSigStat *r_stat )
--- /dev/null
+/* w32-io.c - W32 API I/O functions
+ * Copyright (C) 2000 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 <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <windows.h>
+
+#include "io.h"
+
+/*
+ * We assume that a HANDLE can be represented by an int which should be true
+ * for all i386 systems (HANDLE is defined as void *) and these are the only
+ * systems for which Windows is available.
+ * Further we assume that -1 denotes an invalid handle.
+ */
+
+#define fd_to_handle(a) ((HANDLE)(a))
+#define handle_to_fd(a) ((int)(a))
+#define pid_to_handle(a) ((HANDLE)(a))
+#define handle_to_pid(a) ((pid_t)(a))
+
+
+int
+_gpgme_io_read ( int fd, void *buffer, size_t count )
+{
+ int nread = 0;
+ HANDLE h = fd_to_handle (fd);
+
+ if ( !ReadFile ( h, buffer, count, &nread, NULL) ) {
+ fprintf (stderr, "** ReadFile failed: ec=%d\n", (int)GetLastError ());
+ return -1;
+ }
+
+ return nread;
+}
+
+
+int
+_gpgme_io_write ( int fd, const void *buffer, size_t count )
+{
+ int nwritten;
+ HANDLE h = fd_to_handle (fd);
+
+ if ( !WriteFile ( h, buffer, count, &nwritten, NULL) ) {
+ fprintf (stderr, "** WriteFile failed: ec=%d\n", (int)GetLastError ());
+ return -1;
+ }
+
+ return nwritten;
+}
+
+int
+_gpgme_io_pipe ( int filedes[2] )
+{
+ HANDLE r, w;
+
+ if (!CreatePipe ( &r, &w, NULL, 0))
+ return -1;
+ filedes[0] = handle_to_fd (r);
+ filedes[1] = handle_to_fd (w);
+ return 0
+}
+
+int
+_gpgme_io_set_nonblocking ( int fd )
+{
+ return 0;
+}
+
+
+static char *
+build_commandline ( char **argv );
+{
+ int i, n = 0;
+ char *buf, *p;
+
+ /* FIXME: we have to quote some things because under Windows the
+ * program parses the commandline and does some unquoting */
+ for (i=0; argv[i]; i++)
+ n += strlen (argv[i]) + 1;
+ n += 5; /* "gpg " */
+ buf = p = xtrymalloc (n);
+ if ( !buf )
+ return NULL;
+ p = stpcpy (p, "gpg");
+ for (i = 0; argv[i]; i++)
+ p = stpcpy (stpcpy (p, " "), argv[i]);
+
+ return buf;
+}
+
+
+pid_t
+_gpgme_io_spawn ( const char *path, char **argv,
+ struct spawn_fd_item_s *fd_child_list,
+ struct spawn_fd_item_s *fd_parent_list )
+{
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi = {
+ NULL, /* returns process handle */
+ 0, /* returns primary thread handle */
+ 0, /* returns pid */
+ 0 /* returns tid */
+ };
+ STARTUPINFO si = {
+ 0, NULL, NULL, NULL,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL
+ };
+ char *envblock = NULL;
+ int cr_flags = CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ());
+ int rc;
+ HANDLE save_stdout;
+ HANDLE outputfd[2], statusfd[2], inputfd[2];
+
+ sec_attr.nLength = sizeof (sec_attr);
+ sec_attr.bInheritHandle = FALSE;
+ sec_attr.lpSecurityDescriptor = NULL;
+
+
+ arg_string = build_commandline ( argv );
+ if (!arg_string )
+ return -1;
+
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+ si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+ si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+ if (!SetHandleInformation (si.hStdOutput,
+ HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
+ fprintf (stderr, "** SHI 1 failed: ec=%d\n", (int) GetLastError ());
+ }
+ if (!SetHandleInformation (si.hStdError,
+ HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
+ fprintf (stderr, "** SHI 2 failed: ec=%d\n", (int) GetLastError ());
+ }
+
+
+ fputs ("** CreateProcess ...\n", stderr);
+ fprintf (stderr, "** args=`%s'\n", arg_string);
+ fflush (stderr);
+ if ( !CreateProcessA (GPG_PATH,
+ arg_string,
+ &sec_attr, /* process security attributes */
+ &sec_attr, /* thread security attributes */
+ TRUE, /* inherit handles */
+ cr_flags, /* creation flags */
+ envblock, /* environment */
+ NULL, /* use current drive/directory */
+ &si, /* startup information */
+ &pi /* returns process information */
+ ) ) {
+ fprintf (stderr, "** CreateProcess failed: ec=%d\n",
+ (int) GetLastError ());
+ fflush (stderr);
+ xfree (arg_string);
+ return -1;
+ }
+
+ /* .dup_to is not used in the parent list */
+ for (i=0; fd_parent_list[i].fd != -1; i++ ) {
+ CloseHandle ( fd_to_handle (fd_parent_list[i].fd) );
+ }
+
+ fprintf (stderr, "** CreateProcess ready\n");
+ fprintf (stderr, "** hProcess=%p hThread=%p\n",
+ pi.hProcess, pi.hThread);
+ fprintf (stderr, "** dwProcessID=%d dwThreadId=%d\n",
+ (int) pi.dwProcessId, (int) pi.dwThreadId);
+ fflush (stderr);
+
+ return handle_to_pid (pi.hProcess);
+}
+
+
+int
+_gpgme_io_waitpid ( pid_t pid, int hang, int *r_status, int *r_signal )
+{
+ return 0;
+}
+
+
+/*
+ * Select on the list of fds.
+ * Returns: -1 = error
+ * 0 = timeout or nothing to select
+ * >0 = number of signaled fds
+ */
+int
+_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
+{
+ return -1;
+}
+
+
+
+
+
+
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+
+
+
+
+
+
+
#include "context.h"
#include "ops.h"
#include "wait.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
+#include "io.h"
/* Fixme: implement the following stuff to make the code MT safe.
* To avoid the need to link against a specific threads lib, such
* */
#define enter_crit() do { } while (0)
#define leave_crit() do { } while (0)
-#define lock_queue() do { } while (0)
-#define unlock_queue() do { } while (0)
+#define lock_table() do { } while (0)
+#define unlock_table() do { } while (0)
+
-struct wait_queue_item_s {
- struct wait_queue_item_s *next;
- volatile int used;
+struct wait_item_s {
volatile int active;
int (*handler)(void*,pid_t,int);
void *handler_value;
pid_t pid;
- int fd;
- int inbound; /* this is an inbound data handler fd */
-
+ int inbound; /* this is an inbound data handler fd */
int exited;
int exit_status;
int exit_signal;
-
GpgmeCtx ctx;
};
+static int fd_table_size;
+static struct io_select_fd_s *fd_table;
-static struct wait_queue_item_s wait_queue[SIZEOF_WAIT_QUEUE];
-
-static int the_big_select ( void );
+static int do_select ( void );
-static void
-init_wait_queue (void)
-{
- int i;
- static int initialized = 0;
-
- if ( initialized ) /* FIXME: This leads to a race */
- return;
-
- lock_queue ();
- for (i=1; i < SIZEOF_WAIT_QUEUE; i++ )
- wait_queue[i-1].next = &wait_queue[i];
- initialized = 1;
- unlock_queue();
-}
-
-static struct wait_queue_item_s *
+static struct wait_item_s *
queue_item_from_context ( GpgmeCtx ctx )
{
- struct wait_queue_item_s *q;
+ struct wait_item_s *q;
+ int i;
- for (q=wait_queue; q; q = q->next) {
- if ( q->used && q->ctx == ctx )
+ for (i=0; i < fd_table_size; i++ ) {
+ if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->ctx == ctx )
return q;
}
return NULL;
static void
-propagate_term_results ( const struct wait_queue_item_s *first_q )
+propagate_term_results ( const struct wait_item_s *first_q )
{
- struct wait_queue_item_s *q;
+ struct wait_item_s *q;
+ int i;
- for (q=wait_queue; q; q = q->next) {
- if ( q->used && q != first_q && !q->exited
+ for (i=0; i < fd_table_size; i++ ) {
+ if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
+ && q != first_q && !q->exited
&& q->pid == first_q->pid ) {
q->exited = first_q->exited;
q->exit_status = first_q->exit_status;
static int
count_active_fds ( pid_t pid )
{
- struct wait_queue_item_s *q;
- int count = 0;
+ struct wait_item_s *q;
+ int i, count = 0;
- for (q=wait_queue; q; q = q->next) {
- if ( q->used && q->active && q->pid == pid )
+ for (i=0; i < fd_table_size; i++ ) {
+ if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
+ && q->active && q->pid == pid )
count++;
}
return count;
static void
remove_process ( pid_t pid )
{
- struct wait_queue_item_s *q;
-
- for (q=wait_queue; q; q = q->next) {
- if ( q->used ) {
- close (q->fd);
- q->handler = NULL;
- q->ctx = NULL;
- q->used = 0;
+ struct wait_item_s *q;
+ int i;
+
+ for (i=0; i < fd_table_size; i++ ) {
+ if (fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->pid == pid ) {
+ xfree (q);
+ fd_table[i].opaque = NULL;
+ close (fd_table[i].fd);
+ fd_table[i].fd = -1;
}
}
}
GpgmeCtx
_gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond )
{
- struct wait_queue_item_s *q;
+ struct wait_item_s *q;
- init_wait_queue ();
do {
- int did_work = the_big_select();
+ int did_work = do_select();
if ( cond && *cond )
hang = 0;
if ( !did_work ) {
- int status;
-
- /* We did no read/write - see whether this process is still
+ /* We did no read/write - see whether the process is still
* alive */
assert (c); /* !c is not yet implemented */
q = queue_item_from_context ( c );
if (q->exited)
;
- else if ( waitpid ( q->pid, &status, WNOHANG ) == q->pid ) {
+ else if ( _gpgme_io_waitpid (q->pid, 0,
+ &q->exit_status, &q->exit_signal)){
q->exited = 1;
- if ( WIFSIGNALED (status) ) {
- q->exit_status = 4; /* Need some value here */
- q->exit_signal = WTERMSIG (status);
- }
- else if ( WIFEXITED (status) ) {
- q->exit_status = WEXITSTATUS (status);
- }
- else {
- q->exited++;
- q->exit_status = 4;
- }
propagate_term_results (q);
}
* gpgs. A future version might provide a facility to delegate
* those selects to the GDK select stuff.
* This function must be called only by one thread!!
- * FIXME: The data structures and algorithms are stupid.
* Returns: 0 = nothing to run
* 1 = did run something
*/
static int
-the_big_select ( void )
+do_select ( void )
{
- static fd_set readfds;
- static fd_set writefds;
- struct wait_queue_item_s *q;
- int max_fd, n;
- struct timeval timeout = { 1, 0 }; /* Use a one second timeout */
-
- FD_ZERO ( &readfds );
- FD_ZERO ( &writefds );
- max_fd = 0;
-
+ struct wait_item_s *q;
+ int i, n;
- DEBUG_SELECT ((stderr, "gpgme:select on [ "));
- lock_queue ();
- for ( q = wait_queue; q; q = q->next ) {
- if ( q->used && q->active ) {
- if (q->inbound) {
- assert ( !FD_ISSET ( q->fd, &readfds ) );
- FD_SET ( q->fd, &readfds );
- DEBUG_SELECT ((stderr, "r%d ", q->fd ));
- }
- else {
- assert ( !FD_ISSET ( q->fd, &writefds ) );
- FD_SET ( q->fd, &writefds );
- DEBUG_SELECT ((stderr, "w%d ", q->fd ));
- }
- if ( q->fd > max_fd )
- max_fd = q->fd;
- }
- }
- unlock_queue ();
- DEBUG_SELECT ((stderr, "]\n" ));
-
- n = select ( max_fd+1, &readfds, &writefds, NULL, &timeout );
- if ( n <= 0 ) {
- if ( n && errno != EINTR ) {
- fprintf (stderr, "the_big_select: select failed: %s\n",
- strerror (errno) );
- }
- return 0;
- }
-
-#if DEBUG_SELECT_ENABLED
- {
- int i;
-
- 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 );
- }
- fprintf (stderr, "]\n" );
- }
-#endif
-
- /* something has to be done. Go over the queue and call
- * the handlers */
- restart:
- while ( n ) {
- lock_queue ();
- for ( q = wait_queue; q; q = q->next ) {
- if ( q->used && q->active && q->inbound
- && FD_ISSET (q->fd, &readfds ) ) {
- FD_CLR (q->fd, &readfds );
- assert (n);
- n--;
- unlock_queue ();
- if ( q->handler (q->handler_value, q->pid, q->fd ) )
- q->active = 0;
- goto restart;
- }
- if ( q->used && q->active && !q->inbound
- && FD_ISSET (q->fd, &writefds ) ) {
- FD_CLR (q->fd, &writefds );
- assert (n);
- n--;
- unlock_queue ();
- if ( q->handler (q->handler_value, q->pid, q->fd ) )
- q->active = 0;
- goto restart;
+ n = _gpgme_io_select ( fd_table, fd_table_size );
+ if ( n <= 0 )
+ return 0; /* error or timeout */
+
+ for (i=0; i < fd_table_size && n; i++ ) {
+ if ( fd_table[i].fd != -1 && fd_table[i].signaled ) {
+ q = fd_table[i].opaque;
+ assert (n);
+ n--;
+ if ( q->active && q->handler (q->handler_value,
+ q->pid, fd_table[i].fd ) ) {
+ q->active = 0;
+ fd_table[i].for_read = 0;
+ fd_table[i].for_write = 0;
}
}
- unlock_queue ();
}
+
return 1;
}
pid_t pid, int fd, int inbound )
{
GpgmeCtx ctx = opaque;
- struct wait_queue_item_s *q;
+ struct wait_item_s *q;
+ int i;
- init_wait_queue();
assert (opaque);
assert (handler);
- lock_queue ();
- for ( q = wait_queue; q; q = q->next ) {
- if ( !q->used ) {
- q->used = 1;
- q->active = 0;
- break;
- }
- }
- unlock_queue ();
- if ( !q )
- return mk_error (Too_Many_Procs);
-
- q->fd = fd;
+ q = xtrycalloc ( 1, sizeof *q );
+ if ( !q )
+ return mk_error (Out_Of_Core);
q->inbound = inbound;
q->handler = handler;
q->handler_value = handler_value;
q->pid = pid;
q->ctx = ctx;
-
- /* and enable this entry for the next select */
- q->exited = 0;
q->active = 1;
- return 0;
+
+ lock_table ();
+ again:
+ for (i=0; i < fd_table_size; i++ ) {
+ if ( fd_table[i].fd == -1 ) {
+ fd_table[i].fd = fd;
+ fd_table[i].for_read = inbound;
+ fd_table[i].for_write = !inbound;
+ fd_table[i].signaled = 0;
+ fd_table[i].opaque = q;
+ unlock_table ();
+ return 0;
+ }
+ }
+ if ( fd_table_size < 50 ) {
+ /* FIXME: We have to wait until there are no other readers of the
+ * table, i.e that the io_select is not active in another thread */
+ struct io_select_fd_s *tmp;
+
+ tmp = xtryrealloc ( fd_table, (fd_table_size + 10) * sizeof *tmp );
+ if ( tmp ) {
+ for (i=0; i < 10; i++ )
+ tmp[fd_table_size+i].fd = -1;
+ fd_table_size += i;
+ fd_table = tmp;
+ goto again;
+ }
+ }
+
+ unlock_table ();
+ xfree (q);
+ return mk_error (Too_Many_Procs);
}