Coverage Report

Created: 2026-06-15 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-storage/index/dbox-multi/mdbox-mail.c
Line
Count
Source
1
/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "ioloop.h"
5
#include "istream.h"
6
#include "str.h"
7
#include "index-mail.h"
8
#include "dbox-mail.h"
9
#include "mdbox-storage.h"
10
#include "mdbox-sync.h"
11
#include "mdbox-map.h"
12
#include "mdbox-file.h"
13
14
#include <sys/stat.h>
15
16
int mdbox_mail_lookup(struct mdbox_mailbox *mbox, struct mail_index_view *view,
17
          uint32_t seq, uint32_t *map_uid_r)
18
0
{
19
0
  const struct mdbox_mail_index_record *dbox_rec;
20
0
  struct mdbox_index_header hdr;
21
0
  const void *data;
22
0
  uint32_t uid, cur_map_uid_validity;
23
0
  bool need_resize;
24
25
0
  mail_index_lookup_ext(view, seq, mbox->ext_id, &data, NULL);
26
0
  dbox_rec = data;
27
0
  if (dbox_rec == NULL || dbox_rec->map_uid == 0) {
28
0
    mail_index_lookup_uid(view, seq, &uid);
29
0
    mdbox_set_mailbox_corrupted(&mbox->box, t_strdup_printf(
30
0
      "map uid lost for uid %u", uid));
31
0
    return -1;
32
0
  }
33
34
0
  if (mbox->map_uid_validity == 0) {
35
0
    if (mdbox_read_header(mbox, &hdr, &need_resize) < 0)
36
0
      return -1;
37
0
    mbox->map_uid_validity = hdr.map_uid_validity;
38
0
  }
39
0
  if (mdbox_map_open_or_create(mbox->storage->map) < 0)
40
0
    return -1;
41
42
0
  cur_map_uid_validity = mdbox_map_get_uid_validity(mbox->storage->map);
43
0
  if (cur_map_uid_validity != mbox->map_uid_validity) {
44
0
    mdbox_set_mailbox_corrupted(&mbox->box, t_strdup_printf(
45
0
      "map uidvalidity mismatch (%u vs %u)",
46
0
      mbox->map_uid_validity, cur_map_uid_validity));
47
0
    return -1;
48
0
  }
49
0
  *map_uid_r = dbox_rec->map_uid;
50
0
  return 0;
51
0
}
52
53
static void dbox_mail_set_expunged(struct dbox_mail *mail, uint32_t map_uid)
54
0
{
55
0
  struct mail *_mail = &mail->imail.mail.mail;
56
0
  struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->box);
57
58
0
  mail_index_refresh(_mail->box->index);
59
0
  if (mail_index_is_expunged(_mail->transaction->view, _mail->seq)) {
60
0
    mail_set_expunged(_mail);
61
0
    return;
62
0
  }
63
64
0
  mdbox_map_set_corrupted(mbox->storage->map,
65
0
        "Unexpectedly lost %s uid=%u map_uid=%u",
66
0
        mailbox_get_vname(_mail->box),
67
0
        _mail->uid, map_uid);
68
0
}
69
70
static int dbox_mail_open_init(struct dbox_mail *mail, uint32_t map_uid)
71
0
{
72
0
  struct mdbox_mailbox *mbox = MDBOX_MAILBOX(mail->imail.mail.mail.box);
73
0
  uint32_t file_id;
74
0
  int ret;
75
76
0
  if ((ret = mdbox_map_lookup(mbox->storage->map, map_uid,
77
0
            &file_id, &mail->offset)) <= 0) {
78
0
    if (ret < 0)
79
0
      return -1;
80
81
    /* map_uid doesn't exist anymore. either it
82
       got just expunged or the map index is
83
       corrupted. */
84
0
    dbox_mail_set_expunged(mail, map_uid);
85
0
    return -1;
86
0
  } else {
87
0
    mail->open_file = mdbox_file_init(mbox->storage, file_id);
88
0
  }
89
0
  return 0;
90
0
}
91
92
int mdbox_mail_file_set(struct dbox_mail *mail)
93
0
{
94
0
  struct mail *_mail = &mail->imail.mail.mail;
95
0
  struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->box);
