dovecot: Support for reading maildir files. This makes it possib...

dovecot at dovecot.org dovecot at dovecot.org
Sun Oct 21 18:58:04 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/416d9ee66047
changeset: 6600:416d9ee66047
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Oct 21 18:58:00 2007 +0300
description:
Support for reading maildir files. This makes it possible to do a fast
maildir to dbox conversion by only renaming a few files.

diffstat:

10 files changed, 335 insertions(+), 37 deletions(-)
src/lib-storage/index/dbox/Makefile.am         |    1 
src/lib-storage/index/dbox/dbox-file-maildir.c |   85 ++++++++++++++++++
src/lib-storage/index/dbox/dbox-file-maildir.h |    7 +
src/lib-storage/index/dbox/dbox-file.c         |  108 +++++++++++++++++++-----
src/lib-storage/index/dbox/dbox-file.h         |    5 -
src/lib-storage/index/dbox/dbox-index.c        |   52 ++++++++++-
src/lib-storage/index/dbox/dbox-index.h        |    6 -
src/lib-storage/index/dbox/dbox-mail.c         |    6 -
src/lib-storage/index/dbox/dbox-storage.h      |    2 
src/lib-storage/index/dbox/dbox-sync-rebuild.c |  100 ++++++++++++++++++++--

diffs (truncated from 729 to 300 lines):

diff -r a6f51026b969 -r 416d9ee66047 src/lib-storage/index/dbox/Makefile.am
--- a/src/lib-storage/index/dbox/Makefile.am	Sun Oct 21 18:54:32 2007 +0300
+++ b/src/lib-storage/index/dbox/Makefile.am	Sun Oct 21 18:58:00 2007 +0300
@@ -10,6 +10,7 @@ AM_CPPFLAGS = \
 
 libstorage_dbox_a_SOURCES = \
 	dbox-file.c \
+	dbox-file-maildir.c \
 	dbox-index.c \
 	dbox-mail.c \
 	dbox-save.c \
