Mercurial > dovecot > core-2.2
changeset 12642:46dc31d8769f
lib-index: Removed the old "mailbox list" type index, which is no longer used.
It was rather overdesigned and fragile.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 08 Feb 2011 01:36:19 +0200 |
parents | ad002fdc6a6c |
children | f5f877ecd7f6 |
files | src/lib-index/Makefile.am src/lib-index/mailbox-list-index-private.h src/lib-index/mailbox-list-index-sync.c src/lib-index/mailbox-list-index.c src/lib-index/mailbox-list-index.h src/util/Makefile.am src/util/listview.c |
diffstat | 7 files changed, 0 insertions(+), 2116 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-index/Makefile.am Tue Feb 08 01:35:45 2011 +0200 +++ b/src/lib-index/Makefile.am Tue Feb 08 01:36:19 2011 +0200 @@ -41,8 +41,6 @@ mail-transaction-log-append.c \ mail-transaction-log-file.c \ mail-transaction-log-view.c \ - mailbox-list-index.c \ - mailbox-list-index-sync.c \ mailbox-log.c headers = \ @@ -60,8 +58,6 @@ mail-transaction-log.h \ mail-transaction-log-private.h \ mail-transaction-log-view-private.h \ - mailbox-list-index.h \ - mailbox-list-index-private.h \ mailbox-log.h test_programs = \
--- a/src/lib-index/mailbox-list-index-private.h Tue Feb 08 01:35:45 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -#ifndef MAILBOX_LIST_INDEX_PRIVATE_H -#define MAILBOX_LIST_INDEX_PRIVATE_H - -#include "file-dotlock.h" -#include "mailbox-list-index.h" - -#define MAILBOX_LIST_INDEX_MAJOR_VERSION 1 -#define MAILBOX_LIST_INDEX_MINOR_VERSION 0 - -#define MAILBOX_LIST_COMPRESS_PERCENTAGE 10 -#define MAILBOX_LIST_COMPRESS_MIN_SIZE 1024 - -#define MAILBOX_LIST_INDEX_MMAP_MIN_SIZE (1024*32) - -struct mailbox_list_index_header { - uint8_t major_version; - uint8_t minor_version; - uint8_t unused[2]; - - uint32_t file_seq; - uint32_t header_size; - uint32_t uid_validity; - - /* locking required to access the fields below: */ - uint32_t next_uid; - - uint32_t used_space; - uint32_t deleted_space; -}; - -struct mailbox_list_dir_record { - /* If non-zero, contains a pointer to updated directory list. - Stored using mail_index_uint32_to_offset(). */ - uint32_t next_offset; - /* Bytes required to be able to fully read this directory's records. - This includes also bytes used by mailbox names that follow the - records (but doesn't include bytes for mailbox names that point - to earlier offsets in the file). */ - uint32_t dir_size; - - uint32_t count; - /* The records are sorted 1) by their name_hash, 2) the actual name */ - /* struct mailbox_list_record records[count]; */ -}; - -struct mailbox_list_record { - /* CRC32 hash of the name */ - uint32_t name_hash; - unsigned int uid:31; - /* Set when this record has been marked as deleted. It will be removed - permanently the next time a new record is added to this directory - or on the next index compression. */ - unsigned int deleted:1; - - /* Points to a NUL-terminated record name */ - uint32_t name_offset; - /* Pointer to child mailboxes or 0 if there are no children. - The offset is stored using mail_index_uint32_to_offset() - since it may change while we're reading */ - uint32_t dir_offset; -}; - -struct mailbox_list_index { - char *filepath; - char separator; - struct mail_index *mail_index; - struct file_cache *file_cache; - struct dotlock_settings dotlock_set; - - int fd; - - void *mmap_base; - const void *const_mmap_base; - size_t mmap_size; - const struct mailbox_list_index_header *hdr; - - unsigned int mmap_disable:1; -}; - -#define MAILBOX_LIST_RECORDS(dir) \ - ((const struct mailbox_list_record *)(dir + 1)) -#define MAILBOX_LIST_RECORDS_MODIFIABLE(dir) \ - ((struct mailbox_list_record *)(dir + 1)) -#define MAILBOX_LIST_RECORD_IDX(dir, rec) \ - ((rec) - MAILBOX_LIST_RECORDS(dir)) - -int mailbox_list_index_set_syscall_error(struct mailbox_list_index *index, - const char *function); - -int mailbox_list_index_dir_lookup_rec(struct mailbox_list_index *index, - const struct mailbox_list_dir_record *dir, - const char *name, - const struct mailbox_list_record **rec_r); -int mailbox_list_index_get_dir(struct mailbox_list_index_view *view, - uint32_t *offset, - const struct mailbox_list_dir_record **dir_r); -int mailbox_list_index_map(struct mailbox_list_index *index); - -int mailbox_list_index_file_create(struct mailbox_list_index *index, - uint32_t uid_validity); -void mailbox_list_index_file_close(struct mailbox_list_index *index); - -int mailbox_list_index_refresh(struct mailbox_list_index *index); - -int mailbox_list_index_set_corrupted(struct mailbox_list_index *index, - const char *str); - -#endif
--- a/src/lib-index/mailbox-list-index-sync.c Tue Feb 08 01:35:45 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,991 +0,0 @@ -/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "bsearch-insert-pos.h" -#include "crc32.h" -#include "file-cache.h" -#include "file-set-size.h" -#include "mmap-util.h" -#include "nfs-workarounds.h" -#include "ostream.h" -#include "mail-index-private.h" -#include "mailbox-list-index-private.h" - -#include <stddef.h> - -#define ROOT_INIT_COUNT 128 -#define DIR_ALLOC_MORE_COUNT 4 -#define MAILBOX_LIST_INDEX_GROW_PERCENTAGE 10 -#define MAILBOX_LIST_INDEX_MIN_SIZE 512 - -struct mailbox_list_sync_record { - uint32_t name_hash; - uint32_t seq; - uint32_t uid; - const char *name; - - /* dir is used if it's non-NULL, otherwise dir_offset is used */ - struct mailbox_list_sync_dir *dir; - uint32_t dir_offset; - - uint32_t created:1; - /* This record was seen while syncing, either as parent or as leaf */ - uint32_t seen:1; - /* This record was seen as leaf while syncing, so it exists */ - uint32_t exists:1; -}; - -struct mailbox_list_sync_dir { - /* The records are sorted by their name_hash */ - ARRAY_DEFINE(records, struct mailbox_list_sync_record); - - /* Offset to the original location in the index, or 0 for new dirs */ - uint32_t offset; - unsigned int seen_records_count; - unsigned int new_records_count; -}; - -struct mailbox_list_index_sync_ctx { - struct mailbox_list_index *index; - struct mailbox_list_index_view *view; - pool_t pool; - - enum mailbox_list_sync_flags flags; - const char *sync_path; - struct mail_index_sync_ctx *mail_sync_ctx; - struct mail_index_view *mail_view; - struct mail_index_transaction *trans; - - struct mailbox_list_index_header hdr; - struct mailbox_list_sync_dir *root, *sync_root; - - struct ostream *output; - buffer_t *output_buf; - - unsigned int failed:1; - unsigned int changed:1; - unsigned int restart:1; - unsigned int partial:1; - unsigned int seen_sync_root:1; -}; - -struct mailbox_list_sync_lookup_key { - uint32_t name_hash; - const char *name; -}; - -static bool mailbox_list_index_need_compress(struct mailbox_list_index *index); -static int mailbox_list_index_compress(struct mailbox_list_index_sync_ctx *ctx); - -static struct mailbox_list_sync_dir * -mailbox_list_alloc_sync_dir(struct mailbox_list_index_sync_ctx *ctx, - unsigned int initial_count) -{ - struct mailbox_list_sync_dir *sync_dir; - - sync_dir = p_new(ctx->pool, struct mailbox_list_sync_dir, 1); - p_array_init(&sync_dir->records, ctx->pool, initial_count); - return sync_dir; -} - -static int -mailbox_list_copy_sync_dir(struct mailbox_list_index_sync_ctx *ctx, - uint32_t offset, - struct mailbox_list_sync_dir **sync_dir_r) -{ - const struct mailbox_list_dir_record *dir; - const struct mailbox_list_record *recs; - struct mailbox_list_sync_dir *sync_dir; - struct mailbox_list_sync_record *sync_rec; - const char *name; - size_t max_len; - unsigned int i; - - if (mailbox_list_index_get_dir(ctx->view, &offset, &dir) < 0) - return -1; - - sync_dir = mailbox_list_alloc_sync_dir(ctx, dir->count + - DIR_ALLOC_MORE_COUNT); - sync_dir->offset = offset; - - recs = MAILBOX_LIST_RECORDS(dir); - for (i = 0; i < dir->count; i++) { - if (recs[i].deleted) - continue; - - if (recs[i].uid == 0) { - return mailbox_list_index_set_corrupted(ctx->index, - "Record with UID=0"); - } - - sync_rec = array_append_space(&sync_dir->records); - sync_rec->name_hash = recs[i].name_hash; - sync_rec->uid = recs[i].uid; - sync_rec->dir_offset = - mail_index_offset_to_uint32(recs[i].dir_offset); - - max_len = ctx->index->mmap_size - recs[i].name_offset; - name = CONST_PTR_OFFSET(ctx->index->const_mmap_base, - recs[i].name_offset); - - sync_rec->name = p_strndup(ctx->pool, name, max_len); - } - - *sync_dir_r = sync_dir; - return 0; -} - -static int -mailbox_list_sync_record_cmp(const struct mailbox_list_sync_lookup_key *key, - const struct mailbox_list_sync_record *rec) -{ - if (key->name_hash < rec->name_hash) - return -1; - if (key->name_hash > rec->name_hash) - return 1; - - return strcmp(key->name, rec->name); -} - -static struct mailbox_list_sync_record * -mailbox_list_sync_dir_lookup(struct mailbox_list_sync_dir *dir, - const char *name, unsigned int *idx_r) -{ - struct mailbox_list_sync_lookup_key key; - - /* binary search the current hierarchy level name. the values are - sorted primarily by their hash value and secondarily by the actual - name */ - key.name = name; - key.name_hash = crc32_str(name); - - if (!array_bsearch_insert_pos(&dir->records, &key, - mailbox_list_sync_record_cmp, idx_r)) - return NULL; - - return array_idx_modifiable(&dir->records, *idx_r); -} - -static struct mailbox_list_sync_record * -mailbox_list_alloc_add_record(struct mailbox_list_index_sync_ctx *ctx, - struct mailbox_list_sync_dir *dir, - const char *name, unsigned int idx) -{ - struct mailbox_list_sync_record *rec; - - ctx->changed = TRUE; - - rec = array_insert_space(&dir->records, idx); - rec->name_hash = crc32_str(name); - rec->name = p_strdup(ctx->pool, name); - rec->uid = ctx->hdr.next_uid++; - rec->created = TRUE; - mail_index_append(ctx->trans, rec->uid, &rec->seq); - - dir->new_records_count++; - return rec; -} - -static int -mailbox_list_index_sync_get_seq(struct mailbox_list_index_sync_ctx *ctx, - struct mailbox_list_sync_record *rec) -{ - const struct mail_index_header *mail_hdr; - - if (rec->uid == 0) { - return mailbox_list_index_set_corrupted(ctx->index, - "Record with UID=0"); - } - if (!mail_index_lookup_seq(ctx->mail_view, rec->uid, &rec->seq)) { - mail_hdr = mail_index_get_header(ctx->mail_view); - if (rec->uid < mail_hdr->next_uid) { - i_warning("%s: Desync: Record uid=%u " - "expunged from mail index", - ctx->index->mail_index->filepath, rec->uid); - ctx->restart = TRUE; - return -1; - } - mail_index_append(ctx->trans, rec->uid, &rec->seq); - } - return 0; -} - -static int -mailbox_list_index_sync_int(struct mailbox_list_index_sync_ctx *ctx, - const char *name, - struct mailbox_list_sync_dir **dir_r, - uint32_t *seq_r) -{ - const char *p, *hier_name; - struct mailbox_list_sync_dir *dir; - struct mailbox_list_sync_record *rec = NULL; - unsigned int idx, rec_flags; - - if (ctx->failed) - return -1; - - dir = ctx->sync_root; - rec_flags = MAILBOX_LIST_INDEX_FLAG_CHILDREN; - - for (;;) { - p = strchr(name, ctx->index->separator); - hier_name = p == NULL ? name : t_strdup_until(name, p); - - if (*hier_name == '\0') { - if (p == NULL) { - /* name ended with a separator */ - break; - } - /* two separators adjacently, skip this */ - name = p + 1; - continue; - } - - if (rec != NULL) { - /* add CHILDREN flag to the parent and remove - NOCHILDREN flag. if we happened to create the - parent ourself, also add NONEXISTENT flag. */ - mail_index_update_flags(ctx->trans, rec->seq, - MODIFY_ADD, rec_flags); - mail_index_update_flags(ctx->trans, rec->seq, - MODIFY_REMOVE, - (enum mail_flags) - MAILBOX_LIST_INDEX_FLAG_NOCHILDREN); - } - - rec = mailbox_list_sync_dir_lookup(dir, hier_name, &idx); - if (rec == NULL) { - /* new record */ - rec_flags |= MAILBOX_LIST_INDEX_FLAG_NONEXISTENT; - rec = mailbox_list_alloc_add_record(ctx, dir, - hier_name, idx); - } else if (rec->seq == 0) { - /* this record was copied from existing index. - the uid is known, but the sequence isn't. */ - if (mailbox_list_index_sync_get_seq(ctx, rec) < 0) { - ctx->failed = TRUE; - break; - } - } - *seq_r = rec->seq; - - /* remember that we've seen this record */ - if (!rec->seen) { - rec->seen = TRUE; - dir->seen_records_count++; - } - - if (p == NULL) { - /* leaf */ - rec->exists = TRUE; - mail_index_update_flags(ctx->trans, rec->seq, - MODIFY_REMOVE, - (enum mail_flags) - MAILBOX_LIST_INDEX_FLAG_NONEXISTENT); - break; - } - - /* we were handling a parent, continue with its child */ - if (!rec->exists) { - /* Mark this mailbox non-existent for now. If it - exists, this flag is removed later. */ - mail_index_update_flags(ctx->trans, rec->seq, - MODIFY_ADD, - (enum mail_flags) - MAILBOX_LIST_INDEX_FLAG_NONEXISTENT); - } - - if (rec->dir == NULL) { - if (rec->dir_offset != 0) { - if (mailbox_list_copy_sync_dir(ctx, - rec->dir_offset, - &rec->dir) < 0) { - ctx->failed = TRUE; - break; - } - } else { - rec->dir = mailbox_list_alloc_sync_dir(ctx, - 1 + DIR_ALLOC_MORE_COUNT); - } - } - - name = p + 1; - dir = rec->dir; - } - - i_assert(dir != NULL); - *dir_r = dir; - return ctx->failed ? -1 : 0; -} - -static int mailbox_list_index_get_root(struct mailbox_list_index_sync_ctx *ctx) -{ - uint32_t seq; - int ret; - - i_assert(ctx->index->mmap_size > 0); - - if (ctx->index->mmap_size == sizeof(*ctx->index->hdr)) { - /* root doesn't exist in the file yet */ - ctx->root = mailbox_list_alloc_sync_dir(ctx, - ROOT_INIT_COUNT); - } else { - if (mailbox_list_copy_sync_dir(ctx, sizeof(*ctx->index->hdr), - &ctx->root) < 0) - return -1; - } - - /* keep sync_root=root until we've built the sync_root path. */ - ctx->sync_root = ctx->root; - - if (*ctx->sync_path != '\0') { - if (mailbox_list_index_sync_more(ctx, ctx->sync_path, &seq) < 0) - return -1; - } - - T_BEGIN { - ret = mailbox_list_index_sync_int(ctx, ctx->sync_path, - &ctx->sync_root, &seq); - } T_END; - return ret; -} - -static int sync_mail_sync_init(struct mailbox_list_index_sync_ctx *ctx) -{ - struct mail_index_sync_rec sync_rec; - - if (mail_index_sync_begin(ctx->index->mail_index, &ctx->mail_sync_ctx, - &ctx->mail_view, &ctx->trans, - MAIL_INDEX_SYNC_FLAG_AVOID_FLAG_UPDATES) < 0) - return -1; - - mail_index_flush_read_cache(ctx->index->mail_index, ctx->index->filepath, - ctx->index->fd, FALSE); - - /* we should have only external transactions in here, for which we - don't need to do anything but write them to the index */ - while (mail_index_sync_next(ctx->mail_sync_ctx, &sync_rec)) - ; - return 0; -} - -static int sync_mail_sync_init2(struct mailbox_list_index_sync_ctx *ctx) -{ - const struct mail_index_header *mail_hdr; - uint32_t uid_validity; - - ctx->hdr = *ctx->index->hdr; - mail_hdr = mail_index_get_header(ctx->mail_view); - uid_validity = mail_hdr->uid_validity; - - if (uid_validity != 0 || mail_hdr->next_uid != 1) { - if (uid_validity != ctx->hdr.uid_validity) { - i_warning("%s: Desync: uid_validity changed %u -> %u", - ctx->index->mail_index->filepath, - uid_validity, ctx->hdr.uid_validity); - uid_validity = 0; - mail_index_reset(ctx->trans); - } - } - - if (uid_validity != ctx->hdr.uid_validity ) { - mail_index_update_header(ctx->trans, - offsetof(struct mail_index_header, uid_validity), - &ctx->hdr.uid_validity, sizeof(ctx->hdr.uid_validity), - TRUE); - } - - return 0; -} - -int mailbox_list_index_sync_init(struct mailbox_list_index *index, - const char *path, - enum mailbox_list_sync_flags flags, - struct mailbox_list_index_sync_ctx **ctx_r) -{ - struct mailbox_list_index_sync_ctx *ctx; - struct mailbox_list_index_view *view; - pool_t pool; - size_t len; - - if (mailbox_list_index_view_init(index, NULL, &view) < 0) - return -1; - - /* add separator to end of path if it isn't there */ - len = strlen(path); - if (len > 0 && path[len-1] != index->separator) - path = t_strdup_printf("%s%c", path, index->separator); - - pool = pool_alloconly_create(MEMPOOL_GROWING"mailbox list index sync", - 1024*32); - - ctx = p_new(pool, struct mailbox_list_index_sync_ctx, 1); - ctx->pool = pool; - ctx->index = index; - ctx->view = view; - ctx->sync_path = p_strdup(pool, path); - ctx->flags = flags; - - /* mail index syncing acts as the only locking for us */ - if (sync_mail_sync_init(ctx) < 0 || - mailbox_list_index_refresh(index) < 0 || - sync_mail_sync_init2(ctx) < 0 || - mailbox_list_index_get_root(ctx) < 0) { - mailbox_list_index_sync_rollback(&ctx); - return -1; - } - - *ctx_r = ctx; - return 0; -} - -struct mail_index_view * -mailbox_list_index_sync_get_view(struct mailbox_list_index_sync_ctx *ctx) -{ - return ctx->mail_view; -} - -struct mail_index_transaction * -mailbox_list_index_sync_get_transaction(struct mailbox_list_index_sync_ctx *ctx) -{ - return ctx->trans; -} - -int mailbox_list_index_sync_more(struct mailbox_list_index_sync_ctx *ctx, - const char *name, uint32_t *seq_r) -{ - struct mailbox_list_sync_dir *dir; - int ret; - - T_BEGIN { - ret = mailbox_list_index_sync_int(ctx, name, &dir, seq_r); - } T_END; - return ret; -} - -static int -mailbox_list_index_sync_grow(struct mailbox_list_index_sync_ctx *ctx, - uint32_t size) -{ - struct mailbox_list_index *index = ctx->index; - uoff_t new_fsize, grow_size; - - new_fsize = ctx->hdr.used_space + size; - grow_size = new_fsize / 100 * MAILBOX_LIST_INDEX_GROW_PERCENTAGE; - if (grow_size < MAILBOX_LIST_INDEX_MIN_SIZE) - grow_size = MAILBOX_LIST_INDEX_MIN_SIZE; - new_fsize += grow_size; - new_fsize &= ~(512-1); - - i_assert(new_fsize >= ctx->hdr.used_space + size); - - if (file_set_size(index->fd, (off_t)new_fsize) < 0) { - mailbox_list_index_set_syscall_error(index, "file_set_size()"); - return -1; - } - - return mailbox_list_index_map(index); -} - -static int -mailbox_list_index_sync_alloc_space(struct mailbox_list_index_sync_ctx *ctx, - uint32_t size, void **base_r, - uint32_t *base_offset_r) -{ - size_t pos = ctx->hdr.used_space; - - /* all allocations must be 32bit aligned */ - pos = (pos + 3) & ~3; - - if (ctx->index->mmap_base == NULL) { - /* write the data into temporary buffer first */ - buffer_reset(ctx->output_buf); - *base_r = buffer_append_space_unsafe(ctx->output_buf, size); - } else { - if (pos + size > ctx->index->mmap_size) { - if (mailbox_list_index_sync_grow(ctx, size + 3) < 0) - return -1; - - i_assert(pos + size < ctx->index->mmap_size); - } - *base_r = PTR_OFFSET(ctx->index->mmap_base, pos); - memset(*base_r, 0, size); - } - - *base_offset_r = pos; - ctx->hdr.used_space = pos + size; - ctx->changed = TRUE; - return 0; -} - -static int -mailbox_list_index_sync_recreate_dir(struct mailbox_list_index_sync_ctx *ctx, - struct mailbox_list_sync_dir *sync_dir, - uint32_t offset_pos, bool partial) -{ - struct mailbox_list_index *index = ctx->index; - const struct mailbox_list_dir_record *dir; - const struct mailbox_list_record *recs; - struct mailbox_list_dir_record *new_dir; - struct mailbox_list_record *new_recs; - struct mailbox_list_sync_record *sync_recs; - unsigned int src, dest, orig, count, nondeleted_count; - unsigned int space_needed, deleted_space; - uint32_t base_offset, name_pos, size; - void *base; - - i_assert((offset_pos % sizeof(uint32_t)) == 0); - i_assert(offset_pos < index->mmap_size); - - /* count how much space we need and how much we wasted for deleted - records */ - nondeleted_count = 0; space_needed = 0; - sync_recs = array_get_modifiable(&sync_dir->records, &count); - for (src = 0; src < count; src++) { - if (sync_recs[src].seen || partial) { - nondeleted_count++; - if (sync_recs[src].created) { - /* new record */ - space_needed += strlen(sync_recs[src].name) + 1; - } - } - } - - /* @UNSAFE */ - space_needed += sizeof(*dir) + nondeleted_count * sizeof(*new_recs); - if (mailbox_list_index_sync_alloc_space(ctx, space_needed, - &base, &base_offset) < 0) - return -1; - /* NOTE: any pointers to the index file may have been invalidated - as a result of growing the the memory area */ - - if (sync_dir->offset == 0) { - dir = NULL; - recs = NULL; - deleted_space = 0; - } else { - /* the offset should have been verified already to be valid */ - i_assert(sync_dir->offset == offset_pos); - i_assert(sync_dir->offset < index->mmap_size); - dir = CONST_PTR_OFFSET(index->const_mmap_base, - sync_dir->offset); - recs = MAILBOX_LIST_RECORDS(dir); - - /* approximate deleted_space. some of the mailbox names will be - reused, but don't bother calculating them. */ - deleted_space = sizeof(*dir) + dir->dir_size; - } - - new_dir = base; - new_dir->count = nondeleted_count; - new_dir->dir_size = space_needed; - - new_recs = MAILBOX_LIST_RECORDS_MODIFIABLE(new_dir); - name_pos = (const char *)(new_recs + nondeleted_count) - - (const char *)base; - for (src = dest = 0; src < count;) { - if (!sync_recs[src].seen && !partial) { - /* expunge from mail index */ - uint32_t seq; - - if (mail_index_lookup_seq(ctx->mail_view, - sync_recs[src].uid, &seq)) - mail_index_expunge(ctx->trans, seq); - // FIXME: expunge also NONEXISTENT parents - - /* If we compress the file, the record must be removed - from the array. */ - array_delete(&sync_dir->records, src, 1); - sync_recs = array_get_modifiable(&sync_dir->records, - &count); - continue; - } - - new_recs[dest].name_hash = sync_recs[src].name_hash; - new_recs[dest].dir_offset = - mail_index_uint32_to_offset(sync_recs[src].dir_offset); - if (sync_recs[src].created) { - /* new record */ - new_recs[dest].uid = sync_recs[src].uid; - new_recs[dest].name_offset = base_offset + name_pos; - size = strlen(sync_recs[src].name) + 1; - memcpy(PTR_OFFSET(base, name_pos), sync_recs[src].name, - size); - name_pos += size; - } else { - /* existing record. need to find its name_offset */ - i_assert(dir != NULL); - for (orig = 0; orig < dir->count; orig++) { - if (recs[orig].uid == sync_recs[src].uid) - break; - } - i_assert(orig < dir->count); - - new_recs[dest].uid = sync_recs[src].uid; - new_recs[dest].name_offset = recs[orig].name_offset; - } - src++; dest++; - } - i_assert(dest == nondeleted_count); - i_assert(name_pos == space_needed); - - if (index->mmap_base == NULL) { - file_cache_write(index->file_cache, ctx->output_buf->data, - ctx->output_buf->used, ctx->output->offset); - o_stream_send(ctx->output, ctx->output_buf->data, - ctx->output_buf->used); - } - - if (offset_pos == 0) { - /* we're writing the root directory */ - i_assert(base_offset == sizeof(*index->hdr)); - } else { - /* add a link to this newly created directory. */ - uint32_t data = mail_index_uint32_to_offset(base_offset); - - if (index->mmap_base != NULL) { - uint32_t *pos; - - pos = PTR_OFFSET(index->mmap_base, offset_pos); - i_assert(mail_index_offset_to_uint32(*pos) == 0); - *pos = data; - } else { - uoff_t old_offset = ctx->output->offset; - - file_cache_write(index->file_cache, - &data, sizeof(data), offset_pos); - - o_stream_seek(ctx->output, offset_pos); - o_stream_send(ctx->output, &data, sizeof(data)); - o_stream_seek(ctx->output, old_offset); - } - } - - if (index->mmap_base == NULL) { - /* file_cache_write() calls may have moved mmaping */ - index->const_mmap_base = file_cache_get_map(index->file_cache, - &index->mmap_size); - index->hdr = index->const_mmap_base; - } - - ctx->hdr.deleted_space += deleted_space; - ctx->changed = TRUE; - sync_dir->offset = base_offset; - return 0; -} - -static int -mailbox_list_index_sync_update_dir(struct mailbox_list_index_sync_ctx *ctx, - struct mailbox_list_sync_dir *sync_dir) -{ - const struct mailbox_list_dir_record *dir; - struct mailbox_list_record *recs; - const struct mailbox_list_sync_record *sync_recs; - unsigned int i, j, count; - uint32_t seq; - - i_assert(sync_dir->offset != 0); - - if (mailbox_list_index_get_dir(ctx->view, &sync_dir->offset, &dir) < 0) - return -1; - - sync_recs = array_get(&sync_dir->records, &count); - i_assert(count <= dir->count); - i_assert(sync_dir->seen_records_count < count); - - if (ctx->index->mmap_base != NULL) - recs = MAILBOX_LIST_RECORDS_MODIFIABLE(dir); - else { - /* @UNSAFE: copy the records into a temporary buffer that - we modify and then write back to disk */ - recs = t_new(struct mailbox_list_record, dir->count); - memcpy(recs, MAILBOX_LIST_RECORDS(dir), - sizeof(struct mailbox_list_record) * dir->count); - } - - /* records marked with deleted have been removed from sync_recs, so - we need to skip those */ - for (i = j = 0; i < count; ) { - while (recs[j].uid != sync_recs[i].uid) { - j++; - i_assert(j < dir->count); - } - - if (!sync_recs[i].seen) { - recs[j].deleted = TRUE; - - /* expunge from mail index */ - if (mail_index_lookup_seq(ctx->mail_view, - sync_recs[i].uid, &seq)) - mail_index_expunge(ctx->trans, seq); - - /* If we compress the file, the record must be removed - from the array. */ - array_delete(&sync_dir->records, i, 1); - sync_recs = array_get(&sync_dir->records, &count); - } else { - i++; - } - } - if (ctx->index->mmap_base == NULL) { - uoff_t offset, old_offset; - size_t size = sizeof(struct mailbox_list_record) * dir->count; - - offset = sync_dir->offset + - sizeof(struct mailbox_list_dir_record); - file_cache_write(ctx->index->file_cache, recs, size, offset); - - old_offset = ctx->output->offset; - o_stream_seek(ctx->output, offset); - o_stream_send(ctx->output, recs, size); - o_stream_seek(ctx->output, old_offset); - } - ctx->changed = TRUE; - return 0; -} - -static int -mailbox_list_index_sync_write_dir(struct mailbox_list_index_sync_ctx *ctx, - struct mailbox_list_sync_dir *sync_dir, - uint32_t offset_pos, bool partial) -{ - const struct mailbox_list_dir_record *dir; - const struct mailbox_list_record *recs; - const struct mailbox_list_sync_record *sync_recs; - uint32_t child_offset_pos; - unsigned int i, j, count; - int ret; - - if (!ctx->seen_sync_root && ctx->sync_root == sync_dir) { - i_assert(partial); - ctx->seen_sync_root = TRUE; - partial = (ctx->flags & MAILBOX_LIST_SYNC_FLAG_PARTIAL) != 0; - } - - if (sync_dir->offset != 0) { - /* point to latest dir entry's next_offset */ - offset_pos = sync_dir->offset + - offsetof(struct mailbox_list_dir_record, next_offset); - } - - if (sync_dir->new_records_count > 0) { - /* need to recreate the dir record */ - if (mailbox_list_index_sync_recreate_dir(ctx, sync_dir, - offset_pos, - partial) < 0) - return -1; - /* NOTE: index may have been remaped here */ - } else if (sync_dir->seen_records_count != - array_count(&sync_dir->records) && !partial) { - /* just mark the records deleted */ - T_BEGIN { - ret = mailbox_list_index_sync_update_dir(ctx, sync_dir); - } T_END; - if (ret < 0) - return -1; - } - - if (!partial && (ctx->flags & MAILBOX_LIST_SYNC_FLAG_RECURSIVE) == 0) { - /* we're doing a full sync only for the root */ - partial = TRUE; - } - - /* update child mailboxes */ - sync_recs = array_get(&sync_dir->records, &count); - if (count == 0) - return 0; - - i_assert(sync_dir->offset != 0 && - sync_dir->offset < ctx->index->mmap_size); - for (i = j = 0; i < count; i++) { - if (sync_recs[i].dir == NULL) - continue; - - /* these may change after each sync_write_dir() call */ - dir = CONST_PTR_OFFSET(ctx->index->const_mmap_base, - sync_dir->offset); - recs = MAILBOX_LIST_RECORDS(dir); - - /* child_offset_pos needs to point to record's dir_offset */ - for (; j < dir->count; j++) { - if (recs[j].uid == sync_recs[i].uid) - break; - } - i_assert(j < dir->count); - - child_offset_pos = (const char *)&recs[j].dir_offset - - (const char *)ctx->index->const_mmap_base; - if (mailbox_list_index_sync_write_dir(ctx, sync_recs[i].dir, - child_offset_pos, - partial) < 0) - return -1; - } - return 0; -} - -static int -mailbox_list_index_sync_write(struct mailbox_list_index_sync_ctx *ctx) -{ - struct mailbox_list_index_header *hdr; - bool partial; - int ret = 0; - - if (ctx->index->mmap_base == NULL) { - ctx->output = o_stream_create_fd_file(ctx->index->fd, 0, FALSE); - ctx->output_buf = buffer_create_dynamic(default_pool, 4096); - o_stream_seek(ctx->output, ctx->hdr.used_space); - } - - if (ctx->sync_root == ctx->root) { - ctx->seen_sync_root = TRUE; - partial = (ctx->flags & MAILBOX_LIST_SYNC_FLAG_PARTIAL) != 0; - } else { - /* until we've seen the sync root, we're doing only partial - syncing */ - partial = TRUE; - } - - if (mailbox_list_index_sync_write_dir(ctx, ctx->root, 0, partial) < 0) - ret = -1; - - if (!ctx->changed) { - /* nothing written */ - } else if (ctx->index->mmap_base != NULL) { - /* update header */ - hdr = ctx->index->mmap_base; - if (ret == 0) - memcpy(hdr, &ctx->hdr, sizeof(*hdr)); - - if (msync(ctx->index->mmap_base, - hdr->used_space, MS_SYNC) < 0) { - mailbox_list_index_set_syscall_error(ctx->index, - "msync()"); - ret = -1; - } - } else { - if (ret == 0) { - o_stream_seek(ctx->output, 0); - o_stream_send(ctx->output, &ctx->hdr, sizeof(ctx->hdr)); - } - - if (o_stream_flush(ctx->output) < 0) { - mailbox_list_index_set_syscall_error(ctx->index, - "o_stream_flush()"); - ret = -1; - } - if (ret == 0 && - ctx->index->mail_index->fsync_mode == FSYNC_MODE_ALWAYS && - fdatasync(ctx->index->fd) < 0) { - mailbox_list_index_set_syscall_error(ctx->index, - "fdatasync()"); - ret = -1; - } - } - if (ctx->index->mmap_base == NULL) { - o_stream_destroy(&ctx->output); - buffer_free(&ctx->output_buf); - } - return ret; -} - -int mailbox_list_index_sync_commit(struct mailbox_list_index_sync_ctx **_ctx) -{ - struct mailbox_list_index_sync_ctx *ctx = *_ctx; - int ret = ctx->failed ? -1 : 0; - - *_ctx = NULL; - - if (!ctx->failed) { - /* write all the changes to the index */ - ret = mailbox_list_index_sync_write(ctx); - if (ret == 0 && mailbox_list_index_need_compress(ctx->index)) - ret = mailbox_list_index_compress(ctx); - } - - if (ctx->mail_sync_ctx != NULL) { - if (ret < 0 && !ctx->restart) - mail_index_sync_rollback(&ctx->mail_sync_ctx); - else { - if (ctx->restart) - mail_index_reset(ctx->trans); - if (mail_index_sync_commit(&ctx->mail_sync_ctx) < 0) - ret = -1; - } - } - - mailbox_list_index_view_deinit(&ctx->view); - pool_unref(&ctx->pool); - return ret; -} - -void mailbox_list_index_sync_rollback(struct mailbox_list_index_sync_ctx **ctx) -{ - (*ctx)->failed = TRUE; - (void)mailbox_list_index_sync_commit(ctx); -} - -static bool mailbox_list_index_need_compress(struct mailbox_list_index *index) -{ - uoff_t max_del_space; - - max_del_space = index->hdr->used_space / 100 * - MAILBOX_LIST_COMPRESS_PERCENTAGE; - if (index->hdr->deleted_space >= max_del_space && - index->hdr->used_space >= MAILBOX_LIST_COMPRESS_MIN_SIZE) - return TRUE; - - return FALSE; -} - -static int mailbox_list_copy_to_mem_all(struct mailbox_list_index_sync_ctx *ctx, - struct mailbox_list_sync_dir *dir) -{ - struct mailbox_list_sync_record *recs; - unsigned int i, count; - - /* mark the directories as new */ - dir->offset = 0; - dir->new_records_count = 1; - - recs = array_get_modifiable(&dir->records, &count); - for (i = 0; i < count; i++) { - recs[i].created = TRUE; - recs[i].seen = TRUE; - - if (recs[i].dir == NULL) { - if (recs[i].dir_offset == 0) - continue; - - if (mailbox_list_copy_sync_dir(ctx, recs[i].dir_offset, - &recs[i].dir) < 0) - return -1; - } - recs[i].dir_offset = 0; - - if (mailbox_list_copy_to_mem_all(ctx, recs[i].dir) < 0) - return -1; - } - return 0; -} - -static int mailbox_list_index_compress(struct mailbox_list_index_sync_ctx *ctx) -{ - /* first read everything to memory */ - if (mailbox_list_copy_to_mem_all(ctx, ctx->root) < 0) - return -1; - - /* truncate the index file */ - mailbox_list_index_file_close(ctx->index); - if (mailbox_list_index_file_create(ctx->index, - ctx->hdr.uid_validity) < 0) - return -1; - - /* reset header */ - ctx->hdr.file_seq++; - ctx->hdr.used_space = sizeof(ctx->hdr); - ctx->hdr.deleted_space = 0; - - /* and write everything back */ - return mailbox_list_index_sync_write(ctx); -}
--- a/src/lib-index/mailbox-list-index.c Tue Feb 08 01:35:45 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,770 +0,0 @@ -/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "crc32.h" -#include "ioloop.h" -#include "str.h" -#include "file-cache.h" -#include "file-dotlock.h" -#include "mmap-util.h" -#include "write-full.h" -#include "nfs-workarounds.h" -#include "mail-index-private.h" -#include "mailbox-list-index-private.h" - -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/stat.h> - -struct mailbox_list_iter_path { - const struct mailbox_list_dir_record *dir; - unsigned int pos; - unsigned int name_path_len; -}; - -struct mailbox_list_index_view { - struct mailbox_list_index *index; - struct mail_index_view *mail_view; -}; - -struct mailbox_list_iter_ctx { - struct mailbox_list_index_view *view; - unsigned int recurse_level; - uint32_t max_uid; - - struct mailbox_list_iter_path cur; - ARRAY_DEFINE(path, struct mailbox_list_iter_path); - string_t *name_path; - - unsigned int failed:1; -}; - -static const struct dotlock_settings default_dotlock_set = { - .timeout = 60, - .stale_timeout = 30 -}; - -int mailbox_list_index_set_syscall_error(struct mailbox_list_index *index, - const char *function) -{ - i_error("%s failed with file %s: %m", function, index->filepath); - return -1; -} - -static void mailbox_list_index_unmap(struct mailbox_list_index *index) -{ - if (index->file_cache != NULL) - file_cache_invalidate(index->file_cache, 0, (uoff_t)-1); - - if (index->mmap_base != NULL) { - if (munmap(index->mmap_base, index->mmap_size) < 0) - mailbox_list_index_set_syscall_error(index, "munmap()"); - index->mmap_base = NULL; - } - index->const_mmap_base = NULL; - index->mmap_size = 0; - - index->hdr = NULL; -} - -void mailbox_list_index_file_close(struct mailbox_list_index *index) -{ - mailbox_list_index_unmap(index); - - if (index->file_cache != NULL) - file_cache_free(&index->file_cache); - if (index->fd != -1) { - if (close(index->fd) < 0) - mailbox_list_index_set_syscall_error(index, "close()"); - index->fd = -1; - } -} - -int mailbox_list_index_set_corrupted(struct mailbox_list_index *index, - const char *str) -{ - if (!index->mail_index->readonly) - (void)unlink(index->filepath); - mailbox_list_index_file_close(index); - - i_error("Corrupted mailbox list index file %s: %s", - index->filepath, str); - return -1; -} - -static int -mailbox_list_index_check_header(struct mailbox_list_index *index, - const struct mailbox_list_index_header *hdr) -{ - if (hdr->major_version != MAILBOX_LIST_INDEX_MAJOR_VERSION) - return -1; - - if (hdr->header_size < sizeof(*hdr)) { - return mailbox_list_index_set_corrupted(index, - "header_size is too small"); - } - if (hdr->header_size > index->mmap_size) { - return mailbox_list_index_set_corrupted(index, - "header_size is too large"); - } - - if (hdr->uid_validity == 0) { - return mailbox_list_index_set_corrupted(index, - "uid_validity is 0"); - } - if (hdr->next_uid == 0) - return mailbox_list_index_set_corrupted(index, "next_uid is 0"); - - if (index->mail_index->map == NULL) { - /* index already marked as corrupted */ - return -1; - } - return 0; -} - -int mailbox_list_index_map(struct mailbox_list_index *index) -{ - const struct mailbox_list_index_header *hdr; - struct stat st; - ssize_t ret; - - mailbox_list_index_unmap(index); - - if (!index->mmap_disable) { - if (fstat(index->fd, &st) < 0) { - mailbox_list_index_set_syscall_error(index, "fstat()"); - return -1; - } - } - - if (!index->mmap_disable && - st.st_size >= MAILBOX_LIST_INDEX_MMAP_MIN_SIZE) { - index->mmap_size = st.st_size; - index->mmap_base = mmap(NULL, index->mmap_size, - PROT_READ | PROT_WRITE, - MAP_SHARED, index->fd, 0); - if (index->mmap_base == MAP_FAILED) { - index->mmap_base = NULL; - mailbox_list_index_set_syscall_error(index, "mmap()"); - return -1; - } - - index->const_mmap_base = index->mmap_base; - } else { - if (index->file_cache == NULL) - index->file_cache = file_cache_new(index->fd); - - ret = file_cache_read(index->file_cache, 0, SSIZE_T_MAX); - if (ret < 0) { - mailbox_list_index_set_syscall_error(index, - "file_cache_read()"); - return -1; - } - index->const_mmap_base = file_cache_get_map(index->file_cache, - &index->mmap_size); - } - - if (index->mmap_size < sizeof(*hdr)) { - mailbox_list_index_set_corrupted(index, "File too small"); - index->const_mmap_base = NULL; - return 0; - } - - hdr = index->const_mmap_base; - if (mailbox_list_index_check_header(index, hdr) < 0) { - index->const_mmap_base = NULL; - return 0; - } - - index->hdr = hdr; - return 1; -} - -static int mailbox_list_index_map_area(struct mailbox_list_index *index, - uoff_t offset, size_t size) -{ - if (offset < index->mmap_size && size <= index->mmap_size - offset) - return 1; - - if (mailbox_list_index_map(index) <= 0) - return -1; - - if (offset < index->mmap_size && size <= index->mmap_size - offset) - return 1; - /* outside the file */ - return 0; -} - -static void -mailbox_list_index_init_header(struct mailbox_list_index *index, - struct mailbox_list_index_header *hdr, - uint32_t uid_validity) -{ - memset(hdr, 0, sizeof(*hdr)); - hdr->major_version = MAILBOX_LIST_INDEX_MAJOR_VERSION; - hdr->minor_version = MAILBOX_LIST_INDEX_MINOR_VERSION; - - hdr->file_seq = index->hdr == NULL ? 1 : index->hdr->file_seq + 1; - hdr->header_size = sizeof(*hdr); - hdr->used_space = hdr->header_size; - - hdr->uid_validity = uid_validity; - hdr->next_uid = 1; -} - -static int mailbox_list_index_is_recreated(struct mailbox_list_index *index) -{ - struct stat st1, st2; - - if (index->fd == -1) - return 1; - - if ((index->mail_index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0) - nfs_flush_file_handle_cache(index->filepath); - - if (nfs_safe_stat(index->filepath, &st1) < 0) { - if (errno == ENOENT || errno == ESTALE) - return 1; - - mailbox_list_index_set_syscall_error(index, "stat()"); - return -1; - } - if (fstat(index->fd, &st2) < 0) { - if (errno == ESTALE) - return 1; - mailbox_list_index_set_syscall_error(index, "fstat()"); - return -1; - } - - return st1.st_ino != st2.st_ino || - !CMP_DEV_T(st1.st_dev, st2.st_dev); -} - -int mailbox_list_index_file_create(struct mailbox_list_index *index, - uint32_t uid_validity) -{ - struct mailbox_list_index_header hdr; - struct dotlock *dotlock; - int fd, ret; - - fd = file_dotlock_open(&index->dotlock_set, index->filepath, - 0, &dotlock); - if (fd == -1) { - mailbox_list_index_set_syscall_error(index, - "file_dotlock_open()"); - return -1; - } - - if (index->fd != -1) { - /* if the file has been recreated by someone else, - retry opening it */ - ret = mailbox_list_index_is_recreated(index); - if (ret != 0) { - (void)file_dotlock_delete(&dotlock); - return ret < 0 ? -1 : 0; - } - } - - mailbox_list_index_init_header(index, &hdr, uid_validity); - if (write_full(fd, &hdr, sizeof(hdr)) < 0) { - mailbox_list_index_set_syscall_error(index, "write_full()"); - (void)file_dotlock_delete(&dotlock); - return -1; - } - - if (index->mail_index->fsync_mode == FSYNC_MODE_ALWAYS && - fdatasync(fd) < 0) { - mailbox_list_index_set_syscall_error(index, "fdatasync()"); - (void)file_dotlock_delete(&dotlock); - return -1; - } - - if (file_dotlock_replace(&dotlock, - DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) < 0) { - mailbox_list_index_set_syscall_error(index, - "file_dotlock_replace()"); - (void)close(fd); - return -1; - } - - if (index->fd != -1) - mailbox_list_index_file_close(index); - index->fd = fd; - - ret = mailbox_list_index_map(index); - if (ret == 0) { - i_error("Self-created mailbox list index file %s was corrupted", - index->filepath); - return -1; - } - return ret; -} - -static int -mailbox_list_index_file_try_open_or_create(struct mailbox_list_index *index) -{ - int ret; - - i_assert(index->fd == -1); - - index->fd = open(index->filepath, O_RDWR); - if (index->fd == -1) { - if (errno != ENOENT) { - mailbox_list_index_set_syscall_error(index, "open()"); - return -1; - } - } else { - ret = mailbox_list_index_map(index); - if (ret != 0) { - if (ret < 0) - mailbox_list_index_file_close(index); - return ret; - } - } - - ret = mailbox_list_index_file_create(index, ioloop_time); - if (ret <= 0) - mailbox_list_index_file_close(index); - return ret; -} - -int mailbox_list_index_open_or_create(struct mailbox_list_index *index) -{ - int ret; - - while ((ret = mailbox_list_index_file_try_open_or_create(index)) == 0) { - /* file was recreated by someone else, try reopening */ - } - return ret < 0 ? -1 : 0; -} - -struct mailbox_list_index * -mailbox_list_index_alloc(const char *path, char separator, - struct mail_index *mail_index) -{ - struct mailbox_list_index *index; - - index = i_new(struct mailbox_list_index, 1); - index->filepath = i_strdup(path); - index->separator = separator; - index->mail_index = mail_index; - index->fd = -1; - index->mmap_disable = - (mail_index->flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) != 0; - index->dotlock_set = default_dotlock_set; - index->dotlock_set.use_excl_lock = - (mail_index->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0; - index->dotlock_set.nfs_flush = - (mail_index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0; - return index; -} - -void mailbox_list_index_free(struct mailbox_list_index **_index) -{ - struct mailbox_list_index *index = *_index; - - *_index = NULL; - - mailbox_list_index_file_close(index); - i_free(index->filepath); - i_free(index); -} - -struct mailbox_list_index_lookup_key { - uint32_t name_hash; - - struct mailbox_list_index *index; - const char *name; - - bool *failed; -}; - -static int -mailbox_list_get_name(struct mailbox_list_index *index, pool_t pool, - const struct mailbox_list_record *rec, - const char **name_r) -{ - size_t max_len; - const char *name; - - if (rec->name_offset >= index->mmap_size) { - mailbox_list_index_set_corrupted(index, t_strdup_printf( - "record name_offset (%u) points outside file " - "(%"PRIuSIZE_T")", rec->name_offset, index->mmap_size)); - return -1; - } - max_len = index->mmap_size - rec->name_offset; - name = CONST_PTR_OFFSET(index->const_mmap_base, rec->name_offset); - /* get name length. don't bother checking if it's not NUL-terminated, - because practically it always is even if the file is corrupted. - just make sure we don't crash if it happens. */ - *name_r = p_strndup(pool, name, max_len); - if (*name_r == '\0') { - mailbox_list_index_set_corrupted(index, "Empty mailbox name"); - return -1; - } - return 0; -} - -int mailbox_list_index_get_dir(struct mailbox_list_index_view *view, - uint32_t *offset, - const struct mailbox_list_dir_record **dir_r) -{ - struct mailbox_list_index *index = view->index; - const struct mailbox_list_dir_record *dir; - uint32_t next_offset, cur_offset = *offset; - int ret; - - i_assert(index->mmap_size > 0); - - do { - ret = mailbox_list_index_map_area(index, cur_offset, - sizeof(*dir)); - if (ret <= 0) { - if (ret < 0) - return -1; - return mailbox_list_index_set_corrupted(index, - "dir_offset points outside file"); - } - if ((cur_offset % 4) != 0) { - return mailbox_list_index_set_corrupted(index, - "dir_offset not 32bit aligned"); - } - - dir = CONST_PTR_OFFSET(index->const_mmap_base, cur_offset); - next_offset = mail_index_offset_to_uint32(dir->next_offset); - if (next_offset != 0 && next_offset <= cur_offset) { - return mailbox_list_index_set_corrupted(index, - "next_offset points backwards"); - } - - if (dir->count > - index->mmap_size / sizeof(struct mailbox_list_record)) { - return mailbox_list_index_set_corrupted(index, - "dir count too large"); - } - if (dir->dir_size < sizeof(*dir) + - dir->count * sizeof(struct mailbox_list_record)) { - return mailbox_list_index_set_corrupted(index, - "dir_size is smaller than record count"); - } - cur_offset = next_offset; - } while (cur_offset != 0); - - cur_offset = (const char *)dir - (const char *)index->const_mmap_base; - ret = mailbox_list_index_map_area(index, cur_offset, dir->dir_size); - if (ret <= 0) { - if (ret < 0) - return -1; - return mailbox_list_index_set_corrupted(index, - "dir points outside file"); - } - - *offset = cur_offset; - *dir_r = dir; - return 0; -} - -static int mailbox_list_record_cmp(const void *_key, const void *_rec) -{ - const struct mailbox_list_index_lookup_key *key = _key; - const struct mailbox_list_record *rec = _rec; - int ret; - - if (key->name_hash < rec->name_hash) - return -1; - if (key->name_hash > rec->name_hash) - return 1; - - T_BEGIN { - const char *name; - - if (mailbox_list_get_name(key->index, unsafe_data_stack_pool, - rec, &name) < 0) { - *key->failed = TRUE; - ret = 0; - } else { - ret = strcmp(key->name, name); - } - } T_END; - return ret; -} - -int mailbox_list_index_dir_lookup_rec(struct mailbox_list_index *index, - const struct mailbox_list_dir_record *dir, - const char *name, - const struct mailbox_list_record **rec_r) -{ - const struct mailbox_list_record *rec; - struct mailbox_list_index_lookup_key key; - bool failed = FALSE; - - /* binary search the current hierarchy level name. the values are - sorted primarily by their hash value and secondarily by the actual - name */ - memset(&key, 0, sizeof(key)); - key.index = index; - key.name = name; - key.name_hash = crc32_str(name); - key.failed = &failed; - - rec = bsearch(&key, MAILBOX_LIST_RECORDS(dir), dir->count, sizeof(*rec), - mailbox_list_record_cmp); - if (failed) - return -1; - if (rec == NULL) - return 0; - - *rec_r = rec; - return 1; -} - -static int -mailbox_list_index_lookup_rec(struct mailbox_list_index_view *view, - uint32_t dir_offset, const char *name, - const struct mailbox_list_record **rec_r) -{ - struct mailbox_list_index *index = view->index; - const struct mailbox_list_dir_record *dir; - const char *p, *hier_name; - int ret; - - if (dir_offset == sizeof(*index->hdr) && - index->mmap_size <= sizeof(*index->hdr)) { - /* root doesn't exist in the file yet */ - return 0; - } - - if (mailbox_list_index_get_dir(view, &dir_offset, &dir) < 0) - return -1; - - p = strchr(name, index->separator); - hier_name = p == NULL ? name : t_strdup_until(name, p); - - ret = mailbox_list_index_dir_lookup_rec(index, dir, hier_name, rec_r); - if (ret <= 0) - return ret; - - if (p == NULL) { - /* found it */ - return 1; - } - - /* recurse to children */ - dir_offset = mail_index_offset_to_uint32((*rec_r)->dir_offset); - if (dir_offset == 0) - return 0; - - return mailbox_list_index_lookup_rec(view, dir_offset, p + 1, rec_r); -} - -int mailbox_list_index_refresh(struct mailbox_list_index *index) -{ - int ret; - - if ((ret = mailbox_list_index_is_recreated(index)) <= 0) { - if (ret < 0) - return -1; - - if (mailbox_list_index_map(index) < 0) - ret = -1; - return ret; - } - - mailbox_list_index_file_close(index); - return mailbox_list_index_open_or_create(index); -} - -int mailbox_list_index_view_init(struct mailbox_list_index *index, - struct mail_index_view *mail_view, - struct mailbox_list_index_view **view_r) -{ - struct mailbox_list_index_view *view; - const struct mail_index_header *mail_hdr; - - mail_hdr = mail_view != NULL ? mail_index_get_header(mail_view) : NULL; - if (mail_hdr != NULL && mail_hdr->uid_validity != 0 && - index->hdr != NULL && - mail_hdr->uid_validity != index->hdr->uid_validity) { - mail_index_set_error(index->mail_index, - "uid_validity mismatch in file %s: %u != %u", - index->filepath, index->hdr->uid_validity, - mail_hdr->uid_validity); - return -1; - } - - view = *view_r = i_new(struct mailbox_list_index_view, 1); - view->index = index; - view->mail_view = mail_view; - return 0; -} - -void mailbox_list_index_view_deinit(struct mailbox_list_index_view **_view) -{ - struct mailbox_list_index_view *view = *_view; - - *_view = NULL; - i_free(view); -} - -int mailbox_list_index_lookup(struct mailbox_list_index_view *view, - const char *name, uint32_t *uid_r) -{ - const struct mailbox_list_record *rec; - uint32_t offset = sizeof(*view->index->hdr); - int ret; - - ret = mailbox_list_index_lookup_rec(view, offset, name, &rec); - if (ret == 0) { - /* not found, see if it's found after a refresh */ - if ((ret = mailbox_list_index_refresh(view->index)) <= 0) - return ret; - - ret = mailbox_list_index_lookup_rec(view, offset, name, &rec); - } - - *uid_r = ret <= 0 ? 0 : rec->uid; - return ret; -} - -struct mailbox_list_iter_ctx * -mailbox_list_index_iterate_init(struct mailbox_list_index_view *view, - const char *path, int recurse_level) -{ - struct mailbox_list_iter_ctx *ctx; - const struct mail_index_header *mail_hdr; - const struct mailbox_list_record *rec; - uint32_t offset = sizeof(*view->index->hdr); - int ret; - - ctx = i_new(struct mailbox_list_iter_ctx, 1); - ctx->view = view; - ctx->recurse_level = recurse_level < 0 ? (unsigned int)-1 : - (unsigned int)recurse_level; - ctx->name_path = str_new(default_pool, 512); - - if (view->mail_view != NULL) { - mail_hdr = mail_index_get_header(view->mail_view); - ctx->max_uid = mail_hdr->next_uid - 1; - } else { - ctx->max_uid = (uint32_t)-1; - } - - if (mailbox_list_index_refresh(view->index) < 0) - ctx->failed = TRUE; - if (!ctx->failed && *path != '\0') { - ret = mailbox_list_index_lookup_rec(view, offset, path, &rec); - if (ret < 0) - ctx->failed = TRUE; - else { - offset = ret == 0 ? 0 : - mail_index_offset_to_uint32(rec->dir_offset); - } - } - - if (view->index->mmap_size <= sizeof(*view->index->hdr)) { - /* root doesn't exist */ - } else if (!ctx->failed && offset != 0) { - if (mailbox_list_index_get_dir(view, &offset, - &ctx->cur.dir) < 0) - ctx->failed = TRUE; - } - i_array_init(&ctx->path, I_MIN(ctx->recurse_level, 16)); - return ctx; -} - -int mailbox_list_index_iterate_next(struct mailbox_list_iter_ctx *ctx, - struct mailbox_list_index_info *info_r) -{ - const struct mailbox_list_iter_path *cur; - const struct mailbox_list_record *recs; - uint32_t dir_offset; - unsigned int count; - - if (ctx->failed) - return -1; - - if (ctx->cur.dir == NULL) { - /* no mailboxes */ - i_assert(array_count(&ctx->path) == 0); - return 0; - } - - for (;;) { - if (ctx->cur.pos == ctx->cur.dir->count) { - count = array_count(&ctx->path); - if (count == 0) { - /* we're done */ - return 0; - } - - /* go back to parent path */ - cur = array_idx(&ctx->path, count-1); - ctx->cur = *cur; - array_delete(&ctx->path, count-1, 1); - - ctx->cur.pos++; - } else { - recs = MAILBOX_LIST_RECORDS(ctx->cur.dir); - recs += ctx->cur.pos; - - if (!recs->deleted && recs->uid <= ctx->max_uid) - break; - - ctx->cur.pos++; - } - } - - T_BEGIN { - const char *name; - - if (mailbox_list_get_name(ctx->view->index, - unsafe_data_stack_pool, - recs, &name) < 0) - ctx->failed = TRUE; - else { - str_truncate(ctx->name_path, ctx->cur.name_path_len); - if (ctx->cur.name_path_len > 0) { - str_append_c(ctx->name_path, - ctx->view->index->separator); - } - str_append(ctx->name_path, name); - } - } T_END; - if (ctx->failed) - return -1; - - info_r->name = str_c(ctx->name_path); - info_r->uid = recs->uid; - - dir_offset = mail_index_offset_to_uint32(recs->dir_offset); - if (dir_offset != 0 && array_count(&ctx->path) < ctx->recurse_level) { - /* recurse into children */ - array_append(&ctx->path, &ctx->cur, 1); - - ctx->cur.name_path_len = str_len(ctx->name_path); - ctx->cur.pos = 0; - if (mailbox_list_index_get_dir(ctx->view, &dir_offset, - &ctx->cur.dir) < 0) { - ctx->failed = TRUE; - return -1; - } - recs = NULL; /* don't use anymore */ - } else { - ctx->cur.pos++; - } - info_r->has_children = dir_offset != 0; - return 1; -} - -void mailbox_list_index_iterate_deinit(struct mailbox_list_iter_ctx **_ctx) -{ - struct mailbox_list_iter_ctx *ctx = *_ctx; - - *_ctx = NULL; - array_free(&ctx->path); - str_free(&ctx->name_path); - i_free(ctx); -}
--- a/src/lib-index/mailbox-list-index.h Tue Feb 08 01:35:45 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -#ifndef MAILBOX_LIST_INDEX_H -#define MAILBOX_LIST_INDEX_H - -struct mailbox_list_index_view; -struct mailbox_list_index_sync_ctx; - -/* Mailbox list index contains UID <-> mailbox name mapping. It also takes in - a mail_index index which contains UID -> metadata information for the - mailboxes. The mmap, in-memory and lock settings are taken from the - mail_index. */ - -enum mailbox_list_index_flags { - /* Mailbox has children. They may not be indexed however, so - mailbox_list_index_info.has_children=FALSE is possible. */ - MAILBOX_LIST_INDEX_FLAG_CHILDREN = 0x01, - /* Mailbox has no children. mailbox_list_index_info.has_children - should be FALSE. */ - MAILBOX_LIST_INDEX_FLAG_NOCHILDREN = 0x02, - /* The mailbox isn't selectable (eg. a directory) */ - MAILBOX_LIST_INDEX_FLAG_NOSELECT = 0x04, - /* The mailbox doesn't exist at all. This is only a placeholder for - a child mailbox. When the children are deleted, this mailbox will - be automatically deleted as well. */ - MAILBOX_LIST_INDEX_FLAG_NONEXISTENT = 0x08 -}; - - -enum mailbox_list_sync_flags { - /* All the child mailboxes are also being synced */ - MAILBOX_LIST_SYNC_FLAG_RECURSIVE = 0x01, - /* New mailboxes may be added, but none are removed */ - MAILBOX_LIST_SYNC_FLAG_PARTIAL = 0x02 -}; - -struct mailbox_list_index_info { - const char *name; - uint32_t uid; - bool has_children; -}; - -struct mailbox_list_index * -mailbox_list_index_alloc(const char *path, char separator, - struct mail_index *mail_index); -void mailbox_list_index_free(struct mailbox_list_index **index); - -/* Open or create mailbox list index. */ -int mailbox_list_index_open_or_create(struct mailbox_list_index *index); - -/* Synchronize the index with the backend. */ -int mailbox_list_index_sync_init(struct mailbox_list_index *index, - const char *path, - enum mailbox_list_sync_flags flags, - struct mailbox_list_index_sync_ctx **ctx_r); -struct mail_index_view * -mailbox_list_index_sync_get_view(struct mailbox_list_index_sync_ctx *ctx); -struct mail_index_transaction * -mailbox_list_index_sync_get_transaction(struct mailbox_list_index_sync_ctx*ctx); -int mailbox_list_index_sync_more(struct mailbox_list_index_sync_ctx *ctx, - const char *name, uint32_t *seq_r); -int mailbox_list_index_sync_commit(struct mailbox_list_index_sync_ctx **ctx); -void mailbox_list_index_sync_rollback(struct mailbox_list_index_sync_ctx **ctx); - -/* Mailbox list index and mail index must be kept in sync, so lookups and - iterations must know the mail index view. The mail_view can be set to NULL - to use the latest changes. Returns -1 if uidvalidity doesn't match. */ -int mailbox_list_index_view_init(struct mailbox_list_index *index, - struct mail_index_view *mail_view, - struct mailbox_list_index_view **view_r); -void mailbox_list_index_view_deinit(struct mailbox_list_index_view **view); - -/* Get mailbox UID for a given name. Returns 1 if found, 0 if not, - -1 if error */ -int mailbox_list_index_lookup(struct mailbox_list_index_view *view, - const char *name, uint32_t *uid_r); - -/* Iterate through all the mailboxes. If recurse_level is -1, all the child - mailboxes are returned, otherwise it's the number of levels to return - (0 = only the mailboxes directly under the path). Returned mailbox names - are allocated from name_pool. */ -struct mailbox_list_iter_ctx * -mailbox_list_index_iterate_init(struct mailbox_list_index_view *view, - const char *path, int recurse_level); -/* Returns 1 if mailbox was returned, 0 at the end of iteration, -1 if error */ -int mailbox_list_index_iterate_next(struct mailbox_list_iter_ctx *ctx, - struct mailbox_list_index_info *info_r); -void mailbox_list_index_iterate_deinit(struct mailbox_list_iter_ctx **ctx); - -#endif
--- a/src/util/Makefile.am Tue Feb 08 01:35:45 2011 +0200 +++ b/src/util/Makefile.am Tue Feb 08 01:36:19 2011 +0200 @@ -6,7 +6,6 @@ script-login \ $(TCPWRAP_BIN) \ gdbhelper \ - listview \ maildirlock AM_CPPFLAGS = \ @@ -52,11 +51,6 @@ gdbhelper_SOURCES = \ gdbhelper.c -listview_LDADD = $(LIBDOVECOT) -listview_DEPENDENCIES = $(LIBDOVECOT_DEPS) -listview_SOURCES = \ - listview.c - maildirlock_LDADD = $(LIBDOVECOT) maildirlock_DEPENDENCIES = $(LIBDOVECOT_DEPS) maildirlock_SOURCES = \
--- a/src/util/listview.c Tue Feb 08 01:35:45 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* Copyright (c) 2007-2010 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "crc32.h" -#include "mail-index.h" -#include "mailbox-list-index-private.h" - -#include <stdio.h> -#include <stdlib.h> - -static struct mailbox_list_index_header hdr; - -static uint32_t mail_index_offset_to_uint32(uint32_t offset) -{ - const unsigned char *buf = (const unsigned char *) &offset; - - if ((offset & 0x80808080) != 0x80808080) - return 0; - - return (((uint32_t)buf[3] & 0x7f) << 2) | - (((uint32_t)buf[2] & 0x7f) << 9) | - (((uint32_t)buf[1] & 0x7f) << 16) | - (((uint32_t)buf[0] & 0x7f) << 23); -} - -static void dump_hdr(int fd) -{ - int ret; - - ret = read(fd, &hdr, sizeof(hdr)); - if (ret != sizeof(hdr)) { - i_fatal("file hdr read() %d != %"PRIuSIZE_T"\n", - ret, sizeof(hdr)); - } - - printf("version = %u.%u\n", hdr.major_version, hdr.minor_version); - printf("header size = %u\n", hdr.header_size); - printf("uid validity = %u\n", hdr.uid_validity); - printf("file seq = %u\n", hdr.file_seq); - printf("next uid = %u\n", hdr.next_uid); - printf("used space = %u\n", hdr.used_space); - printf("deleted space = %u\n", hdr.deleted_space); -} - -static void dump_dir(int fd, unsigned int show_offset, const char *path) -{ - struct mailbox_list_dir_record dir; - struct mailbox_list_record rec; - off_t offset; - char name[1024]; - unsigned int i; - int ret; - - offset = lseek(fd, 0, SEEK_CUR); - ret = read(fd, &dir, sizeof(dir)); - if (ret == 0) { - if (*path != '\0') - i_fatal("unexpected EOF when reading dir"); - return; - } - - if (ret != sizeof(dir)) - i_fatal("dir read() %d != %"PRIuSIZE_T, ret, sizeof(dir)); - - dir.next_offset = mail_index_offset_to_uint32(dir.next_offset); - printf("%s: DIR: offset=%"PRIuUOFF_T" next_offset=%u count=%u dir_size=%u\n", - path, offset, dir.next_offset, dir.count, dir.dir_size); - - if (dir.next_offset != 0 && dir.next_offset != show_offset) { - lseek(fd, dir.next_offset, SEEK_SET); - dump_dir(fd, show_offset, path); - return; - } - - offset += sizeof(dir); - for (i = 0; i < dir.count; i++) { - lseek(fd, offset, SEEK_SET); - ret = read(fd, &rec, sizeof(rec)); - if (ret == 0) - i_fatal("unexpected EOF, %d/%d records", i, dir.count); - - if (ret != sizeof(rec)) { - i_fatal("rec read() %d != %"PRIuSIZE_T, - ret, sizeof(rec)); - } - rec.dir_offset = mail_index_offset_to_uint32(rec.dir_offset); - - ret = pread(fd, name, sizeof(name)-1, rec.name_offset); - name[ret < 0 ? 0 : ret] = '\0'; - - printf("%s%s: offset=%"PRIuUOFF_T" uid=%u " - "name_offset=%u name_hash=%u", path, name, offset, - rec.uid, rec.name_offset, rec.name_hash); - - if (rec.deleted != 0) - printf(" deleted=%u", rec.deleted); - if (rec.dir_offset != 0) - printf(" dir_offset=%u", rec.dir_offset); - printf("\n"); - - if (ret <= 0) - printf("%s%s: - invalid name_offset", path, name); - else if (strlen(name) == (size_t)ret) { - printf("%s%s: - name missing NUL terminator", - path, name); - } - - if (crc32_str(name) != rec.name_hash) { - printf("%s%s: - invalid name hash %u vs %u\n", - path, name, crc32_str(name), rec.name_hash); - } - - if (rec.dir_offset != 0) T_BEGIN { - const char *new_path; - - lseek(fd, rec.dir_offset, SEEK_SET); - if (*path == '\0') - new_path = t_strdup_printf("%s/", name); - else - new_path = t_strdup_printf("%s%s/", path, name); - dump_dir(fd, show_offset, new_path); - } T_END; - - offset += sizeof(rec); - } -} - -int main(int argc ATTR_UNUSED, const char *argv[]) -{ - int fd; - - lib_init(); - - fd = open(argv[1], O_RDONLY); - if (fd < 0) { - i_error("open(): %m"); - return 1; - } - - printf("-- LIST INDEX: %s\n", argv[1]); - - dump_hdr(fd); - lseek(fd, hdr.header_size, SEEK_SET); - - printf("---------------\n"); - - dump_dir(fd, argv[2] == NULL ? 0 : atoi(argv[2]), ""); - return 0; -}