1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

gpg: Make progress work for large files on Windows.

* common/iobuf.c (iobuf_get_filelength): Change return type to
uint64_t and remove the overflow args.  For Windows always use
GetFileSizeEx which is available since the long EOL-ed Windows XP.

* g10/sign.c (write_plaintext_packet): Adjust for changed
iobuf_get_filelength.
* g10/encrypt.c (encrypt_simple, encrypt_crypt): Ditto.
* g10/photoid.c (generate_photo_id): Ditto.  Also add an upper limit.

* g10/filter.h (progress_filter_context_t): Change amount values to
use uint64_t.
* g10/progress.c (write_status_progress): Change accordingly.

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

View File

@ -2608,13 +2608,10 @@ iobuf_set_limit (iobuf_t a, off_t nlimit)
} }
/* Return the length of the file behind A. If there is no file, return 0. */
off_t uint64_t
iobuf_get_filelength (iobuf_t a, int *overflow) iobuf_get_filelength (iobuf_t a)
{ {
if (overflow)
*overflow = 0;
/* Hmmm: file_filter may have already been removed */ /* Hmmm: file_filter may have already been removed */
for ( ; a->chain; a = a->chain ) for ( ; a->chain; a = a->chain )
; ;
@ -2627,56 +2624,18 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
gnupg_fd_t fp = b->fp; gnupg_fd_t fp = b->fp;
#if defined(HAVE_W32_SYSTEM) #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 (GetFileSizeEx (fp, &exsize))
{ return exsize.QuadPart;
if (!exsize.u.HighPart)
return exsize.u.LowPart;
if (overflow)
*overflow = 1;
return 0;
}
}
else
{
if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
return size;
}
log_error ("GetFileSize for handle %p failed: %s\n", log_error ("GetFileSize for handle %p failed: %s\n",
fp, w32_strerror (-1)); fp, w32_strerror (-1));
#else /*!HAVE_W32_SYSTEM*/ #else /*!HAVE_W32_SYSTEM*/
{
struct stat st; struct stat st;
if ( !fstat (fp, &st) ) if ( !fstat (fp, &st) )
return st.st_size; return st.st_size;
log_error("fstat() failed: %s\n", strerror(errno) ); log_error("fstat() failed: %s\n", strerror(errno) );
}
#endif /*!HAVE_W32_SYSTEM*/ #endif /*!HAVE_W32_SYSTEM*/
} }

View File

@ -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); size_t iobuf_copy (iobuf_t dest, iobuf_t source);
/* Return the size of any underlying file. This only works with /* Return the size of any underlying file. This only works with
file_filter based pipelines. file_filter based pipelines. */
uint64_t iobuf_get_filelength (iobuf_t a);
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);
#define IOBUF_FILELENGTH_LIMIT 0xffffffff #define IOBUF_FILELENGTH_LIMIT 0xffffffff
/* Return the file descriptor designating the underlying file. This /* Return the file descriptor designating the underlying file. This

View File

@ -580,12 +580,12 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode ) if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
{ {
off_t tmpsize; uint64_t tmpsize;
int overflow;
if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) tmpsize = iobuf_get_filelength(inp);
&& !overflow && opt.verbose) if (!tmpsize && opt.verbose)
log_info(_("WARNING: '%s' is an empty file\n"), filename ); log_info(_("WARNING: '%s' is an empty file\n"), filename );
/* We can't encode the length of very large files because /* We can't encode the length of very large files because
OpenPGP uses only 32 bit for file sizes. So if the OpenPGP uses only 32 bit for file sizes. So if the
size of a file is larger than 2^32 minus some bytes for size of a file is larger than 2^32 minus some bytes for
@ -942,11 +942,10 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (filename && *filename if (filename && *filename
&& !iobuf_is_pipe_filename (filename) && !opt.textmode ) && !iobuf_is_pipe_filename (filename) && !opt.textmode )
{ {
off_t tmpsize; uint64_t tmpsize;
int overflow;
if ( !(tmpsize = iobuf_get_filelength(inp, &overflow)) tmpsize = iobuf_get_filelength (inp);
&& !overflow && opt.verbose) if (!tmpsize && opt.verbose)
log_info(_("WARNING: '%s' is an empty file\n"), filename ); log_info(_("WARNING: '%s' is an empty file\n"), filename );
/* We can't encode the length of very large files because /* We can't encode the length of very large files because
OpenPGP uses only 32 bit for file sizes. So if the size OpenPGP uses only 32 bit for file sizes. So if the size

View File

@ -155,9 +155,9 @@ typedef struct {
typedef struct { typedef struct {
char *what; /* description */ char *what; /* description */
u32 last_time; /* last time reported */ u32 last_time; /* last time reported */
unsigned long last; /* last amount reported */ uint64_t last; /* last amount reported */
unsigned long offset; /* current amount */ uint64_t offset; /* current amount */
unsigned long total; /* total amount */ uint64_t total; /* total amount */
int refcount; int refcount;
} progress_filter_context_t; } progress_filter_context_t;

View File

@ -3499,7 +3499,13 @@ main (int argc, char **argv)
case oAllowFreeformUID: opt.allow_freeform_uid = 1; break; case oAllowFreeformUID: opt.allow_freeform_uid = 1; break;
case oNoAllowFreeformUID: opt.allow_freeform_uid = 0; break; case oNoAllowFreeformUID: opt.allow_freeform_uid = 0; break;
case oNoLiteral: opt.no_literal = 1; break; case oNoLiteral: opt.no_literal = 1; break;
case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break;
case oSetFilesize:
/* There are restricts on the value (e.g. < 2^32); you
* need to check the entire code to understand this. */
opt.set_filesize = pargs.r.ret_ulong;
break;
case oFastListMode: opt.fast_list_mode = 1; break; case oFastListMode: opt.fast_list_mode = 1; break;
case oFixedListMode: /* Dummy */ break; case oFixedListMode: /* Dummy */ break;
case oLegacyListMode: opt.legacy_list_mode = 1; break; case oLegacyListMode: opt.legacy_list_mode = 1; break;

