static void bzlib_read_error(struct bzlib_istream *zstream, const char *error)
{
- i_error("bzlib.read(%s): %s at %"PRIuUOFF_T,
- i_stream_get_name(&zstream->istream.istream), error,
- zstream->istream.abs_start_offset +
- zstream->istream.istream.v_offset);
+ io_stream_set_error(&zstream->istream.iostream,
+ "bzlib.read(%s): %s at %"PRIuUOFF_T,
+ i_stream_get_name(&zstream->istream.istream), error,
+ zstream->istream.abs_start_offset +
+ zstream->istream.istream.v_offset);
+ if (zstream->log_errors)
+ i_error("%s", zstream->istream.iostream.error);
}
static ssize_t i_stream_bzlib_read(struct istream_private *stream)
stream->parent->stream_errno;
} else {
i_assert(stream->parent->eof);
- if (zstream->log_errors)
- bzlib_read_error(zstream, "unexpected EOF");
+ bzlib_read_error(zstream, "unexpected EOF");
stream->istream.stream_errno = EINVAL;
}
return -1;
case BZ_PARAM_ERROR:
i_unreached();
case BZ_DATA_ERROR:
- if (zstream->log_errors)
- bzlib_read_error(zstream, "corrupted data");
+ bzlib_read_error(zstream, "corrupted data");
stream->istream.stream_errno = EINVAL;
return -1;
case BZ_DATA_ERROR_MAGIC:
- if (zstream->log_errors) {
- bzlib_read_error(zstream,
- "wrong magic in header (not bz2 file?)");
- }
+ bzlib_read_error(zstream,
+ "wrong magic in header (not bz2 file?)");
stream->istream.stream_errno = EINVAL;
return -1;
case BZ_MEM_ERROR:
static void zlib_read_error(struct zlib_istream *zstream, const char *error)
{
- i_error("zlib.read(%s): %s at %"PRIuUOFF_T,
- i_stream_get_name(&zstream->istream.istream), error,
- zstream->istream.abs_start_offset +
- zstream->istream.istream.v_offset);
+ io_stream_set_error(&zstream->istream.iostream,
+ "zlib.read(%s): %s at %"PRIuUOFF_T,
+ i_stream_get_name(&zstream->istream.istream), error,
+ zstream->istream.abs_start_offset +
+ zstream->istream.istream.v_offset);
+ if (zstream->log_errors)
+ i_error("%s", zstream->istream.iostream.error);
}
static int i_stream_zlib_read_header(struct istream_private *stream)
zstream->prev_size);
if (size == zstream->prev_size) {
if (ret == -1) {
- if (zstream->log_errors)
- zlib_read_error(zstream, "missing gz header");
+ zlib_read_error(zstream, "missing gz header");
stream->istream.stream_errno = EINVAL;
}
return ret;
if (data[0] != GZ_MAGIC1 || data[1] != GZ_MAGIC2) {
/* missing gzip magic header */
- if (zstream->log_errors) {
- zlib_read_error(zstream, "wrong magic in header "
- "(not gz file?)");
- }
+ zlib_read_error(zstream, "wrong magic in header (not gz file?)");
stream->istream.stream_errno = EINVAL;
return -1;
}
GZ_TRAILER_SIZE-1);
if (size == zstream->prev_size) {
if (ret == -1) {
- if (zstream->log_errors)
- zlib_read_error(zstream, "missing gz trailer");
+ zlib_read_error(zstream, "missing gz trailer");
stream->istream.stream_errno = EINVAL;
}
return ret;
return 0;
if (data_get_uint32(data) != zstream->crc32) {
- if (zstream->log_errors) {
- zlib_read_error(zstream,
- "gz trailer has wrong CRC value");
- }
+ zlib_read_error(zstream, "gz trailer has wrong CRC value");
stream->istream.stream_errno = EINVAL;
return -1;
}
stream->parent->stream_errno;
} else {
i_assert(stream->parent->eof);
- if (zstream->log_errors)
- zlib_read_error(zstream, "unexpected EOF");
+ zlib_read_error(zstream, "unexpected EOF");
stream->istream.stream_errno = EPIPE;
}
return -1;
case Z_OK:
break;
case Z_NEED_DICT:
- if (zstream->log_errors)
- zlib_read_error(zstream, "can't read file without dict");
+ zlib_read_error(zstream, "can't read file without dict");
stream->istream.stream_errno = EINVAL;
return -1;
case Z_DATA_ERROR:
- if (zstream->log_errors)
- zlib_read_error(zstream, "corrupted data");
+ zlib_read_error(zstream, "corrupted data");
stream->istream.stream_errno = EINVAL;
return -1;
case Z_MEM_ERROR:
}
p = strchr(line, ':');
if (p == NULL) {
+ io_stream_set_error(&mstream->istream.iostream,
+ "Metadata header line is missing ':'");
mstream->istream.istream.stream_errno = EINVAL;
return -1;
}
stream->parent->stream_errno;
} else if (ret < 0 && stream->parent->eof) {
/* we didn't see "." line */
+ io_stream_set_error(&stream->iostream,
+ "dot-input stream ends without '.' line");
stream->istream.stream_errno = EPIPE;
}
return ret;
#include "lib.h"
#include "buffer.h"
+#include "hex-binary.h"
#include "istream-private.h"
#include "quoted-printable.h"
#include "istream-qp.h"
ret = !eof ? quoted_printable_decode(data, size, &pos, &buf) :
quoted_printable_decode_final(data, size, &pos, &buf);
if (ret < 0) {
+ io_stream_set_error(&stream->iostream,
+ "Invalid quoted-printable data: 0x%s",
+ binary_to_hex(data+pos, I_MAX(size-pos, 8)));
stream->istream.stream_errno = EINVAL;
return -1;
}
{
struct qp_decoder_istream *bstream =
(struct qp_decoder_istream *)stream;
- size_t pre_count, post_count;
+ const unsigned char *data;
+ size_t pre_count, post_count, size;
int ret;
size_t prev_size = 0;
}
/* partial qp input */
i_assert(ret < 0);
+ data = i_stream_get_data(stream->parent, &size);
+ io_stream_set_error(&stream->iostream,
+ "quoted-printable input ends with a partial block: 0x%s",
+ binary_to_hex(data, size));
stream->istream.stream_errno = EINVAL;
return -1;
}
o_stream_unref(&ssl_io->plain_output);
BIO_free(ssl_io->bio_ext);
SSL_free(ssl_io->ssl);
+ i_free(ssl_io->plain_stream_errstr);
i_free(ssl_io->last_error);
i_free(ssl_io->host);
i_free(ssl_io->log_prefix);
if (sent < 0) {
i_assert(ssl_io->plain_output->closed ||
ssl_io->plain_output->stream_errno != 0);
+ i_free(ssl_io->plain_stream_errstr);
+ ssl_io->plain_stream_errstr =
+ i_strdup(o_stream_get_error(ssl_io->plain_output));
ssl_io->plain_stream_errno =
ssl_io->plain_output->stream_errno;
ssl_io->closed = TRUE;
ret = openssl_iostream_read_more(ssl_io, &data, &size);
ssl_io->plain_input->real_stream->try_alloc_limit = 0;
if (ret == -1 && size == 0 && !bytes_read) {
+ i_free(ssl_io->plain_stream_errstr);
+ ssl_io->plain_stream_errstr =
+ i_strdup(i_stream_get_error(ssl_io->plain_input));
ssl_io->plain_stream_errno =
ssl_io->plain_input->stream_errno;
ssl_io->closed = TRUE;
if (bytes == 0 && !bytes_read && ssl_io->want_read) {
/* shouldn't happen */
i_error("SSL BIO buffer size too small");
+ i_free(ssl_io->plain_stream_errstr);
+ ssl_io->plain_stream_errstr =
+ i_strdup("SSL BIO buffer size too small");
ssl_io->plain_stream_errno = EINVAL;
ssl_io->closed = TRUE;
return FALSE;
}
if (i_stream_get_data_size(ssl_io->plain_input) > 0) {
i_error("SSL: Too much data in buffered plain input buffer");
+ i_free(ssl_io->plain_stream_errstr);
+ ssl_io->plain_stream_errstr =
+ i_strdup("SSL: Too much data in buffered plain input buffer");
ssl_io->plain_stream_errno = EINVAL;
ssl_io->closed = TRUE;
return FALSE;
return 0;
}
if (ssl_io->closed) {
+ if (ssl_io->plain_stream_errstr != NULL)
+ openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr);
errno = ssl_io->plain_stream_errno != 0 ?
ssl_io->plain_stream_errno : EPIPE;
return -1;
ssl_io->want_read = TRUE;
(void)openssl_iostream_bio_sync(ssl_io);
if (ssl_io->closed) {
+ if (ssl_io->plain_stream_errstr != NULL)
+ openssl_iostream_set_error(ssl_io, ssl_io->plain_stream_errstr);
errno = ssl_io->plain_stream_errno != 0 ?
ssl_io->plain_stream_errno : EPIPE;
return -1;
case SSL_ERROR_ZERO_RETURN:
/* clean connection closing */
errno = ECONNRESET;
- break;
+ i_free_and_null(ssl_io->last_error);
+ return -1;
case SSL_ERROR_SSL:
errstr = t_strdup_printf("%s failed: %s",
func_name, openssl_iostream_error());
break;
}
- if (errstr != NULL)
- openssl_iostream_set_error(ssl_io, errstr);
+ openssl_iostream_set_error(ssl_io, errstr);
return -1;
}
char *host;
char *last_error;
char *log_prefix;
+ char *plain_stream_errstr;
int plain_stream_errno;
/* copied settings */
if (ret < 0) {
/* handshake failed */
i_assert(errno != 0);
+ io_stream_set_error(&stream->iostream,
+ "%s", ssl_io->last_error);
stream->istream.stream_errno = errno;
}
return ret;
ret = openssl_iostream_handle_error(ssl_io, ret, "SSL_read");
if (ret <= 0) {
if (ret < 0) {
+ io_stream_set_error(&stream->iostream,
+ "%s", ssl_io->last_error);
stream->istream.stream_errno = errno;
stream->istream.eof = TRUE;
sstream->seen_eof = TRUE;
ret = openssl_iostream_handle_write_error(sstream->ssl_io,
ret, "SSL_write");
if (ret < 0) {
+ io_stream_set_error(&sstream->ostream.iostream,
+ "%s", sstream->ssl_io->last_error);
sstream->ostream.ostream.stream_errno = errno;
break;
}
if ((ret = openssl_iostream_more(sstream->ssl_io)) < 0) {
/* handshake failed */
+ io_stream_set_error(&stream->iostream, "%s",
+ sstream->ssl_io->last_error);
stream->ostream.stream_errno = errno;
} else if (ret > 0 && sstream->buffer != NULL &&
sstream->buffer->used > 0) {
chr = '>';
}
- mail_storage_set_critical(mstream->mail->box->storage,
+ io_stream_set_error(&mstream->istream.iostream,
"Cached message size %s than expected "
"(%"PRIuUOFF_T" %c %"PRIuUOFF_T")", str,
mstream->expected_size, chr, cur_size);
+ mail_storage_set_critical(mstream->mail->box->storage, "%s",
+ mstream->istream.iostream.error);
mail_set_cache_corrupted(mstream->mail, MAIL_FETCH_PHYSICAL_SIZE);
mstream->istream.istream.stream_errno = EINVAL;
}
&received_time, &tz, &sender) < 0) {
/* broken From - should happen only at beginning of
file if this isn't a mbox.. */
+ io_stream_set_error(&rstream->istream.iostream,
+ "mbox file doesn't begin with 'From ' line");
rstream->istream.istream.stream_errno = EINVAL;
return -1;
}
return i_stream_raw_mbox_read(stream);
}
if (mbox_read_from_line(rstream) < 0) {
- if (stream->istream.v_offset != 0) {
- i_error("Next message unexpectedly corrupted in mbox file "
- "%s at %"PRIuUOFF_T,
- i_stream_get_name(&stream->istream),
- stream->istream.v_offset);
- }
+ io_stream_set_error(&stream->iostream,
+ "Next message unexpectedly corrupted in mbox file "
+ "%s at %"PRIuUOFF_T,
+ i_stream_get_name(&stream->istream),
+ stream->istream.v_offset);
+ if (stream->istream.v_offset != 0)
+ i_error("%s", stream->iostream.error);
stream->pos = 0;
rstream->eof = TRUE;
rstream->corrupted = TRUE;
rstream->hdr_offset + new_pos > rstream->mail_size) {
/* istream_raw_mbox_set_next_offset() used invalid
cached next_offset? */
- i_error("Next message unexpectedly lost from mbox file "
+ io_stream_set_error(&stream->iostream,
+ "Next message unexpectedly lost from mbox file "
"%s at %"PRIuUOFF_T" (%s)",
i_stream_get_name(&stream->istream),
rstream->hdr_offset + rstream->mail_size,
rstream->mail_size_forced ? "cached" : "noncached");
+ i_error("%s", stream->iostream.error);
rstream->eof = TRUE;
rstream->corrupted = TRUE;
rstream->istream.istream.stream_errno = EINVAL;
#include "lib.h"
#include "buffer.h"
#include "base64.h"
+#include "hex-binary.h"
#include "istream-private.h"
#include "istream-base64.h"
buffer_create_from_data(&buf, stream->w_buffer + stream->pos,
buffer_avail);
if (base64_decode(data, size, &pos, &buf) < 0) {
+ io_stream_set_error(&stream->iostream,
+ "Invalid base64 data: 0x%s",
+ binary_to_hex(data+pos, I_MAX(size-pos, 8)));
stream->istream.stream_errno = EINVAL;
return -1;
}
{
struct base64_decoder_istream *bstream =
(struct base64_decoder_istream *)stream;
- size_t pre_count, post_count;
+ const unsigned char *data;
+ size_t pre_count, post_count, size;
int ret;
do {
if (ret < 0 && stream->istream.stream_errno == 0 &&
i_stream_get_data_size(stream->parent) > 0) {
/* base64 input with a partial block */
+ data = i_stream_get_data(stream->parent, &size);
+ io_stream_set_error(&stream->iostream,
+ "base64 input ends with a partial block: 0x%s",
+ binary_to_hex(data, size));
stream->istream.stream_errno = EINVAL;
}
return ret;
if (i == cstream->unknown_size_idx) {
/* we'll need to figure out this stream's size */
if (i_stream_stat(cstream->input[i], TRUE, &st) < 0) {
- i_error("istream-concat: "
- "Failed to get size of stream %s",
- i_stream_get_name(cstream->input[i]));
+ io_stream_set_error(&cstream->istream.iostream,
+ "stat(%s) failed: %s",
+ i_stream_get_name(cstream->input[i]),
+ i_stream_get_error(cstream->input[i]));
+ i_error("istream-concat: stat(%s) failed: %s",
+ i_stream_get_name(cstream->input[i]),
+ i_stream_get_error(cstream->input[i]));
cstream->istream.istream.stream_errno =
cstream->input[i]->stream_errno;
return UINT_MAX;
stream->fd = open(path, O_RDONLY);
if (stream->fd == -1) {
+ io_stream_set_error(&stream->iostream,
+ "open(%s) failed: %m", path);
stream->istream.stream_errno = errno;
- i_error("file_istream.open(%s) failed: %m", path);
return -1;
}
return 0;
}
static struct istream *
-i_stream_create_file_common(int fd, size_t max_buffer_size, bool autoclose_fd)
+i_stream_create_file_common(int fd, const char *path,
+ size_t max_buffer_size, bool autoclose_fd)
{
struct file_istream *fstream;
struct istream *input;
else {
/* we're trying to open a directory.
we're not designed for it. */
+ io_stream_set_error(&fstream->istream.iostream,
+ "%s is a directory, can't read it as file",
+ path != NULL ? path : t_strdup_printf("<fd %d>", fd));
fstream->istream.istream.stream_errno = EISDIR;
is_file = FALSE;
}
{
i_assert(fd != -1);
- return i_stream_create_file_common(fd, max_buffer_size, autoclose_fd);
+ return i_stream_create_file_common(fd, NULL, max_buffer_size, autoclose_fd);
}
struct istream *i_stream_create_file(const char *path, size_t max_buffer_size)
{
struct istream *input;
- input = i_stream_create_file_common(-1, max_buffer_size, TRUE);
+ input = i_stream_create_file_common(-1, path, max_buffer_size, TRUE);
i_stream_set_name(input, path);
return input;
}
struct hash_istream *hstream = (struct hash_istream *)stream;
if (hstream->hash_context != NULL) {
- /* we support seeking only after the hash is finished */
+ io_stream_set_error(&stream->iostream,
+ "Seeking not supported before hashing is finished");
stream->istream.stream_errno = ESPIPE;
}
stream->istream.v_offset = v_offset;
stream->w_buffer + dest,
&srcskip, &destskip) < 0) {
/* invalid string */
+ io_stream_set_error(&stream->iostream,
+ "Invalid JSON string");
stream->istream.stream_errno = EINVAL;
return -1;
}
stream->buffer = NULL;
stream->buffer_size = 0;
stream->skip = stream->pos = 0;
+ io_stream_set_error(&stream->iostream,
+ "mmap() failed: %m");
i_error("mmap_istream.mmap(%s) failed: %m",
i_stream_get_name(&stream->istream));
return -1;
if (pos == left)
stream->istream.eof = TRUE;
else if (pos > left) {
- i_error("%s is larger than expected (%"PRIuUOFF_T")",
- i_stream_get_name(stream->parent), sstream->size);
+ io_stream_set_error(&stream->iostream,
+ "Stream is larger than expected "
+ "(%"PRIuUOFF_T" > %"PRIuUOFF_T", eof=%d)",
+ stream->istream.v_offset+pos, sstream->size,
+ stream->istream.eof);
+ i_error("read(%s) failed: %s",
+ i_stream_get_name(stream->parent),
+ stream->iostream.error);
pos = left;
stream->istream.eof = TRUE;
} else if (!stream->istream.eof) {
} else if (stream->istream.stream_errno == ENOENT) {
/* lost the file */
} else {
- i_error("%s smaller than expected "
- "(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
+ io_stream_set_error(&stream->iostream,
+ "Stream is smaller than expected "
+ "(%"PRIuUOFF_T" < %"PRIuUOFF_T")",
+ stream->istream.v_offset+pos, sstream->size);
+ i_error("read(%s) failed: %s",
i_stream_get_name(stream->parent),
- stream->istream.v_offset, sstream->size);
+ stream->iostream.error);
stream->istream.stream_errno = EINVAL;
}
ret = lseek(fstream->fd, (off_t)fstream->buffer_offset, SEEK_SET);
if (ret < 0) {
+ io_stream_set_error(&fstream->ostream.iostream,
+ "lseek() failed: %m");
fstream->ostream.ostream.stream_errno = errno;
return -1;
}
if (ret != (off_t)fstream->buffer_offset) {
+ io_stream_set_error(&fstream->ostream.iostream,
+ "lseek() returned wrong value");
fstream->ostream.ostream.stream_errno = EINVAL;
return -1;
}
{
struct file_ostream *fstream = (struct file_ostream *)stream;
- if (offset > OFF_T_MAX || !fstream->file) {
+ if (offset > OFF_T_MAX) {
stream->ostream.stream_errno = EINVAL;
return -1;
}
+ if (!fstream->file) {
+ stream->ostream.stream_errno = ESPIPE;
+ return -1;
+ }
if (buffer_flush(fstream) < 0)
return -1;