Skip to content

Commit

Permalink
lib: i_stream_default_stat() - Get seekable streams' sizes by reading…
Browse files Browse the repository at this point in the history
… the stream

After the stream size is found, seek back to original offset.
  • Loading branch information
sirainen committed Jun 6, 2018
1 parent 3e62638 commit bd7afb3
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/lib/istream-private.h
Expand Up @@ -45,6 +45,9 @@ struct istream_private {

struct istream *parent; /* for filter streams */
uoff_t parent_start_offset;
/* Initially (uoff_t)-1. Otherwise it's the exact known stream size,
which can be used by stat() / get_size(). */
uoff_t cached_stream_size;

/* parent stream's expected offset is kept here. i_stream_read()
always seeks parent stream to here before calling read(). */
Expand Down
32 changes: 32 additions & 0 deletions src/lib/istream.c
Expand Up @@ -1066,6 +1066,28 @@ bool i_stream_nonseekable_try_seek(struct istream_private *stream,
return TRUE;
}

static int
seekable_i_stream_get_size(struct istream_private *stream)
{
if (stream->cached_stream_size == (uoff_t)-1) {
uoff_t old_offset = stream->istream.v_offset;
ssize_t ret;

do {
i_stream_skip(&stream->istream,
i_stream_get_data_size(&stream->istream));
} while ((ret = i_stream_read(&stream->istream)) > 0);
i_assert(ret == -1);
if (stream->istream.stream_errno != 0)
return -1;

stream->cached_stream_size = stream->istream.v_offset;
i_stream_seek(&stream->istream, old_offset);
}
stream->statbuf.st_size = stream->cached_stream_size;
return 0;
}

static int
i_stream_default_stat(struct istream_private *stream, bool exact)
{
Expand All @@ -1082,6 +1104,15 @@ i_stream_default_stat(struct istream_private *stream, bool exact)
if (exact && !stream->stream_size_passthrough) {
/* exact size is not known, even if parent returned something */
stream->statbuf.st_size = -1;
if (stream->istream.seekable) {
if (seekable_i_stream_get_size(stream) < 0)
return -1;
}
} else {
/* When exact=FALSE always return the parent stat's size, even
if we know the exact value. This is necessary because
otherwise e.g. mbox code can see two different values and
think that the mbox file keeps changing. */
}
return 0;
}
Expand Down Expand Up @@ -1159,6 +1190,7 @@ i_stream_create(struct istream_private *_stream, struct istream *parent, int fd,
_stream->statbuf.st_atime =
_stream->statbuf.st_mtime =
_stream->statbuf.st_ctime = ioloop_time;
_stream->cached_stream_size = (uoff_t)-1;

io_stream_init(&_stream->iostream);

Expand Down

0 comments on commit bd7afb3

Please sign in to comment.