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