istream-file.c revision c0435c854a0e7246373b9752d163095cc4fbe985
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen istream-file.c : Input stream handling for files
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen Copyright (c) 2002 Timo 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 The above copyright notice and this permission notice shall be
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen included in all copies or substantial portions of the Software.
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.
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen/* @UNSAFE: whole file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen void (*timeout_func)(void *);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = (struct _istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (fstream->autoclose_fd && _stream->fd != -1) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct _istream *_stream = (struct _istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen p_free(_stream->iostream.pool, _stream->w_buffer);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _set_blocking(struct _iostream *stream, int timeout_msecs,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen net_set_nonblock(fstream->istream.fd, timeout_msecs == 0);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void i_stream_grow_buffer(struct _istream *stream, size_t bytes)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size <= I_STREAM_MIN_SIZE ? I_STREAM_MIN_SIZE :
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size > fstream->max_buffer_size)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer_size = fstream->max_buffer_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen p_realloc(stream->iostream.pool, stream->w_buffer,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void i_stream_compress(struct _istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen memmove(stream->w_buffer, stream->w_buffer + stream->skip,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* we're a file, so we can lseek() */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* remove the unused bytes from beginning of buffer */
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 i_assert(stream->istream.v_limit >= stream->istream.v_offset);
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 if (ret == 0 && timeout_time > 0 && time(NULL) > timeout_time) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* timeouted */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->timeout_func(fstream->timeout_context);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = read(stream->fd, stream->w_buffer + stream->pos, size);
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen if (errno == ECONNRESET || errno == ETIMEDOUT) {
d54ef607275c4899e082fbeeb210346484d2e85fTimo Sirainen /* treat as disconnection */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } while (ret == 0 && STREAM_IS_BLOCKING(fstream));
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _skip(struct _istream *stream, uoff_t count)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->skip_left += count - (stream->pos - stream->skip);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _seek(struct _istream *stream, uoff_t v_offset)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen real_offset = stream->istream.start_offset + v_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = lseek(stream->fd, (off_t)real_offset, SEEK_SET);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstruct istream *i_stream_create_file(int fd, pool_t pool,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen fstream = p_new(pool, struct file_istream, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fstream->istream.iostream.set_blocking = _set_blocking;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* get size of fd if it's a file */