dovecot-2.0: Moved some code from mail-index-map.c to mail-index...

dovecot at dovecot.org dovecot at dovecot.org
Thu May 21 00:32:22 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/e55de8b34144
changeset: 9332:e55de8b34144
user:      Timo Sirainen <tss at iki.fi>
date:      Wed May 20 17:28:53 2009 -0400
description:
Moved some code from mail-index-map.c to mail-index-map-read.c

diffstat:

3 files changed, 449 insertions(+), 442 deletions(-)
src/lib-index/Makefile.am           |    1 
src/lib-index/mail-index-map-read.c |  448 +++++++++++++++++++++++++++++++++++
src/lib-index/mail-index-map.c      |  442 ----------------------------------

diffs (truncated from 932 to 300 lines):

diff -r 768b25cabd6c -r e55de8b34144 src/lib-index/Makefile.am
--- a/src/lib-index/Makefile.am	Wed May 20 15:39:39 2009 -0400
+++ b/src/lib-index/Makefile.am	Wed May 20 17:28:53 2009 -0400
@@ -19,6 +19,7 @@ libindex_la_SOURCES = \
         mail-index-lock.c \
         mail-index-map.c \
         mail-index-map-hdr.c \
+        mail-index-map-read.c \
         mail-index-modseq.c \
         mail-index-transaction.c \
         mail-index-transaction-export.c \
