[dovecot-cvs] dovecot: Moved mail index map related code to its own file.
dovecot at dovecot.org
dovecot at dovecot.org
Mon Jun 11 06:22:17 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/0d2a6a7f2a1b
changeset: 5686:0d2a6a7f2a1b
user: Timo Sirainen <tss at iki.fi>
date: Mon Jun 11 06:07:40 2007 +0300
description:
Moved mail index map related code to its own file.
diffstat:
4 files changed, 940 insertions(+), 929 deletions(-)
src/lib-index/Makefile.am | 1
src/lib-index/mail-index-map.c | 916 ++++++++++++++++++++++++++++++++++
src/lib-index/mail-index-private.h | 5
src/lib-index/mail-index.c | 947 ------------------------------------
diffs (truncated from 1942 to 300 lines):
diff -r d36a14c37c22 -r 0d2a6a7f2a1b src/lib-index/Makefile.am
--- a/src/lib-index/Makefile.am Mon Jun 11 05:06:46 2007 +0300
+++ b/src/lib-index/Makefile.am Mon Jun 11 06:07:40 2007 +0300
@@ -17,6 +17,7 @@ libindex_a_SOURCES = \
mail-index-dummy-view.c \
mail-index-fsck.c \
mail-index-lock.c \
+ mail-index-map.c \
mail-index-transaction.c \
mail-index-transaction-view.c \
mail-index-sync.c \
diff -r d36a14c37c22 -r 0d2a6a7f2a1b src/lib-index/mail-index-map.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-index/mail-index-map.c Mon Jun 11 06:07:40 2007 +0300
@@ -0,0 +1,916 @@
+/* Copyright (C) 2003-2007 Timo Sirainen */
+
+#include "lib.h"
+#include "array.h"
+#include "nfs-workarounds.h"
+#include "mmap-util.h"
+#include "read-full.h"
+#include "mail-index-private.h"
+#include "mail-index-sync-private.h"
+
+static void mail_index_map_init_extbufs(struct mail_index_map *map,
+ unsigned int initial_count)
+{
+#define EXTENSION_NAME_APPROX_LEN 20
+#define EXT_GLOBAL_ALLOC_SIZE \
+ ((sizeof(map->extensions) + BUFFER_APPROX_SIZE) * 2)
+#define EXT_PER_ALLOC_SIZE \
+ (EXTENSION_NAME_APPROX_LEN + \
+ sizeof(struct mail_index_ext) + sizeof(uint32_t))
+ size_t size;
+
+ if (map->extension_pool == NULL) {
+ size = EXT_GLOBAL_ALLOC_SIZE +
+ initial_count * EXT_PER_ALLOC_SIZE;
+ map->extension_pool =
+ pool_alloconly_create("map extensions",
+ nearest_power(size));
+ } else {
+ p_clear(map->extension_pool);
+
+ /* try to use the existing pool's size for initial_count so
+ we don't grow it unneededly */
+ size = p_get_max_easy_alloc_size(map->extension_pool);
+ if (size > EXT_GLOBAL_ALLOC_SIZE + EXT_PER_ALLOC_SIZE) {
+ initial_count = (size - EXT_GLOBAL_ALLOC_SIZE) /
+ EXT_PER_ALLOC_SIZE;
+ }
+ }
+
+ p_array_init(&map->extensions, map->extension_pool, initial_count);
+ p_array_init(&map->ext_id_map, map->extension_pool, initial_count);
+}
+
+uint32_t mail_index_map_lookup_ext(struct mail_index_map *map, const char *name)
+{
+ const struct mail_index_ext *extensions;
+ unsigned int i, size;
+
+ if (!array_is_created(&map->extensions))
+ return (uint32_t)-1;
+
+ extensions = array_get(&map->extensions, &size);
+ for (i = 0; i < size; i++) {
+ if (strcmp(extensions[i].name, name) == 0)
+ return i;
+ }
+ return (uint32_t)-1;
+}
+
+uint32_t
+mail_index_map_register_ext(struct mail_index *index,
+ struct mail_index_map *map, const char *name,
+ uint32_t hdr_offset, uint32_t hdr_size,
+ uint32_t record_offset, uint32_t record_size,
+ uint32_t record_align, uint32_t reset_id)
+{
+ struct mail_index_ext *ext;
+ uint32_t idx, empty_idx = (uint32_t)-1;
+
+ if (!array_is_created(&map->extensions)) {
+ mail_index_map_init_extbufs(map, 5);
+ idx = 0;
+ } else {
+ idx = array_count(&map->extensions);
+ }
+ i_assert(mail_index_map_lookup_ext(map, name) == (uint32_t)-1);
+
+ ext = array_append_space(&map->extensions);
+ ext->name = p_strdup(map->extension_pool, name);
+ ext->hdr_offset = hdr_offset;
+ ext->hdr_size = hdr_size;
+ ext->record_offset = record_offset;
+ ext->record_size = record_size;
+ ext->record_align = record_align;
+ ext->reset_id = reset_id;
+
+ ext->index_idx = mail_index_ext_register(index, name, hdr_size,
+ record_size, record_align);
+
+ /* Update index ext_id -> map ext_id mapping. Fill non-used
+ ext_ids with (uint32_t)-1 */
+ while (array_count(&map->ext_id_map) < ext->index_idx)
+ array_append(&map->ext_id_map, &empty_idx, 1);
+ array_idx_set(&map->ext_id_map, ext->index_idx, &idx);
+ return idx;
+}
+
+static bool size_check(size_t *size_left, size_t size)
+{
+ if (size > *size_left)
+ return FALSE;
+ *size_left -= size;
+ return TRUE;
+}
+
+static size_t get_align(size_t name_len)
+{
+ size_t size = sizeof(struct mail_index_ext_header) + name_len;
+ return MAIL_INDEX_HEADER_SIZE_ALIGN(size) - size;
+}
+
+static int mail_index_parse_extensions(struct mail_index *index,
+ struct mail_index_map *map)
+{
+ const struct mail_index_ext_header *ext_hdr;
+ unsigned int i, old_count;
+ const char *name;
+ uint32_t ext_id, offset, name_offset;
+ size_t size_left;
+
+ /* extension headers always start from 64bit offsets, so if base header
+ doesn't happen to be 64bit aligned we'll skip some bytes */
+ offset = MAIL_INDEX_HEADER_SIZE_ALIGN(map->hdr.base_header_size);
+ if (offset >= map->hdr.header_size && map->extension_pool == NULL) {
+ /* nothing to do, skip allocatations and all */
+ return 1;
+ }
+
+ old_count = array_count(&index->extensions);
+ mail_index_map_init_extbufs(map, old_count + 5);
+
+ ext_id = (uint32_t)-1;
+ for (i = 0; i < old_count; i++)
+ array_append(&map->ext_id_map, &ext_id, 1);
+
+ while (offset < map->hdr.header_size) {
+ ext_hdr = CONST_PTR_OFFSET(map->hdr_base, offset);
+
+ /* Extension header contains:
+ - struct mail_index_ext_header
+ - name (not 0-terminated)
+ - 64bit alignment padding
+ - extension header contents
+ - 64bit alignment padding
+ */
+ size_left = map->hdr.header_size - offset;
+ if (!size_check(&size_left, sizeof(*ext_hdr)) ||
+ !size_check(&size_left, ext_hdr->name_size) ||
+ !size_check(&size_left, get_align(ext_hdr->name_size)) ||
+ !size_check(&size_left, ext_hdr->hdr_size)) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "Header extension goes outside header",
+ index->filepath);
+ return -1;
+ }
+
+ offset += sizeof(*ext_hdr);
+ name_offset = offset;
+ offset += ext_hdr->name_size + get_align(ext_hdr->name_size);
+
+ t_push();
+ name = t_strndup(CONST_PTR_OFFSET(map->hdr_base, name_offset),
+ ext_hdr->name_size);
+
+ if (mail_index_map_lookup_ext(map, name) != (uint32_t)-1) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "Duplicate header extension %s",
+ index->filepath, name);
+ t_pop();
+ return -1;
+ }
+
+ if (map->hdr.record_size <
+ ext_hdr->record_offset + ext_hdr->record_size) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "Record field %s points outside record size "
+ "(%u < %u+%u)", index->filepath, name,
+ map->hdr.record_size,
+ ext_hdr->record_offset, ext_hdr->record_size);
+ t_pop();
+ return -1;
+ }
+
+ if ((ext_hdr->record_offset % ext_hdr->record_align) != 0 ||
+ (map->hdr.record_size % ext_hdr->record_align) != 0) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "Record field %s alignmentation %u not used",
+ index->filepath, name, ext_hdr->record_align);
+ t_pop();
+ return -1;
+ }
+ mail_index_map_register_ext(index, map, name,
+ offset, ext_hdr->hdr_size,
+ ext_hdr->record_offset,
+ ext_hdr->record_size,
+ ext_hdr->record_align,
+ ext_hdr->reset_id);
+ t_pop();
+
+ offset += MAIL_INDEX_HEADER_SIZE_ALIGN(ext_hdr->hdr_size);
+ }
+ return 1;
+}
+
+static bool mail_index_check_header_compat(const struct mail_index_header *hdr)
+{
+ enum mail_index_header_compat_flags compat_flags = 0;
+
+#ifndef WORDS_BIGENDIAN
+ compat_flags |= MAIL_INDEX_COMPAT_LITTLE_ENDIAN;
+#endif
+
+ if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
+ /* major version change - handle silently(?) */
+ return FALSE;
+ }
+ if (hdr->compat_flags != compat_flags) {
+ /* architecture change - handle silently(?) */
+ return FALSE;
+ }
+
+ if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
+ /* we've already complained about it */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int mail_index_check_header(struct mail_index *index,
+ struct mail_index_map *map)
+{
+ const struct mail_index_header *hdr = &map->hdr;
+
+ if (!mail_index_check_header_compat(hdr))
+ return -1;
+
+ /* following some extra checks that only take a bit of CPU */
+ if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "uid_validity = 0, next_uid = %u",
+ index->filepath, hdr->next_uid);
+ return -1;
+ }
+
+ if (hdr->record_size < sizeof(struct mail_index_record)) {
+ mail_index_set_error(index, "Corrupted index file %s: "
+ "record_size too small: %u < %"PRIuSIZE_T,
+ index->filepath, hdr->record_size,
+ sizeof(struct mail_index_record));
+ return -1;
+ }
+
+ if ((hdr->flags & MAIL_INDEX_HDR_FLAG_FSCK) != 0)
+ return 0;
+
+ if (hdr->next_uid == 0)
+ return 0;
+
+ if (hdr->recent_messages_count > hdr->messages_count ||
+ hdr->seen_messages_count > hdr->messages_count ||
+ hdr->deleted_messages_count > hdr->messages_count)
+ return 0;
+ if (hdr->first_recent_uid_lowwater > hdr->next_uid ||
+ hdr->first_unseen_uid_lowwater > hdr->next_uid ||
+ hdr->first_deleted_uid_lowwater > hdr->next_uid)
+ return 0;
+
+ if (map->records_count > 0) {
+ /* last message's UID must be smaller than next_uid.
+ also make sure it's not zero. */
+ const struct mail_index_record *rec;
+
+ rec = MAIL_INDEX_MAP_IDX(map, map->records_count-1);
+ if (rec->uid == 0 || rec->uid >= hdr->next_uid)
+ return 0;
+ }
+
+ return mail_index_parse_extensions(index, map);
+}
+
+static void mail_index_map_clear(struct mail_index *index,
+ struct mail_index_map *map)
+{
+ if (map->buffer != NULL) {
More information about the dovecot-cvs
mailing list