[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