ostream-file.c revision 4c52424aaaa0e1ad5a63a5e5540767634f207806
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* Copyright (c) 2002-2003 Timo Sirainen */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* @UNSAFE: whole file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* try to keep the buffer size within 4k..128k. ReiserFS may actually return
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen 128k as optimal size. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ((fstream)->head == (fstream)->tail && !(fstream)->full)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ((size) < SSIZE_T_MAX ? (size_t)(size) : SSIZE_T_MAX)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t buffer_size, max_buffer_size, optimal_block_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size_t head, tail; /* first unsent/unused byte */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int full:1; /* if head == tail, is buffer empty or full? */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void stream_closed(struct file_ostream *fstream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (fstream->autoclose_fd && fstream->fd != -1) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* flush output before really closing it */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen p_free(fstream->ostream.iostream.pool, fstream->buffer);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void update_buffer(struct file_ostream *fstream, size_t size)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* ...HXXXT... */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic ssize_t o_stream_writev(struct file_ostream *fstream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = write(fstream->fd, iov->iov_base, iov->iov_len);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < UIO_MAXIOV; i++)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = writev(fstream->fd, (const struct iovec *)iov,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = writev(fstream->fd, (const struct iovec *)iov,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fstream->ostream.ostream.stream_errno = errno;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen/* returns how much of vector was used */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int o_stream_fill_iovec(struct file_ostream *fstream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[0].iov_base = fstream->buffer + fstream->head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[0].iov_len = fstream->tail - fstream->head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[0].iov_base = fstream->buffer + fstream->head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov[0].iov_len = fstream->buffer_size - fstream->head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int buffer_flush(struct file_ostream *fstream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void _cork(struct _ostream *stream, int set)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct file_ostream *fstream = (struct file_ostream *) stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic size_t get_unused_space(struct file_ostream *fstream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* ...HXXXT... */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return (fstream->buffer_size - fstream->tail) + fstream->head;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* either fully unused or fully used */
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen return fstream->full ? 0 : fstream->buffer_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic size_t _get_used_size(struct _ostream *stream)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return fstream->buffer_size - get_unused_space(fstream);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int _seek(struct _ostream *stream, uoff_t offset)
04b7dc631f33bf61f273138c679da9bd0910fb6dTimo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = lseek(fstream->fd, (off_t)offset, SEEK_SET);
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainenstatic void o_stream_grow_buffer(struct file_ostream *fstream, size_t bytes)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen size = nearest_power(fstream->buffer_size + bytes);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* limit the size */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* use optimal buffer size with corking */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fstream->buffer = p_realloc(fstream->ostream.iostream.pool,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (fstream->tail <= fstream->head && !IS_STREAM_EMPTY(fstream)) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen head_size = I_MIN(fstream->head, size - fstream->buffer_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memcpy(fstream->buffer + fstream->buffer_size, fstream->buffer,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen fstream->tail = fstream->buffer_size + head_size;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen memmove(fstream->buffer, fstream->buffer + head_size,
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen fstream->ostream.callback(fstream->ostream.context);
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (IS_STREAM_EMPTY(fstream) && fstream->io != NULL) {
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen /* all sent */
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainenstatic size_t o_stream_add(struct file_ostream *fstream,
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen for (i = 0; i < 2 && sent < size && !fstream->full; i++) {
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen fstream->io = io_add(fstream->fd, IO_WRITE, stream_send_io,
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainenstatic ssize_t _sendv(struct _ostream *stream, const struct const_iovec *iov,
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen optimal_size = I_MIN(fstream->optimal_block_size,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* send immediately */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = o_stream_writev(fstream, iov, iov_count);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* buffer full */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* buffer it, at least partly */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 0; i < iov_count; i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen added = o_stream_add(fstream, iov[i].iov_base, iov[i].iov_len);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic off_t io_stream_sendfile(struct _ostream *outstream,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct file_ostream *foutstream = (struct file_ostream *)outstream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* flush out any data in buffer */
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen offset = instream->real_stream->abs_start_offset + v_offset;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = safe_sendfile(foutstream->fd, in_fd, &offset,
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen if (ret == 0 || errno == EINTR || errno == EAGAIN) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* close only if error wasn't because
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen sendfile() isn't supported */
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen return ret < 0 ? -1 : (off_t)(instream->v_offset - start_offset);
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainenstatic off_t io_stream_copy(struct _ostream *outstream,
d3a7d023b47d2a137f01109e7b38702dca3f11d3Timo Sirainen struct file_ostream *foutstream = (struct file_ostream *)outstream;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const unsigned char *data;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen iov_len = o_stream_fill_iovec(foutstream, iov);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen while (in_size > 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen block_size = I_MIN(foutstream->optimal_block_size, in_size);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (void)i_stream_read_data(instream, &data, &size, block_size-1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* all sent */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = o_stream_writev(foutstream, iov, iov_len);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return (off_t) (instream->v_offset - start_offset);
const unsigned char *data;
if (ret < 0) {
overlapping = 0;
if (ret == 0) {
return ret;
if (overlapping <= 0)
struct ostream *
int autoclose_fd)
if (offset >= 0) {
#ifndef HAVE_LINUX_SENDFILE
if (max_buffer_size == 0)
return ostream;