gpgsm: Print PROGRESS status lines.

* common/ksba-io-support.c (struct writer_cb_parm_s): Add field
progress.
(struct gnupg_ksba_io_s): Add field is_writer.
(update_write_progress): New.
(base64_writer_cb, plain_writer_cb): Call update_write_progress.
(base64_finish_write): Ditto.
(gnupg_ksba_create_writer): Set is_writer.
(gnupg_ksba_set_progress_cb): New.
(gnupg_ksba_set_total): New.
* common/ksba-io-support.h (gnupg_ksba_progress_cb_t): New type.
* sm/server.c (gpgsm_status2): Return error from statusfp writes.
(gpgsm_progress_cb): New.
* sm/decrypt.c (gpgsm_decrypt): Set progress handler.
* sm/encrypt.c (gpgsm_encrypt): Ditto.
* sm/sign.c (gpgsm_sign): Ditto.
* sm/verify.c (gpgsm_verify): Ditto.
--

GnuPG-bug-id: 6534
This commit is contained in:
Werner Koch 2023-06-15 10:37:07 +02:00
parent 808494b485
commit c58067415f
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
8 changed files with 167 additions and 10 deletions

View File

@ -1,6 +1,6 @@
/* kska-io-support.c - Supporting functions for ksba reader and writer /* kska-io-support.c - Supporting functions for ksba reader and writer
* Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch * Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch
* Copyright (C) 2006 g10 Code GmbH * Copyright (C) 2006, 2023 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -26,6 +26,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>. * along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
*/ */
#include <config.h> #include <config.h>
@ -96,6 +97,15 @@ struct writer_cb_parm_s
char *pem_name; /* Malloced. */ char *pem_name; /* Malloced. */
struct {
gnupg_ksba_progress_cb_t cb;
ctrl_t ctrl;
u32 last_time; /* last time reported */
uint64_t last; /* last amount reported */
uint64_t current; /* current amount */
uint64_t total; /* total amount */
} progress;
int wrote_begin; int wrote_begin;
int did_finish; int did_finish;
@ -110,6 +120,7 @@ struct writer_cb_parm_s
/* Context for this module's functions. */ /* Context for this module's functions. */
struct gnupg_ksba_io_s { struct gnupg_ksba_io_s {
int is_writer; /* True if this context refers a writer object. */
union { union {
struct reader_cb_parm_s rparm; struct reader_cb_parm_s rparm;
struct writer_cb_parm_s wparm; struct writer_cb_parm_s wparm;
@ -527,6 +538,33 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
/* Call the progress callback if its time. We do this very 2 seconds
* or if FORCE is set. However, we also require that at least 64KiB
* have been written to avoid unnecessary progress lines for small
* files. */
static gpg_error_t
update_write_progress (struct writer_cb_parm_s *parm, size_t count, int force)
{
gpg_error_t err = 0;
u32 timestamp;
parm->progress.current += count;
if (parm->progress.current >= (64*1024))
{
timestamp = make_timestamp ();
if (force || (timestamp - parm->progress.last_time > 1))
{
parm->progress.last = parm->progress.current;
parm->progress.last_time = timestamp;
err = parm->progress.cb (parm->progress.ctrl,
parm->progress.current,
parm->progress.total);
}
}
return err;
}
static int static int
base64_writer_cb (void *cb_value, const void *buffer, size_t count) base64_writer_cb (void *cb_value, const void *buffer, size_t count)
{ {
@ -535,6 +573,8 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
int i, c, idx, quad_count; int i, c, idx, quad_count;
const unsigned char *p; const unsigned char *p;
estream_t stream = parm->stream; estream_t stream = parm->stream;
int rc;
size_t nleft;
if (!count) if (!count)
return 0; return 0;
@ -557,7 +597,7 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
for (i=0; i < idx; i++) for (i=0; i < idx; i++)
radbuf[i] = parm->base64.radbuf[i]; radbuf[i] = parm->base64.radbuf[i];
for (p=buffer; count; p++, count--) for (p=buffer, nleft = count; nleft; p++, nleft--)
{ {
radbuf[idx++] = *p; radbuf[idx++] = *p;
if (idx > 2) if (idx > 2)
@ -583,7 +623,11 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
parm->base64.idx = idx; parm->base64.idx = idx;
parm->base64.quad_count = quad_count; parm->base64.quad_count = quad_count;
return es_ferror (stream)? gpg_error_from_syserror () : 0; rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
/* Note that we use the unencoded count for the progress. */
if (!rc && parm->progress.cb)
rc = update_write_progress (parm, count, 0);
return rc;
} }
@ -594,13 +638,16 @@ plain_writer_cb (void *cb_value, const void *buffer, size_t count)
{ {
struct writer_cb_parm_s *parm = cb_value; struct writer_cb_parm_s *parm = cb_value;
estream_t stream = parm->stream; estream_t stream = parm->stream;
int rc;
if (!count) if (!count)
return 0; return 0;
es_write (stream, buffer, count, NULL); es_write (stream, buffer, count, NULL);
rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
return es_ferror (stream)? gpg_error_from_syserror () : 0; if (!rc && parm->progress.cb)
rc = update_write_progress (parm, count, 0);
return rc;
} }
@ -610,6 +657,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
unsigned char *radbuf; unsigned char *radbuf;
int c, idx, quad_count; int c, idx, quad_count;
estream_t stream = parm->stream; estream_t stream = parm->stream;
int rc;
if (!parm->wrote_begin) if (!parm->wrote_begin)
return 0; /* Nothing written or we are not called in base-64 mode. */ return 0; /* Nothing written or we are not called in base-64 mode. */
@ -656,7 +704,10 @@ base64_finish_write (struct writer_cb_parm_s *parm)
es_fputs ("-----\n", stream); es_fputs ("-----\n", stream);
} }
return es_ferror (stream)? gpg_error_from_syserror () : 0; rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
if (!rc && parm->progress.cb)
rc = update_write_progress (parm, 0, 1);
return rc;
} }
@ -788,6 +839,7 @@ gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, unsigned int flags,
*ctx = xtrycalloc (1, sizeof **ctx); *ctx = xtrycalloc (1, sizeof **ctx);
if (!*ctx) if (!*ctx)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
(*ctx)->is_writer = 1;
rc = ksba_writer_new (&w); rc = ksba_writer_new (&w);
if (rc) if (rc)
@ -865,3 +917,37 @@ gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx)
xfree (ctx->u.wparm.pem_name); xfree (ctx->u.wparm.pem_name);
xfree (ctx); xfree (ctx);
} }
/* Set a callback to the writer object. CTRL will be bassed to the
* callback. */
void
gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx,
gnupg_ksba_progress_cb_t cb, ctrl_t ctrl)
{
struct writer_cb_parm_s *parm;
if (!ctx || !ctx->is_writer)
return; /* Currently only supported for writer objects. */
parm = &ctx->u.wparm;
parm->progress.cb = cb;
parm->progress.ctrl = ctrl;
parm->progress.last_time = 0;
parm->progress.last = 0;
parm->progress.current = 0;
parm->progress.total = 0;
}
/* Update the total count for the progress thingy. */
void
gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total)
{
struct writer_cb_parm_s *parm;
if (!ctx || !ctx->is_writer)
return; /* Currently only supported for writer objects. */
parm = &ctx->u.wparm;
parm->progress.total = total;
}

