bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch#include "lib.h"
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch#include "fdpass.h"
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch#include "ostream-file-private.h"
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch#include "ostream-unix.h"
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Boschstruct unix_ostream {
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch struct file_ostream fstream;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch int write_fd;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch};
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Boschstatic void
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Boscho_stream_unix_close(struct iostream_private *stream, bool close_parent)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch{
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch struct unix_ostream *ustream = (struct unix_ostream *)stream;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
7b032348d7bbb93ff96188289d3dfc1899b9abb3Josef 'Jeff' Sipek i_close_fd(&ustream->write_fd);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch o_stream_file_close(stream, close_parent);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch}
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Boschstatic ssize_t o_stream_unix_writev(struct file_ostream *fstream,
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch const struct const_iovec *iov,
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch unsigned int iov_count)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch{
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch struct unix_ostream *ustream = (struct unix_ostream *)fstream;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch size_t sent;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ssize_t ret;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch if (ustream->write_fd == -1) {
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch /* no fd */
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return o_stream_file_writev(fstream, iov, iov_count);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch }
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch /* send first iovec along with fd */
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch if (iov_count == 0)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return 0;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch i_assert(iov[0].iov_len > 0);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ret = fd_send(fstream->fd, ustream->write_fd,
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch iov[0].iov_base, iov[0].iov_len);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch if (ret < 0)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return ret;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch /* update stream */
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch sent = ret;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch fstream->real_offset += sent;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ustream->write_fd = -1;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch if (sent < iov[0].iov_len || iov_count == 1) {
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch /* caller will call us again to write the rest */
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return sent;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch }
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch /* send remaining iovecs */
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ret = o_stream_file_writev(fstream, &iov[1], iov_count-1);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch if (ret < 0)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return (errno == EAGAIN || errno == EINTR ? (ssize_t)sent : ret);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch sent += ret;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return sent;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch}
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Boschstruct ostream *o_stream_create_unix(int fd, size_t max_buffer_size)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch{
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch struct unix_ostream *ustream;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch struct ostream *output;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch i_assert(fd != -1);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ustream = i_new(struct unix_ostream, 1);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ustream->write_fd = -1;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch output = o_stream_create_file_common(&ustream->fstream, fd,
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch max_buffer_size, FALSE);
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch output->real_stream->iostream.close = o_stream_unix_close;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ustream->fstream.writev = o_stream_unix_writev;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return output;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch}
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Boschbool o_stream_unix_write_fd(struct ostream *output, int fd)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch{
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch struct unix_ostream *ustream =
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch (struct unix_ostream *)output->real_stream;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch
eb8143d997a69e688c4349a47464c47837d3f53dTimo Sirainen i_assert(fd >= 0);
eb8143d997a69e688c4349a47464c47837d3f53dTimo Sirainen
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch if (ustream->write_fd >= 0)
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return FALSE;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch ustream->write_fd = fd;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch return TRUE;
ea623e25e8d03cb1c28677f418d3dcd5729d09e1Stephan Bosch}