static int o_stream_temp_dup_istream(struct temp_ostream *outstream, struct istream *instream) { uoff_t in_size; off_t ret; if (!instream->readable_fd || i_stream_get_fd(instream) == -1) return 0; if (i_stream_get_size(instream, TRUE, &in_size) <= 0) { if (outstream->dupstream != NULL) return o_stream_temp_dup_cancel(outstream); return 0; } if (outstream->dupstream == NULL) { outstream->dupstream = instream; outstream->dupstream_start_offset = instream->v_offset; i_stream_ref(outstream->dupstream); } else { if (outstream->dupstream != instream || outstream->dupstream_offset != instream->v_offset || outstream->dupstream_offset > in_size) return o_stream_temp_dup_cancel(outstream); } ret = in_size - instream->v_offset; i_stream_seek(instream, in_size); outstream->dupstream_offset = instream->v_offset; return ret; }
static ssize_t o_stream_temp_sendv(struct ostream_private *stream, const struct const_iovec *iov, unsigned int iov_count) { struct temp_ostream *tstream = (struct temp_ostream *)stream; ssize_t ret = 0; unsigned int i; enum ostream_send_istream_result res; tstream->flags &= ~IOSTREAM_TEMP_FLAG_TRY_FD_DUP; if (tstream->dupstream != NULL) { if (o_stream_temp_dup_cancel(tstream, &res)) return -1; } if (tstream->fd != -1) return o_stream_temp_fd_sendv(tstream, iov, iov_count); for (i = 0; i < iov_count; i++) { if (tstream->buf->used + iov[i].iov_len > tstream->max_mem_size) { if (o_stream_temp_move_to_fd(tstream) == 0) { return o_stream_temp_fd_sendv(tstream, iov+i, iov_count-i); } /* failed to move to temp fd, just keep it in memory */ } buffer_append(tstream->buf, iov[i].iov_base, iov[i].iov_len); ret += iov[i].iov_len; stream->ostream.offset += iov[i].iov_len; } return ret; }
static bool o_stream_temp_dup_istream(struct temp_ostream *outstream, struct istream *instream, enum ostream_send_istream_result *res_r) { uoff_t in_size; if (!instream->readable_fd || i_stream_get_fd(instream) == -1) return FALSE; if (i_stream_get_size(instream, TRUE, &in_size) <= 0) { if (outstream->dupstream != NULL) return o_stream_temp_dup_cancel(outstream, res_r); return FALSE; } i_assert(instream->v_offset <= in_size); if (outstream->dupstream == NULL) { outstream->dupstream = instream; outstream->dupstream_start_offset = instream->v_offset; i_stream_ref(outstream->dupstream); } else { if (outstream->dupstream != instream || outstream->dupstream_offset != instream->v_offset || outstream->dupstream_offset > in_size) return o_stream_temp_dup_cancel(outstream, res_r); } i_stream_seek(instream, in_size); /* we should be at EOF now. o_stream_send_istream() asserts if eof isn't set. */ instream->eof = TRUE; outstream->dupstream_offset = instream->v_offset; outstream->ostream.ostream.offset = outstream->dupstream_offset - outstream->dupstream_start_offset; *res_r = OSTREAM_SEND_ISTREAM_RESULT_FINISHED; return TRUE; }