diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/iobuf.c | 77 | ||||
-rw-r--r-- | common/iobuf.h | 8 | ||||
-rw-r--r-- | common/ksba-io-support.c | 98 | ||||
-rw-r--r-- | common/ksba-io-support.h | 10 | ||||
-rw-r--r-- | common/name-value.c | 2 | ||||
-rw-r--r-- | common/stringhelp.c | 44 | ||||
-rw-r--r-- | common/stringhelp.h | 5 | ||||
-rw-r--r-- | common/sysutils.c | 5 | ||||
-rw-r--r-- | common/sysutils.h | 2 | ||||
-rw-r--r-- | common/tlv.c | 9 |
10 files changed, 176 insertions, 84 deletions
diff --git a/common/iobuf.c b/common/iobuf.c index 2adf61e3c..fb87ff65d 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -505,7 +505,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (ec != ERROR_BROKEN_PIPE) { rc = gpg_error_from_errno (ec); - log_error ("%s: read error: ec=%d\n", a->fname, ec); + log_error ("%s: read error: %s (ec=%d)\n", + a->fname, gpg_strerror (rc), ec); } } else if (!nread) @@ -573,9 +574,10 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, { if (size && !WriteFile (f, p, nbytes, &n, NULL)) { - int ec = (int) GetLastError (); - rc = gpg_error_from_errno (ec); - log_error ("%s: write error: ec=%d\n", a->fname, ec); + int ec = gnupg_w32_set_errno (-1); + rc = gpg_error_from_syserror (); + log_error ("%s: write error: %s (ec=%d)\n", + a->fname, gpg_strerror (rc), ec); break; } p += n; @@ -634,7 +636,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (ec != ERROR_BROKEN_PIPE) { rc = gpg_error_from_errno (ec); - log_error ("%s: read error: ec=%d\n", a->fname, ec); + log_error ("%s: read error: %s (ec=%d)\n", + a->fname, gpg_strerror (rc), ec); } a->npeeked = 0; } @@ -883,7 +886,8 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (n == SOCKET_ERROR) { int ec = (int) WSAGetLastError (); - rc = gpg_error_from_errno (ec); + gnupg_w32_set_errno (ec); + rc = gpg_error_from_syserror (); log_error ("socket write error: ec=%d\n", ec); break; } @@ -2606,13 +2610,10 @@ iobuf_set_limit (iobuf_t a, off_t nlimit) } - -off_t -iobuf_get_filelength (iobuf_t a, int *overflow) +/* Return the length of the file behind A. If there is no file, return 0. */ +uint64_t +iobuf_get_filelength (iobuf_t a) { - if (overflow) - *overflow = 0; - /* Hmmm: file_filter may have already been removed */ for ( ; a->chain; a = a->chain ) ; @@ -2625,56 +2626,18 @@ iobuf_get_filelength (iobuf_t a, int *overflow) gnupg_fd_t fp = b->fp; #if defined(HAVE_W32_SYSTEM) - ulong size; - static int (* __stdcall get_file_size_ex) (void *handle, - LARGE_INTEGER *r_size); - static int get_file_size_ex_initialized; - - if (!get_file_size_ex_initialized) - { - void *handle; - - handle = dlopen ("kernel32.dll", RTLD_LAZY); - if (handle) - { - get_file_size_ex = dlsym (handle, "GetFileSizeEx"); - if (!get_file_size_ex) - dlclose (handle); - } - get_file_size_ex_initialized = 1; - } - - if (get_file_size_ex) - { - /* This is a newer system with GetFileSizeEx; we use this - then because it seem that GetFileSize won't return a - proper error in case a file is larger than 4GB. */ - LARGE_INTEGER exsize; + LARGE_INTEGER exsize; - if (get_file_size_ex (fp, &exsize)) - { - if (!exsize.u.HighPart) - return exsize.u.LowPart; - if (overflow) - *overflow = 1; - return 0; - } - } - else - { - if ((size=GetFileSize (fp, NULL)) != 0xffffffff) - return size; - } + if (GetFileSizeEx (fp, &exsize)) + return exsize.QuadPart; log_error ("GetFileSize for handle %p failed: %s\n", fp, w32_strerror (-1)); #else /*!HAVE_W32_SYSTEM*/ - { - struct stat st; + struct stat st; - if ( !fstat (fp, &st) ) - return st.st_size; - log_error("fstat() failed: %s\n", strerror(errno) ); - } + if ( !fstat (fp, &st) ) + return st.st_size; + log_error("fstat() failed: %s\n", strerror(errno) ); #endif /*!HAVE_W32_SYSTEM*/ } diff --git a/common/iobuf.h b/common/iobuf.h index ad416fe86..04e6b4421 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -584,12 +584,8 @@ size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen); size_t iobuf_copy (iobuf_t dest, iobuf_t source); /* Return the size of any underlying file. This only works with - file_filter based pipelines. - - On Win32, it is sometimes not possible to determine the size of - files larger than 4GB. In this case, *OVERFLOW (if not NULL) is - set to 1. Otherwise, *OVERFLOW is set to 0. */ -off_t iobuf_get_filelength (iobuf_t a, int *overflow); + file_filter based pipelines. */ +uint64_t iobuf_get_filelength (iobuf_t a); #define IOBUF_FILELENGTH_LIMIT 0xffffffff /* Return the file descriptor designating the underlying file. This diff --git a/common/ksba-io-support.c b/common/ksba-io-support.c index a279b67ad..352485ffa 100644 --- a/common/ksba-io-support.c +++ b/common/ksba-io-support.c @@ -1,6 +1,6 @@ /* kska-io-support.c - Supporting functions for ksba reader and writer * 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. * @@ -26,6 +26,7 @@ * * You should have received a copy of the GNU General Public License * 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> @@ -96,6 +97,15 @@ struct writer_cb_parm_s 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 did_finish; @@ -110,6 +120,7 @@ struct writer_cb_parm_s /* Context for this module's functions. */ struct gnupg_ksba_io_s { + int is_writer; /* True if this context refers a writer object. */ union { struct reader_cb_parm_s rparm; 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 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; const unsigned char *p; estream_t stream = parm->stream; + int rc; + size_t nleft; if (!count) return 0; @@ -557,7 +597,7 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count) for (i=0; i < idx; i++) radbuf[i] = parm->base64.radbuf[i]; - for (p=buffer; count; p++, count--) + for (p=buffer, nleft = count; nleft; p++, nleft--) { radbuf[idx++] = *p; 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.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; estream_t stream = parm->stream; + int rc; if (!count) return 0; es_write (stream, buffer, count, NULL); - - 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, count, 0); + return rc; } @@ -610,6 +657,7 @@ base64_finish_write (struct writer_cb_parm_s *parm) unsigned char *radbuf; int c, idx, quad_count; estream_t stream = parm->stream; + int rc; if (!parm->wrote_begin) 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); } - 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); if (!*ctx) return gpg_error_from_syserror (); + (*ctx)->is_writer = 1; rc = ksba_writer_new (&w); if (rc) @@ -865,3 +917,37 @@ gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx) xfree (ctx->u.wparm.pem_name); 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; +} diff --git a/common/ksba-io-support.h b/common/ksba-io-support.h index 02e541b16..1dbc303c8 100644 --- a/common/ksba-io-support.h +++ b/common/ksba-io-support.h @@ -25,6 +25,7 @@ * * You should have received a copy of the GNU General Public License * 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 @@ -42,6 +43,10 @@ /* Context object. */ 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, @@ -57,10 +62,13 @@ gpg_error_t gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, const char *pem_name, estream_t stream, ksba_writer_t *r_writer); - 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_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); + diff --git a/common/name-value.c b/common/name-value.c index 6f3df5a8d..0dffc63b4 100644 --- a/common/name-value.c +++ b/common/name-value.c @@ -616,7 +616,7 @@ nve_next_value (nve_t entry, const char *name) /* Return the string for the first entry in NVC with NAME. If an * entry with NAME is missing in NVC or its value is the empty string - * NULL is returned. Note that the The returned string is a pointer + * NULL is returned. Note that the the returned string is a pointer * into NVC. */ const char * nvc_get_string (nvc_t nvc, const char *name) diff --git a/common/stringhelp.c b/common/stringhelp.c index 6959299e4..1049c78e2 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -1689,10 +1689,16 @@ format_text (const char *text_in, int target_cols, int max_cols) } -/* Substitute environment variables in STRING and return a new string. - * On error the function returns NULL. */ +/* Substitute variables in STRING and return a new string. GETVAL is + * a function which maps NAME to its value; that value is a string + * which may not change during the execution time of this function. + * If GETVAL returns NULL substitute_vars returns NULL and the caller + * may inspect ERRNO for the reason. In all other error cases this + * function also returns NULL. Caller must free the returned string. */ char * -substitute_envvars (const char *string) +substitute_vars (const char *string, + const char *(*getval)(void *cookie, const char *name), + void *cookie) { char *line, *p, *pend; const char *value; @@ -1743,19 +1749,22 @@ substitute_envvars (const char *string) { int save = *pend; *pend = 0; - value = getenv (p+2); + value = getval (cookie, p+2); *pend++ = save; } else { int save = *pend; *pend = 0; - value = getenv (p+1); + value = getval (cookie, p+1); *pend = save; } if (!value) - value = ""; + { + xfree (result); + return NULL; + } valuelen = strlen (value); if (valuelen <= pend - p) { @@ -1791,3 +1800,26 @@ substitute_envvars (const char *string) leave: return result; } + + +/* Helper for substitute_envvars. */ +static const char * +subst_getenv (void *cookie, const char *name) +{ + const char *s; + + (void)cookie; + + s = getenv (name); + return s? s : ""; +} + + +/* Substitute environment variables in STRING and return a new string. + * On error the function returns NULL. */ +char * +substitute_envvars (const char *string) +{ + return substitute_vars (string, subst_getenv, NULL); + +} diff --git a/common/stringhelp.h b/common/stringhelp.h index 915b3aa72..cd185e49a 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -169,7 +169,10 @@ int compare_version_strings (const char *my_version, const char *req_version); /* Format a string so that it fits within about TARGET_COLS columns. */ char *format_text (const char *text, int target_cols, int max_cols); -/* Substitute environmen variabales in STRING. */ +/* Substitute variables in STRING. */ +char *substitute_vars (const char *string, + const char *(*getval)(void *cookie, const char *name), + void *cookie); char *substitute_envvars (const char *string); diff --git a/common/sysutils.c b/common/sysutils.c index 8a1554a28..fc60af49c 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -327,9 +327,10 @@ map_w32_to_errno (DWORD w32_err) #endif /*HAVE_W32_SYSTEM*/ -/* Set ERRNO from the Windows error. EC may be -1 to use the last error. */ +/* Set ERRNO from the Windows error. EC may be -1 to use the last + * error. Returns the Windows error code. */ #ifdef HAVE_W32_SYSTEM -void +int gnupg_w32_set_errno (int ec) { /* FIXME: Replace by gpgrt_w32_set_errno. */ diff --git a/common/sysutils.h b/common/sysutils.h index 7fd01bae1..50e59175f 100644 --- a/common/sysutils.h +++ b/common/sysutils.h @@ -111,7 +111,7 @@ int gnupg_inotify_has_name (int fd, const char *name); #ifdef HAVE_W32_SYSTEM -void gnupg_w32_set_errno (int ec); +int gnupg_w32_set_errno (int ec); void *w32_get_user_sid (void); #include "../common/w32help.h" diff --git a/common/tlv.c b/common/tlv.c index 4cc1dc7cf..4ba9ef20d 100644 --- a/common/tlv.c +++ b/common/tlv.c @@ -150,13 +150,16 @@ find_tlv_unchecked (const unsigned char *buffer, size_t length, /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag - and the length part from the TLV triplet. Update BUFFER and SIZE - on success. */ + * and the length part from the TLV triplet. Update BUFFER and SIZE + * on success. Note that this function does not check that the value + * fits into the provided buffer; this allows to work on the TL part + * of a TLV. */ gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size, int *r_class, int *r_tag, int *r_constructed, int *r_ndef, - size_t *r_length, size_t *r_nhdr){ + size_t *r_length, size_t *r_nhdr) +{ int c; unsigned long tag; const unsigned char *buf = *buffer; |