2005-11-18 Marcus Brinkmann <marcus@g10code.de>

* priv-io.h (_gpgme_io_fd2str): New prototype.
	* posix-io.c (_gpgme_io_fd2str): New function.
	* w32-io.c (_gpgme_io_fd2str): New function.
	* rungpg.c: Use this new function.
	* w32-glib-io.c (_gpgme_io_fd2str): Rewrote the file handle code
	again.  Two's company, three's the musketeers.
This commit is contained in:
Marcus Brinkmann 2005-11-18 14:00:50 +00:00
parent b9401b8f6c
commit 3418d23ec5
6 changed files with 202 additions and 157 deletions

View File

@ -1,5 +1,12 @@
2005-11-18 Marcus Brinkmann <marcus@g10code.de> 2005-11-18 Marcus Brinkmann <marcus@g10code.de>
* priv-io.h (_gpgme_io_fd2str): New prototype.
* posix-io.c (_gpgme_io_fd2str): New function.
* w32-io.c (_gpgme_io_fd2str): New function.
* rungpg.c: Use this new function.
* w32-glib-io.c (_gpgme_io_fd2str): Rewrote the file handle code
again. Two's company, three's the musketeers.
* w32-glib-io.c: Rewrote the file handle code. We don't create * w32-glib-io.c: Rewrote the file handle code. We don't create
system fds for every handle (doesn't work for inherited handles), system fds for every handle (doesn't work for inherited handles),
but we create pseudo fds in a private namespace that designate a but we create pseudo fds in a private namespace that designate a

View File

@ -56,6 +56,16 @@ _gpgme_io_subsystem_init (void)
} }
} }
/* Write the printable version of FD to the buffer BUF of length
BUFLEN. The printable version is the representation on the command
line that the child process expects. */
int
_gpgme_io_fd2str (char *buf, int buflen, int fd)
{
return snprintf (buf, buflen, "%d", fd);
}
static struct static struct
{ {

View File

@ -59,7 +59,9 @@ int _gpgme_io_spawn (const char *path, char **argv,
struct spawn_fd_item_s *fd_parent_list); struct spawn_fd_item_s *fd_parent_list);
int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock); int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock);
/* Write the printable version of FD to the buffer BUF of length
BUFLEN. The printable version is the representation on the command
line that the child process expects. */
int _gpgme_io_fd2str (char *buf, int buflen, int fd);
#endif /* IO_H */ #endif /* IO_H */

View File

@ -407,7 +407,7 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
{ {
char buf[25]; char buf[25];
sprintf (buf, "%d", gpg->status.fd[1]); _gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]);
rc = add_arg (gpg, buf); rc = add_arg (gpg, buf);
if (rc) if (rc)
goto leave; goto leave;
@ -720,7 +720,10 @@ build_argv (engine_gpg_t gpg)
fd_data_map[datac].dup_to = a->dup_to; fd_data_map[datac].dup_to = a->dup_to;
if (a->dup_to == -1) if (a->dup_to == -1)
{ {
argv[argc] = malloc (25); char *ptr;
int buflen = 25;
argv[argc] = malloc (buflen);
if (!argv[argc]) if (!argv[argc])
{ {
int saved_errno = errno; int saved_errno = errno;
@ -728,9 +731,16 @@ build_argv (engine_gpg_t gpg)
free_argv (argv); free_argv (argv);
return gpg_error_from_errno (saved_errno); return gpg_error_from_errno (saved_errno);
} }
sprintf (argv[argc],
a->print_fd ? "%d" : "-&%d", ptr = argv[argc];
fd_data_map[datac].peer_fd); if (!a->print_fd)
{
*(ptr++) = '-';
*(ptr++) = '&';
buflen -= 2;
}
_gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
argc++; argc++;
} }
datac++; datac++;

View File

