/src/dovecot/src/lib/istream-unix.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "fdpass.h" |
5 | | #include "istream-file-private.h" |
6 | | #include "istream-unix.h" |
7 | | |
8 | | struct unix_istream { |
9 | | struct file_istream fstream; |
10 | | bool next_read_fd; |
11 | | int read_fd; |
12 | | }; |
13 | | |
14 | | static void |
15 | | i_stream_unix_close(struct iostream_private *stream, bool close_parent) |
16 | 0 | { |
17 | 0 | struct unix_istream *ustream = |
18 | 0 | container_of(stream, struct unix_istream, |
19 | 0 | fstream.istream.iostream); |
20 | |
|
21 | 0 | i_close_fd(&ustream->read_fd); |
22 | 0 | i_stream_file_close(stream, close_parent); |
23 | 0 | } |
24 | | |
25 | | static ssize_t i_stream_unix_read(struct istream_private *stream) |
26 | 0 | { |
27 | 0 | struct unix_istream *ustream = |
28 | 0 | container_of(stream, struct unix_istream, fstream.istream); |
29 | 0 | size_t size; |
30 | 0 | ssize_t ret; |
31 | |
|
32 | 0 | if (!ustream->next_read_fd) |
33 | 0 | return i_stream_file_read(stream); |
34 | | |
35 | 0 | i_assert(ustream->read_fd == -1); |
36 | 0 | i_assert(ustream->fstream.skip_left == 0); /* not supported here.. */ |
37 | 0 | if (!i_stream_try_alloc(stream, 1, &size)) |
38 | 0 | return -2; |
39 | | |
40 | 0 | ret = fd_read(stream->fd, stream->w_buffer + stream->pos, size, |
41 | 0 | &ustream->read_fd); |
42 | 0 | if (ustream->read_fd != -1) |
43 | 0 | ustream->next_read_fd = FALSE; |
44 | |
|
45 | 0 | if (ret == 0) { |
46 | | /* EOF */ |
47 | 0 | stream->istream.eof = TRUE; |
48 | 0 | ustream->fstream.seen_eof = TRUE; |
49 | 0 | return -1; |
50 | 0 | } |
51 | | |
52 | 0 | if (unlikely(ret < 0)) { |
53 | 0 | if ((errno == EINTR || errno == EAGAIN) && |
54 | 0 | !stream->istream.blocking) { |
55 | 0 | return 0; |
56 | 0 | } else { |
57 | 0 | i_assert(errno != 0); |
58 | | /* if we get EBADF for a valid fd, it means something's |
59 | | really wrong and we'd better just crash. */ |
60 | 0 | i_assert(errno != EBADF); |
61 | 0 | stream->istream.stream_errno = errno; |
62 | 0 | return -1; |
63 | 0 | } |
64 | 0 | } |
65 | 0 | stream->pos += ret; |
66 | 0 | return ret; |
67 | 0 | } |
68 | | |
69 | | struct istream *i_stream_create_unix(int fd, size_t max_buffer_size) |
70 | 0 | { |
71 | 0 | struct unix_istream *ustream; |
72 | 0 | struct istream *input; |
73 | |
|
74 | 0 | i_assert(fd != -1); |
75 | | |
76 | 0 | ustream = i_new(struct unix_istream, 1); |
77 | 0 | ustream->read_fd = -1; |
78 | 0 | input = i_stream_create_file_common(&ustream->fstream, fd, NULL, |
79 | 0 | max_buffer_size, FALSE); |
80 | 0 | input->real_stream->iostream.close = i_stream_unix_close; |
81 | 0 | input->real_stream->read = i_stream_unix_read; |
82 | 0 | return input; |
83 | 0 | } |
84 | | |
85 | | void i_stream_unix_set_read_fd(struct istream *input) |
86 | 0 | { |
87 | 0 | struct unix_istream *ustream = |
88 | 0 | container_of(input->real_stream, struct unix_istream, |
89 | 0 | fstream.istream); |
90 | |
|
91 | 0 | ustream->next_read_fd = TRUE; |
92 | 0 | } |
93 | | |
94 | | void i_stream_unix_unset_read_fd(struct istream *input) |
95 | 0 | { |
96 | 0 | struct unix_istream *ustream = |
97 | 0 | container_of(input->real_stream, struct unix_istream, |
98 | 0 | fstream.istream); |
99 | |
|
100 | 0 | ustream->next_read_fd = FALSE; |
101 | 0 | } |
102 | | |
103 | | int i_stream_unix_get_read_fd(struct istream *input) |
104 | 0 | { |
105 | 0 | struct unix_istream *ustream = |
106 | 0 | container_of(input->real_stream, struct unix_istream, |
107 | 0 | fstream.istream); |
108 | 0 | int fd; |
109 | |
|
110 | 0 | fd = ustream->read_fd; |
111 | 0 | ustream->read_fd = -1; |
112 | 0 | return fd; |
113 | 0 | } |