diff -r a6f51026b969 -r 416d9ee66047 src/lib-storage/index/dbox/dbox-file-maildir.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/index/dbox/dbox-file-maildir.c	Sun Oct 21 18:58:00 2007 +0300
@@ -0,0 +1,85 @@
+/* Copyright (c) 2007-2007 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "dbox-storage.h"
+#include "../maildir/maildir-storage.h"
+#include "../maildir/maildir-filename.h"
+#include "dbox-file.h"
+#include "dbox-file-maildir.h"
+
+static const char *
+dbox_file_maildir_get_flags(struct dbox_file *file, enum dbox_metadata_key key)
+{
+	ARRAY_TYPE(keyword_indexes) keyword_indexes;
+	struct mail_keywords *keywords;
+	enum mail_flags flags;
+	string_t *str;
+	const char *fname;
+
+	if (file->mbox->maildir_sync_keywords == NULL)
+		return NULL;
+
+	fname = strrchr(file->path, '/');
+	i_assert(fname != NULL);
+	fname++;
+
+	t_array_init(&keyword_indexes, 32);
+	maildir_filename_get_flags(file->mbox->maildir_sync_keywords,
+				   fname, &flags, &keyword_indexes);
+	str = t_str_new(64);
+	if (key == DBOX_METADATA_FLAGS)
+		dbox_mail_metadata_flags_append(str, flags);
+	else {
+		keywords = mail_index_keywords_create_from_indexes(
+			file->mbox->ibox.index, &keyword_indexes);
+		dbox_mail_metadata_keywords_append(file->mbox, str, keywords);
+		mail_index_keywords_free(&keywords);
+	}
+	return str_c(str);
+}
+
+const char *dbox_file_maildir_metadata_get(struct dbox_file *file,
+					   enum dbox_metadata_key key)
+{
+	const char *fname;
+	struct stat st;
+	uoff_t size;
+
+	switch (key) {
+	case DBOX_METADATA_FLAGS:
+	case DBOX_METADATA_KEYWORDS:
+		return dbox_file_maildir_get_flags(file, key);
+	case DBOX_METADATA_RECEIVED_TIME:
+	case DBOX_METADATA_SAVE_TIME:
+		if (file->fd != -1) {
+			if (fstat(file->fd, &st) < 0) {
+				dbox_file_set_syscall_error(file, "fstat");
+				return NULL;
+			}
+		} else {
+			if (stat(file->path, &st) < 0) {
+				if (errno == ENOENT)
+					return NULL;
+				dbox_file_set_syscall_error(file, "stat");
+				return NULL;
+			}
+		}
+		if (key == DBOX_METADATA_RECEIVED_TIME)
+			return dec2str(st.st_mtime);
+		else
+			return dec2str(st.st_ctime);
+	case DBOX_METADATA_VIRTUAL_SIZE:
+		fname = strrchr(file->path, '/');
+		i_assert(fname != NULL);
+		maildir_filename_get_size(fname + 1, MAILDIR_EXTRA_VIRTUAL_SIZE,
+					  &size);
+		return dec2str(size);
+	case DBOX_METADATA_EXPUNGED:
+	case DBOX_METADATA_EXT_REF:
+	case DBOX_METADATA_SPACE:
+		break;
+	}
+	return NULL;
+}
diff -r a6f51026b969 -r 416d9ee66047 src/lib-storage/index/dbox/dbox-file-maildir.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/index/dbox/dbox-file-maildir.h	Sun Oct 21 18:58:00 2007 +0300
@@ -0,0 +1,7 @@
+#ifndef DBOX_FILE_MAILDIR_H
+#define DBOX_FILE_MAILDIR_H
+
+const char *dbox_file_maildir_metadata_get(struct dbox_file *file,
+					   enum dbox_metadata_key key);
+
+#endif
diff -r a6f51026b969 -r 416d9ee66047 src/lib-storage/index/dbox/dbox-file.c
--- a/src/lib-storage/index/dbox/dbox-file.c	Sun Oct 21 18:54:32 2007 +0300
+++ b/src/lib-storage/index/dbox/dbox-file.c	Sun Oct 21 18:58:00 2007 +0300
@@ -12,6 +12,7 @@
 #include "dbox-storage.h"
 #include "dbox-index.h"
 #include "dbox-file.h"
+#include "dbox-file-maildir.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -128,16 +129,29 @@ dbox_close_open_files(struct dbox_mailbo
 }
 
 static char *
-dbox_file_id_get_path(struct dbox_mailbox *mbox, unsigned int file_id)
-{
+dbox_file_id_get_path(struct dbox_mailbox *mbox, unsigned int file_id,
+		      bool *maildir_file_r)
+{
+	struct dbox_index_record *rec;
+	const char *p;
+
+	*maildir_file_r = FALSE;
 	if ((file_id & DBOX_FILE_ID_FLAG_UID) != 0) {
 		file_id &= ~DBOX_FILE_ID_FLAG_UID;
 		return i_strdup_printf("%s/"DBOX_MAIL_FILE_UID_FORMAT,
 				       mbox->path, file_id);
-	} else {
-		return i_strdup_printf("%s/"DBOX_MAIL_FILE_MULTI_FORMAT,
-				       mbox->path, file_id);
-	}
+	}
+
+	rec = dbox_index_record_lookup(mbox->dbox_index, file_id);
+	if (rec != NULL && rec->status == DBOX_INDEX_FILE_STATUS_MAILDIR) {
+		/* data contains <uid> <filename> */
+		*maildir_file_r = TRUE;
+		p = strchr(rec->data, ' ');
+		return i_strdup_printf("%s/%s", mbox->path, p + 1);
+	}
+
+	return i_strdup_printf("%s/"DBOX_MAIL_FILE_MULTI_FORMAT,
+			       mbox->path, file_id);
 }
 
 struct dbox_file *
