diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/iobuf.c | 97 | ||||
-rw-r--r-- | common/iobuf.h | 4 | ||||
-rw-r--r-- | common/miscellaneous.c | 77 | ||||
-rw-r--r-- | common/util.h | 2 |
4 files changed, 129 insertions, 51 deletions
diff --git a/common/iobuf.c b/common/iobuf.c index 2d2c8a585..f4766c6a4 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -1,7 +1,7 @@ /* iobuf.c - File Handling for OpenPGP. * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006, 2007, 2008, * 2009, 2010, 2011 Free Software Foundation, Inc. - * Copyright (C) 2015 g10 Code GmbH + * Copyright (C) 2015, 2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -93,6 +93,9 @@ typedef struct int no_cache; int eof_seen; int print_only_name; /* Flags indicating that fname is not a real file. */ + char peeked[32]; /* Read ahead buffer. */ + byte npeeked; /* Number of bytes valid in peeked. */ + byte upeeked; /* Number of bytes used from peeked. */ char fname[1]; /* Name of the file. */ } file_filter_ctx_t; @@ -454,7 +457,16 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (control == IOBUFCTRL_UNDERFLOW) { log_assert (size); /* We need a buffer. */ - if (a->eof_seen) + if (a->npeeked > a->upeeked) + { + nbytes = a->npeeked - a->upeeked; + if (nbytes > size) + nbytes = size; + memcpy (buf, a->peeked + a->upeeked, nbytes); + a->upeeked += nbytes; + *ret_len = nbytes; + } + else if (a->eof_seen) { rc = -1; *ret_len = 0; @@ -573,6 +585,68 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, a->eof_seen = 0; a->keep_open = 0; a->no_cache = 0; + a->npeeked = 0; + a->upeeked = 0; + } + else if (control == IOBUFCTRL_PEEK) + { + /* Peek on the input. */ +#ifdef HAVE_W32_SYSTEM + unsigned long nread; + + nbytes = 0; + if (!ReadFile (f, a->peeked, sizeof a->peeked, &nread, NULL)) + { + int ec = (int) GetLastError (); + if (ec != ERROR_BROKEN_PIPE) + { + rc = gpg_error_from_errno (ec); + log_error ("%s: read error: ec=%d\n", a->fname, ec); + } + a->npeeked = 0; + } + else if (!nread) + { + a->eof_seen = 1; + a->npeeked = 0; + } + else + { + a->npeeked = nread; + } + +#else /* Unix */ + + int n; + + peek_more: + do + { + n = read (f, a->peeked + a->npeeked, sizeof a->peeked - a->npeeked); + } + while (n == -1 && errno == EINTR); + if (n > 0) + { + a->npeeked += n; + if (a->npeeked < sizeof a->peeked) + goto peek_more; + } + else if (!n) /* eof */ + { + a->eof_seen = 1; + } + else /* error */ + { + rc = gpg_error_from_syserror (); + if (gpg_err_code (rc) != GPG_ERR_EPIPE) + log_error ("%s: read error: %s\n", a->fname, gpg_strerror (rc)); + } +#endif /* Unix */ + + size = a->npeeked < size? a->npeeked : size; + memcpy (buf, a->peeked, size); + *ret_len = size; + rc = 0; /* Return success - the user needs to check ret_len. */ } else if (control == IOBUFCTRL_DESC) { @@ -1487,6 +1561,25 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval) return fd_cache_synchronize (ptrval); } } + else if (cmd == IOBUF_IOCTL_PEEK) + { + /* Peek at a justed opened file. Use this only directly after a + * file has been opened for reading. Don't use it after you did + * a seek. This works only if just file filter has been + * pushed. Expects a buffer wit size INTVAL at PTRVAL and returns + * the number of bytes put into the buffer. */ + if (DBG_IOBUF) + log_debug ("iobuf-%d.%d: ioctl '%s' peek\n", + a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a, desc)); + if (a->filter == file_filter && ptrval && intval) + { + file_filter_ctx_t *fcx = a->filter_ov; + size_t len = intval; + + if (!file_filter (fcx, IOBUFCTRL_PEEK, NULL, ptrval, &len)) + return (int)len; + } + } return -1; diff --git a/common/iobuf.h b/common/iobuf.h index 624e154d8..79d361c18 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -106,6 +106,7 @@ enum IOBUFCTRL_FLUSH = 4, IOBUFCTRL_DESC = 5, IOBUFCTRL_CANCEL = 6, + IOBUFCTRL_PEEK = 7, IOBUFCTRL_USER = 16 }; @@ -116,7 +117,8 @@ typedef enum IOBUF_IOCTL_KEEP_OPEN = 1, /* Uses intval. */ IOBUF_IOCTL_INVALIDATE_CACHE = 2, /* Uses ptrval. */ IOBUF_IOCTL_NO_CACHE = 3, /* Uses intval. */ - IOBUF_IOCTL_FSYNC = 4 /* Uses ptrval. */ + IOBUF_IOCTL_FSYNC = 4, /* Uses ptrval. */ + IOBUF_IOCTL_PEEK = 5 /* Uses intval and ptrval. */ } iobuf_ioctl_t; enum iobuf_use diff --git a/common/miscellaneous.c b/common/miscellaneous.c index c3775547b..b73239eaa 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -466,7 +466,7 @@ decode_c_string (const char *src) /* Check whether (BUF,LEN) is valid header for an OpenPGP compressed * packet. LEN should be at least 6. */ static int -is_openpgp_compressed_packet (unsigned char *buf, size_t len) +is_openpgp_compressed_packet (const unsigned char *buf, size_t len) { int c, ctb, pkttype; int lenbytes; @@ -508,63 +508,46 @@ is_openpgp_compressed_packet (unsigned char *buf, size_t len) /* - * Check if the file is compressed. + * Check if the file is compressed. You need to pass the first bytes + * of the file as (BUF,BUFLEN). Returns true if the buffer seems to + * be compressed. */ int -is_file_compressed (const char *s, int *ret_rc) +is_file_compressed (const byte *buf, unsigned int buflen) { - iobuf_t a; - byte buf[6]; - int i; - int rc = 0; - int overflow; - - struct magic_compress_s { - size_t len; - byte magic[4]; - } magic[] = { - { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ - { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ - { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ - }; - - if ( iobuf_is_pipe_filename (s) || !ret_rc ) - return 0; /* We can't check stdin or no file was given */ - - a = iobuf_open( s ); - if ( a == NULL ) { - *ret_rc = gpg_error_from_syserror (); - return 0; - } - iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL); + int i; - if ( iobuf_get_filelength( a, &overflow ) < 6 && !overflow) { - *ret_rc = 0; - goto leave; - } + struct magic_compress_s + { + byte len; + byte magic[5]; + } magic[] = + { + { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ + { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ + { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ + { 5, { '%', 'P', 'D', 'F', '-'} } /* PDF */ + }; - if ( iobuf_read( a, buf, 6 ) == -1 ) { - *ret_rc = a->error; - goto leave; + if ( buflen < 6 ) + { + return 0; /* Too short to check - assume uncompressed. */ } - for ( i = 0; i < DIM( magic ); i++ ) { - if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) { - *ret_rc = 0; - rc = 1; - goto leave; + for ( i = 0; i < DIM (magic); i++ ) + { + if ( !memcmp( buf, magic[i].magic, magic[i].len )) + { + return 1; /* Is compressed. */ } } - if (is_openpgp_compressed_packet (buf, 6)) - { - *ret_rc = 0; - rc = 1; - } + if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen)) + { + return 1; /* Already compressed. */ + } - leave: - iobuf_close( a ); - return rc; + return 0; /* Not detected as compressed. */ } diff --git a/common/util.h b/common/util.h index cd961d212..e4f8d2470 100644 --- a/common/util.h +++ b/common/util.h @@ -347,7 +347,7 @@ char *try_make_printable_string (const void *p, size_t n, int delim); char *make_printable_string (const void *p, size_t n, int delim); char *decode_c_string (const char *src); -int is_file_compressed (const char *s, int *ret_rc); +int is_file_compressed (const byte *buf, unsigned int buflen); int match_multistr (const char *multistr,const char *match); |