View File

@ -160,12 +160,11 @@ generate_photo_id (ctrl_t ctrl, PKT_public_key *pk,const char *photo_name)
{ {
PKT_user_id *uid; PKT_user_id *uid;
int error=1,i; int error=1,i;
unsigned int len; uint64_t len;
char *filename; char *filename;
byte *photo=NULL; byte *photo=NULL;
byte header[16]; byte header[16];
IOBUF file; IOBUF file;
int overflow;
header[0]=0x10; /* little side of photo header length */ header[0]=0x10; /* little side of photo header length */
header[1]=0; /* big side of photo header length */ header[1]=0; /* big side of photo header length */
@ -233,11 +232,18 @@ generate_photo_id (ctrl_t ctrl, PKT_public_key *pk,const char *photo_name)
} }
len=iobuf_get_filelength(file, &overflow); len = iobuf_get_filelength(file);
if(len>6144 || overflow) if(len>6144)
{ {
tty_printf( _("This JPEG is really large (%d bytes) !\n"),len); /* We silently skip JPEGs larger than 1MiB because we have a
if(!cpr_get_answer_is_yes("photoid.jpeg.size", * 2MiB limit on the user ID packets and we need some limit
* anyway because the returned u64 is larger than the u32 or
* OpenPGP. Note that the diagnostic may print a wrong
* value if the value is really large; we don't fix this to
* avoid a string change. */
tty_printf( _("This JPEG is really large (%d bytes) !\n"), (int)len);
if(len > 1024*1024
|| !cpr_get_answer_is_yes("photoid.jpeg.size",
_("Are you sure you want to use it? (y/N) "))) _("Are you sure you want to use it? (y/N) ")))
{ {
iobuf_close(file); iobuf_close(file);

View File

@ -72,13 +72,11 @@ release_progress_context (progress_filter_context_t *pfx)
static void static void
write_status_progress (const char *what, write_status_progress (const char *what, uint64_t current, uint64_t total)
unsigned long current, unsigned long total_arg)
{ {
char buffer[60]; char buffer[60];
char units[] = "BKMGTPEZY?"; char units[] = "BKMGTPEZY?";
int unitidx = 0; int unitidx = 0;
uint64_t total = total_arg;
/* Although we use an unsigned long for the values, 32 bit /* Although we use an unsigned long for the values, 32 bit
* applications using GPGME will use an "int" and thus are limited * applications using GPGME will use an "int" and thus are limited
@ -91,7 +89,10 @@ write_status_progress (const char *what,
* to display how many percent of the operation has been done and * to display how many percent of the operation has been done and
* thus scaling CURRENT and TOTAL down before they get to large, * thus scaling CURRENT and TOTAL down before they get to large,
* should not have a noticeable effect except for rounding * should not have a noticeable effect except for rounding
* imprecision. */ * imprecision.
* Update 2023-06-13: We now use uint64_t but to keep the API stable
* we still do the scaling.
*/
if (!total && opt.input_size_hint) if (!total && opt.input_size_hint)
total = opt.input_size_hint; total = opt.input_size_hint;
@ -121,7 +122,7 @@ write_status_progress (const char *what,
unitidx = 9; unitidx = 9;
snprintf (buffer, sizeof buffer, "%.20s ? %lu %lu %c%s", snprintf (buffer, sizeof buffer, "%.20s ? %lu %lu %c%s",
what? what : "?", current, (unsigned long)total, what? what : "?", (unsigned long)current, (unsigned long)total,
units[unitidx], units[unitidx],
unitidx? "iB" : ""); unitidx? "iB" : "");
write_status_text (STATUS_PROGRESS, buffer); write_status_text (STATUS_PROGRESS, buffer);
@ -181,7 +182,7 @@ progress_filter (void *opaque, int control,
void void
handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name) handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
{ {
off_t filesize = 0; uint64_t filesize = 0;
if (!pfx) if (!pfx)
return; return;
@ -190,7 +191,7 @@ handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
log_assert (is_status_enabled ()); log_assert (is_status_enabled ());
if ( !iobuf_is_pipe_filename (name) && *name ) if ( !iobuf_is_pipe_filename (name) && *name )
filesize = iobuf_get_filelength (inp, NULL); filesize = iobuf_get_filelength (inp);
else if (opt.set_filesize) else if (opt.set_filesize)
filesize = opt.set_filesize; filesize = opt.set_filesize;

View File

@ -823,11 +823,10 @@ write_plaintext_packet (iobuf_t out, iobuf_t inp,
/* Try to calculate the length of the data. */ /* Try to calculate the length of the data. */
if ( !iobuf_is_pipe_filename (fname) && *fname) if ( !iobuf_is_pipe_filename (fname) && *fname)
{ {
off_t tmpsize; uint64_t tmpsize;
int overflow;
if (!(tmpsize = iobuf_get_filelength (inp, &overflow)) tmpsize = iobuf_get_filelength (inp);
&& !overflow && opt.verbose) if (!tmpsize && opt.verbose)
log_info (_("WARNING: '%s' is an empty file\n"), fname); log_info (_("WARNING: '%s' is an empty file\n"), fname);
/* We can't encode the length of very large files because /* We can't encode the length of very large files because