aboutsummaryrefslogtreecommitdiffstats
path: root/common/iobuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/iobuf.c')
-rw-r--r--common/iobuf.c192
1 files changed, 140 insertions, 52 deletions
diff --git a/common/iobuf.c b/common/iobuf.c
index 161769a35..e46eeac95 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -166,7 +166,8 @@ block_filter_ctx_t;
/* Local prototypes. */
static int underflow (iobuf_t a, int clear_pending_eof);
static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
-static int translate_file_handle (int fd, int for_write);
+static iobuf_t do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open);
+
/* Sends any pending data to the filter's FILTER function. Note: this
works on the filter and not on the whole pipeline. That is,
@@ -389,7 +390,7 @@ fd_cache_close (const char *fname, gnupg_fd_t fp)
close (fp);
#endif
if (DBG_IOBUF)
- log_debug ("fd_cache_close (%d) real\n", (int)fp);
+ log_debug ("fd_cache_close (%d) real\n", FD_DBG (fp));
return;
}
/* try to reuse a slot */
@@ -696,7 +697,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
if (f != FD_FOR_STDIN && f != FD_FOR_STDOUT)
{
if (DBG_IOBUF)
- log_debug ("%s: close fd/handle %d\n", a->fname, FD2INT (f));
+ log_debug ("%s: close fd/handle %d\n", a->fname, FD_DBG (f));
if (!a->keep_open)
fd_cache_close (a->no_cache ? NULL : a->fname, f);
}
@@ -1410,7 +1411,7 @@ iobuf_is_pipe_filename (const char *fname)
{
if (!fname || (*fname=='-' && !fname[1]) )
return 1;
- return check_special_filename (fname, 0, 1) != -1;
+ return gnupg_check_special_filename (fname) != GNUPG_INVALID_FD;
}
@@ -1423,7 +1424,7 @@ do_open (const char *fname, int special_filenames,
file_filter_ctx_t *fcx;
size_t len = 0;
int print_only = 0;
- int fd;
+ gnupg_fd_t fd;
byte desc[MAX_IOBUF_DESC];
log_assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT);
@@ -1447,9 +1448,8 @@ do_open (const char *fname, int special_filenames,
else if (!fname)
return NULL;
else if (special_filenames
- && (fd = check_special_filename (fname, 0, 1)) != -1)
- return iobuf_fdopen (translate_file_handle (fd, use == IOBUF_INPUT ? 0 : 1),
- opentype);
+ && (fd = gnupg_check_special_filename (fname)) != GNUPG_INVALID_FD)
+ return do_iobuf_fdopen (fd, opentype, 0);
else
{
if (use == IOBUF_INPUT)
@@ -1472,7 +1472,8 @@ do_open (const char *fname, int special_filenames,
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
if (DBG_IOBUF)
log_debug ("iobuf-%d.%d: open '%s' desc=%s fd=%d\n",
- a->no, a->subno, fname, iobuf_desc (a, desc), FD2INT (fcx->fp));
+ a->no, a->subno, fname, iobuf_desc (a, desc),
+ FD_DBG (fcx->fp));
return a;
}
@@ -1497,22 +1498,19 @@ iobuf_openrw (const char *fname)
static iobuf_t
-do_iobuf_fdopen (int fd, const char *mode, int keep_open)
+do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open)
{
iobuf_t a;
- gnupg_fd_t fp;
file_filter_ctx_t *fcx;
size_t len = 0;
- fp = INT2FD (fd);
-
a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
iobuf_buffer_size);
fcx = xmalloc (sizeof *fcx + 20);
fcx->fp = fp;
fcx->print_only_name = 1;
fcx->keep_open = keep_open;
- sprintf (fcx->fname, "[fd %d]", fd);
+ sprintf (fcx->fname, "[fd %d]", FD_DBG (fp));
a->filter = file_filter;
a->filter_ov = fcx;
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
@@ -1525,15 +1523,15 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open)
iobuf_t
-iobuf_fdopen (int fd, const char *mode)
+iobuf_fdopen (gnupg_fd_t fp, const char *mode)
{
- return do_iobuf_fdopen (fd, mode, 0);
+ return do_iobuf_fdopen (fp, mode, 0);
}
iobuf_t
-iobuf_fdopen_nc (int fd, const char *mode)
+iobuf_fdopen_nc (gnupg_fd_t fp, const char *mode)
{
- return do_iobuf_fdopen (fd, mode, 1);
+ return do_iobuf_fdopen (fp, mode, 1);
}
@@ -1585,7 +1583,7 @@ iobuf_sockopen (int fd, const char *mode)
log_debug ("iobuf-%d.%d: sockopen '%s'\n", a->no, a->subno, scx->fname);
iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
#else
- a = iobuf_fdopen (fd, mode);
+ a = do_iobuf_fdopen (fd, mode, 0);
#endif
return a;
}
@@ -2644,20 +2642,20 @@ iobuf_get_filelength (iobuf_t a)
}
-int
+gnupg_fd_t
iobuf_get_fd (iobuf_t a)
{
for (; a->chain; a = a->chain)
;
if (a->filter != file_filter)
- return -1;
+ return GNUPG_INVALID_FD;
{
file_filter_ctx_t *b = a->filter_ov;
gnupg_fd_t fp = b->fp;
- return FD2INT (fp);
+ return fp;
}
}
@@ -2948,36 +2946,6 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
return nbytes;
}
-static int
-translate_file_handle (int fd, int for_write)
-{
-#if defined(HAVE_W32_SYSTEM)
- {
- int x;
-
- (void)for_write;
-
- if (fd == 0)
- x = (int) GetStdHandle (STD_INPUT_HANDLE);
- else if (fd == 1)
- x = (int) GetStdHandle (STD_OUTPUT_HANDLE);
- else if (fd == 2)
- x = (int) GetStdHandle (STD_ERROR_HANDLE);
- else
- x = fd;
-
- if (x == -1)
- log_debug ("GetStdHandle(%d) failed: ec=%d\n",
- fd, (int) GetLastError ());
-
- fd = x;
- }
-#else
- (void)for_write;
-#endif
- return fd;
-}
-
void
iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
@@ -3028,3 +2996,123 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
}
}
}
+
+
+/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
+ * packet. LEN should be at least 6. */
+static int
+is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
+{
+ int c, ctb, pkttype;
+ int lenbytes;
+
+ ctb = *buf++; len--;
+ if (!(ctb & 0x80))
+ return 0; /* Invalid packet. */
+
+ if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
+ {
+ pkttype = (ctb & 0x3f);
+ if (!len)
+ return 0; /* Expected first length octet missing. */
+ c = *buf++; len--;
+ if (c < 192)
+ ;
+ else if (c < 224)
+ {
+ if (!len)
+ return 0; /* Expected second length octet missing. */
+ }
+ else if (c == 255)
+ {
+ if (len < 4)
+ return 0; /* Expected length octets missing */
+ }
+ }
+ else /* Old style CTB. */
+ {
+ pkttype = (ctb>>2)&0xf;
+ lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
+ if (len < lenbytes)
+ return 0; /* Not enough length bytes. */
+ }
+
+ return (pkttype == 8);
+}
+
+
+/*
+ * Check if the file is compressed, by peeking the iobuf. You need to
+ * pass the iobuf with INP. Returns true if the buffer seems to be
+ * compressed.
+ */
+int
+is_file_compressed (iobuf_t inp)
+{
+ int i;
+ char buf[32];
+ int buflen;
+
+ struct magic_compress_s
+ {
+ byte len;
+ byte extchk;
+ byte magic[5];
+ } magic[] =
+ {
+ { 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
+ { 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
+ { 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
+ { 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
+ { 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
+ { 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */
+ };
+
+ if (!inp)
+ return 0;
+
+ for ( ; inp->chain; inp = inp->chain )
+ ;
+
+ buflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof buf, buf);
+ if (buflen < 0)
+ {
+ buflen = 0;
+ log_debug ("peeking at input failed\n");
+ }
+
+ 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))
+ {
+ switch (magic[i].extchk)
+ {
+ case 0:
+ return 1; /* Is compressed. */
+ case 1:
+ if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
+ return 1; /* JFIF: this likely a compressed JPEG. */
+ break;
+ case 2:
+ if (buflen > 8
+ && buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
+ return 1; /* This is a PNG. */
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
+ {
+ return 1; /* Already compressed. */
+ }
+
+ return 0; /* Not detected as compressed. */
+}