1 /* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "istream.h"
6 #include "ostream.h"
7 #include "ioloop.h"
8 #include "str.h"
9 #include "str-sanitize.h"
10 #include "mkdir-parents.h"
11 #include "dict.h"
12 #include "fs-api.h"
13 #include "message-header-parser.h"
14 #include "mail-index-alloc-cache.h"
15 #include "mail-index-private.h"
16 #include "mail-index-modseq.h"
17 #include "mailbox-log.h"
18 #include "mailbox-list-private.h"
19 #include "mail-search-build.h"
20 #include "index-storage.h"
21 #include "index-mail.h"
22 #include "index-attachment.h"
23 #include "index-thread-private.h"
24 #include "index-mailbox-size.h"
25
26 #include <time.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29
30 #define LOCK_NOTIFY_INTERVAL 30
31
32 struct index_storage_module index_storage_module =
33 MODULE_CONTEXT_INIT(&mail_storage_module_register);
34
set_cache_decisions(struct mail_cache * cache,const char * set,const char * fields,enum mail_cache_decision_type dec)35 static void set_cache_decisions(struct mail_cache *cache,
36 const char *set, const char *fields,
37 enum mail_cache_decision_type dec)
38 {
39 struct mail_cache_field field;
40 const char *const *arr;
41 unsigned int idx;
42
43 if (fields == NULL || *fields == '\0')
44 return;
45
46 for (arr = t_strsplit_spaces(fields, " ,"); *arr != NULL; arr++) {
47 const char *name = *arr;
48
49 idx = mail_cache_register_lookup(cache, name);
50 if (idx != UINT_MAX) {
51 field = *mail_cache_register_get_field(cache, idx);
52 } else if (strncasecmp(name, "hdr.", 4) == 0) {
53 /* Do some sanity checking for the header name. Mainly
54 to make sure there aren't UTF-8 characters that look
55 like their ASCII equivalents or are completely
56 invisible. */
57 if (message_header_name_is_valid(name+4)) {
58 i_zero(&field);
59 field.name = name;
60 field.type = MAIL_CACHE_FIELD_HEADER;
61 } else {
62 i_error("%s: Header name '%s' has invalid character, ignoring",
63 set, name);
64 continue;
65 }
66 } else {
67 i_error("%s: Unknown cache field name '%s', ignoring",
68 set, *arr);
69 continue;
70 }
71
72 field.decision = dec;
73 mail_cache_register_fields(cache, &field, 1);
74 }
75 }
76
index_cache_register_defaults(struct mailbox * box)77 static void index_cache_register_defaults(struct mailbox *box)
78 {
79 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
80 const struct mail_storage_settings *set = box->storage->set;
81 struct mail_cache *cache = box->cache;
82
83 ibox->cache_fields = i_malloc(sizeof(global_cache_fields));
84 memcpy(ibox->cache_fields, global_cache_fields,
85 sizeof(global_cache_fields));
86 mail_cache_register_fields(cache, ibox->cache_fields,
87 MAIL_INDEX_CACHE_FIELD_COUNT);
88
89 if (strcmp(set->mail_never_cache_fields, "*") == 0) {
90 /* all caching disabled for now */
91 box->mail_cache_disabled = TRUE;
92 return;
93 }
94
95 set_cache_decisions(cache, "mail_cache_fields",
96 set->mail_cache_fields,
97 MAIL_CACHE_DECISION_TEMP);
98 set_cache_decisions(cache, "mail_always_cache_fields",
99 set->mail_always_cache_fields,
100 MAIL_CACHE_DECISION_YES |
101 MAIL_CACHE_DECISION_FORCED);
102 set_cache_decisions(cache, "mail_never_cache_fields",
103 set->mail_never_cache_fields,
104 MAIL_CACHE_DECISION_NO |
105 MAIL_CACHE_DECISION_FORCED);
106 }
107
index_storage_lock_notify(struct mailbox * box,enum mailbox_lock_notify_type notify_type,unsigned int secs_left)108 void index_storage_lock_notify(struct mailbox *box,
109 enum mailbox_lock_notify_type notify_type,
110 unsigned int secs_left)
111 {
112 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
113 struct mail_storage *storage = box->storage;
114 const char *str;
115 time_t now;
116
117 /* if notify type changes, print the message immediately */
118 now = time(NULL);
119 if (ibox->last_notify_type == MAILBOX_LOCK_NOTIFY_NONE ||
120 ibox->last_notify_type == notify_type) {
121 if (ibox->last_notify_type == MAILBOX_LOCK_NOTIFY_NONE &&
122 notify_type == MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE) {
123 /* first override notification, show it */
124 } else {
125 if (now < ibox->next_lock_notify || secs_left < 15)
126 return;
127 }
128 }
129
130 ibox->next_lock_notify = now + LOCK_NOTIFY_INTERVAL;
131 ibox->last_notify_type = notify_type;
132
133 switch (notify_type) {
134 case MAILBOX_LOCK_NOTIFY_NONE:
135 break;
136 case MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT:
137 if (storage->callbacks.notify_no == NULL)
138 break;
139
140 str = t_strdup_printf("Mailbox is locked, will abort in "
141 "%u seconds", secs_left);
142 storage->callbacks.
143 notify_no(box, str, storage->callback_context);
144 break;
145 case MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE:
146 if (storage->callbacks.notify_ok == NULL)
147 break;
148
149 str = t_strdup_printf("Stale mailbox lock file detected, "
150 "will override in %u seconds", secs_left);
151 storage->callbacks.
152 notify_ok(box, str, storage->callback_context);
153 break;
154 }
155 }
156
index_storage_lock_notify_reset(struct mailbox * box)157 void index_storage_lock_notify_reset(struct mailbox *box)
158 {
159 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
160
161 ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
162 ibox->last_notify_type = MAILBOX_LOCK_NOTIFY_NONE;
163 }
164
165 static int
index_mailbox_alloc_index(struct mailbox * box,struct mail_index ** index_r)166 index_mailbox_alloc_index(struct mailbox *box, struct mail_index **index_r)
167 {
168 const char *index_dir, *mailbox_path;
169
170 if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
171 &mailbox_path) < 0)
172 return -1;
173 if ((box->flags & MAILBOX_FLAG_NO_INDEX_FILES) != 0 ||
174 mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX,
175 &index_dir) <= 0)
176 index_dir = NULL;
177 /* Note that this may cause box->event to live longer than box */
178 *index_r = mail_index_alloc_cache_get(box->event,
179 mailbox_path, index_dir,
180 box->index_prefix);
181 return 0;
182 }
183
index_storage_mailbox_exists(struct mailbox * box,bool auto_boxes,enum mailbox_existence * existence_r)184 int index_storage_mailbox_exists(struct mailbox *box, bool auto_boxes,
185 enum mailbox_existence *existence_r)
186 {
187 if (auto_boxes && mailbox_is_autocreated(box)) {
188 *existence_r = MAILBOX_EXISTENCE_SELECT;
189 return 0;
190 }
191
192 return index_storage_mailbox_exists_full(box, NULL, existence_r);
193 }
194
index_storage_mailbox_exists_full(struct mailbox * box,const char * subdir,enum mailbox_existence * existence_r)195 int index_storage_mailbox_exists_full(struct mailbox *box, const char *subdir,
196 enum mailbox_existence *existence_r)
197 {
198 struct stat st;
199 const char *path, *path2, *index_path;
200 int ret;
201
202 /* see if it's selectable */
203 ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX, &path);
204 if (ret < 0) {
205 if (mailbox_get_last_mail_error(box) != MAIL_ERROR_NOTFOUND)
206 return -1;
207 *existence_r = MAILBOX_EXISTENCE_NONE;
208 return 0;
209 }
210 if (ret == 0) {
211 /* no mailboxes in this storage? */
212 *existence_r = MAILBOX_EXISTENCE_NONE;
213 return 0;
214 }
215
216 ret = (subdir != NULL || !box->list->set.iter_from_index_dir) ? 0 :
217 mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX, &index_path);
218 if (ret > 0 && strcmp(path, index_path) != 0) {
219 /* index directory is different - prefer looking it up first
220 since it might be on a faster storage. since the directory
221 itself exists also for \NoSelect mailboxes, we'll need to
222 check the dovecot.index.log existence. */
223 index_path = t_strconcat(index_path, "/", box->index_prefix,
224 ".log", NULL);
225 if (stat(index_path, &st) == 0) {
226 *existence_r = MAILBOX_EXISTENCE_SELECT;
227 return 0;
228 }
229 }
230
231 if (subdir != NULL)
232 path = t_strconcat(path, "/", subdir, NULL);
233 if (stat(path, &st) == 0) {
234 *existence_r = MAILBOX_EXISTENCE_SELECT;
235 return 0;
236 }
237 if (!ENOTFOUND(errno) && errno != EACCES) {
238 mailbox_set_critical(box, "stat(%s) failed: %m", path);
239 return -1;
240 }
241
242 /* see if it's non-selectable */
243 if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_DIR, &path2) <= 0 ||
244 (strcmp(path, path2) != 0 && stat(path2, &st) == 0)) {
245 *existence_r = MAILBOX_EXISTENCE_NOSELECT;
246 return 0;
247 }
248 *existence_r = MAILBOX_EXISTENCE_NONE;
249 return 0;
250 }
251
index_storage_mailbox_alloc_index(struct mailbox * box)252 int index_storage_mailbox_alloc_index(struct mailbox *box)
253 {
254 const char *cache_dir;
255
256 if (box->index != NULL)
257 return 0;
258
259 if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX) < 0)
260 return -1;
261 if (index_mailbox_alloc_index(box, &box->index) < 0)
262 return -1;
263
264 if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX_CACHE,
265 &cache_dir) > 0) {
266 if (mailbox_create_missing_dir(box, MAILBOX_LIST_PATH_TYPE_INDEX_CACHE) < 0)
267 return -1;
268 mail_index_set_cache_dir(box->index, cache_dir);
269 }
270 mail_index_set_fsync_mode(box->index,
271 box->storage->set->parsed_fsync_mode, 0);
272 mail_index_set_lock_method(box->index,
273 box->storage->set->parsed_lock_method,
274 mail_storage_get_lock_timeout(box->storage, UINT_MAX));
275
276 const struct mail_storage_settings *set = box->storage->set;
277 struct mail_index_optimization_settings optimization_set = {
278 .index = {
279 .rewrite_min_log_bytes = set->mail_index_rewrite_min_log_bytes,
280 .rewrite_max_log_bytes = set->mail_index_rewrite_max_log_bytes,
281 },
282 .log = {
283 .min_size = set->mail_index_log_rotate_min_size,
284 .max_size = set->mail_index_log_rotate_max_size,
285 .min_age_secs = set->mail_index_log_rotate_min_age,
286 .log2_max_age_secs = set->mail_index_log2_max_age,
287 },
288 .cache = {
289 .unaccessed_field_drop_secs = set->mail_cache_unaccessed_field_drop,
290 .record_max_size = set->mail_cache_record_max_size,
291 .max_size = set->mail_cache_max_size,
292 .purge_min_size = set->mail_cache_purge_min_size,
293 .purge_delete_percentage = set->mail_cache_purge_delete_percentage,
294 .purge_continued_percentage = set->mail_cache_purge_continued_percentage,
295 .purge_header_continue_count = set->mail_cache_purge_header_continue_count,
296 },
297 };
298 mail_index_set_optimization_settings(box->index, &optimization_set);
299 return 0;
300 }
301
index_storage_mailbox_open(struct mailbox * box,bool move_to_memory)302 int index_storage_mailbox_open(struct mailbox *box, bool move_to_memory)
303 {
304 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
305 enum mail_index_open_flags index_flags;
306 int ret;
307
308 i_assert(!box->opened);
309
310 index_flags = ibox->index_flags;
311 if (move_to_memory)
312 index_flags &= ENUM_NEGATE(MAIL_INDEX_OPEN_FLAG_CREATE);
313
314 if (index_storage_mailbox_alloc_index(box) < 0)
315 return -1;
316
317 /* make sure mail_index_set_permissions() has been called */
318 (void)mailbox_get_permissions(box);
319
320 ret = mail_index_open(box->index, index_flags);
321 if (ret <= 0 || move_to_memory) {
322 if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
323 i_assert(ret <= 0);
324 mailbox_set_index_error(box);
325 return -1;
326 }
327
328 if (mail_index_move_to_memory(box->index) < 0) {
329 /* try opening once more. it should be created
330 directly into memory now. */
331 if (mail_index_open_or_create(box->index,
332 index_flags) < 0)
333 i_panic("in-memory index creation failed");
334 }
335 }
336 if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
337 if (mail_index_is_in_memory(box->index)) {
338 mailbox_set_critical(box,
339 "Couldn't create index file");
340 mail_index_close(box->index);
341 return -1;
342 }
343 }
344
345 if ((box->flags & MAILBOX_FLAG_OPEN_DELETED) == 0) {
346 if (mail_index_is_deleted(box->index)) {
347 mailbox_set_deleted(box);
348 mail_index_close(box->index);
349 return -1;
350 }
351 }
352 if ((box->flags & MAILBOX_FLAG_FSCK) != 0) {
353 if (mail_index_fsck(box->index) < 0) {
354 mailbox_set_index_error(box);
355 return -1;
356 }
357 }
358
359 box->cache = mail_index_get_cache(box->index);
360 index_cache_register_defaults(box);
361 box->view = mail_index_view_open(box->index);
362 ibox->keyword_names = mail_index_get_keywords(box->index);
363 box->vsize_hdr_ext_id =
364 mail_index_ext_register(box->index, "hdr-vsize",
365 sizeof(struct mailbox_index_vsize), 0,
366 sizeof(uint64_t));
367 box->pop3_uidl_hdr_ext_id =
368 mail_index_ext_register(box->index, "hdr-pop3-uidl",
369 sizeof(struct mailbox_index_pop3_uidl), 0, 0);
370 box->box_name_hdr_ext_id =
371 mail_index_ext_register(box->index, "box-name", 0, 0, 0);
372
373 box->box_last_rename_stamp_ext_id =
374 mail_index_ext_register(box->index, "last-rename-stamp",
375 sizeof(uint32_t), 0, sizeof(uint32_t));
376 box->mail_vsize_ext_id = mail_index_ext_register(box->index, "vsize", 0,
377 sizeof(uint32_t),
378 sizeof(uint32_t));
379
380 box->opened = TRUE;
381
382 if ((box->enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0)
383 mail_index_modseq_enable(box->index);
384
385 index_thread_mailbox_opened(box);
386 hook_mailbox_opened(box);
387 return 0;
388 }
389
index_storage_mailbox_alloc(struct mailbox * box,const char * vname,enum mailbox_flags flags,const char * index_prefix)390 void index_storage_mailbox_alloc(struct mailbox *box, const char *vname,
391 enum mailbox_flags flags,
392 const char *index_prefix)
393 {
394 static unsigned int mailbox_generation_sequence = 0;
395 struct index_mailbox_context *ibox;
396
397 i_assert(vname != NULL);
398
399 box->generation_sequence = ++mailbox_generation_sequence;
400 box->vname = p_strdup(box->pool, vname);
401 box->name = p_strdup(box->pool,
402 mailbox_list_get_storage_name(box->list, vname));
403 box->flags = flags;
404 box->index_prefix = p_strdup(box->pool, index_prefix);
405 box->event = event_create(box->storage->event);
406 event_add_category(box->event, &event_category_mailbox);
407 event_add_str(box->event, "mailbox", box->vname);
408 event_set_append_log_prefix(box->event,
409 t_strdup_printf("Mailbox %s: ", str_sanitize(box->vname, 128)));
410
411 p_array_init(&box->search_results, box->pool, 16);
412 array_create(&box->module_contexts,
413 box->pool, sizeof(void *), 5);
414
415 ibox = p_new(box->pool, struct index_mailbox_context, 1);
416 ibox->list_index_sync_ext_id = (uint32_t)-1;
417 ibox->index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
418 mail_storage_settings_to_index_flags(box->storage->set);
419 if ((box->flags & MAILBOX_FLAG_SAVEONLY) != 0)
420 ibox->index_flags |= MAIL_INDEX_OPEN_FLAG_SAVEONLY;
421 if (event_want_debug(box->event))
422 ibox->index_flags |= MAIL_INDEX_OPEN_FLAG_DEBUG;
423 ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
424 MODULE_CONTEXT_SET(box, index_storage_module, ibox);
425
426 box->inbox_user = strcmp(box->name, "INBOX") == 0 &&
427 (box->list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0;
428 box->inbox_any = strcmp(box->name, "INBOX") == 0 &&
429 (box->list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0;
430 }
431
index_storage_mailbox_enable(struct mailbox * box,enum mailbox_feature feature)432 int index_storage_mailbox_enable(struct mailbox *box,
433 enum mailbox_feature feature)
434 {
435 if ((feature & MAILBOX_FEATURE_CONDSTORE) != 0) {
436 box->enabled_features |= MAILBOX_FEATURE_CONDSTORE;
437 if (box->opened)
438 mail_index_modseq_enable(box->index);
439 }
440 return 0;
441 }
442
index_storage_mailbox_close(struct mailbox * box)443 void index_storage_mailbox_close(struct mailbox *box)
444 {
445 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
446
447 mailbox_watch_remove_all(box);
448 i_stream_unref(&box->input);
449
450 if (box->view_pvt != NULL)
451 mail_index_view_close(&box->view_pvt);
452 if (box->index_pvt != NULL)
453 mail_index_close(box->index_pvt);
454 if (box->view != NULL) {
455 mail_index_view_close(&box->view);
456 mail_index_close(box->index);
457 }
458 box->cache = NULL;
459
460 ibox->keyword_names = NULL;
461 i_free_and_null(ibox->cache_fields);
462
463 ibox->sync_last_check = 0;
464 }
465
index_storage_mailbox_unref_indexes(struct mailbox * box)466 static void index_storage_mailbox_unref_indexes(struct mailbox *box)
467 {
468 if (box->index_pvt != NULL)
469 mail_index_alloc_cache_unref(&box->index_pvt);
470 if (box->index != NULL)
471 mail_index_alloc_cache_unref(&box->index);
472 }
473
index_storage_mailbox_free(struct mailbox * box)474 void index_storage_mailbox_free(struct mailbox *box)
475 {
476 index_storage_mailbox_unref_indexes(box);
477 event_unref(&box->event);
478 }
479
480 static void
index_storage_mailbox_update_cache(struct mailbox * box,const struct mailbox_update * update)481 index_storage_mailbox_update_cache(struct mailbox *box,
482 const struct mailbox_update *update)
483 {
484 const struct mailbox_cache_field *updates = update->cache_updates;
485 ARRAY(struct mail_cache_field) new_fields;
486 const struct mail_cache_field *old_fields;
487 struct mail_cache_field field;
488 unsigned int i, j, old_count;
489
490 old_fields = mail_cache_register_get_list(box->cache,
491 pool_datastack_create(),
492 &old_count);
493
494 /* There shouldn't be many fields, so don't worry about O(n^2). */
495 t_array_init(&new_fields, 32);
496 for (i = 0; updates[i].name != NULL; i++) {
497 /* see if it's an existing field */
498 for (j = 0; j < old_count; j++) {
499 if (strcmp(updates[i].name, old_fields[j].name) == 0)
500 break;
501 }
502 if (j != old_count) {
503 field = old_fields[j];
504 } else if (str_begins(updates[i].name, "hdr.")) {
505 /* new header */
506 i_zero(&field);
507 field.name = updates[i].name;
508 field.type = MAIL_CACHE_FIELD_HEADER;
509 } else {
510 /* new unknown field. we can't do anything about
511 this since we don't know its type */
512 continue;
513 }
514 field.decision = updates[i].decision;
515 if (updates[i].last_used != (time_t)-1)
516 field.last_used = updates[i].last_used;
517 array_push_back(&new_fields, &field);
518 }
519 if (array_count(&new_fields) > 0) {
520 mail_cache_register_fields(box->cache,
521 array_front_modifiable(&new_fields),
522 array_count(&new_fields));
523 }
524 }
525
526 static int
index_storage_mailbox_update_pvt(struct mailbox * box,const struct mailbox_update * update)527 index_storage_mailbox_update_pvt(struct mailbox *box,
528 const struct mailbox_update *update)
529 {
530 struct mail_index_transaction *trans;
531 struct mail_index_view *view;
532 int ret;
533
534 if ((ret = mailbox_open_index_pvt(box)) <= 0)
535 return ret;
536
537 mail_index_refresh(box->index_pvt);
538 view = mail_index_view_open(box->index_pvt);
539 trans = mail_index_transaction_begin(view,
540 MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
541 if (update->min_highest_modseq != 0 &&
542 mail_index_modseq_get_highest(view) < update->min_highest_pvt_modseq) {
543 mail_index_modseq_enable(box->index_pvt);
544 mail_index_update_highest_modseq(trans,
545 update->min_highest_pvt_modseq);
546 }
547
548 if ((ret = mail_index_transaction_commit(&trans)) < 0)
549 mailbox_set_index_error(box);
550 mail_index_view_close(&view);
551 return ret;
552 }
553
index_storage_mailbox_update_common(struct mailbox * box,const struct mailbox_update * update)554 int index_storage_mailbox_update_common(struct mailbox *box,
555 const struct mailbox_update *update)
556 {
557 int ret = 0;
558
559 if (update->cache_updates != NULL)
560 index_storage_mailbox_update_cache(box, update);
561
562 if (update->min_highest_pvt_modseq != 0) {
563 if (index_storage_mailbox_update_pvt(box, update) < 0)
564 ret = -1;
565 }
566 return ret;
567 }
568
index_storage_mailbox_update(struct mailbox * box,const struct mailbox_update * update)569 int index_storage_mailbox_update(struct mailbox *box,
570 const struct mailbox_update *update)
571 {
572 const struct mail_index_header *hdr;
573 struct mail_index_view *view;
574 struct mail_index_transaction *trans;
575 int ret;
576
577 if (mailbox_open(box) < 0)
578 return -1;
579
580 /* make sure we get the latest index info */
581 mail_index_refresh(box->index);
582 view = mail_index_view_open(box->index);
583 hdr = mail_index_get_header(view);
584
585 trans = mail_index_transaction_begin(view,
586 MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
587 if (update->uid_validity != 0 &&
588 hdr->uid_validity != update->uid_validity) {
589 uint32_t uid_validity = update->uid_validity;
590
591 if (hdr->uid_validity != 0) {
592 /* UIDVALIDITY change requires index to be reset */
593 mail_index_reset(trans);
594 }
595 mail_index_update_header(trans,
596 offsetof(struct mail_index_header, uid_validity),
597 &uid_validity, sizeof(uid_validity), TRUE);
598 }
599 if (update->min_next_uid != 0 &&
600 hdr->next_uid < update->min_next_uid) {
601 uint32_t next_uid = update->min_next_uid;
602
603 mail_index_update_header(trans,
604 offsetof(struct mail_index_header, next_uid),
605 &next_uid, sizeof(next_uid), FALSE);
606 }
607 if (update->min_first_recent_uid != 0 &&
608 hdr->first_recent_uid < update->min_first_recent_uid) {
609 uint32_t first_recent_uid = update->min_first_recent_uid;
610
611 mail_index_update_header(trans,
612 offsetof(struct mail_index_header, first_recent_uid),
613 &first_recent_uid, sizeof(first_recent_uid), FALSE);
614 }
615 if (update->min_highest_modseq != 0 &&
616 mail_index_modseq_get_highest(view) < update->min_highest_modseq) {
617 mail_index_modseq_enable(box->index);
618 mail_index_update_highest_modseq(trans,
619 update->min_highest_modseq);
620 }
621
622 if ((ret = mail_index_transaction_commit(&trans)) < 0)
623 mailbox_set_index_error(box);
624 mail_index_view_close(&view);
625 return ret < 0 ? -1 :
626 index_storage_mailbox_update_common(box, update);
627 }
628
index_storage_mailbox_create(struct mailbox * box,bool directory)629 int index_storage_mailbox_create(struct mailbox *box, bool directory)
630 {
631 const char *path, *p;
632 enum mailbox_list_path_type type;
633 enum mailbox_existence existence;
634 bool create_parent_dir;
635 int ret;
636
637 if ((box->list->props & MAILBOX_LIST_PROP_NO_NOSELECT) != 0) {
638 /* Layout doesn't support creating \NoSelect mailboxes.
639 Switch to creating a selectable mailbox. */
640 directory = FALSE;
641 }
642
643 type = directory ? MAILBOX_LIST_PATH_TYPE_DIR :
644 MAILBOX_LIST_PATH_TYPE_MAILBOX;
645 if ((ret = mailbox_get_path_to(box, type, &path)) < 0)
646 return -1;
647 if (ret == 0) {
648 /* layout=none */
649 mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
650 "Mailbox creation not supported");
651 return -1;
652 }
653 create_parent_dir = !directory &&
654 (box->list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) != 0;
655 if (create_parent_dir) {
656 /* we only need to make sure that the parent directory exists */
657 p = strrchr(path, '/');
658 if (p == NULL)
659 return 1;
660 path = t_strdup_until(path, p);
661 }
662
663 if ((ret = mailbox_mkdir(box, path, type)) < 0)
664 return -1;
665 if (box->list->set.iter_from_index_dir) {
666 /* need to also create the directory to index path or
667 iteration won't find it. */
668 int ret2;
669
670 if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX, &path) <= 0)
671 i_unreached();
672 if ((ret2 = mailbox_mkdir(box, path, type)) < 0)
673 return -1;
674 if (ret == 0 && ret2 > 0) {
675 /* finish partial creation: existed in mail directory,
676 but not in index directory. */
677 ret = 1;
678 }
679 }
680 mailbox_refresh_permissions(box);
681 if (ret == 0) {
682 /* directory already exists */
683 if (create_parent_dir)
684 return 1;
685 if (!directory && *box->list->set.mailbox_dir_name == '\0') {
686 /* For example: layout=fs, path=~/Maildir/foo
687 might itself exist, but does it have the
688 cur|new|tmp subdirs? */
689 if (mailbox_exists(box, FALSE, &existence) < 0)
690 return -1;
691 if (existence != MAILBOX_EXISTENCE_SELECT)
692 return 1;
693 } else if (!box->storage->rebuilding_list_index) {
694 /* ignore existing location if we are recovering list index */
695 mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
696 "Mailbox already exists");
697 return -1;
698 }
699 }
700
701 if (directory) {
702 /* we only wanted to create the directory and it's done now */
703 return 0;
704 }
705 /* the caller should still create the mailbox */
706 return 1;
707 }
708
index_storage_mailbox_delete_dir(struct mailbox * box,bool mailbox_deleted)709 int index_storage_mailbox_delete_dir(struct mailbox *box, bool mailbox_deleted)
710 {
711 guid_128_t dir_sha128;
712 enum mail_error error;
713
714 if (mailbox_list_delete_dir(box->list, box->name) == 0)
715 return 0;
716
717 mailbox_list_get_last_error(box->list, &error);
718 if (error != MAIL_ERROR_NOTFOUND || !mailbox_deleted) {
719 mail_storage_copy_list_error(box->storage, box->list);
720 return -1;
721 }
722 /* failed directory deletion, but mailbox deletion succeeded.
723 this was probably maildir++, which internally deleted the
724 directory as well. add changelog record about that too. */
725 mailbox_name_get_sha128(box->vname, dir_sha128);
726 mailbox_list_add_change(box->list, MAILBOX_LOG_RECORD_DELETE_DIR,
727 dir_sha128);
728 return 0;
729 }
730
731 static int
mailbox_delete_all_attributes(struct mailbox_transaction_context * t,enum mail_attribute_type type)732 mailbox_delete_all_attributes(struct mailbox_transaction_context *t,
733 enum mail_attribute_type type)
734 {
735 struct mailbox_attribute_iter *iter;
736 const char *key;
737 int ret = 0;
738 bool inbox = t->box->inbox_any;
739
740 iter = mailbox_attribute_iter_init(t->box, type, "");
741 while ((key = mailbox_attribute_iter_next(iter)) != NULL) {
742 if (inbox &&
743 str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER))
744 continue;
745
746 if (mailbox_attribute_unset(t, type, key) < 0) {
747 if (mailbox_get_last_mail_error(t->box) != MAIL_ERROR_NOTPOSSIBLE) {
748 ret = -1;
749 break;
750 }
751 }
752 }
753 if (mailbox_attribute_iter_deinit(&iter) < 0)
754 ret = -1;
755 return ret;
756 }
757
mailbox_expunge_all_data(struct mailbox * box)758 static int mailbox_expunge_all_data(struct mailbox *box)
759 {
760 struct mail_search_context *ctx;
761 struct mailbox_transaction_context *t;
762 struct mail *mail;
763 struct mail_search_args *search_args;
764
765 (void)mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
766
767 t = mailbox_transaction_begin(box, 0, __func__);
768
769 search_args = mail_search_build_init();
770 mail_search_build_add_all(search_args);
771 ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
772 mail_search_args_unref(&search_args);
773
774 while (mailbox_search_next(ctx, &mail))
775 mail_expunge(mail);
776
777 if (mailbox_search_deinit(&ctx) < 0) {
778 mailbox_transaction_rollback(&t);
779 return -1;
780 }
781
782 if (mailbox_delete_all_attributes(t, MAIL_ATTRIBUTE_TYPE_PRIVATE) < 0 ||
783 mailbox_delete_all_attributes(t, MAIL_ATTRIBUTE_TYPE_SHARED) < 0) {
784 mailbox_transaction_rollback(&t);
785 return -1;
786 }
787 if (mailbox_transaction_commit(&t) < 0)
788 return -1;
789 /* sync to actually perform the expunges */
790 return mailbox_sync(box, 0);
791 }
792
index_storage_mailbox_delete_pre(struct mailbox * box)793 int index_storage_mailbox_delete_pre(struct mailbox *box)
794 {
795 struct mailbox_status status;
796
797 if (!box->opened) {
798 /* \noselect mailbox, try deleting only the directory */
799 if (index_storage_mailbox_delete_dir(box, FALSE) == 0)
800 return 0;
801 if (mailbox_is_autocreated(box)) {
802 /* Return success when trying to delete autocreated
803 mailbox. The client sees it as existing, so we
804 shouldn't be returning an error. */
805 return 0;
806 }
807 return -1;
808 }
809
810 if ((box->list->flags & MAILBOX_LIST_FLAG_MAILBOX_FILES) == 0) {
811 /* specifically support symlinked shared mailboxes. a deletion
812 will simply remove the symlink, not actually expunge any
813 mails */
814 if (mailbox_list_delete_symlink(box->list, box->name) == 0)
815 return 0;
816 }
817
818 /* we can't easily atomically delete all mails and the mailbox. so:
819 1) expunge all mails
820 2) mark the mailbox deleted (modifications after this will fail)
821 3) check if a race condition between 1) and 2) added any mails:
822 yes) abort and undelete mailbox
823 no) finish deleting the mailbox
824 */
825
826 if (!box->deleting_must_be_empty) {
827 if (mailbox_expunge_all_data(box) < 0)
828 return -1;
829 }
830 if (mailbox_mark_index_deleted(box, TRUE) < 0)
831 return -1;
832
833 if (!box->delete_skip_empty_check || box->deleting_must_be_empty) {
834 if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0)
835 return -1;
836 mailbox_get_open_status(box, STATUS_MESSAGES, &status);
837 if (status.messages == 0)
838 ;
839 else if (box->deleting_must_be_empty) {
840 mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
841 "Mailbox isn't empty");
842 return -1;
843 } else {
844 mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
845 "New mails were added to mailbox during deletion");
846 return -1;
847 }
848 }
849 return 1;
850 }
851
index_storage_mailbox_delete_post(struct mailbox * box)852 int index_storage_mailbox_delete_post(struct mailbox *box)
853 {
854 struct mailbox_metadata metadata;
855 int ret_guid;
856
857 ret_guid = mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata);
858
859 /* Make sure the indexes are closed before trying to delete the
860 directory that contains them. It can still fail with some NFS
861 implementations if indexes are opened by another session, but
862 that can't really be helped. */
863 mailbox_close(box);
864 index_storage_mailbox_unref_indexes(box);
865 mail_index_alloc_cache_destroy_unrefed();
866
867 if (box->list->v.delete_mailbox(box->list, box->name) < 0) {
868 mail_storage_copy_list_error(box->storage, box->list);
869 return -1;
870 }
871
872 if (ret_guid == 0) {
873 mailbox_list_add_change(box->list,
874 MAILBOX_LOG_RECORD_DELETE_MAILBOX,
875 metadata.guid);
876 }
877 if (index_storage_mailbox_delete_dir(box, TRUE) < 0) {
878 if (mailbox_get_last_mail_error(box) != MAIL_ERROR_EXISTS)
879 return -1;
880 /* we deleted the mailbox, but couldn't delete the directory
881 because it has children. that's not an error. */
882 }
883 return 0;
884 }
885
index_storage_mailbox_delete(struct mailbox * box)886 int index_storage_mailbox_delete(struct mailbox *box)
887 {
888 int ret;
889
890 if ((ret = index_storage_mailbox_delete_pre(box)) <= 0)
891 return ret;
892 /* mails have been now successfully deleted. some mailbox formats may
893 at this point do some other deletion that is required for it.
894 the _post() deletion will close the index and delete the
895 directory. */
896 return index_storage_mailbox_delete_post(box);
897 }
898
index_storage_mailbox_rename(struct mailbox * src,struct mailbox * dest)899 int index_storage_mailbox_rename(struct mailbox *src, struct mailbox *dest)
900 {
901 guid_128_t guid;
902
903 if (src->list->v.rename_mailbox(src->list, src->name,
904 dest->list, dest->name) < 0) {
905 mail_storage_copy_list_error(src->storage, src->list);
906 return -1;
907 }
908
909 if (mailbox_open(dest) == 0) {
910 struct mail_index_transaction *t =
911 mail_index_transaction_begin(dest->view, 0);
912
913 uint32_t stamp = ioloop_time;
914
915 mail_index_update_header_ext(t, dest->box_last_rename_stamp_ext_id,
916 0, &stamp, sizeof(stamp));
917
918 /* can't do much if this fails anyways */
919 (void)mail_index_transaction_commit(&t);
920 }
921
922 /* we'll track mailbox names, instead of GUIDs. We may be renaming a
923 non-selectable mailbox (directory), which doesn't even have a GUID */
924 mailbox_name_get_sha128(dest->vname, guid);
925 mailbox_list_add_change(src->list, MAILBOX_LOG_RECORD_RENAME, guid);
926 return 0;
927 }
928
index_mailbox_update_last_temp_file_scan(struct mailbox * box)929 int index_mailbox_update_last_temp_file_scan(struct mailbox *box)
930 {
931 uint32_t last_temp_file_scan = ioloop_time;
932 struct mail_index_transaction *trans =
933 mail_index_transaction_begin(box->view,
934 MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
935 mail_index_update_header(trans,
936 offsetof(struct mail_index_header, last_temp_file_scan),
937 &last_temp_file_scan, sizeof(last_temp_file_scan), TRUE);
938 if (mail_index_transaction_commit(&trans) < 0) {
939 mailbox_set_index_error(box);
940 return -1;
941 }
942 return 0;
943 }
944
index_storage_is_readonly(struct mailbox * box)945 bool index_storage_is_readonly(struct mailbox *box)
946 {
947 return (box->flags & MAILBOX_FLAG_READONLY) != 0;
948 }
949
index_storage_is_inconsistent(struct mailbox * box)950 bool index_storage_is_inconsistent(struct mailbox *box)
951 {
952 return box->view != NULL &&
953 mail_index_view_is_inconsistent(box->view);
954 }
955
index_save_context_free(struct mail_save_context * ctx)956 void index_save_context_free(struct mail_save_context *ctx)
957 {
958 index_mail_save_finish(ctx);
959 if (ctx->data.keywords != NULL)
960 mailbox_keywords_unref(&ctx->data.keywords);
961 i_free_and_null(ctx->data.from_envelope);
962 i_free_and_null(ctx->data.guid);
963 i_free_and_null(ctx->data.pop3_uidl);
964 index_attachment_save_free(ctx);
965 i_zero(&ctx->data);
966
967 ctx->unfinished = FALSE;
968 }
969
970 static void
mail_copy_cache_field(struct mail_save_context * ctx,struct mail * src_mail,uint32_t dest_seq,const char * name,buffer_t * buf)971 mail_copy_cache_field(struct mail_save_context *ctx, struct mail *src_mail,
972 uint32_t dest_seq, const char *name, buffer_t *buf)
973 {
974 struct mailbox_transaction_context *dest_trans = ctx->transaction;
975 const struct mail_cache_field *dest_field;
976 unsigned int src_field_idx, dest_field_idx;
977 uint32_t t;
978 bool add = FALSE;
979
980 src_field_idx = mail_cache_register_lookup(src_mail->box->cache, name);
981 i_assert(src_field_idx != UINT_MAX);
982
983 dest_field_idx = mail_cache_register_lookup(dest_trans->box->cache, name);
984 if (dest_field_idx == UINT_MAX) {
985 /* unknown field */
986 return;
987 }
988 dest_field = mail_cache_register_get_field(dest_trans->box->cache,
989 dest_field_idx);
990 if ((dest_field->decision &
991 ENUM_NEGATE(MAIL_CACHE_DECISION_FORCED)) == MAIL_CACHE_DECISION_NO) {
992 /* field not wanted in destination mailbox */
993 return;
994 }
995
996 buffer_set_used_size(buf, 0);
997 if (strcmp(name, "date.save") == 0) {
998 /* save date must update when mail is copied */
999 t = ioloop_time;
1000 buffer_append(buf, &t, sizeof(t));
1001 add = TRUE;
1002 } else if (mail_cache_lookup_field(src_mail->transaction->cache_view, buf,
1003 src_mail->seq, src_field_idx) <= 0) {
1004 /* error / not found */
1005 buffer_set_used_size(buf, 0);
1006 } else {
1007 if (strcmp(name, "size.physical") == 0 ||
1008 strcmp(name, "size.virtual") == 0) {
1009 /* FIXME: until mail_cache_lookup() can read unwritten
1010 cached data from buffer, we'll do this optimization
1011 to make quota plugin's work faster */
1012 struct index_mail *imail =
1013 INDEX_MAIL(ctx->dest_mail);
1014 uoff_t size;
1015
1016 i_assert(buf->used == sizeof(size));
1017 memcpy(&size, buf->data, sizeof(size));
1018 if (strcmp(name, "size.physical") == 0)
1019 imail->data.physical_size = size;
1020 else
1021 imail->data.virtual_size = size;
1022 }
1023 /* NOTE: we'll want to add also nonexistent headers, which
1024 will keep the buf empty */
1025 add = TRUE;
1026 }
1027 if (add) {
1028 mail_cache_add(dest_trans->cache_trans, dest_seq,
1029 dest_field_idx, buf->data, buf->used);
1030 }
1031 }
1032
1033 static void
index_copy_vsize_extension(struct mail_save_context * ctx,struct mail * src_mail,uint32_t dest_seq)1034 index_copy_vsize_extension(struct mail_save_context *ctx,
1035 struct mail *src_mail, uint32_t dest_seq)
1036 {
1037 const uint32_t *vsizep;
1038 bool expunged ATTR_UNUSED;
1039
1040 vsizep = index_mail_get_vsize_extension(src_mail);
1041 if (vsizep == NULL || *vsizep == 0)
1042 return;
1043 uint32_t vsize = *vsizep;
1044
1045 if (vsize < (uint32_t)-1) {
1046 /* copy the vsize record to the destination index */
1047 mail_index_update_ext(ctx->transaction->itrans, dest_seq,
1048 ctx->transaction->box->mail_vsize_ext_id,
1049 &vsize, NULL);
1050 }
1051 }
1052
index_copy_cache_fields(struct mail_save_context * ctx,struct mail * src_mail,uint32_t dest_seq)1053 void index_copy_cache_fields(struct mail_save_context *ctx,
1054 struct mail *src_mail, uint32_t dest_seq)
1055 {
1056 T_BEGIN {
1057 struct mailbox_metadata src_metadata, dest_metadata;
1058 const struct mailbox_cache_field *field;
1059 buffer_t *buf;
1060
1061 if (mailbox_get_metadata(src_mail->box,
1062 MAILBOX_METADATA_CACHE_FIELDS,
1063 &src_metadata) < 0)
1064 i_unreached();
1065 /* the only reason we're doing the destination lookup is to
1066 make sure that the cache file is opened and the cache
1067 decisions are up to date */
1068 if (mailbox_get_metadata(ctx->transaction->box,
1069 MAILBOX_METADATA_CACHE_FIELDS,
1070 &dest_metadata) < 0)
1071 i_unreached();
1072
1073 buf = t_buffer_create(1024);
1074 array_foreach(src_metadata.cache_fields, field) {
1075 mail_copy_cache_field(ctx, src_mail, dest_seq,
1076 field->name, buf);
1077 }
1078 index_copy_vsize_extension(ctx, src_mail, dest_seq);
1079 } T_END;
1080 }
1081
index_storage_set_subscribed(struct mailbox * box,bool set)1082 int index_storage_set_subscribed(struct mailbox *box, bool set)
1083 {
1084 struct mail_namespace *ns;
1085 struct mailbox_list *list = box->list;
1086 const char *subs_name;
1087 guid_128_t guid;
1088
1089 if ((list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
1090 subs_name = box->name;
1091 else {
1092 /* subscriptions=no namespace, find another one where we can
1093 add the subscription to */
1094 ns = mail_namespace_find_subscribable(list->ns->user->namespaces,
1095 box->vname);
1096 if (ns == NULL) {
1097 mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
1098 "This namespace has no subscriptions");
1099 return -1;
1100 }
1101 /* use <orig ns prefix><orig storage name> as the
1102 subscription name */
1103 subs_name = t_strconcat(list->ns->prefix, box->name, NULL);
1104 /* drop the common prefix (typically there isn't one) */
1105 i_assert(str_begins(subs_name, ns->prefix));
1106 subs_name += strlen(ns->prefix);
1107
1108 list = ns->list;
1109 }
1110 if (mailbox_list_set_subscribed(list, subs_name, set) < 0) {
1111 mail_storage_copy_list_error(box->storage, list);
1112 return -1;
1113 }
1114
1115 /* subscriptions are about names, not about mailboxes. it's possible
1116 to have a subscription to nonexistent mailbox. renames also don't
1117 change subscriptions. so instead of using actual GUIDs, we'll use
1118 hash of the name. */
1119 mailbox_name_get_sha128(box->vname, guid);
1120 mailbox_list_add_change(list, set ? MAILBOX_LOG_RECORD_SUBSCRIBE :
1121 MAILBOX_LOG_RECORD_UNSUBSCRIBE, guid);
1122 return 0;
1123 }
1124
index_storage_destroy(struct mail_storage * storage)1125 void index_storage_destroy(struct mail_storage *storage)
1126 {
1127 if (storage->_shared_attr_dict != NULL) {
1128 dict_wait(storage->_shared_attr_dict);
1129 dict_deinit(&storage->_shared_attr_dict);
1130 }
1131 fs_unref(&storage->mailboxes_fs);
1132 }
1133
index_storage_expunging_init(struct mailbox * box)1134 static void index_storage_expunging_init(struct mailbox *box)
1135 {
1136 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
1137
1138 if (ibox->vsize_update != NULL)
1139 return;
1140
1141 ibox->vsize_update = index_mailbox_vsize_update_init(box);
1142 if (!index_mailbox_vsize_want_updates(ibox->vsize_update) ||
1143 !index_mailbox_vsize_update_wait_lock(ibox->vsize_update))
1144 index_mailbox_vsize_update_deinit(&ibox->vsize_update);
1145 }
1146
index_storage_expunging_deinit(struct mailbox * box)1147 void index_storage_expunging_deinit(struct mailbox *box)
1148 {
1149 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
1150
1151 if (ibox->vsize_update != NULL)
1152 index_mailbox_vsize_update_deinit(&ibox->vsize_update);
1153 }
1154
index_storage_expunging_want_updates(struct mailbox * box)1155 static bool index_storage_expunging_want_updates(struct mailbox *box)
1156 {
1157 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
1158 bool ret;
1159
1160 i_assert(ibox->vsize_update == NULL);
1161
1162 ibox->vsize_update = index_mailbox_vsize_update_init(box);
1163 ret = index_mailbox_vsize_want_updates(ibox->vsize_update);
1164 index_mailbox_vsize_update_deinit(&ibox->vsize_update);
1165 return ret;
1166 }
1167
index_storage_expunged_sync_begin(struct mailbox * box,struct mail_index_sync_ctx ** ctx_r,struct mail_index_view ** view_r,struct mail_index_transaction ** trans_r,enum mail_index_sync_flags flags)1168 int index_storage_expunged_sync_begin(struct mailbox *box,
1169 struct mail_index_sync_ctx **ctx_r,
1170 struct mail_index_view **view_r,
1171 struct mail_index_transaction **trans_r,
1172 enum mail_index_sync_flags flags)
1173 {
1174 struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
1175 int ret;
1176
1177 /* try to avoid locking vsize updates by checking if we see any
1178 expunges */
1179 if (mail_index_sync_have_any_expunges(box->index))
1180 index_storage_expunging_init(box);
1181
1182 ret = mail_index_sync_begin(box->index, ctx_r, view_r,
1183 trans_r, flags);
1184 if (ret <= 0) {
1185 if (ret < 0)
1186 mailbox_set_index_error(box);
1187 index_storage_expunging_deinit(box);
1188 return ret;
1189 }
1190 if (ibox->vsize_update == NULL &&
1191 mail_index_sync_has_expunges(*ctx_r) &&
1192 index_storage_expunging_want_updates(box)) {
1193 /* race condition - need to abort the sync and retry with
1194 the vsize locked */
1195 mail_index_sync_rollback(ctx_r);
1196 index_storage_expunging_deinit(box);
1197 return index_storage_expunged_sync_begin(box, ctx_r, view_r,
1198 trans_r, flags);
1199 }
1200 return 1;
1201 }
1202
index_storage_save_continue(struct mail_save_context * ctx,struct istream * input,struct mail * cache_dest_mail)1203 int index_storage_save_continue(struct mail_save_context *ctx,
1204 struct istream *input,
1205 struct mail *cache_dest_mail)
1206 {
1207 struct mail_storage *storage = ctx->transaction->box->storage;
1208
1209 do {
1210 switch (o_stream_send_istream(ctx->data.output, input)) {
1211 case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
1212 break;
1213 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
1214 break;
1215 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
1216 i_unreached();
1217 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
1218 /* handle below */
1219 break;
1220 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
1221 if (!mail_storage_set_error_from_errno(storage)) {
1222 mail_set_critical(ctx->dest_mail,
1223 "save: write(%s) failed: %s",
1224 o_stream_get_name(ctx->data.output),
1225 o_stream_get_error(ctx->data.output));
1226 }
1227 return -1;
1228 }
1229 if (cache_dest_mail != NULL)
1230 index_mail_cache_parse_continue(cache_dest_mail);
1231
1232 /* both tee input readers may consume data from our primary
1233 input stream. we'll have to make sure we don't return with
1234 one of the streams still having data in them. */
1235 } while (i_stream_read(input) > 0);
1236
1237 if (input->stream_errno != 0) {
1238 mail_set_critical(ctx->dest_mail, "save: read(%s) failed: %s",
1239 i_stream_get_name(input), i_stream_get_error(input));
1240 return -1;
1241 }
1242 return 0;
1243 }
1244
index_storage_save_abort_last(struct mail_save_context * ctx,uint32_t seq)1245 void index_storage_save_abort_last(struct mail_save_context *ctx, uint32_t seq)
1246 {
1247 struct index_mail *imail = INDEX_MAIL(ctx->dest_mail);
1248
1249 /* Close the mail before it's expunged. This allows it to be
1250 reset cleanly. */
1251 imail->data.no_caching = TRUE;
1252 imail->mail.v.close(&imail->mail.mail);
1253
1254 mail_index_expunge(ctx->transaction->itrans, seq);
1255 /* currently we can't just drop pending cache updates for this one
1256 specific record, so we'll reset the whole cache transaction. */
1257 mail_cache_transaction_reset(ctx->transaction->cache_trans);
1258 }
1259
index_mailbox_fix_inconsistent_existence(struct mailbox * box,const char * path)1260 int index_mailbox_fix_inconsistent_existence(struct mailbox *box,
1261 const char *path)
1262 {
1263 const char *index_path;
1264 struct stat st;
1265
1266 /* Could be a race condition or could be because ITERINDEX is used
1267 and the index directory exists, but the storage directory doesn't.
1268 Handle the existence inconsistency by creating this directory if
1269 the index directory exists (don't bother checking if ITERINDEX is
1270 set or not - it doesn't matter since either both dirs should exist
1271 or not). */
1272 if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX,
1273 &index_path) < 0)
1274 return -1;
1275
1276 if (strcmp(index_path, path) == 0) {
1277 /* there's no separate index path - mailbox was just deleted */
1278 } else if (stat(index_path, &st) == 0) {
1279 /* inconsistency - create also the mail directory */
1280 return mailbox_mkdir(box, path, MAILBOX_LIST_PATH_TYPE_MAILBOX);
1281 } else if (errno == ENOENT) {
1282 /* race condition - mailbox was just deleted */
1283 } else {
1284 mailbox_set_critical(box, "stat(%s) failed: %m", index_path);
1285 return -1;
1286 }
1287 mailbox_set_deleted(box);
1288 return -1;
1289 }
1290