@ -56,17 +56,7 @@
whole thing is also interconnected with the creation of pipes and whole thing is also interconnected with the creation of pipes and
child processes. child processes.
The following rules apply only to this I/O backend: The following rule applies only to this I/O backend:
* All "file descriptors" that GPGME gives to the application are
not system file descriptors, but some internal number maintained by
GPGME. I call them "Something like a file descriptor" (SLAFD).
It's an ugly name for an ugly thing.
* The application can use this "file descriptor" for exactly one
thing: To call gpgme_get_giochannel on it. This returns the
GIOChannel that the application can actually use. The channel can
then be integrated in the event loop.
* ALL operations must use the user defined event loop. GPGME can * ALL operations must use the user defined event loop. GPGME can
not anymore provide its own event loop. This is mostly a sanity not anymore provide its own event loop. This is mostly a sanity
@ -79,78 +69,41 @@
a per-context level. */ a per-context level. */
/* Something like a file descriptor. We can not use "real" file #define MAX_SLAFD 256
descriptors, because for some reason we can't create them from
osfhandles to be inherited. Argh! */
static struct
{
/* This is non-null if the entry is used. */
HANDLE osfhandle;
/* This is non-null if there is a GIOChannel for this handle. Only GIOChannel *giochannel_table[MAX_SLAFD];
for our end of the pipe. */
GIOChannel *channel;
} slafd_table[256];
#define MAX_SLAFD ((int) DIM (slafd_table))
static int
create_slafd (HANDLE handle, int create_channel)
{
int slafd;
for (slafd = 0; slafd < MAX_SLAFD; slafd++)
if (slafd_table[slafd].osfhandle == NULL)
break;
if (slafd == MAX_SLAFD)
return -1;
if (create_channel)
{
/* FIXME: Do we need to specify the direction, too? */
// int fd = _open_osfhandle ((long) handle, 0);
// DEBUG2("opened handle %p to %i\n", handle, fd);
slafd_table[slafd].channel = g_io_channel_unix_new ((int)handle);
if (!slafd_table[slafd].channel)
{
errno = EIO; /* XXX */
return -1;
}
}
else
slafd_table[slafd].channel = NULL;
slafd_table[slafd].osfhandle = handle;
return slafd;
}
static GIOChannel * static GIOChannel *
find_channel (int fd) find_channel (int fd, int create)
{ {
if (fd < 0 || fd >= MAX_SLAFD) if (fd < 0 || fd >= MAX_SLAFD)
return NULL; return NULL;
return slafd_table[fd].channel; if (create && !giochannel_table[fd])
giochannel_table[fd] = g_io_channel_unix_new (fd);
return giochannel_table[fd];
} }
static HANDLE
find_handle (int fd)
{
if (fd < 0 || fd >= MAX_SLAFD)
return NULL;
return slafd_table[fd].osfhandle;
}
/* Look up the giochannel for "file descriptor" FD. */ /* Look up the giochannel for "file descriptor" FD. */
GIOChannel * GIOChannel *
gpgme_get_giochannel (int fd) gpgme_get_giochannel (int fd)
{ {
return find_channel (fd); return find_channel (fd, 0);
}
/* Write the printable version of FD to the buffer BUF of length
BUFLEN. The printable version is the representation on the command
line that the child process expects. */
int
_gpgme_io_fd2str (char *buf, int buflen, int fd)
{
printf ("Converting fd %d to %ld\n", fd, (long) _get_osfhandle (fd));
printf ("Converting fd %d to %ld\n", fd, (long) _get_osfhandle (fd));
printf ("Converting fd %d to %ld\n", fd, (long) _get_osfhandle (fd));
return snprintf (buf, buflen, "%ld", (long) _get_osfhandle (fd));
} }
@ -176,7 +129,7 @@ _gpgme_io_read (int fd, void *buffer, size_t count)
DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count); DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
chan = find_channel (fd); chan = find_channel (fd, 0);
if (!chan) if (!chan)
{ {
DEBUG1 ("fd %d: no channel registered\n", fd); DEBUG1 ("fd %d: no channel registered\n", fd);
@ -225,7 +178,7 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count); DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count);
_gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer); _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
chan = find_channel (fd); chan = find_channel (fd, 0);
if (!chan) if (!chan)
{ {
DEBUG1 ("fd %d: no channel registered\n", fd); DEBUG1 ("fd %d: no channel registered\n", fd);
@ -249,66 +202,58 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
int int
_gpgme_io_pipe (int filedes[2], int inherit_idx) _gpgme_io_pipe (int filedes[2], int inherit_idx)
{ {
HANDLE r, w; GIOChannel *chan;
SECURITY_ATTRIBUTES sec_attr;
memset (&sec_attr, 0, sizeof sec_attr );
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
DEBUG1("INHERIT: %i\n", inherit_idx);
#define PIPEBUF_SIZE 4096 #define PIPEBUF_SIZE 4096
if (!CreatePipe ( &r, &w, &sec_attr, PIPEBUF_SIZE)) if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT) == -1)
return -1; return -1;
/* Make one end inheritable. */ /* Make one end inheritable. */
if ( inherit_idx == 0 ) { if (inherit_idx == 0)
HANDLE h;
if (!DuplicateHandle( GetCurrentProcess(), r,
GetCurrentProcess(), &h, 0,
TRUE, DUPLICATE_SAME_ACCESS ) ) {
DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
CloseHandle (r);
CloseHandle (w);
return -1;
}
CloseHandle (r);
r = h;
}
else if ( inherit_idx == 1 ) {
HANDLE h;
if (!DuplicateHandle( GetCurrentProcess(), w,
GetCurrentProcess(), &h, 0,
TRUE, DUPLICATE_SAME_ACCESS ) ) {
DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
CloseHandle (r);
CloseHandle (w);
return -1;
}
CloseHandle (w);
w = h;
}
filedes[0] = create_slafd (r, inherit_idx == 1);
if (filedes[0] == -1)
{ {
DEBUG1 ("create_slafd failed: ec=%d\n", errno); int new_read;
CloseHandle (r);
CloseHandle (w); new_read = _dup (filedes[0]);
_close (filedes[0]);
filedes[0] = new_read;
if (new_read < 0)
{
_close (filedes[1]);
return -1;
}
}
else if (inherit_idx == 1)
{
int new_write;
new_write = _dup (filedes[1]);
_close (filedes[1]);
filedes[1] = new_write;
if (new_write < 0)
{
_close (filedes[0]);
return -1;
}
}
/* Now we have a pipe with the right end inheritable. The other end
should have a giochannel. */
chan = find_channel (filedes[1 - inherit_idx], 1);
if (!chan)
{
DEBUG2 ("channel creation for %d failed: ec=%d\n",
filedes[1 - inherit_idx], errno);
_close (filedes[0]);
_close (filedes[1]);
return -1; return -1;
} }
filedes[1] = create_slafd (w, inherit_idx == 0); DEBUG5 ("CreatePipe %d (%p) %d (%p) inherit=%p\n",
if (filedes[1] == -1) filedes[0], (HANDLE) _get_osfhandle (filedes[0]),
{ filedes[1], (HANDLE) _get_osfhandle (filedes[1]),
DEBUG1 ("create_slafd failed: ec=%d\n", errno); chan);
_gpgme_io_close (filedes[0]);
CloseHandle (r);
CloseHandle (w);
return -1;
}
DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w,
filedes[0], filedes[1], inherit_idx );
return 0; return 0;
} }
@ -334,20 +279,15 @@ _gpgme_io_close (int fd)
} }
/* Then do the close. */ /* Then do the close. */
chan = slafd_table[fd].channel; chan = giochannel_table[fd];
if (chan) if (chan)
{ {
g_io_channel_shutdown (chan, 1, NULL); g_io_channel_shutdown (chan, 1, NULL);
g_io_channel_unref (chan); g_io_channel_unref (chan);
giochannel_table[fd] = NULL;
} }
if (!CloseHandle (slafd_table[fd].osfhandle)) _close (fd);
{
DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n",
fd, (int)GetLastError ());
}
slafd_table[fd].osfhandle = NULL;
return 0; return 0;
} }
@ -373,7 +313,7 @@ _gpgme_io_set_nonblocking (int fd)
GIOChannel *chan; GIOChannel *chan;
GIOStatus status; GIOStatus status;
chan = find_channel (fd); chan = find_channel (fd, 0);
if (!chan) if (!chan)
{ {
errno = EIO; errno = EIO;
@ -471,19 +411,20 @@ _gpgme_io_spawn ( const char *path, char **argv,
for (i=0; fd_child_list[i].fd != -1; i++ ) { for (i=0; fd_child_list[i].fd != -1; i++ ) {
if (fd_child_list[i].dup_to == 0 ) { if (fd_child_list[i].dup_to == 0 ) {
si.hStdInput = find_handle (fd_child_list[i].fd); si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
DEBUG2 ("using %d (%p) for stdin", fd_child_list[i].fd, DEBUG2 ("using %d (%p) for stdin", fd_child_list[i].fd,
find_handle (fd_child_list[i].fd)); _get_osfhandle (fd_child_list[i].fd));
duped_stdin=1; duped_stdin=1;
} }
else if (fd_child_list[i].dup_to == 1 ) { else if (fd_child_list[i].dup_to == 1 ) {
si.hStdOutput = find_handle (fd_child_list[i].fd); si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
DEBUG2 ("using %d (%p) for stdout", fd_child_list[i].fd, DEBUG2 ("using %d (%p) for stdout", fd_child_list[i].fd,
find_handle (fd_child_list[i].fd)); _get_osfhandle (fd_child_list[i].fd));
} }
else if (fd_child_list[i].dup_to == 2 ) { else if (fd_child_list[i].dup_to == 2 ) {
si.hStdError = find_handle (fd_child_list[i].fd); si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
DEBUG1 ("using %d for stderr", fd_child_list[i].fd ); DEBUG2 ("using %d (%p) for stderr", fd_child_list[i].fd,
_get_osfhandle (fd_child_list[i].fd));
duped_stderr = 1; duped_stderr = 1;
} }
} }
@ -574,7 +515,72 @@ _gpgme_io_spawn ( const char *path, char **argv,
int int
_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
{ {
assert (!"ARGH! The user of this library MUST define io callbacks!"); int i;
errno = EINVAL; int res = 0;
return -1; void *dbg_help = NULL;
/* Use g_io_channel_get_buffer_condition. This will help with the
_gpgme_io_select uses in rungpg.c and wait.c::_gpgme_run_io_cb,
but not with the global or private event loop. The user still
must define io cbs for all operations. */
if (!nonblock)
assert (!"Can not provide blocking select on this target.");
DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ ");
for (i = 0; i < nfds; i++)
{
if (fds[i].fd == -1)
continue;
if (fds[i].frozen)
DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd);
else if (fds[i].for_read)
{
GIOChannel *chan = find_channel (fds[i].fd, 0);
assert (chan);
DEBUG2("channel %p cond %i\n",
chan,
g_io_channel_get_buffer_condition (chan));
if (g_io_channel_get_buffer_condition (chan) & G_IO_IN)
{
fds[i].signaled = 1;
res++;
}
DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd);
}
else if (fds[i].for_write)
{
GIOChannel *chan = find_channel (fds[i].fd, 0);
assert (chan);
if (g_io_channel_get_buffer_condition (chan) & G_IO_OUT)
{
fds[i].signaled = 1;
res++;
}
DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd);
}
else
fds[i].signaled = 0;
}
DEBUG_END (dbg_help, "]");
DEBUG_BEGIN (dbg_help, 3, "select OK [ ");
if (DEBUG_ENABLED (dbg_help))
{
for (i = 0; i <= nfds; i++)
{
if (fds[i].fd == -1 || fds[i].frozen || !fds[i].signaled)
continue;
else if (fds[i].for_read)
DEBUG_ADD1 (dbg_help, "r%d ", i);
else if (fds[i].for_write)
DEBUG_ADD1 (dbg_help, "w%d ", i);
}
DEBUG_END (dbg_help, "]");
}
return 1;
} }

View File

@ -1091,6 +1091,16 @@ _gpgme_io_subsystem_init (void)
} }
/* Write the printable version of FD to the buffer BUF of length
BUFLEN. The printable version is the representation on the command
line that the child process expects. */
int
_gpgme_io_fd2str (char *buf, int buflen, int fd)
{
return snprintf (buf, buflen, "%d", fd);
}
/* The following interface is only useful for GPGME Glib. */ /* The following interface is only useful for GPGME Glib. */