istream-file.c revision c0435c854a0e7246373b9752d163095cc4fbe985
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen/*
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen istream-file.c : Input stream handling for files
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Copyright (c) 2002 Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Permission is hereby granted, free of charge, to any person obtaining
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen a copy of this software and associated documentation files (the
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen "Software"), to deal in the Software without restriction, including
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen without limitation the rights to use, copy, modify, merge, publish,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen distribute, sublicense, and/or sell copies of the Software, and to
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen permit persons to whom the Software is furnished to do so, subject to
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen the following conditions:
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen The above copyright notice and this permission notice shall be
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen included in all copies or substantial portions of the Software.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen*/
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen/* @UNSAFE: whole file */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "alarm-hup.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream-internal.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "network.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <time.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <unistd.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <sys/stat.h>
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define I_STREAM_MIN_SIZE 4096
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define STREAM_IS_BLOCKING(fstream) \
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ((fstream)->timeout_msecs != 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstruct file_istream {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream istream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t max_buffer_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uoff_t skip_left;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int timeout_msecs;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen void (*timeout_func)(void *);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen void *timeout_context;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int file:1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int autoclose_fd:1;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _close(struct _iostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = (struct _istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstream->autoclose_fd && _stream->fd != -1) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (close(_stream->fd) < 0)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen i_error("file_istream.close() failed: %m");
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen _stream->fd = -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _destroy(struct _iostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = (struct _istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen p_free(_stream->iostream.pool, _stream->w_buffer);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->max_buffer_size = max_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _set_blocking(struct _iostream *stream, int timeout_msecs,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen void (*timeout_func)(void *), void *context)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->timeout_msecs = timeout_msecs;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->timeout_func = timeout_func;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->timeout_context = context;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen net_set_nonblock(fstream->istream.fd, timeout_msecs == 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (timeout_msecs != 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen alarm_hup_init();
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void i_stream_grow_buffer(struct _istream *stream, size_t bytes)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size = stream->pos + bytes;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size <= I_STREAM_MIN_SIZE ? I_STREAM_MIN_SIZE :
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen nearest_power(stream->buffer_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstream->max_buffer_size > 0 &&
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size > fstream->max_buffer_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size = fstream->max_buffer_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer = stream->w_buffer =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen p_realloc(stream->iostream.pool, stream->w_buffer,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void i_stream_compress(struct _istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->pos - stream->skip);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->pos -= stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->skip > stream->cr_lookup_pos)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->cr_lookup_pos = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->cr_lookup_pos -= stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->skip = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic ssize_t _read(struct _istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen time_t timeout_time;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uoff_t read_limit;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssize_t ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->istream.closed)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstream->skip_left > 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(stream->skip == stream->pos);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstream->file) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we're a file, so we can lseek() */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_seek(&stream->istream,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.v_offset);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->istream.closed)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->pos == stream->buffer_size) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->skip > 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* remove the unused bytes from beginning of buffer */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_compress(stream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else if (fstream->max_buffer_size == 0 ||
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size < fstream->max_buffer_size) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* buffer is full - grow it */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->pos == stream->buffer_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -2; /* buffer full */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size = stream->buffer_size - stream->pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (stream->istream.v_limit > 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(stream->istream.v_limit >= stream->istream.v_offset);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen read_limit = stream->istream.v_limit -
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.v_offset + fstream->skip_left;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (read_limit <= stream->pos - stream->skip) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* virtual limit reached == EOF */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen read_limit -= stream->pos - stream->skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (size > read_limit)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size = read_limit;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen timeout_time = GET_TIMEOUT_TIME(fstream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen do {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret == 0 && timeout_time > 0 && time(NULL) > timeout_time) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* timeouted */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstream->timeout_func != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->timeout_func(fstream->timeout_context);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = EAGAIN;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = read(stream->fd, stream->w_buffer + stream->pos, size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret == 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* EOF */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret < 0) {
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen if (errno == ECONNRESET || errno == ETIMEDOUT) {
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen /* treat as disconnection */
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen stream->istream.stream_errno = 0;
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen return -1;
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen }
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (errno == EINTR || errno == EAGAIN)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = errno;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret > 0 && fstream->skip_left > 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstream->skip_left >= (size_t)ret) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->skip_left -= ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret -= fstream->skip_left;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->pos += fstream->skip_left;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->skip += fstream->skip_left;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->skip_left = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } while (ret == 0 && STREAM_IS_BLOCKING(fstream));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->pos += ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _skip(struct _istream *stream, uoff_t count)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->skip_left += count - (stream->pos - stream->skip);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->skip = stream->pos = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.v_offset += count;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _seek(struct _istream *stream, uoff_t v_offset)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uoff_t real_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen off_t ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen real_offset = stream->istream.start_offset + v_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (real_offset > OFF_T_MAX) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = EOVERFLOW;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = lseek(stream->fd, (off_t)real_offset, SEEK_SET);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = errno;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else if (ret != (off_t)real_offset) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = EINVAL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->skip = stream->pos = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->skip_left = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_close(&stream->istream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.stream_errno = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.v_offset = v_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstruct istream *i_stream_create_file(int fd, pool_t pool,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen size_t max_buffer_size, int autoclose_fd)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct stat st;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen fstream = p_new(pool, struct file_istream, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->max_buffer_size = max_buffer_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->autoclose_fd = autoclose_fd;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.iostream.close = _close;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.iostream.destroy = _destroy;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.iostream.set_blocking = _set_blocking;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.read = _read;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.skip_count = _skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.seek = _seek;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* get size of fd if it's a file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstat(fd, &st) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen st.st_size = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen else if (S_ISREG(st.st_mode))
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->file = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return _i_stream_create(&fstream->istream, pool, fd, 0,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (uoff_t)st.st_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}