1 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "fdpass.h"
5 #include "ostream-file-private.h"
6 #include "ostream-unix.h"
7
8 struct unix_ostream {
9 struct file_ostream fstream;
10 int write_fd;
11 };
12
13 static void
o_stream_unix_close(struct iostream_private * stream,bool close_parent)14 o_stream_unix_close(struct iostream_private *stream, bool close_parent)
15 {
16 struct unix_ostream *ustream =
17 container_of(stream, struct unix_ostream,
18 fstream.ostream.iostream);
19
20 i_close_fd(&ustream->write_fd);
21 o_stream_file_close(stream, close_parent);
22 }
23
o_stream_unix_writev(struct file_ostream * fstream,const struct const_iovec * iov,unsigned int iov_count)24 static ssize_t o_stream_unix_writev(struct file_ostream *fstream,
25 const struct const_iovec *iov,
26 unsigned int iov_count)
27 {
28 struct unix_ostream *ustream =
29 container_of(fstream, struct unix_ostream, fstream);
30 size_t sent;
31 ssize_t ret;
32
33 if (ustream->write_fd == -1) {
34 /* no fd */
35 return o_stream_file_writev(fstream, iov, iov_count);
36 }
37
38 /* send first iovec along with fd */
39 if (iov_count == 0)
40 return 0;
41 i_assert(iov[0].iov_len > 0);
42 ret = fd_send(fstream->fd, ustream->write_fd,
43 iov[0].iov_base, iov[0].iov_len);
44 if (ret < 0)
45 return ret;
46
47 /* update stream */
48 sent = ret;
49 fstream->real_offset += sent;
50
51 ustream->write_fd = -1;
52
53 if (sent < iov[0].iov_len || iov_count == 1) {
54 /* caller will call us again to write the rest */
55 return sent;
56 }
57
58 /* send remaining iovecs */
59 ret = o_stream_file_writev(fstream, &iov[1], iov_count-1);
60 if (ret < 0)
61 return (errno == EAGAIN || errno == EINTR ? (ssize_t)sent : ret);
62 sent += ret;
63 return sent;
64 }
65
o_stream_create_unix(int fd,size_t max_buffer_size)66 struct ostream *o_stream_create_unix(int fd, size_t max_buffer_size)
67 {
68 struct unix_ostream *ustream;
69 struct ostream *output;
70
71 i_assert(fd != -1);
72
73 ustream = i_new(struct unix_ostream, 1);
74 ustream->write_fd = -1;
75 output = o_stream_create_file_common(&ustream->fstream, fd,
76 max_buffer_size, FALSE);
77 output->real_stream->iostream.close = o_stream_unix_close;
78 ustream->fstream.writev = o_stream_unix_writev;
79
80 return output;
81 }
82
o_stream_unix_write_fd(struct ostream * output,int fd)83 bool o_stream_unix_write_fd(struct ostream *output, int fd)
84 {
85 struct unix_ostream *ustream =
86 container_of(output->real_stream, struct unix_ostream,
87 fstream.ostream);
88
89 i_assert(fd >= 0);
90
91 if (ustream->write_fd >= 0)
92 return FALSE;
93 ustream->write_fd = fd;
94 return TRUE;
95 }
96