diff -r 768b25cabd6c -r e55de8b34144 src/lib-index/mail-index-map-read.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-index/mail-index-map-read.c	Wed May 20 17:28:53 2009 -0400
@@ -0,0 +1,448 @@
+/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */
+
+#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"
+#include "mail-transaction-log-private.h"
+
+static void mail_index_map_copy_hdr(struct mail_index_map *map,
+				    const struct mail_index_header *hdr)
+{
+	if (hdr->base_header_size < sizeof(map->hdr)) {
+		/* header smaller than ours, make a copy so our newer headers
+		   won't have garbage in them */
+		memset(&map->hdr, 0, sizeof(map->hdr));
+		memcpy(&map->hdr, hdr, hdr->base_header_size);
+	} else {
+		map->hdr = *hdr;
+	}
+
+	/* FIXME: backwards compatibility, remove later. In case this index is
+	   accessed with Dovecot v1.0, avoid recent message counter errors. */
+	map->hdr.unused_old_recent_messages_count = 0;
+}
+
+static int mail_index_mmap(struct mail_index_map *map, uoff_t file_size)
+{
+	struct mail_index *index = map->index;
+	struct mail_index_record_map *rec_map = map->rec_map;
+	const struct mail_index_header *hdr;
+
+	i_assert(rec_map->mmap_base == NULL);
+
+	buffer_free(&rec_map->buffer);
+	if (file_size > SSIZE_T_MAX) {
+		/* too large file to map into memory */
+		mail_index_set_error(index, "Index file too large: %s",
+				     index->filepath);
+		return -1;
+	}
+
+	rec_map->mmap_base = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
+				  MAP_PRIVATE, index->fd, 0);
+	if (rec_map->mmap_base == MAP_FAILED) {
+		rec_map->mmap_base = NULL;
+		mail_index_set_syscall_error(index, "mmap()");
+		return -1;
+	}
+	rec_map->mmap_size = file_size;
+
+	hdr = rec_map->mmap_base;
+	if (rec_map->mmap_size >
+	    offsetof(struct mail_index_header, major_version) &&
+	    hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
+		/* major version change - handle silently */
+		return 0;
+	}
+
+	if (rec_map->mmap_size < MAIL_INDEX_HEADER_MIN_SIZE) {
+		mail_index_set_error(index, "Corrupted index file %s: "
+				     "File too small (%"PRIuSIZE_T")",
+				     index->filepath, rec_map->mmap_size);
+		return 0;
+	}
+
+	if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size)) {
+		/* Can't use this file */
+		return 0;
+	}
+
+	rec_map->mmap_used_size = hdr->header_size +
+		hdr->messages_count * hdr->record_size;
+
+	if (rec_map->mmap_used_size <= rec_map->mmap_size)
+		rec_map->records_count = hdr->messages_count;
+	else {
+		rec_map->records_count =
+			(rec_map->mmap_size - hdr->header_size) /
+			hdr->record_size;
+		rec_map->mmap_used_size = hdr->header_size +
+			rec_map->records_count * hdr->record_size;
+		mail_index_set_error(index, "Corrupted index file %s: "
+				     "messages_count too large (%u > %u)",
+				     index->filepath, hdr->messages_count,
+				     rec_map->records_count);
+	}
+
+	mail_index_map_copy_hdr(map, hdr);
+
+	map->hdr_base = rec_map->mmap_base;
+	rec_map->records = PTR_OFFSET(rec_map->mmap_base, map->hdr.header_size);
+	return 1;
+}
+
+static int mail_index_read_header(struct mail_index *index,
+				  void *buf, size_t buf_size, size_t *pos_r)
+{
+	size_t pos;
+	int ret;
+
+	memset(buf, 0, sizeof(struct mail_index_header));
+
+        /* try to read the whole header, but it's not necessarily an error to
+	   read less since the older versions of the index format could be
+	   smaller. Request reading up to buf_size, but accept if we only got
+	   the header. */
+        pos = 0;
+	do {
+		ret = pread(index->fd, PTR_OFFSET(buf, pos),
+			    buf_size - pos, pos);
+		if (ret > 0)
+			pos += ret;
+	} while (ret > 0 && pos < sizeof(struct mail_index_header));
+
+	*pos_r = pos;
+	return ret;
+}
+
+static int
+mail_index_try_read_map(struct mail_index_map *map,
+			uoff_t file_size, bool *retry_r, bool try_retry)
+{
+	struct mail_index *index = map->index;
+	const struct mail_index_header *hdr;
+	unsigned char read_buf[4096];
+	const void *buf;
+	void *data = NULL;
+	ssize_t ret;
+	size_t pos, records_size, initial_buf_pos = 0;
+	unsigned int records_count = 0, extra;
+
+	i_assert(map->rec_map->mmap_base == NULL);
+
+	*retry_r = FALSE;
+	ret = mail_index_read_header(index, read_buf, sizeof(read_buf), &pos);
+	buf = read_buf; hdr = buf;
+
+	if (pos > (ssize_t)offsetof(struct mail_index_header, major_version) &&
+	    hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
+		/* major version change - handle silently */
+		return 0;
+	}
+
+	if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
+	    (ret > 0 || pos >= hdr->base_header_size)) {
+		if (!mail_index_check_header_compat(index, hdr, file_size)) {
+			/* Can't use this file */
+			return 0;
+		}
+
+		initial_buf_pos = pos;
+		if (pos > hdr->header_size)
+			pos = hdr->header_size;
+
+		/* place the base header into memory. */
+		buffer_reset(map->hdr_copy_buf);
+		buffer_append(map->hdr_copy_buf, buf, pos);
+
+		if (pos != hdr->header_size) {
+			/* @UNSAFE: read the rest of the header into memory */
+			data = buffer_append_space_unsafe(map->hdr_copy_buf,
+							  hdr->header_size -
+							  pos);
+			ret = pread_full(index->fd, data,
+					 hdr->header_size - pos, pos);
+		}
+	}
+
+	if (ret > 0) {
+		/* header read, read the records now. */
+		records_size = (size_t)hdr->messages_count * hdr->record_size;
+		records_count = hdr->messages_count;
+
+		if (file_size - hdr->header_size < records_size ||
+		    (hdr->record_size != 0 &&
+		     records_size / hdr->record_size != hdr->messages_count)) {
+			records_count = (file_size - hdr->header_size) /
+				hdr->record_size;
+			records_size = (size_t)records_count * hdr->record_size;
+			mail_index_set_error(index, "Corrupted index file %s: "
+				"messages_count too large (%u > %u)",
+				index->filepath, hdr->messages_count,
+				records_count);
+		}
+
+		if (map->rec_map->buffer == NULL) {
+			map->rec_map->buffer =
+				buffer_create_dynamic(default_pool,
+						      records_size);
+		}
+
+		/* @UNSAFE */
+		buffer_set_used_size(map->rec_map->buffer, 0);
+		if (initial_buf_pos <= hdr->header_size)
+			extra = 0;
+		else {
+			extra = initial_buf_pos - hdr->header_size;
+			buffer_append(map->rec_map->buffer,
+				      CONST_PTR_OFFSET(buf, hdr->header_size),
+				      extra);
+		}
+		if (records_size > extra) {
+			data = buffer_append_space_unsafe(map->rec_map->buffer,
+							  records_size - extra);
+			ret = pread_full(index->fd, data, records_size - extra,
+					 hdr->header_size + extra);
+		}
+	}
+
+	if (ret < 0) {
+		if (errno == ESTALE && try_retry) {
+			/* a new index file was renamed over this one. */
+			*retry_r = TRUE;
+			return 0;
+		}
+		mail_index_set_syscall_error(index, "pread_full()");
+		return -1;
+	}
+	if (ret == 0) {
+		mail_index_set_error(index,
+			"Corrupted index file %s: File too small",
+			index->filepath);
+		return 0;
+	}
+
+	map->rec_map->records =
+		buffer_get_modifiable_data(map->rec_map->buffer, NULL);
+	map->rec_map->records_count = records_count;
+
+	mail_index_map_copy_hdr(map, hdr);
+	map->hdr_base = map->hdr_copy_buf->data;
+	return 1;
+}
+
+static int mail_index_read_map(struct mail_index_map *map, uoff_t file_size,
+			       unsigned int *lock_id)
+{
+	struct mail_index *index = map->index;
+	mail_index_sync_lost_handler_t *const *handlers;
+	struct stat st;
+	unsigned int i, count;
+	int ret;
+	bool try_retry, retry;
+
+	/* notify all "sync lost" handlers */
+	handlers = array_get(&index->sync_lost_handlers, &count);
+	for (i = 0; i < count; i++)
+		(*handlers[i])(index);
+
+	for (i = 0;; i++) {
+		try_retry = i < MAIL_INDEX_ESTALE_RETRY_COUNT;
+		if (file_size == (uoff_t)-1) {
+			/* fstat() below failed */
+			ret = 0;
+			retry = try_retry;
+		} else {
+			ret = mail_index_try_read_map(map, file_size,
+						      &retry, try_retry);
+		}
+		if (ret != 0 || !retry)
+			break;
+
+		/* ESTALE - reopen index file */
+		mail_index_close_file(index);
+		*lock_id = 0;
+
+                ret = mail_index_try_open_only(index);
+		if (ret <= 0) {
+			if (ret == 0) {
+				/* the file was lost */
+				errno = ENOENT;
+				mail_index_set_syscall_error(index, "open()");
+			}
+			return -1;
+		}
+		if (mail_index_lock_shared(index, lock_id) < 0)
+			return -1;
+
+		if (fstat(index->fd, &st) == 0)
+			file_size = st.st_size;
+		else {
+			if (errno != ESTALE) {


More information about the dovecot-cvs mailing list