Added some comments and prepared for W32 support
This commit is contained in:
parent
f9a167c516
commit
6bf05e9c06
@ -57,6 +57,7 @@ dnl
|
|||||||
dnl
|
dnl
|
||||||
dnl Checks for library functions
|
dnl Checks for library functions
|
||||||
dnl
|
dnl
|
||||||
|
AC_CHECK_FUNCS(stpcpy)
|
||||||
|
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
|
@ -24,6 +24,7 @@ libgpgme_la_SOURCES = \
|
|||||||
key.c key.h \
|
key.c key.h \
|
||||||
keylist.c \
|
keylist.c \
|
||||||
rungpg.c rungpg.h status-table.h \
|
rungpg.c rungpg.h status-table.h \
|
||||||
|
io.h posix-io.c w32-io.c \
|
||||||
gpgme.c version.c errors.c
|
gpgme.c version.c errors.c
|
||||||
|
|
||||||
|
|
||||||
@ -36,3 +37,6 @@ status-table.h : rungpg.h
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
68
gpgme/data.c
68
gpgme/data.c
@ -38,6 +38,14 @@
|
|||||||
|| ((a) >= 'f' && (a) <= 'f') )
|
|| ((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
|
GpgmeError
|
||||||
gpgme_data_new ( GpgmeData *r_dh )
|
gpgme_data_new ( GpgmeData *r_dh )
|
||||||
{
|
{
|
||||||
@ -104,6 +112,19 @@ gpgme_data_new_from_mem ( GpgmeData *r_dh,
|
|||||||
return 0;
|
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
|
GpgmeError
|
||||||
gpgme_data_new_from_file ( GpgmeData *r_dh, const char *fname, int copy )
|
gpgme_data_new_from_file ( GpgmeData *r_dh, const char *fname, int copy )
|
||||||
{
|
{
|
||||||
@ -210,6 +231,18 @@ _gpgme_data_release_and_return_string ( GpgmeData dh )
|
|||||||
return val;
|
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 *
|
char *
|
||||||
gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len )
|
gpgme_data_release_and_get_mem ( GpgmeData dh, size_t *r_len )
|
||||||
{
|
{
|
||||||
@ -233,6 +266,15 @@ 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
|
GpgmeDataType
|
||||||
gpgme_data_get_type ( GpgmeData dh )
|
gpgme_data_get_type ( GpgmeData dh )
|
||||||
{
|
{
|
||||||
@ -257,6 +299,16 @@ _gpgme_data_get_mode ( GpgmeData dh )
|
|||||||
return dh->mode;
|
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
|
GpgmeError
|
||||||
gpgme_data_rewind ( GpgmeData dh )
|
gpgme_data_rewind ( GpgmeData dh )
|
||||||
{
|
{
|
||||||
@ -268,6 +320,22 @@ gpgme_data_rewind ( GpgmeData dh )
|
|||||||
return 0;
|
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
|
GpgmeError
|
||||||
gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
|
gpgme_data_read ( GpgmeData dh, char *buffer, size_t length, size_t *nread )
|
||||||
{
|
{
|
||||||
|
@ -95,6 +95,16 @@ _gpgme_release_result ( GpgmeCtx c )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 *
|
char *
|
||||||
gpgme_get_notation ( GpgmeCtx c )
|
gpgme_get_notation ( GpgmeCtx c )
|
||||||
{
|
{
|
||||||
@ -104,6 +114,13 @@ 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
|
void
|
||||||
gpgme_set_armor ( GpgmeCtx c, int yes )
|
gpgme_set_armor ( GpgmeCtx c, int yes )
|
||||||
{
|
{
|
||||||
@ -112,6 +129,14 @@ gpgme_set_armor ( GpgmeCtx c, int yes )
|
|||||||
c->use_armor = 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
|
void
|
||||||
gpgme_set_textmode ( GpgmeCtx c, int yes )
|
gpgme_set_textmode ( GpgmeCtx c, int yes )
|
||||||
{
|
{
|
||||||
@ -136,3 +161,5 @@ gpgme_set_passphrase_cb ( GpgmeCtx c, GpgmePassphraseCb fnc, void *fncval )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
64
gpgme/io.h
Normal file
64
gpgme/io.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* 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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
284
gpgme/posix-io.c
Normal file
284
gpgme/posix-io.c
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
/* 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*/
|
||||||
|
|
||||||
|
|
||||||
|
|
189
gpgme/rungpg.c
189
gpgme/rungpg.c
@ -37,6 +37,7 @@
|
|||||||
#include "wait.h"
|
#include "wait.h"
|
||||||
#include "rungpg.h"
|
#include "rungpg.h"
|
||||||
#include "context.h" /*temp hack until we have GpmeData methods to do I/O */
|
#include "context.h" /*temp hack until we have GpmeData methods to do I/O */
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
#include "status-table.h"
|
#include "status-table.h"
|
||||||
|
|
||||||
@ -137,7 +138,7 @@ _gpgme_gpg_new ( GpgObject *r_gpg )
|
|||||||
}
|
}
|
||||||
/* In any case we need a status pipe - create it right here and
|
/* In any case we need a status pipe - create it right here and
|
||||||
* don't handle it with our generic GpgmeData mechanism */
|
* 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);
|
rc = mk_error (Pipe_Error);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
@ -202,19 +203,6 @@ kill_gpg ( GpgObject gpg )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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
|
GpgmeError
|
||||||
_gpgme_gpg_add_arg ( GpgObject gpg, const char *arg )
|
_gpgme_gpg_add_arg ( GpgObject gpg, const char *arg )
|
||||||
{
|
{
|
||||||
@ -281,7 +269,7 @@ _gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
|
|||||||
if (!gpg->colon.buffer) {
|
if (!gpg->colon.buffer) {
|
||||||
return mk_error (Out_Of_Core);
|
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;
|
xfree (gpg->colon.buffer); gpg->colon.buffer = NULL;
|
||||||
return mk_error (Pipe_Error);
|
return mk_error (Pipe_Error);
|
||||||
}
|
}
|
||||||
@ -428,7 +416,7 @@ build_argv ( GpgObject gpg )
|
|||||||
{
|
{
|
||||||
int fds[2];
|
int fds[2];
|
||||||
|
|
||||||
if (pipe (fds) == -1) {
|
if (_gpgme_io_pipe (fds) == -1) {
|
||||||
xfree (fd_data_map);
|
xfree (fd_data_map);
|
||||||
free_argv (argv);
|
free_argv (argv);
|
||||||
return mk_error (Pipe_Error);
|
return mk_error (Pipe_Error);
|
||||||
@ -477,8 +465,9 @@ GpgmeError
|
|||||||
_gpgme_gpg_spawn( GpgObject gpg, void *opaque )
|
_gpgme_gpg_spawn( GpgObject gpg, void *opaque )
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int i;
|
int i, n;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
|
||||||
|
|
||||||
if ( !gpg )
|
if ( !gpg )
|
||||||
return mk_error (Invalid_Value);
|
return mk_error (Invalid_Value);
|
||||||
@ -492,88 +481,75 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
|
|||||||
if ( rc )
|
if ( rc )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
|
||||||
fflush (stderr);
|
fflush (stderr);
|
||||||
pid = fork ();
|
pid = _gpgme_io_spawn (GPG_PATH, gpg->argv, fd_child_list, fd_parent_list);
|
||||||
|
xfree (fd_child_list);
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
return mk_error (Exec_Error);
|
return mk_error (Exec_Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
execv ( GPG_PATH, gpg->argv );
|
|
||||||
fprintf (stderr,"exec of gpg failed\n");
|
|
||||||
_exit (8);
|
|
||||||
}
|
|
||||||
/* parent */
|
|
||||||
gpg->pid = pid;
|
gpg->pid = pid;
|
||||||
|
|
||||||
/*_gpgme_register_term_handler ( closure, closure_value, 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,
|
if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
|
||||||
gpg, pid, gpg->status.fd[0], 1 ) ) {
|
gpg, pid, gpg->status.fd[0], 1 ) ) {
|
||||||
/* FIXME: kill the child */
|
/* FIXME: kill the child */
|
||||||
@ -581,9 +557,7 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( gpg->colon.fd[1] != -1 ) {
|
if ( gpg->colon.fnc ) {
|
||||||
close (gpg->colon.fd[1]);
|
|
||||||
gpg->colon.fd[1] = -1;
|
|
||||||
assert ( gpg->colon.fd[0] != -1 );
|
assert ( gpg->colon.fd[0] != -1 );
|
||||||
if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler,
|
if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler,
|
||||||
gpg, pid, gpg->colon.fd[0], 1 ) ) {
|
gpg, pid, gpg->colon.fd[0], 1 ) ) {
|
||||||
@ -594,13 +568,10 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; gpg->fd_data_map[i].data; i++ ) {
|
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
|
/* Due to problems with select and write we set outbound pipes
|
||||||
* to non-blocking */
|
* to non-blocking */
|
||||||
if (!gpg->fd_data_map[i].inbound) {
|
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 (
|
if ( _gpgme_register_pipe_handler (
|
||||||
@ -633,9 +604,7 @@ gpg_inbound_handler ( void *opaque, pid_t pid, int fd )
|
|||||||
|
|
||||||
assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
|
assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
|
||||||
|
|
||||||
do {
|
nread = _gpgme_io_read (fd, buf, 200 );
|
||||||
nread = read (fd, buf, 200 );
|
|
||||||
} while ( nread == -1 && errno == EINTR);
|
|
||||||
fprintf(stderr, "inbound on fd %d: nread=%d\n", fd, nread );
|
fprintf(stderr, "inbound on fd %d: nread=%d\n", fd, nread );
|
||||||
if ( nread < 0 ) {
|
if ( nread < 0 ) {
|
||||||
fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n",
|
fprintf (stderr, "read_mem_data: read failed on fd %d (n=%d): %s\n",
|
||||||
@ -683,12 +652,10 @@ write_mem_data ( GpgmeData dh, int fd )
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
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 );
|
fd, (int)nbytes, (int)dh->len, dh->readpos );
|
||||||
nwritten = write ( fd, dh->data+dh->readpos, nbytes );
|
nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
|
||||||
fprintf (stderr, "write_mem_data(%d): wrote %d bytes\n", fd, nwritten );
|
fprintf (stderr, "write_mem_data(%d): wrote %d bytes\n", fd, nwritten );
|
||||||
} while ( nwritten == -1 && errno == EINTR );
|
|
||||||
if (nwritten == -1 && errno == EAGAIN )
|
if (nwritten == -1 && errno == EAGAIN )
|
||||||
return 0;
|
return 0;
|
||||||
if ( nwritten < 1 ) {
|
if ( nwritten < 1 ) {
|
||||||
@ -779,10 +746,8 @@ read_status ( GpgObject gpg )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
do {
|
nread = _gpgme_io_read ( gpg->status.fd[0],
|
||||||
nread = read ( gpg->status.fd[0], buffer+readpos, bufsize-readpos );
|
buffer+readpos, bufsize-readpos );
|
||||||
} while (nread == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (nread == -1)
|
if (nread == -1)
|
||||||
return mk_error(Read_Error);
|
return mk_error(Read_Error);
|
||||||
|
|
||||||
@ -887,10 +852,8 @@ read_colon_line ( GpgObject gpg )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
do {
|
nread = _gpgme_io_read ( gpg->colon.fd[0],
|
||||||
nread = read ( gpg->colon.fd[0], buffer+readpos, bufsize-readpos );
|
buffer+readpos, bufsize-readpos );
|
||||||
} while (nread == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (nread == -1)
|
if (nread == -1)
|
||||||
return mk_error(Read_Error);
|
return mk_error(Read_Error);
|
||||||
|
|
||||||
|
16
gpgme/util.c
16
gpgme/util.c
@ -61,3 +61,19 @@ _gpgme_free ( void *a )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************
|
||||||
|
********** missing string functions *********
|
||||||
|
*********************************************/
|
||||||
|
|
||||||
|
#ifndef HAVE_STPCPY
|
||||||
|
char *
|
||||||
|
stpcpy (char *a, const char *b)
|
||||||
|
{
|
||||||
|
while( *b )
|
||||||
|
*a++ = *b++;
|
||||||
|
*a = 0;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@ -42,6 +42,13 @@ void _gpgme_free ( void *a );
|
|||||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HAVE_STPCPY
|
||||||
|
char *stpcpy (char *a, const char *b);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* UTIL_H */
|
#endif /* UTIL_H */
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,6 +195,28 @@ gpgme_op_verify_start ( GpgmeCtx c, GpgmeData sig, GpgmeData text )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
GpgmeError
|
||||||
gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
|
gpgme_op_verify ( GpgmeCtx c, GpgmeData sig, GpgmeData text,
|
||||||
GpgmeSigStat *r_stat )
|
GpgmeSigStat *r_stat )
|
||||||
|
239
gpgme/w32-io.c
Normal file
239
gpgme/w32-io.c
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/* 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*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
272
gpgme/wait.c
272
gpgme/wait.c
@ -33,14 +33,7 @@
|
|||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "ops.h"
|
#include "ops.h"
|
||||||
#include "wait.h"
|
#include "wait.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
|
|
||||||
|
|
||||||
/* Fixme: implement the following stuff to make the code MT safe.
|
/* Fixme: implement the following stuff to make the code MT safe.
|
||||||
* To avoid the need to link against a specific threads lib, such
|
* To avoid the need to link against a specific threads lib, such
|
||||||
@ -52,55 +45,36 @@
|
|||||||
* */
|
* */
|
||||||
#define enter_crit() do { } while (0)
|
#define enter_crit() do { } while (0)
|
||||||
#define leave_crit() do { } while (0)
|
#define leave_crit() do { } while (0)
|
||||||
#define lock_queue() do { } while (0)
|
#define lock_table() do { } while (0)
|
||||||
#define unlock_queue() do { } while (0)
|
#define unlock_table() do { } while (0)
|
||||||
|
|
||||||
struct wait_queue_item_s {
|
|
||||||
struct wait_queue_item_s *next;
|
struct wait_item_s {
|
||||||
volatile int used;
|
|
||||||
volatile int active;
|
volatile int active;
|
||||||
int (*handler)(void*,pid_t,int);
|
int (*handler)(void*,pid_t,int);
|
||||||
void *handler_value;
|
void *handler_value;
|
||||||
pid_t pid;
|
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 exited;
|
||||||
int exit_status;
|
int exit_status;
|
||||||
int exit_signal;
|
int exit_signal;
|
||||||
|
|
||||||
GpgmeCtx ctx;
|
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 do_select ( void );
|
||||||
|
|
||||||
static int the_big_select ( void );
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static struct wait_item_s *
|
||||||
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 *
|
|
||||||
queue_item_from_context ( GpgmeCtx ctx )
|
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) {
|
for (i=0; i < fd_table_size; i++ ) {
|
||||||
if ( q->used && q->ctx == ctx )
|
if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->ctx == ctx )
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -108,12 +82,14 @@ queue_item_from_context ( GpgmeCtx ctx )
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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) {
|
for (i=0; i < fd_table_size; i++ ) {
|
||||||
if ( q->used && q != first_q && !q->exited
|
if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
|
||||||
|
&& q != first_q && !q->exited
|
||||||
&& q->pid == first_q->pid ) {
|
&& q->pid == first_q->pid ) {
|
||||||
q->exited = first_q->exited;
|
q->exited = first_q->exited;
|
||||||
q->exit_status = first_q->exit_status;
|
q->exit_status = first_q->exit_status;
|
||||||
@ -125,11 +101,12 @@ propagate_term_results ( const struct wait_queue_item_s *first_q )
|
|||||||
static int
|
static int
|
||||||
count_active_fds ( pid_t pid )
|
count_active_fds ( pid_t pid )
|
||||||
{
|
{
|
||||||
struct wait_queue_item_s *q;
|
struct wait_item_s *q;
|
||||||
int count = 0;
|
int i, count = 0;
|
||||||
|
|
||||||
for (q=wait_queue; q; q = q->next) {
|
for (i=0; i < fd_table_size; i++ ) {
|
||||||
if ( q->used && q->active && q->pid == pid )
|
if ( fd_table[i].fd != -1 && (q=fd_table[i].opaque)
|
||||||
|
&& q->active && q->pid == pid )
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
@ -140,14 +117,15 @@ count_active_fds ( pid_t pid )
|
|||||||
static void
|
static void
|
||||||
remove_process ( pid_t pid )
|
remove_process ( pid_t pid )
|
||||||
{
|
{
|
||||||
struct wait_queue_item_s *q;
|
struct wait_item_s *q;
|
||||||
|
int i;
|
||||||
for (q=wait_queue; q; q = q->next) {
|
|
||||||
if ( q->used ) {
|
for (i=0; i < fd_table_size; i++ ) {
|
||||||
close (q->fd);
|
if (fd_table[i].fd != -1 && (q=fd_table[i].opaque) && q->pid == pid ) {
|
||||||
q->handler = NULL;
|
xfree (q);
|
||||||
q->ctx = NULL;
|
fd_table[i].opaque = NULL;
|
||||||
q->used = 0;
|
close (fd_table[i].fd);
|
||||||
|
fd_table[i].fd = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,19 +154,16 @@ gpgme_wait ( GpgmeCtx c, int hang )
|
|||||||
GpgmeCtx
|
GpgmeCtx
|
||||||
_gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond )
|
_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 {
|
do {
|
||||||
int did_work = the_big_select();
|
int did_work = do_select();
|
||||||
|
|
||||||
if ( cond && *cond )
|
if ( cond && *cond )
|
||||||
hang = 0;
|
hang = 0;
|
||||||
|
|
||||||
if ( !did_work ) {
|
if ( !did_work ) {
|
||||||
int status;
|
/* We did no read/write - see whether the process is still
|
||||||
|
|
||||||
/* We did no read/write - see whether this process is still
|
|
||||||
* alive */
|
* alive */
|
||||||
assert (c); /* !c is not yet implemented */
|
assert (c); /* !c is not yet implemented */
|
||||||
q = queue_item_from_context ( c );
|
q = queue_item_from_context ( c );
|
||||||
@ -196,19 +171,9 @@ _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond )
|
|||||||
|
|
||||||
if (q->exited)
|
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;
|
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);
|
propagate_term_results (q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,99 +199,34 @@ _gpgme_wait_on_condition ( GpgmeCtx c, int hang, volatile int *cond )
|
|||||||
* gpgs. A future version might provide a facility to delegate
|
* gpgs. A future version might provide a facility to delegate
|
||||||
* those selects to the GDK select stuff.
|
* those selects to the GDK select stuff.
|
||||||
* This function must be called only by one thread!!
|
* This function must be called only by one thread!!
|
||||||
* FIXME: The data structures and algorithms are stupid.
|
|
||||||
* Returns: 0 = nothing to run
|
* Returns: 0 = nothing to run
|
||||||
* 1 = did run something
|
* 1 = did run something
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
the_big_select ( void )
|
do_select ( void )
|
||||||
{
|
{
|
||||||
static fd_set readfds;
|
struct wait_item_s *q;
|
||||||
static fd_set writefds;
|
int i, n;
|
||||||
struct wait_queue_item_s *q;
|
|
||||||
int max_fd, n;
|
|
||||||
struct timeval timeout = { 1, 0 }; /* Use a one second timeout */
|
|
||||||
|
|
||||||
FD_ZERO ( &readfds );
|
n = _gpgme_io_select ( fd_table, fd_table_size );
|
||||||
FD_ZERO ( &writefds );
|
if ( n <= 0 )
|
||||||
max_fd = 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unlock_queue ();
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,35 +242,53 @@ _gpgme_register_pipe_handler( void *opaque,
|
|||||||
pid_t pid, int fd, int inbound )
|
pid_t pid, int fd, int inbound )
|
||||||
{
|
{
|
||||||
GpgmeCtx ctx = opaque;
|
GpgmeCtx ctx = opaque;
|
||||||
struct wait_queue_item_s *q;
|
struct wait_item_s *q;
|
||||||
|
int i;
|
||||||
|
|
||||||
init_wait_queue();
|
|
||||||
assert (opaque);
|
assert (opaque);
|
||||||
assert (handler);
|
assert (handler);
|
||||||
|
|
||||||
lock_queue ();
|
q = xtrycalloc ( 1, sizeof *q );
|
||||||
for ( q = wait_queue; q; q = q->next ) {
|
if ( !q )
|
||||||
if ( !q->used ) {
|
return mk_error (Out_Of_Core);
|
||||||
q->used = 1;
|
|
||||||
q->active = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unlock_queue ();
|
|
||||||
if ( !q )
|
|
||||||
return mk_error (Too_Many_Procs);
|
|
||||||
|
|
||||||
q->fd = fd;
|
|
||||||
q->inbound = inbound;
|
q->inbound = inbound;
|
||||||
q->handler = handler;
|
q->handler = handler;
|
||||||
q->handler_value = handler_value;
|
q->handler_value = handler_value;
|
||||||
q->pid = pid;
|
q->pid = pid;
|
||||||
q->ctx = ctx;
|
q->ctx = ctx;
|
||||||
|
|
||||||
/* and enable this entry for the next select */
|
|
||||||
q->exited = 0;
|
|
||||||
q->active = 1;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user