96
97
0
  if (mail->open_file != NULL) {
98
    /* already open */
99
0
  } else if (!_mail->saving) {
100
0
    uint32_t map_uid;
101
0
    if (mdbox_mail_lookup(mbox, _mail->transaction->view,
102
0
              _mail->seq, &map_uid) < 0)
103
0
      return -1;
104
0
    if (dbox_mail_open_init(mail, map_uid) < 0)
105
0
      return -1;
106
0
  } else {
107
    /* mail is being saved in this transaction */
108
0
    mail->open_file =
109
0
      mdbox_save_file_get_file(_mail->transaction,
110
0
             _mail->seq,
111
0
             &mail->offset);
112
0
  }
113
0
  return 0;
114
0
}
115
116
int mdbox_mail_open(struct dbox_mail *mail, uoff_t *offset_r,
117
        struct dbox_file **file_r)
118
0
{
119
0
  struct mail *_mail = &mail->imail.mail.mail;
120
0
  struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->box);
121
0
  uint32_t prev_file_id = 0;
122
0
  bool deleted;
123
124
0
  if (!mail_stream_access_start(_mail))
125
0
    return -1;
126
127
0
  do {
128
0
    if (mdbox_mail_file_set(mail) < 0)
129
0
      return -1;
130
0
    if (!dbox_file_is_open(mail->open_file))
131
0
      _mail->transaction->stats.open_lookup_count++;
132
0
    if (dbox_file_open(mail->open_file, &deleted) <= 0)
133
0
      return -1;
134
0
    if (deleted) {
135
      /* either it's expunged now or moved to another file. */
136
0
      struct mdbox_file *mfile =
137
0
        (struct mdbox_file *)mail->open_file;
138
139
0
      if (mfile->file_id == prev_file_id) {
140
0
        uint32_t map_uid;
141
0
        if (mdbox_mail_lookup(mbox, _mail->transaction->view,
142
0
                  _mail->seq, &map_uid) < 0)
143
0
          return -1;
144
0
        dbox_mail_set_expunged(mail, map_uid);
145
0
        return -1;
146
0
      }
147
0
      prev_file_id = mfile->file_id;
148
0
      if (mdbox_map_refresh(mbox->storage->map) < 0)
149
0
        return -1;
150
0
      dbox_file_unref(&mail->open_file);
151
0
    }
152
0
  } while (mail->open_file == NULL);
153
154
0
  *file_r = mail->open_file;
155
0
  *offset_r = mail->offset;
156
0
  return 0;
157
0
}
158
159
static int mdbox_mail_get_save_date(struct mail *mail, time_t *date_r)
160
0
{
161
0
  struct mdbox_mailbox *mbox = MDBOX_MAILBOX(mail->transaction->box);
162
0
  const struct mdbox_mail_index_record *dbox_rec;
163
0
  const void *data;
164
165
0
  mail_index_lookup_ext(mail->transaction->view, mail->seq,
166
0
            mbox->ext_id, &data, NULL);
167
0
  dbox_rec = data;
168
0
  if (dbox_rec == NULL || dbox_rec->map_uid == 0) {
169
    /* lost for some reason, use fallback */
170
0
    return dbox_mail_get_save_date(mail, date_r);
171
0
  }
172
173
0
  *date_r = dbox_rec->save_date;
174
0
  return 1;
175
0
}
176
177
static int
178
mdbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field,
179
           const char **value_r)