View File

@ -25,6 +25,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>. * along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
*/ */
#ifndef GNUPG_KSBA_IO_SUPPORT_H #ifndef GNUPG_KSBA_IO_SUPPORT_H
@ -42,6 +43,10 @@
/* Context object. */ /* Context object. */
typedef struct gnupg_ksba_io_s *gnupg_ksba_io_t; typedef struct gnupg_ksba_io_s *gnupg_ksba_io_t;
/* Progress callback type. */
typedef gpg_error_t (*gnupg_ksba_progress_cb_t)(ctrl_t ctrl,
uint64_t current,
uint64_t total);
gpg_error_t gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx, gpg_error_t gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
@ -57,10 +62,13 @@ gpg_error_t gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx,
const char *pem_name, const char *pem_name,
estream_t stream, estream_t stream,
ksba_writer_t *r_writer); ksba_writer_t *r_writer);
gpg_error_t gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx); gpg_error_t gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx);
void gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx); void gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx);
void gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx,
gnupg_ksba_progress_cb_t cb, ctrl_t ctrl);
void gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total);

View File

@ -1107,6 +1107,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
goto leave; goto leave;
} }
gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
rc = ksba_cms_new (&cms); rc = ksba_cms_new (&cms);
if (rc) if (rc)
goto leave; goto leave;

