Mercurial > dovecot > core-2.2
changeset 6748:d712370dfd14 HEAD
Added raw storage for opening single-mail files/streams as mailboxes.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 08 Nov 2007 21:18:55 +0200 |
parents | 0cee1cccd14c |
children | ced2ffbeef8b |
files | configure.in src/lib-storage/index/Makefile.am src/lib-storage/index/raw/Makefile.am src/lib-storage/index/raw/raw-mail.c src/lib-storage/index/raw/raw-storage.c src/lib-storage/index/raw/raw-storage.h src/lib-storage/index/raw/raw-sync.c src/lib-storage/index/raw/raw-sync.h src/lib-storage/index/raw/raw-transaction.c |
diffstat | 9 files changed, 615 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Thu Nov 08 21:18:10 2007 +0200 +++ b/configure.in Thu Nov 08 21:18:55 2007 +0200 @@ -339,7 +339,7 @@ AC_MSG_ERROR([--with-storages needs storage list as parameter]) fi mail_storages=`echo "$withval"|sed 's/,/ /g'` ], - mail_storages="maildir mbox dbox cydir") + mail_storages="maildir mbox dbox cydir raw") AC_SUBST(mail_storages) AC_ARG_WITH(sql-drivers, @@ -1928,6 +1928,7 @@ mbox_libs='$(top_builddir)/src/lib-storage/index/mbox/libstorage_mbox.a' dbox_libs='$(top_builddir)/src/lib-storage/index/dbox/libstorage_dbox.a' cydir_libs='$(top_builddir)/src/lib-storage/index/cydir/libstorage_cydir.a' +raw_libs='$(top_builddir)/src/lib-storage/index/raw/libstorage_raw.a' index_libs='$(top_builddir)/src/lib-storage/index/libstorage_index.a $(top_builddir)/src/lib-index/libindex.a' deliver_storage="mbox" @@ -2028,6 +2029,7 @@ src/lib-storage/index/mbox/Makefile src/lib-storage/index/dbox/Makefile src/lib-storage/index/cydir/Makefile +src/lib-storage/index/raw/Makefile src/lib-storage/register/Makefile src/auth/Makefile src/deliver/Makefile
--- a/src/lib-storage/index/Makefile.am Thu Nov 08 21:18:10 2007 +0200 +++ b/src/lib-storage/index/Makefile.am Thu Nov 08 21:18:55 2007 +0200 @@ -1,4 +1,4 @@ -SUBDIRS = maildir mbox dbox cydir +SUBDIRS = maildir mbox dbox cydir raw noinst_LIBRARIES = libstorage_index.a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/raw/Makefile.am Thu Nov 08 21:18:55 2007 +0200 @@ -0,0 +1,26 @@ +noinst_LIBRARIES = libstorage_raw.a + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-index \ + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/lib-storage/index + +libstorage_raw_a_SOURCES = \ + raw-mail.c \ + raw-sync.c \ + raw-storage.c \ + raw-transaction.c + +headers = \ + raw-storage.h \ + raw-sync.h + +if INSTALL_HEADERS + pkginc_libdir=$(pkgincludedir)/src/lib-storage/index/raw + pkginc_lib_HEADERS = $(headers) +else + noinst_HEADERS = $(headers) +endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/raw/raw-mail.c Thu Nov 08 21:18:55 2007 +0200 @@ -0,0 +1,109 @@ +/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "istream.h" +#include "index-mail.h" +#include "raw-storage.h" + +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> + +static int raw_mail_stat(struct mail *mail) +{ + struct raw_mailbox *mbox = (struct raw_mailbox *)mail->box; + const struct stat *st; + + st = i_stream_stat(mbox->input, TRUE); + if (st == NULL) { + mail_storage_set_critical(mail->box->storage, + "stat(%s) failed: %m", mbox->path); + return -1; + } + + mbox->mtime = st->st_mtime; + mbox->ctime = st->st_ctime; + mbox->size = st->st_size; + return 0; +} + +static int raw_mail_get_received_date(struct mail *_mail, time_t *date_r) +{ + struct index_mail *mail = (struct index_mail *)_mail; + struct raw_mailbox *mbox = (struct raw_mailbox *)_mail->box; + + if (mbox->mtime == (time_t)-1) { + if (raw_mail_stat(_mail) < 0) + return -1; + } + + *date_r = mail->data.received_date = mbox->mtime; + return 0; +} + +static int raw_mail_get_save_date(struct mail *_mail, time_t *date_r) +{ + struct index_mail *mail = (struct index_mail *)_mail; + struct raw_mailbox *mbox = (struct raw_mailbox *)_mail->box; + + if (mbox->ctime == (time_t)-1) { + if (raw_mail_stat(_mail) < 0) + return -1; + } + + *date_r = mail->data.save_date = mbox->ctime; + return 0; +} + +static int raw_mail_get_physical_size(struct mail *_mail, uoff_t *size_r) +{ + struct index_mail *mail = (struct index_mail *)_mail; + struct raw_mailbox *mbox = (struct raw_mailbox *)_mail->box; + + if (mbox->size == (uoff_t)-1) { + if (raw_mail_stat(_mail) < 0) + return -1; + } + + *size_r = mail->data.physical_size = mbox->size; + return 0; +} + +static int +raw_mail_get_stream(struct mail *_mail, struct message_size *hdr_size, + struct message_size *body_size, struct istream **stream_r) +{ + struct index_mail *mail = (struct index_mail *)_mail; + struct raw_mailbox *mbox = (struct raw_mailbox *)_mail->box; + + if (mail->data.stream == NULL) { + i_stream_ref(mbox->input); + mail->data.stream = mbox->input; + } + + return index_mail_init_stream(mail, hdr_size, body_size, stream_r); +} + +struct mail_vfuncs raw_mail_vfuncs = { + index_mail_close, + index_mail_free, + index_mail_set_seq, + index_mail_set_uid, + + index_mail_get_flags, + index_mail_get_keywords, + index_mail_get_parts, + index_mail_get_date, + raw_mail_get_received_date, + raw_mail_get_save_date, + index_mail_get_virtual_size, + raw_mail_get_physical_size, + index_mail_get_first_header, + index_mail_get_headers, + index_mail_get_header_stream, + raw_mail_get_stream, + index_mail_get_special, + index_mail_update_flags, + index_mail_update_keywords, + index_mail_expunge +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/raw/raw-storage.c Thu Nov 08 21:18:55 2007 +0200 @@ -0,0 +1,307 @@ +/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "ioloop.h" +#include "istream.h" +#include "index-mail.h" +#include "mail-copy.h" +#include "raw-sync.h" +#include "raw-storage.h" + +#define RAW_LIST_CONTEXT(obj) \ + MODULE_CONTEXT(obj, raw_mailbox_list_module) + +extern struct mail_storage raw_storage; +extern struct mailbox raw_mailbox; + +static MODULE_CONTEXT_DEFINE_INIT(raw_mailbox_list_module, + &mailbox_list_module_register); + +static int raw_list_delete_mailbox(struct mailbox_list *list, const char *name); +static int raw_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx, + const char *dir, const char *fname, + enum mailbox_list_file_type type, + enum mailbox_info_flags *flags); + +static int +raw_get_list_settings(struct mailbox_list_settings *list_set, + const char *data, enum mail_storage_flags flags, + const char **layout_r, const char **error_r) +{ + bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0; + + *layout_r = "fs"; + + memset(list_set, 0, sizeof(*list_set)); + list_set->subscription_fname = RAW_SUBSCRIPTION_FILE_NAME; + list_set->maildir_name = ""; + + if (data == NULL || *data == '\0' || *data == ':') { + /* we won't do any guessing for this format. */ + if (debug) + i_info("raw: mailbox location not given"); + *error_r = "Root mail directory not given"; + return -1; + } + + if (debug) + i_info("raw: data=%s", data); + return mailbox_list_settings_parse(data, list_set, layout_r, NULL, + error_r); +} + +static struct mail_storage *raw_alloc(void) +{ + struct raw_storage *storage; + pool_t pool; + + pool = pool_alloconly_create("raw storage", 512+256); + storage = p_new(pool, struct raw_storage, 1); + storage->storage = raw_storage; + storage->storage.pool = pool; + + return &storage->storage; +} + +static int raw_create(struct mail_storage *_storage, const char *data, + const char **error_r) +{ + struct raw_storage *storage = (struct raw_storage *)_storage; + struct mailbox_list_settings list_set; + struct stat st; + const char *layout; + + if (raw_get_list_settings(&list_set, data, _storage->flags, + &layout, error_r) < 0) + return -1; + list_set.mail_storage_flags = &_storage->flags; + list_set.lock_method = &_storage->lock_method; + + if (stat(list_set.root_dir, &st) < 0) { + if (errno != ENOENT) { + *error_r = t_strdup_printf("stat(%s) failed: %m", + list_set.root_dir); + } else { + *error_r = t_strdup_printf( + "Root mail directory doesn't exist: %s", + list_set.root_dir); + } + return -1; + } + + if (mailbox_list_alloc(layout, &_storage->list, error_r) < 0) + return -1; + storage->list_module_ctx.super = _storage->list->v; + _storage->list->v.iter_is_mailbox = raw_list_iter_is_mailbox; + _storage->list->v.delete_mailbox = raw_list_delete_mailbox; + + MODULE_CONTEXT_SET_FULL(_storage->list, raw_mailbox_list_module, + storage, &storage->list_module_ctx); + + /* finish list init after we've overridden vfuncs */ + mailbox_list_init(_storage->list, _storage->ns, &list_set, + mail_storage_get_list_flags(_storage->flags)); + return 0; +} + +static int +raw_mailbox_open_input(struct mail_storage *storage, const char *name, + const char *path, struct istream **input_r) +{ + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) { + if (ENOTFOUND(errno)) { + mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND, + T_MAIL_ERR_MAILBOX_NOT_FOUND(name)); + } else if (!mail_storage_set_error_from_errno(storage)) { + mail_storage_set_critical(storage, + "open(%s) failed: %m", path); + } + return -1; + } + *input_r = i_stream_create_fd(fd, MAIL_READ_BLOCK_SIZE, TRUE); + return 0; +} + +static struct mailbox * +raw_mailbox_open(struct mail_storage *_storage, const char *name, + struct istream *input, enum mailbox_open_flags flags) +{ + struct raw_storage *storage = (struct raw_storage *)_storage; + struct raw_mailbox *mbox; + const char *path; + pool_t pool; + bool stream = input != NULL; + + flags |= MAILBOX_OPEN_READONLY | MAILBOX_OPEN_NO_INDEX_FILES; + + path = mailbox_list_get_path(_storage->list, name, + MAILBOX_LIST_PATH_TYPE_MAILBOX); + if (input != NULL) + i_stream_ref(input); + else { + if (raw_mailbox_open_input(_storage, name, path, &input) < 0) + return NULL; + } + + pool = pool_alloconly_create("raw mailbox", 1024+512); + mbox = p_new(pool, struct raw_mailbox, 1); + mbox->ibox.box = raw_mailbox; + mbox->ibox.box.pool = pool; + mbox->ibox.storage = &storage->storage; + mbox->ibox.mail_vfuncs = &raw_mail_vfuncs; + mbox->ibox.index = index_storage_alloc(_storage, name, flags, NULL); + + mbox->storage = storage; + mbox->path = p_strdup(pool, path); + mbox->input = input; + + if (stream) + mbox->mtime = mbox->ctime = ioloop_time; + else + mbox->mtime = mbox->ctime = (time_t)-1; + mbox->size = (uoff_t)-1; + + index_storage_mailbox_init(&mbox->ibox, name, flags, FALSE); + return &mbox->ibox.box; +} + +static int raw_mailbox_close(struct mailbox *box) +{ + struct raw_mailbox *mbox = (struct raw_mailbox *)box; + + i_stream_unref(&mbox->input); + return index_storage_mailbox_close(box); +} + +static int raw_mailbox_create(struct mail_storage *storage, + const char *name ATTR_UNUSED, + bool directory ATTR_UNUSED) +{ + mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE, + "Raw mailbox creation isn't supported"); + return -1; +} + +static int raw_list_delete_mailbox(struct mailbox_list *list, + const char *name ATTR_UNUSED) +{ + mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE, + "Raw mailbox deletion isn't supported"); + return -1; +} + +static void raw_notify_changes(struct mailbox *box ATTR_UNUSED) +{ +} + +static int raw_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx, + const char *dir, const char *fname, + enum mailbox_list_file_type type, + enum mailbox_info_flags *flags_r) +{ + struct mail_storage *storage = RAW_LIST_CONTEXT(ctx->list); + const char *path; + struct stat st; + int ret = 1; + + /* try to avoid stat() with these checks */ + if (type == MAILBOX_LIST_FILE_TYPE_DIR) { + *flags_r = MAILBOX_NOSELECT | MAILBOX_CHILDREN; + return 1; + } + if (type != MAILBOX_LIST_FILE_TYPE_SYMLINK && + type != MAILBOX_LIST_FILE_TYPE_UNKNOWN && + (ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) != 0) { + *flags_r = MAILBOX_NOINFERIORS; + return 1; + } + + /* need to stat() then */ + t_push(); + path = t_strconcat(dir, "/", fname, NULL); + if (stat(path, &st) == 0) { + if (S_ISDIR(st.st_mode)) + *flags_r = MAILBOX_NOSELECT | MAILBOX_CHILDREN; + else + *flags_r = MAILBOX_NOINFERIORS; + } else if (errno == EACCES || errno == ELOOP) + *flags_r = MAILBOX_NOSELECT; + else if (ENOTFOUND(errno)) { + *flags_r = MAILBOX_NONEXISTENT; + ret = 0; + } else { + mail_storage_set_critical(storage, "stat(%s) failed: %m", path); + ret = -1; + } + t_pop(); + + return ret; +} + +static void raw_class_init(void) +{ + raw_transaction_class_init(); +} + +static void raw_class_deinit(void) +{ + raw_transaction_class_deinit(); +} + +struct mail_storage raw_storage = { + MEMBER(name) RAW_STORAGE_NAME, + MEMBER(mailbox_is_file) TRUE, + + { + raw_class_init, + raw_class_deinit, + raw_alloc, + raw_create, + NULL, + NULL, + raw_mailbox_open, + raw_mailbox_create + } +}; + +struct mailbox raw_mailbox = { + MEMBER(name) NULL, + MEMBER(storage) NULL, + + { + index_storage_is_readonly, + index_storage_allow_new_keywords, + raw_mailbox_close, + index_storage_get_status, + NULL, + NULL, + raw_storage_sync_init, + index_mailbox_sync_next, + index_mailbox_sync_deinit, + NULL, + raw_notify_changes, + index_transaction_begin, + index_transaction_commit, + index_transaction_rollback, + index_keywords_create, + index_keywords_free, + index_storage_get_uids, + index_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, + NULL, + NULL, + NULL, + NULL, + mail_storage_copy, + index_storage_is_inconsistent + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/raw/raw-storage.h Thu Nov 08 21:18:55 2007 +0200 @@ -0,0 +1,33 @@ +#ifndef RAW_STORAGE_H +#define RAW_STORAGE_H + +#include "index-storage.h" +#include "mailbox-list-private.h" + +#define RAW_STORAGE_NAME "raw" +#define RAW_SUBSCRIPTION_FILE_NAME "subscriptions" + +struct raw_storage { + struct mail_storage storage; + union mailbox_list_module_context list_module_ctx; +}; + +struct raw_mailbox { + struct index_mailbox ibox; + struct raw_storage *storage; + + const char *path; + struct istream *input; + + time_t mtime, ctime; + uoff_t size; + + unsigned int synced:1; +}; + +extern struct mail_vfuncs raw_mail_vfuncs; + +void raw_transaction_class_init(void); +void raw_transaction_class_deinit(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/raw/raw-sync.c Thu Nov 08 21:18:55 2007 +0200 @@ -0,0 +1,58 @@ +/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "raw-storage.h" +#include "raw-sync.h" + +static int raw_sync(struct raw_mailbox *mbox) +{ + struct mail_index_sync_ctx *index_sync_ctx; + struct mail_index_view *sync_view; + struct mail_index_transaction *trans; + uint32_t seq, uid_validity = ioloop_time; + enum mail_index_sync_flags sync_flags; + + i_assert(!mbox->synced); + + sync_flags = MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY; + if (!mbox->ibox.keep_recent) + sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT; + + if (mail_index_sync_begin(mbox->ibox.index, &index_sync_ctx, + &sync_view, &trans, sync_flags) < 0) { + mail_storage_set_index_error(&mbox->ibox); + return -1; + } + + /* set our uidvalidity */ + mail_index_update_header(trans, + offsetof(struct mail_index_header, uid_validity), + &uid_validity, sizeof(uid_validity), TRUE); + + /* add our one and only message */ + mail_index_append(trans, 1, &seq); + index_mailbox_set_recent_uid(&mbox->ibox, 1); + + if (mail_index_sync_commit(&index_sync_ctx) < 0) { + mail_storage_set_index_error(&mbox->ibox); + return -1; + } + mbox->synced = TRUE; + return 0; +} + +struct mailbox_sync_context * +raw_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags) +{ + struct raw_mailbox *mbox = (struct raw_mailbox *)box; + int ret = 0; + + if (!box->opened) + index_storage_mailbox_open(&mbox->ibox); + + if (!mbox->synced) + ret = raw_sync(mbox); + + return index_mailbox_sync_init(box, flags, ret < 0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/raw/raw-sync.h Thu Nov 08 21:18:55 2007 +0200 @@ -0,0 +1,9 @@ +#ifndef RAW_SYNC_H +#define RAW_SYNC_H + +struct mailbox; + +struct mailbox_sync_context * +raw_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-storage/index/raw/raw-transaction.c Thu Nov 08 21:18:55 2007 +0200 @@ -0,0 +1,69 @@ +/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "raw-storage.h" + +struct raw_transaction_context { + struct index_transaction_context ictx; + union mail_index_transaction_module_context module_ctx; +}; + +static void (*next_hook_mail_index_transaction_created) + (struct mail_index_transaction *t) = NULL; + +static int +raw_transaction_commit(struct mail_index_transaction *t, + uint32_t *log_file_seq_r, uoff_t *log_file_offset_r) +{ + struct raw_transaction_context *mt = MAIL_STORAGE_CONTEXT(t); + + return index_transaction_finish_commit(&mt->ictx, log_file_seq_r, + log_file_offset_r); +} + +static void raw_transaction_rollback(struct mail_index_transaction *t) +{ + struct raw_transaction_context *mt = MAIL_STORAGE_CONTEXT(t); + + index_transaction_finish_rollback(&mt->ictx); +} + +static void raw_transaction_created(struct mail_index_transaction *t) +{ + struct mailbox *box = MAIL_STORAGE_CONTEXT(t->view); + + /* index can be for mailbox list index, in which case box=NULL */ + if (box != NULL && + strcmp(box->storage->name, RAW_STORAGE_NAME) == 0) { + struct raw_mailbox *raw = (struct raw_mailbox *)box; + struct raw_transaction_context *mt; + + mt = i_new(struct raw_transaction_context, 1); + mt->ictx.trans = t; + mt->ictx.super = t->v; + + t->v.commit = raw_transaction_commit; + t->v.rollback = raw_transaction_rollback; + MODULE_CONTEXT_SET(t, mail_storage_mail_index_module, mt); + index_transaction_init(&mt->ictx, &raw->ibox); + } + + if (next_hook_mail_index_transaction_created != NULL) + next_hook_mail_index_transaction_created(t); +} + +void raw_transaction_class_init(void) +{ + next_hook_mail_index_transaction_created = + hook_mail_index_transaction_created; + hook_mail_index_transaction_created = raw_transaction_created; +} + +void raw_transaction_class_deinit(void) +{ + i_assert(hook_mail_index_transaction_created == + raw_transaction_created); + hook_mail_index_transaction_created = + next_hook_mail_index_transaction_created; +}