istream-file.c revision 14175321ddb88619015866978c05a27786ca4814
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen/* @UNSAFE: whole file */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "lib.h"
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "ioloop.h"
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "istream-internal.h"
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen#include "network.h"
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen#include <time.h>
6daca8888bbf2b5bf26903cf397d5219ea752241Timo Sirainen#include <unistd.h>
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen#include <sys/stat.h>
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainenstruct file_istream {
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen struct istream_private istream;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen uoff_t skip_left;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen unsigned int file:1;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen unsigned int autoclose_fd:1;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen};
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainenstatic void i_stream_file_close(struct iostream_private *stream)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen{
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen struct file_istream *fstream = (struct file_istream *)stream;
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
d8eedfaad386a8776e4931086b039b72e1ad38c4Timo Sirainen
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen if (fstream->autoclose_fd && _stream->fd != -1) {
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen if (close(_stream->fd) < 0)
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen i_error("file_istream.close() failed: %m");
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen _stream->fd = -1;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen}
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainenstatic void i_stream_file_destroy(struct iostream_private *stream)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen{
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen struct istream_private *_stream = (struct istream_private *)stream;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_free(_stream->w_buffer);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen}
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainenstatic ssize_t i_stream_file_read(struct istream_private *stream)
e6bdf53eb0143af99e3eb977ff0f8a496ecd1a8dTimo Sirainen{
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen size_t size;
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen ssize_t ret;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen stream->istream.stream_errno = 0;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (!i_stream_get_buffer_space(stream, 1, &size))
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return -2;
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen do {
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen if (fstream->file) {
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen ret = pread(stream->fd, stream->w_buffer + stream->pos,
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen size, stream->istream.v_offset +
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen (stream->pos - stream->skip));
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen } else {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen ret = read(stream->fd, stream->w_buffer + stream->pos,
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen size);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
ad3a1b8f8e2a5596afb1b099a69ae6f688887eecTimo Sirainen } while (ret < 0 && errno == EINTR && stream->istream.blocking);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (ret == 0) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* EOF */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->istream.eof = TRUE;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return -1;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (ret < 0) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (errno == EINTR || errno == EAGAIN) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_assert(!stream->istream.blocking);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen ret = 0;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen } else {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->istream.eof = TRUE;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->istream.stream_errno = errno;
e6bdf53eb0143af99e3eb977ff0f8a496ecd1a8dTimo Sirainen return -1;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen }
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen if (ret > 0 && fstream->skip_left > 0) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_assert(!fstream->file);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_assert(stream->skip == stream->pos);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (fstream->skip_left >= (size_t)ret) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen fstream->skip_left -= ret;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen ret = 0;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen } else {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen ret -= fstream->skip_left;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->pos += fstream->skip_left;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->skip += fstream->skip_left;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen fstream->skip_left = 0;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->pos += ret;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_assert(ret != 0 || !fstream->file);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return ret;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen}
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainenstatic void i_stream_file_seek(struct istream_private *stream, uoff_t v_offset,
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen bool mark ATTR_UNUSED)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen{
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (!stream->istream.seekable) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (v_offset < stream->istream.v_offset) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->istream.stream_errno = ESPIPE;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen fstream->skip_left += v_offset - stream->istream.v_offset;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->istream.stream_errno = 0;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->istream.v_offset = v_offset;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->skip = stream->pos = 0;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen}
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainenstatic void i_stream_file_sync(struct istream_private *stream)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen{
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (!stream->istream.seekable) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* can't do anything or data would be lost */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen stream->skip = stream->pos = 0;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen}
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainenstatic const struct stat *
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Siraineni_stream_file_stat(struct istream_private *stream, bool exact ATTR_UNUSED)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen{
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen struct file_istream *fstream = (struct file_istream *) stream;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (fstream->file) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (fstat(fstream->istream.fd, &fstream->istream.statbuf) < 0) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_error("file_istream.fstat() failed: %m");
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
return &stream->statbuf;
}
struct istream *i_stream_create_fd(int fd, size_t max_buffer_size,
bool autoclose_fd)
{
struct file_istream *fstream;
struct stat st;
fstream = i_new(struct file_istream, 1);
fstream->autoclose_fd = autoclose_fd;
fstream->istream.iostream.close = i_stream_file_close;
fstream->istream.iostream.destroy = i_stream_file_destroy;
fstream->istream.max_buffer_size = max_buffer_size;
fstream->istream.read = i_stream_file_read;
fstream->istream.seek = i_stream_file_seek;
fstream->istream.sync = i_stream_file_sync;
fstream->istream.stat = i_stream_file_stat;
/* if it's a file, set the flags properly */
if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
fstream->file = TRUE;
fstream->istream.istream.blocking = TRUE;
fstream->istream.istream.seekable = TRUE;
}
return i_stream_create(&fstream->istream, fd, 0);
}