View File

@ -653,6 +653,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
goto leave; goto leave;
} }
gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
err = ksba_cms_new (&cms); err = ksba_cms_new (&cms);
if (err) if (err)
{ {
@ -828,7 +830,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
err = ksba_cms_build (cms, &stopreason); err = ksba_cms_build (cms, &stopreason);
if (err) if (err)
{ {
log_debug ("ksba_cms_build failed: %s\n", gpg_strerror (err)); log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
rc = err; rc = err;
goto leave; goto leave;
} }

View File

@ -316,6 +316,7 @@ gpg_error_t gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
gpg_err_code_t ec); gpg_err_code_t ec);
gpg_error_t gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text, gpg_error_t gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
gpg_error_t err); gpg_error_t err);
gpg_error_t gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total);
gpg_error_t gpgsm_proxy_pinentry_notify (ctrl_t ctrl, gpg_error_t gpgsm_proxy_pinentry_notify (ctrl_t ctrl,
const unsigned char *line); const unsigned char *line);

View File

@ -1506,7 +1506,14 @@ gpgsm_status2 (ctrl_t ctrl, int no, ...)
} }
} }
putc ('\n', statusfp); putc ('\n', statusfp);
fflush (statusfp); if (ferror (statusfp))
err = gpg_error_from_syserror ();
else
{
fflush (statusfp);
if (ferror (statusfp))
err = gpg_error_from_syserror ();
}
} }
else else
{ {
@ -1551,6 +1558,53 @@ gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
} }
/* This callback is used to emit progress status lines. */
gpg_error_t
gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total)
{
char buffer[60];
char units[] = "BKMGTPEZY?";
int unitidx = 0;
if (current > 1024*1024*20)
{
static int closed;
if (closed)
close (5);
closed = 1;
}
if (total)
{
if (total > current)
current = total;
while (total > 1024*1024)
{
total /= 1024;
current /= 1024;
unitidx++;
}
}
else
{
while (current > 1024*1024)
{
current /= 1024;
unitidx++;
}
}
if (unitidx > 9)
unitidx = 9;
snprintf (buffer, sizeof buffer, "? %lu %lu %c%s",
(unsigned long)current, (unsigned long)total,
units[unitidx], unitidx? "iB" : "");
return gpgsm_status2 (ctrl, STATUS_PROGRESS, "?", buffer, NULL);
}
/* Helper to notify the client about Pinentry events. Because that /* Helper to notify the client about Pinentry events. Because that
might disturb some older clients, this is only done when enabled might disturb some older clients, this is only done when enabled
via an option. Returns an gpg error code. */ via an option. Returns an gpg error code. */

View File

@ -687,6 +687,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
goto leave; goto leave;
} }
gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
err = ksba_cms_new (&cms); err = ksba_cms_new (&cms);
if (err) if (err)
{ {
@ -1027,7 +1029,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
err = ksba_cms_build (cms, &stopreason); err = ksba_cms_build (cms, &stopreason);
if (err) if (err)
{ {
log_debug ("ksba_cms_build failed: %s\n", gpg_strerror (err)); log_error ("creating CMS object failed: %s\n", gpg_strerror (err));
rc = err; rc = err;
goto leave; goto leave;
} }

View File

@ -158,6 +158,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
} }
} }
gnupg_ksba_set_progress_cb (b64writer, gpgsm_progress_cb, ctrl);
rc = ksba_cms_new (&cms); rc = ksba_cms_new (&cms);
if (rc) if (rc)
goto leave; goto leave;