ostream-file.c revision 0ce5f96804e81cb0f857e7df32c0272f1eed9377
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2002-2003 Timo Sirainen */
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody/* @UNSAFE: whole file */
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody/* try to keep the buffer size within 4k..128k. ReiserFS may actually return
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody 128k as optimal size. */
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody ((fstream)->head == (fstream)->tail && !(fstream)->full)
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody ((size) < SSIZE_T_MAX ? (size_t)(size) : SSIZE_T_MAX)
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody size_t buffer_size, max_buffer_size, optimal_block_size;
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody size_t head, tail; /* first unsent/unused byte */
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody unsigned int full:1; /* if head == tail, is buffer empty or full? */
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmodystatic void stream_closed(struct file_ostream *fstream)
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody if (fstream->autoclose_fd && fstream->fd != -1) {
629e96c5e2d4724b713ca7d62e59ed033107edcdPhil Carmody struct file_ostream *fstream = (struct file_ostream *)stream;
d6bbf85809664a810726b5c711c7213874d8df57Phil Carmody /* flush output before really closing it */
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch struct file_ostream *fstream = (struct file_ostream *)stream;
87b4215acbf020aa5b8dea686b23fc664140cda0Stephan Bosch p_free(fstream->ostream.iostream.pool, fstream->buffer);
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Boschstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch struct file_ostream *fstream = (struct file_ostream *)stream;
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Boschstatic void update_buffer(struct file_ostream *fstream, size_t size)
d6bbf85809664a810726b5c711c7213874d8df57Phil Carmody /* ...HXXXT... */
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Boschstatic ssize_t o_stream_writev(struct file_ostream *fstream,
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch ret = write(fstream->fd, iov->iov_base, iov->iov_len);
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch for (i = 0; i < UIO_MAXIOV; i++)
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch ret = writev(fstream->fd, (const struct iovec *)iov,
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch ret = writev(fstream->fd, (const struct iovec *)iov,
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch fstream->ostream.ostream.stream_errno = errno;
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch/* returns how much of vector was used */
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Boschstatic int o_stream_fill_iovec(struct file_ostream *fstream,
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch iov[0].iov_base = fstream->buffer + fstream->head;
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch iov[0].iov_len = fstream->tail - fstream->head;
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch iov[0].iov_base = fstream->buffer + fstream->head;
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch iov[0].iov_len = fstream->buffer_size - fstream->head;
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Boschstatic int buffer_flush(struct file_ostream *fstream)
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Boschstatic void _cork(struct _ostream *stream, int set)
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch struct file_ostream *fstream = (struct file_ostream *)stream;
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch if (fstream->corked != set && !stream->ostream.closed) {
d6bbf85809664a810726b5c711c7213874d8df57Phil Carmody } else if (!set) {
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody struct file_ostream *fstream = (struct file_ostream *) stream;
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmodystatic void _flush_pending(struct _ostream *stream, int set)
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody struct file_ostream *fstream = (struct file_ostream *) stream;
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody if (set && !fstream->corked && fstream->io == NULL) {
47ca7a853a116b1be3d73b46301d97e572f2f806Phil Carmodystatic size_t get_unused_space(struct file_ostream *fstream)
47ca7a853a116b1be3d73b46301d97e572f2f806Phil Carmody /* ...HXXXT... */
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody return (fstream->buffer_size - fstream->tail) + fstream->head;
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody /* either fully unused or fully used */
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody return fstream->full ? 0 : fstream->buffer_size;
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmodystatic size_t _get_used_size(struct _ostream *stream)
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody struct file_ostream *fstream = (struct file_ostream *)stream;
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody return fstream->buffer_size - get_unused_space(fstream);
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmodystatic int _seek(struct _ostream *stream, uoff_t offset)
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody struct file_ostream *fstream = (struct file_ostream *)stream;
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody ret = lseek(fstream->fd, (off_t)offset, SEEK_SET);
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmodystatic void o_stream_grow_buffer(struct file_ostream *fstream, size_t bytes)
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody size = pool_get_exp_grown_size(fstream->ostream.iostream.pool,
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody /* limit the size */
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody /* try to use optimal buffer size with corking */
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody fstream->buffer = p_realloc(fstream->ostream.iostream.pool,
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody if (fstream->tail <= fstream->head && !IS_STREAM_EMPTY(fstream)) {
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody /* move head forward to end of buffer */
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody end_size = fstream->buffer_size - fstream->head;
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody /* Set flush_pending = FALSE first before calling the flush callback,
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody and change it to TRUE only if callback returns 0. That way the
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody callback can call o_stream_set_flush_pending() again and we don't
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody forget it even if flush callback returns 1. */
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody ret = fstream->ostream.callback(fstream->ostream.context);
4a272f5b8bacf2852c2e53f3aa8e899e0d5c604fStephan Bosch if (!fstream->flush_pending && IS_STREAM_EMPTY(fstream)) {
42826d96c8d0bba9eddc85b01bf70d7db571ae7fPhil Carmody /* all sent */
sent = 0;
fstream);
return sent;
unsigned int iov_count)
if (ret < 0)
iov++;
iov_count--;
if (iov_count > 0) {
return ret;
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) {
if (max_buffer_size == 0)
return ostream;