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