Coverage Report

Created: 2026-05-30 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}