180
0
{
181
0
  struct dbox_mail *mail = DBOX_MAIL(_mail);
182
0
  struct mdbox_mailbox *mbox = MDBOX_MAILBOX(_mail->transaction->box);
183
0
  struct mdbox_map_mail_index_record rec;
184
0
  uint32_t map_uid;
185
0
  uint16_t refcount;
186
187
0
  switch (field) {
188
0
  case MAIL_FETCH_REFCOUNT:
189
0
    if (mdbox_mail_lookup(mbox, _mail->transaction->view,
190
0
              _mail->seq, &map_uid) < 0)
191
0
      return -1;
192
0
    if (mdbox_map_lookup_full(mbox->storage->map, map_uid,
193
0
            &rec, &refcount) < 0)
194
0
      return -1;
195
0
    *value_r = p_strdup_printf(mail->imail.mail.data_pool, "%u",
196
0
             refcount);
197
0
    return 0;
198
0
  case MAIL_FETCH_REFCOUNT_ID:
199
0
    if (mdbox_mail_lookup(mbox, _mail->transaction->view,
200
0
              _mail->seq, &map_uid) < 0)
201
0
      return -1;
202
0
    *value_r = p_strdup_printf(mail->imail.mail.data_pool, "%u",
203
0
             map_uid);
204
0
    return 0;
205
0
  case MAIL_FETCH_UIDL_BACKEND:
206
0
    if (!dbox_header_have_flag(&mbox->box, mbox->hdr_ext_id,
207
0
        offsetof(struct mdbox_index_header, flags),
208
0
        DBOX_INDEX_HEADER_FLAG_HAVE_POP3_UIDLS)) {
209
0
      *value_r = "";
210
0
      return 0;
211
0
    }
212
0
    break;
213
0
  case MAIL_FETCH_POP3_ORDER:
214
0
    if (!dbox_header_have_flag(&mbox->box, mbox->hdr_ext_id,
215
0
        offsetof(struct mdbox_index_header, flags),
216
0
        DBOX_INDEX_HEADER_FLAG_HAVE_POP3_ORDERS)) {
217
0
      *value_r = "";
218
0
      return 0;
219
0
    }
220
0
    break;
221
0
  default:
222
0
    break;
223
0
  }
224
0
  return dbox_mail_get_special(_mail, field, value_r);
225
0
}
226
227
static void
228
mdbox_mail_update_flags(struct mail *mail, enum modify_type modify_type,
229
      enum mail_flags flags)
230
0
{
231
0
  if ((flags & DBOX_INDEX_FLAG_ALT) != 0) {
232
0
    mdbox_purge_alt_flag_change(mail, modify_type != MODIFY_REMOVE);
233
0
    flags &= ENUM_NEGATE(DBOX_INDEX_FLAG_ALT);
234
0
    if (flags == 0 && modify_type != MODIFY_REPLACE)
235
0
      return;
236
0
  }
237
238
0
  index_mail_update_flags(mail, modify_type, flags);
239
0
}
240
241
struct mail_vfuncs mdbox_mail_vfuncs = {
242
  dbox_mail_close,
243
  index_mail_free,
244
  index_mail_set_seq,
245
  index_mail_set_uid,
246
  index_mail_set_uid_cache_updates,
247
  index_mail_prefetch,
248
  index_mail_precache,
249
  index_mail_add_temp_wanted_fields,
250
251
  index_mail_get_flags,
252
  index_mail_get_keywords,
253
  index_mail_get_keyword_indexes,
254
  index_mail_get_modseq,
255
  index_mail_get_pvt_modseq,
256
  index_mail_get_parts,
257
  index_mail_get_date,
258
  dbox_mail_get_received_date,
259
  mdbox_mail_get_save_date,
260
  dbox_mail_get_virtual_size,
261
  dbox_mail_get_physical_size,
262
  index_mail_get_first_header,
263
  index_mail_get_headers,
264
  index_mail_get_header_stream,
265
  dbox_mail_get_stream,
266
  index_mail_get_binary_stream,
267
  mdbox_mail_get_special,
268
  index_mail_get_backend_mail,
269
  mdbox_mail_update_flags,
270
  index_mail_update_keywords,
271
  index_mail_update_modseq,
272
  index_mail_update_pvt_modseq,
273
  NULL,
274
  index_mail_expunge,
275
  index_mail_set_cache_corrupted,
276
  index_mail_opened,
277
};