aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/iobuf.c102
-rw-r--r--common/iobuf.h4
-rw-r--r--common/miscellaneous.c77
-rw-r--r--common/util.h2
4 files changed, 134 insertions, 51 deletions
diff --git a/common/iobuf.c b/common/iobuf.c
index ab8368b54..62cde27f9 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.
*
@@ -95,6 +95,9 @@ typedef struct
int eof_seen;
int delayed_rc;
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;
@@ -458,7 +461,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;
@@ -596,6 +608,73 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
a->delayed_rc = 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 */
+ {
+ if (a->npeeked)
+ a->delayed_rc = -1;
+ else
+ 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));
+ if (a->npeeked)
+ a->delayed_rc = 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)
{
@@ -1576,6 +1655,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 f527fbf16..c132c2f3c 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 df6b68784..60ac4b4df 100644
--- a/common/miscellaneous.c
+++ b/common/miscellaneous.c
@@ -418,7 +418,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;
@@ -460,63 +460,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 6978ab896..d80e4fb25 100644
--- a/common/util.h
+++ b/common/util.h
@@ -359,7 +359,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);