static gpg_error_t armor_data (char **r_string, const void *data, size_t datalen) { gpg_error_t err; struct b64state b64state; estream_t fp; long length; char *buffer; size_t nread; *r_string = NULL; fp = es_fopenmem (0, "rw"); if (!fp) return gpg_error_from_syserror (); if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK")) || (err=b64enc_write (&b64state, data, datalen)) || (err = b64enc_finish (&b64state))) { es_fclose (fp); return err; } /* FIXME: To avoid the extra buffer allocation estream should provide a function to snatch the internal allocated memory from such a memory stream. */ length = es_ftell (fp); if (length < 0) { err = gpg_error_from_syserror (); es_fclose (fp); return err; } buffer = xtrymalloc (length+1); if (!buffer) { err = gpg_error_from_syserror (); es_fclose (fp); return err; } es_rewind (fp); if (es_read (fp, buffer, length, &nread)) { err = gpg_error_from_syserror (); es_fclose (fp); return err; } buffer[nread] = 0; es_fclose (fp); *r_string = buffer; return 0; }
/* Copy all data from IN to OUT. */ static gpg_error_t copy_stream (estream_t in, estream_t out) { char buffer[512]; size_t nread; while (!es_read (in, buffer, sizeof buffer, &nread)) { if (!nread) return 0; /* EOF */ if (es_write (out, buffer, nread, NULL)) break; } return gpg_error_from_syserror (); }
/* The thread started by start_writer. */ static void * writer_thread_main (void *arg) { gpg_error_t err = 0; struct writer_thread_parms *parm = arg; char _buffer[4096]; char *buffer; size_t length; if (parm->stream) { buffer = _buffer; err = es_read (parm->stream, buffer, sizeof _buffer, &length); if (err) { log_error ("reading stream failed: %s\n", gpg_strerror (err)); goto leave; } } else { buffer = (char *) parm->data; length = parm->datalen; } while (length) { ssize_t nwritten; nwritten = npth_write (parm->fd, buffer, length < 4096? length:4096); if (nwritten < 0) { if (errno == EINTR) continue; err = my_error_from_syserror (); break; /* Write error. */ } length -= nwritten; if (parm->stream) { if (length == 0) { err = es_read (parm->stream, buffer, sizeof _buffer, &length); if (err) { log_error ("reading stream failed: %s\n", gpg_strerror (err)); break; } if (length == 0) /* We're done. */ break; } } else buffer += nwritten; } leave: *parm->err_addr = err; if (close (parm->fd)) log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno)); xfree (parm); return NULL; }
/* The thread started by start_feede3. */ static void * feeder_thread (void *arg) { struct feeder_thread_parms *parm = arg; char buffer[4096]; int rc; if (parm->direction) { size_t nread = 0; DWORD nwritten; log_debug ("feeder_thread estream->pipe: stream=%p pipe=%p\n", parm->stream, parm->hd); while (parm->stream_valid && !es_read (parm->stream, buffer, sizeof buffer, &nread)) { do { pth_enter (); rc = WriteFile (parm->hd, buffer, nread, &nwritten, NULL); pth_leave (); if (!rc) { log_debug ("feeder(%p): WriteFile error: rc=%d\n", parm->hd, (int)GetLastError ()); goto leave; } nread -= nwritten; } while (nread); } if (!parm->stream_valid) log_debug ("feeder(%p): closed by other thread\n", parm->hd); else if (nread) log_debug ("feeder(%p): es_read error: %s\n", parm->hd, strerror (errno)); } else { DWORD nread = 0; size_t nwritten; log_debug ("feeder_thread pipe->estream: stream=%p pipe=%p\n", parm->stream, parm->hd); while ( (pth_enter (), (rc = ReadFile (parm->hd, buffer, sizeof buffer, &nread, NULL)), pth_leave (), rc) && nread) { log_debug ("feeder_thread pipe->estream: read %d bytes\n", (int)nread); do { if (parm->stream_valid && es_write (parm->stream, buffer, nread, &nwritten)) { log_debug ("feeder(%p): es_write error: %s\n", parm->hd, strerror (errno)); goto leave; } log_debug ("feeder_thread pipe->estream: es_wrote %d bytes\n", (int)nwritten); nread -= nwritten; } while (nread && parm->stream_valid); } if (!parm->stream_valid) log_debug ("feeder(%p): closed by other thread\n", parm->hd); else if (nread) log_debug ("feeder(%p): ReadFile error: rc=%d\n", parm->hd, (int)GetLastError ()); else log_debug ("feeder(%p): eof\n", parm->hd); } leave: log_debug ("feeder(%p): waiting for es_fclose\n", parm->hd); while (parm->stream_valid) pth_yield (NULL); log_debug ("feeder(%p): about to close the pipe handle\n", parm->hd); CloseHandle (parm->hd); log_debug ("feeder(%p): pipe handle closed\n", parm->hd); xfree (parm); return NULL; }