ostream-file.c revision 1b3ba631030085c5f5afdae503909cee9c192f96
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2003 Timo Sirainen */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen/* @UNSAFE: whole file */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen/* try to keep the buffer size within 4k..128k. ReiserFS may actually return
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen 128k as optimal size. */
bbadd5331f534017cf62d5183003b3d9fdad079eTimo Sirainen ((fstream)->head == (fstream)->tail && !(fstream)->full)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen ((size) < SSIZE_T_MAX ? (size_t)(size) : SSIZE_T_MAX)
635df5b4cbcd7b24c825e01d9dd66d3a4274c4c7Timo Sirainen size_t buffer_size, max_buffer_size, optimal_block_size;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen size_t head, tail; /* first unsent/unused byte */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen unsigned int full:1; /* if head == tail, is buffer empty or full? */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void stream_closed(struct file_ostream *fstream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (fstream->autoclose_fd && fstream->fd != -1) {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen /* flush output before really closing it */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen p_free(fstream->ostream.iostream.pool, fstream->buffer);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void update_buffer(struct file_ostream *fstream, size_t size)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* ...HXXXT... */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* whole buffer is sent */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen/* NOTE: modifies iov */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstatic ssize_t o_stream_writev(struct file_ostream *fstream,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen ret = write(fstream->fd, iov->iov_base, iov->iov_len);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for (i = 0; i < UIO_MAXIOV; i++)
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen ret = writev(fstream->fd, (const struct iovec *)iov,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen ret = writev(fstream->fd, (const struct iovec *)iov,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen fstream->ostream.ostream.stream_errno = errno;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen/* returns how much of vector was used */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic int o_stream_fill_iovec(struct file_ostream *fstream,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen iov[0].iov_base = fstream->buffer + fstream->head;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen iov[0].iov_len = fstream->tail - fstream->head;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen iov[0].iov_base = fstream->buffer + fstream->head;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen iov[0].iov_len = fstream->buffer_size - fstream->head;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic int buffer_flush(struct file_ostream *fstream)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void _cork(struct _ostream *stream, int set)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct file_ostream *fstream = (struct file_ostream *) stream;
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainenstatic size_t get_unused_space(struct file_ostream *fstream)
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen /* ...HXXXT... */
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return (fstream->buffer_size - fstream->tail) + fstream->head;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen /* either fully unused or fully used */
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen return fstream->full ? 0 : fstream->buffer_size;
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainenstatic size_t _get_used_size(struct _ostream *stream)
15f526e5ac611b4532568d131fcd0abf664abe41Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen return fstream->buffer_size - get_unused_space(fstream);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainenstatic int _seek(struct _ostream *stream, uoff_t offset)
0f62889d833767acf9c2ad010c3269806b4cfae3Timo Sirainen struct file_ostream *fstream = (struct file_ostream *)stream;
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen ret = lseek(fstream->fd, (off_t)offset, SEEK_SET);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainenstatic void o_stream_grow_buffer(struct file_ostream *fstream, size_t bytes)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen size = nearest_power(fstream->buffer_size + bytes);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* limit the size */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* use optimal buffer size with corking */
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen fstream->buffer = p_realloc(fstream->ostream.iostream.pool,
2024157e8de36edd31f5fd72f5ea7364a0955fa7Timo Sirainen if (fstream->tail <= fstream->head && !IS_STREAM_EMPTY(fstream)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen head_size = I_MIN(fstream->head, size - fstream->buffer_size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memcpy(fstream->buffer + fstream->buffer_size, fstream->buffer,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen fstream->tail = fstream->buffer_size + head_size;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen memmove(fstream->buffer, fstream->buffer + head_size,
sent = 0;
fstream);
return sent;
if (ret < 0)
iov++;
iov_count--;
if (iov_count > 0) {
return added;
iov++;
iov_count--;
for (i = 0; i < iov_count; i++) {
return ret;
return ret;
if (ret <= 0) {
ret = 0;
int iov_len;
const unsigned char *data;
int pos;
skip_size = 0;
while (in_size > 0) {
if (size == 0) {
if (ret < 0)
if (skip_size > 0) {
ret = 0;
skip_size = 0;
iov_len = 0;
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;