sdbox-storage.c revision 4c51dc7df5256942f023947489fe085bc1b73951
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen/* Copyright (c) 2007-2010 Dovecot authors, see the included COPYING file */
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "lib.h"
345648b341f228bd7f0b89f8aa3ecb9c470d817eTimo Sirainen#include "master-service.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "mail-index-modseq.h"
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen#include "mailbox-list-private.h"
5a2cb3d097a2d9a9e930af997e7bf3400a8d840dTimo Sirainen#include "dbox-mail.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "dbox-save.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "sdbox-file.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "sdbox-sync.h"
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen#include "sdbox-storage.h"
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenextern struct mail_storage dbox_storage, sdbox_storage;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenextern struct mailbox sdbox_mailbox;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenextern struct dbox_storage_vfuncs sdbox_dbox_storage_vfuncs;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenstatic struct mail_storage *sdbox_storage_alloc(void)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen{
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct sdbox_storage *storage;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen pool_t pool;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen pool = pool_alloconly_create("sdbox storage", 512+256);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen storage = p_new(pool, struct sdbox_storage, 1);
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen storage->storage.v = sdbox_dbox_storage_vfuncs;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen storage->storage.storage = dbox_storage;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen storage->storage.storage.pool = pool;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen return &storage->storage.storage;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen}
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenstatic int
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainensdbox_storage_create(struct mail_storage *storage ATTR_UNUSED,
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct mail_namespace *ns ATTR_UNUSED,
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen const char **error_r ATTR_UNUSED)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen{
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen return 0;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen}
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainenstatic struct mailbox *
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainensdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen const char *name, enum mailbox_flags flags)
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen{
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen struct sdbox_mailbox *mbox;
c57776c06ec99ba9b0dafdbf9475ea72ea8ca134Timo Sirainen struct index_mailbox_context *ibox;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen pool_t pool;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen /* dbox can't work without index files */
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen flags &= ~MAILBOX_FLAG_NO_INDEX_FILES;
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen pool = pool_alloconly_create("sdbox mailbox", 1024*3);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mbox = p_new(pool, struct sdbox_mailbox, 1);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mbox->box = sdbox_mailbox;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mbox->box.pool = pool;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mbox->box.storage = storage;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mbox->box.list = list;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mbox->box.mail_vfuncs = &sdbox_mail_vfuncs;
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen mail_index_set_fsync_mode(mbox->box.index,
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen storage->set->parsed_fsync_mode,
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen MAIL_INDEX_SYNC_TYPE_APPEND |
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen MAIL_INDEX_SYNC_TYPE_EXPUNGE);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
e70d5895795732b8247ab9abb045b438e954bc46Timo Sirainen ibox->save_commit_pre = sdbox_transaction_save_commit_pre;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen ibox->save_commit_post = sdbox_transaction_save_commit_post;
33c6d5807b449463e9b81db5ec99fe027cc1b984Timo Sirainen ibox->save_rollback = sdbox_transaction_save_rollback;
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen ibox->index_flags |= MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS |
94a78eb438622fa53abef1e1726714dacad4b61cTimo Sirainen MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen mbox->storage = (struct sdbox_storage *)storage;
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen mbox->hdr_ext_id =
b7c2065b3f10f9ae27787a9db5aaefbfc70d4502Timo Sirainen mail_index_ext_register(mbox->box.index, "dbox-hdr",
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen sizeof(struct sdbox_index_header), 0, 0);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen return &mbox->box;
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen}
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainenint sdbox_read_header(struct sdbox_mailbox *mbox,
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen struct sdbox_index_header *hdr, bool log_error)
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen{
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen struct mail_index_view *view;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen const void *data;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen size_t data_size;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen int ret;
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen view = mail_index_view_open(mbox->box.index);
97c339398f1aba6f315b55a9b6ee6b020e33bea4Timo Sirainen mail_index_get_header_ext(view, mbox->hdr_ext_id,
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen &data, &data_size);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen if (data_size < SDBOX_INDEX_HEADER_MIN_SIZE &&
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen (!mbox->creating || data_size != 0)) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (log_error) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen mail_storage_set_critical(
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen &mbox->storage->storage.storage,
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen "sdbox %s: Invalid dbox header size",
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen mbox->box.path);
33c6d5807b449463e9b81db5ec99fe027cc1b984Timo Sirainen }
8eea67470c1bd8562a62e7445d930bb2079b1a43Timo Sirainen ret = -1;
94a78eb438622fa53abef1e1726714dacad4b61cTimo Sirainen } else {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen memset(hdr, 0, sizeof(*hdr));
c7480644202e5451fbed448508ea29a25cffc99cTimo Sirainen memcpy(hdr, data, I_MIN(data_size, sizeof(*hdr)));
a4ac325c2802693c6b761e5a8fda961e5d7490eaTimo Sirainen ret = 0;
b7c2065b3f10f9ae27787a9db5aaefbfc70d4502Timo Sirainen }
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen mail_index_view_close(&view);
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen return ret;
0469ed17dafcc56589ce00960a23f4f06817dfb5Timo Sirainen}
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen
void sdbox_update_header(struct sdbox_mailbox *mbox,
struct mail_index_transaction *trans,
const struct mailbox_update *update)
{
struct sdbox_index_header hdr, new_hdr;
if (sdbox_read_header(mbox, &hdr, TRUE) < 0)
memset(&hdr, 0, sizeof(hdr));
new_hdr = hdr;
if (update != NULL && !mail_guid_128_is_empty(update->mailbox_guid)) {
memcpy(new_hdr.mailbox_guid, update->mailbox_guid,
sizeof(new_hdr.mailbox_guid));
} else if (mail_guid_128_is_empty(new_hdr.mailbox_guid)) {
mail_generate_guid_128(new_hdr.mailbox_guid);
}
if (memcmp(&hdr, &new_hdr, sizeof(hdr)) != 0) {
mail_index_update_header_ext(trans, mbox->hdr_ext_id, 0,
&new_hdr, sizeof(new_hdr));
}
}
static int sdbox_write_index_header(struct mailbox *box,
const struct mailbox_update *update,
struct mail_index_transaction *trans)
{
struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
struct mail_index_transaction *new_trans = NULL;
const struct mail_index_header *hdr;
uint32_t uid_validity, uid_next;
if (trans == NULL) {
new_trans = mail_index_transaction_begin(box->view, 0);
trans = new_trans;
}
hdr = mail_index_get_header(box->view);
if (update != NULL && update->uid_validity != 0)
uid_validity = update->uid_validity;
else if (hdr->uid_validity != 0)
uid_validity = hdr->uid_validity;
else {
/* set uidvalidity */
uid_validity = dbox_get_uidvalidity_next(box->list);
}
if (hdr->uid_validity != uid_validity) {
if (hdr->uid_validity != 0) {
/* UIDVALIDITY change requires index to be reset */
mail_index_reset(trans);
}
mail_index_update_header(trans,
offsetof(struct mail_index_header, uid_validity),
&uid_validity, sizeof(uid_validity), TRUE);
}
if (update != NULL && hdr->next_uid < update->min_next_uid) {
uid_next = update->min_next_uid;
mail_index_update_header(trans,
offsetof(struct mail_index_header, next_uid),
&uid_next, sizeof(uid_next), TRUE);
}
if (update != NULL && update->min_highest_modseq != 0 &&
mail_index_modseq_get_highest(box->view) <
update->min_highest_modseq) {
mail_index_modseq_enable(box->index);
mail_index_update_highest_modseq(trans,
update->min_highest_modseq);
}
sdbox_update_header(mbox, trans, update);
if (new_trans != NULL) {
if (mail_index_transaction_commit(&new_trans) < 0) {
mail_storage_set_internal_error(box->storage);
mail_index_reset_error(box->index);
return -1;
}
}
return 0;
}
static int sdbox_mailbox_create_indexes(struct mailbox *box,
const struct mailbox_update *update,
struct mail_index_transaction *trans)
{
struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
int ret;
mbox->creating = TRUE;
ret = sdbox_write_index_header(box, update, trans);
mbox->creating = FALSE;
return ret;
}
static void sdbox_set_mailbox_corrupted(struct mailbox *box)
{
struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
struct sdbox_index_header hdr;
if (sdbox_read_header(mbox, &hdr, TRUE) < 0 || hdr.rebuild_count == 0)
mbox->corrupted_rebuild_count = 1;
else
mbox->corrupted_rebuild_count = hdr.rebuild_count;
}
static void sdbox_set_file_corrupted(struct dbox_file *_file)
{
struct sdbox_file *file = (struct sdbox_file *)_file;
sdbox_set_mailbox_corrupted(&file->mbox->box);
}
static void sdbox_mailbox_close(struct mailbox *box)
{
struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
if (mbox->corrupted_rebuild_count != 0)
(void)sdbox_sync(mbox, 0);
index_storage_mailbox_close(box);
}
static int
sdbox_mailbox_get_guid(struct mailbox *box, uint8_t guid[MAIL_GUID_128_SIZE])
{
struct sdbox_mailbox *mbox = (struct sdbox_mailbox *)box;
struct sdbox_index_header hdr;
if (sdbox_read_header(mbox, &hdr, TRUE) < 0)
memset(&hdr, 0, sizeof(hdr));
if (mail_guid_128_is_empty(hdr.mailbox_guid)) {
/* regenerate it */
if (sdbox_write_index_header(box, NULL, NULL) < 0 ||
sdbox_read_header(mbox, &hdr, TRUE) < 0)
return -1;
}
memcpy(guid, hdr.mailbox_guid, MAIL_GUID_128_SIZE);
return 0;
}
static int
dbox_mailbox_update(struct mailbox *box, const struct mailbox_update *update)
{
if (!box->opened) {
if (index_storage_mailbox_open(box, FALSE) < 0)
return -1;
}
if (update->cache_fields != NULL)
index_storage_mailbox_update_cache_fields(box, update);
return sdbox_write_index_header(box, update, NULL);
}
struct mail_storage sdbox_storage = {
.name = SDBOX_STORAGE_NAME,
.class_flags = 0,
.v = {
NULL,
sdbox_storage_alloc,
sdbox_storage_create,
NULL,
NULL,
dbox_storage_get_list_settings,
NULL,
sdbox_mailbox_alloc,
NULL
}
};
struct mail_storage dbox_storage = {
.name = "dbox", /* alias */
.class_flags = 0,
.v = {
NULL,
sdbox_storage_alloc,
sdbox_storage_create,
NULL,
NULL,
dbox_storage_get_list_settings,
NULL,
sdbox_mailbox_alloc,
NULL
}
};
struct mailbox sdbox_mailbox = {
.v = {
index_storage_is_readonly,
index_storage_allow_new_keywords,
index_storage_mailbox_enable,
dbox_mailbox_open,
sdbox_mailbox_close,
index_storage_mailbox_free,
dbox_mailbox_create,
dbox_mailbox_update,
index_storage_mailbox_delete,
index_storage_mailbox_rename,
index_storage_get_status,
sdbox_mailbox_get_guid,
NULL,
NULL,
sdbox_storage_sync_init,
index_mailbox_sync_next,
index_mailbox_sync_deinit,
NULL,
dbox_notify_changes,
index_transaction_begin,
index_transaction_commit,
index_transaction_rollback,
index_transaction_set_max_modseq,
index_keywords_create,
index_keywords_create_from_indexes,
index_keywords_ref,
index_keywords_unref,
index_keyword_is_valid,
index_storage_get_seq_range,
index_storage_get_uid_range,
index_storage_get_expunges,
NULL,
NULL,
NULL,
dbox_mail_alloc,
index_header_lookup_init,
index_header_lookup_deinit,
index_storage_search_init,
index_storage_search_deinit,
index_storage_search_next_nonblock,
index_storage_search_next_update_seq,
sdbox_save_alloc,
sdbox_save_begin,
dbox_save_continue,
sdbox_save_finish,
sdbox_save_cancel,
sdbox_copy,
index_storage_is_inconsistent
}
};
struct dbox_storage_vfuncs sdbox_dbox_storage_vfuncs = {
dbox_file_free,
sdbox_file_create_fd,
sdbox_mail_open,
sdbox_mailbox_create_indexes,
sdbox_set_mailbox_corrupted,
sdbox_set_file_corrupted
};