@@ -145,6 +159,7 @@ dbox_file_init(struct dbox_mailbox *mbox
 {
 	struct dbox_file *file;
 	unsigned int count;
+	bool maildir;
 
 	file = file_id == 0 ? NULL :
 		dbox_find_and_move_open_file(mbox, file_id);
@@ -162,7 +177,8 @@ dbox_file_init(struct dbox_mailbox *mbox
 	file->mbox = mbox;
 	if (file_id != 0) {
 		file->file_id = file_id;
-		file->path = dbox_file_id_get_path(mbox, file_id);
+		file->path = dbox_file_id_get_path(mbox, file_id, &maildir);
+		file->maildir_file = maildir;
 	} else {
 		file->path = dbox_generate_tmp_filename(mbox->path);
 	}
@@ -173,23 +189,37 @@ dbox_file_init(struct dbox_mailbox *mbox
 	return file;
 }
 
+struct dbox_file *
+dbox_file_init_new_maildir(struct dbox_mailbox *mbox, const char *fname)
+{
+	struct dbox_file *file;
+
+	file = dbox_file_init(mbox, 0);
+	file->maildir_file = TRUE;
+	file->path = i_strdup_printf("%s/%s", mbox->path, fname);
+	return file;
+}
+
 int dbox_file_assign_id(struct dbox_file *file, unsigned int file_id)
 {
 	char *new_path;
+	bool maildir;
 
 	i_assert(file->file_id == 0);
 	i_assert(file_id != 0);
 
-	new_path = dbox_file_id_get_path(file->mbox, file_id);
-	if (rename(file->path, new_path) < 0) {
-		mail_storage_set_critical(file->mbox->ibox.box.storage,
-			"rename(%s, %s) failed: %m", file->path, new_path);
-		i_free(new_path);
-		return -1;
-	}
-
-	i_free(file->path);
-	file->path = new_path;
+	if (!file->maildir_file) {
+		new_path = dbox_file_id_get_path(file->mbox, file_id, &maildir);
+		if (rename(file->path, new_path) < 0) {
+			mail_storage_set_critical(file->mbox->ibox.box.storage,
+						  "rename(%s, %s) failed: %m",
+						  file->path, new_path);
+			i_free(new_path);
+			return -1;
+		}
+		i_free(file->path);
+		file->path = new_path;
+	}
 
 	file->file_id = file_id;
 	array_append(&file->mbox->open_files, &file, 1);
@@ -252,7 +282,7 @@ bool dbox_file_can_append(struct dbox_fi
 bool dbox_file_can_append(struct dbox_file *file, uoff_t mail_size)
 {
 	if (file->nonappendable)
-		return 0;
+		return FALSE;
 
 	if (file->append_offset == 0) {
 		/* messages have been expunged */
@@ -352,7 +382,8 @@ static int dbox_file_open(struct dbox_fi
 	}
 
 	file->input = i_stream_create_fd(file->fd, MAIL_READ_BLOCK_SIZE, FALSE);
-	return !read_header ? 1 : dbox_file_read_header(file);
+	return !read_header || file->maildir_file ? 1 :
+		dbox_file_read_header(file);
 }
 
 static int dbox_file_create(struct dbox_file *file)
@@ -406,6 +437,30 @@ int dbox_file_open_or_create(struct dbox
 		return dbox_file_open(file, read_header, deleted_r);
 }
 
+static int
+dbox_file_get_maildir_data(struct dbox_file *file, uint32_t *uid_r,
+			   uoff_t *physical_size_r)
+{
+	struct dbox_index_record *rec;
+	struct stat st;
+
+	if (fstat(file->fd, &st) < 0) {
+		dbox_file_set_syscall_error(file, "fstat");
+		return -1;
+	}
+
+	rec = dbox_index_record_lookup(file->mbox->dbox_index, file->file_id);
+	if (rec == NULL) {
+		/* should happen only when we're rebuilding the index */
+		*uid_r = 0;
+	} else {
+		i_assert(rec->status == DBOX_INDEX_FILE_STATUS_MAILDIR);
+		*uid_r = strtoul(rec->data, NULL, 10);
+	}
+	*physical_size_r = st.st_size;
+	return 1;
+}
+
 static int dbox_file_read_mail_header(struct dbox_file *file, uint32_t *uid_r,
 				      uoff_t *physical_size_r)
 {
@@ -413,6 +468,9 @@ static int dbox_file_read_mail_header(st
 	const unsigned char *data;
 	size_t size;
 	int ret;
+
+	if (file->maildir_file)
+		return dbox_file_get_maildir_data(file, uid_r, physical_size_r);
 
 	ret = i_stream_read_data(file->input, &data, &size,
 				 file->msg_header_size - 1);
@@ -627,6 +685,9 @@ uoff_t dbox_file_get_metadata_offset(str
 				     uoff_t physical_size)
 {
 	if (offset == 0) {
+		if (file->maildir_file)
+			return 0;
+
 		i_assert(file->file_header_size != 0);
 		offset = file->file_header_size;
 	}
@@ -683,6 +744,12 @@ int dbox_file_metadata_seek(struct dbox_
 	}
 	file->metadata_read_offset = 0;
 
+	if (file->maildir_file) {
+		/* no metadata in maildir files, but we do later some kludging


More information about the dovecot-cvs mailing list