dovecot-1.1: MAIL_INDEX_MAIL_FLAG_BACKEND specifies if file shou...

dovecot at dovecot.org dovecot at dovecot.org
Tue Mar 4 06:28:08 EET 2008


details:   http://hg.dovecot.org/dovecot-1.1/rev/9ef06104648a
changeset: 7331:9ef06104648a
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Mar 04 04:07:32 2008 +0200
description:
MAIL_INDEX_MAIL_FLAG_BACKEND specifies if file should be in alt dir or
primary dir. If the flag is changed, the file is moved.

diffstat:

6 files changed, 183 insertions(+), 15 deletions(-)
src/lib-storage/index/dbox/dbox-file.c      |  118 ++++++++++++++++++++++++++-
src/lib-storage/index/dbox/dbox-file.h      |    4 
src/lib-storage/index/dbox/dbox-storage.c   |   13 ++
src/lib-storage/index/dbox/dbox-storage.h   |    3 
src/lib-storage/index/dbox/dbox-sync-file.c |   33 ++++++-
src/lib-storage/index/dbox/dbox-sync.c      |   27 ++++--

diffs (truncated from 340 to 300 lines):

diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-file.c
--- a/src/lib-storage/index/dbox/dbox-file.c	Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-file.c	Tue Mar 04 04:07:32 2008 +0200
@@ -7,6 +7,8 @@
 #include "hostpid.h"
 #include "istream.h"
 #include "ostream.h"
+#include "mkdir-parents.h"
+#include "fdatasync-path.h"
 #include "write-full.h"
 #include "str.h"
 #include "dbox-storage.h"
@@ -375,6 +377,7 @@ static int dbox_file_open_fd(struct dbox
 static int dbox_file_open_fd(struct dbox_file *file)
 {
 	const char *path;
+	bool alt = FALSE;
 	int i;
 
 	/* try the primary path first */
@@ -398,7 +401,11 @@ static int dbox_file_open_fd(struct dbox
 		/* try the alternative path */
 		path = t_strdup_printf("%s/%s", file->mbox->alt_path,
 				       file->fname);
-	}
+		alt = TRUE;
+	}
+	i_free(file->current_path);
+	file->current_path = i_strdup(path);
+	file->alt_path = alt;
 	return 1;
 }
 
@@ -1015,7 +1022,7 @@ static int dbox_file_grow_metadata(struc
 	} else {
 		i_error("%s: Metadata changed unexpectedly",
 			dbox_file_get_path(file));
-		ret = 0;
+		ret = -1;
 	}
 
 	dbox_index_unlock_file(file->mbox->dbox_index, file->file_id);
@@ -1199,6 +1206,113 @@ bool dbox_file_lookup(struct dbox_mailbo
 	return TRUE;
 }
 
+int dbox_file_move(struct dbox_file *file, bool alt_path)
+{
+	struct ostream *output;
+	const char *dest_dir, *temp_path, *dest_path;
+	struct stat st;
+	bool deleted;
+	int out_fd, ret = 0;
+
+	i_assert(file->input != NULL);
+
+	if (file->alt_path == alt_path)
+		return 0;
+
+	if (stat(file->current_path, &st) < 0 && errno == ENOENT) {
+		/* already expunged by another session */
+		return 0;
+	}
+
+	dest_dir = alt_path ? file->mbox->alt_path : file->mbox->path;
+	temp_path = t_strdup_printf("%s/%s", dest_dir,
+				    dbox_generate_tmp_filename());
+
+	/* first copy the file. make sure to catch every possible error
+	   since we really don't want to break the file. */
+	out_fd = open(temp_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+	if (out_fd == -1 && errno == ENOENT) {
+		if (mkdir_parents(dest_dir, 0700) < 0) {
+			i_error("mkdir_parents(%s) failed: %m", dest_dir);
+			return -1;
+		}
+		out_fd = open(temp_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+	}
+	if (out_fd == -1) {
+		i_error("open(%s, O_CREAT) failed: %m", temp_path);
+		return -1;
+	}
+	output = o_stream_create_fd_file(out_fd, 0, FALSE);
+	i_stream_seek(file->input, 0);
+	while ((ret = o_stream_send_istream(output, file->input)) > 0) ;
+	if (ret == 0)
+		ret = o_stream_flush(output);
+	if (output->stream_errno != 0) {
+		errno = output->stream_errno;
+		i_error("write(%s) failed: %m", temp_path);
+		ret = -1;
+	} else if (file->input->stream_errno != 0) {
+		errno = file->input->stream_errno;
+		i_error("read(%s) failed: %m", file->current_path);
+		ret = -1;
+	} else if (ret < 0) {
+		i_error("o_stream_send_istream(%s, %s) "
+			"failed with unknown error",
+			temp_path, file->current_path);
+	}
+	o_stream_unref(&output);
+
+	if (!file->mbox->ibox.fsync_disable && ret == 0) {
+		if (fsync(out_fd) < 0) {
+			i_error("fsync(%s) failed: %m", temp_path);
+			ret = -1;
+		}
+	}
+	if (close(out_fd) < 0) {
+		i_error("close(%s) failed: %m", temp_path);
+		ret = -1;
+	}
+	if (ret < 0) {
+		(void)unlink(temp_path);
+		return -1;
+	}
+
+	/* the temp file was successfully written. rename it now to the
+	   destination file. the destination shouldn't exist, but if it does
+	   its contents should be the same (except for maybe older metadata) */
+	dest_path = t_strdup_printf("%s/%s", dest_dir, file->fname);
+	if (rename(temp_path, dest_path) < 0) {
+		i_error("rename(%s, %s) failed: %m", temp_path, dest_path);
+		(void)unlink(temp_path);
+		return -1;
+	}
+	if (!file->mbox->ibox.fsync_disable) {
+		if (fdatasync_path(dest_dir) < 0) {
+			i_error("fdatasync(%s) failed: %m", dest_dir);
+			(void)unlink(dest_path);
+			return -1;
+		}
+	}
+	if (unlink(file->current_path) < 0) {
+		i_error("unlink(%s) failed: %m", file->current_path);
+		if (errno == EACCES) {
+			/* configuration problem? revert the write */
+			(void)unlink(dest_path);
+		}
+		/* who knows what happened to the file. keep both just to be
+		   sure both won't get deleted. */
+		return -1;
+	}
+
+	/* file was successfully moved - reopen it */
+	dbox_file_close(file);
+	if (dbox_file_open(file, TRUE, &deleted) <= 0) {
+		i_error("dbox_file_move(%s): reopening file failed", dest_path);
+		return -1;
+	}
+	return 0;
+}
+
 void dbox_mail_metadata_flags_append(string_t *str, enum mail_flags flags)
 {
 	unsigned int i;
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-file.h
--- a/src/lib-storage/index/dbox/dbox-file.h	Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-file.h	Tue Mar 04 04:07:32 2008 +0200
@@ -128,6 +128,7 @@ struct dbox_file {
 	/* Includes the trailing LF that shouldn't be used */
 	unsigned int metadata_len;
 
+	unsigned int alt_path:1;
 	unsigned int maildir_file:1;
 	unsigned int nonappendable:1;
 	unsigned int deleted:1;
@@ -217,6 +218,9 @@ bool dbox_file_lookup(struct dbox_mailbo
 bool dbox_file_lookup(struct dbox_mailbox *mbox, struct mail_index_view *view,
 		      uint32_t seq, uint32_t *file_id_r, uoff_t *offset_r);
 
+/* Move the file to alt path or back. */
+int dbox_file_move(struct dbox_file *file, bool alt_path);
+
 /* Append flags as metadata value to given string */
 void dbox_mail_metadata_flags_append(string_t *str, enum mail_flags flags);
 /* Append keywords as metadata value to given string */
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-storage.c
--- a/src/lib-storage/index/dbox/dbox-storage.c	Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Tue Mar 04 04:07:32 2008 +0200
@@ -151,16 +151,21 @@ static const char *
 static const char *
 dbox_get_alt_path(struct dbox_storage *storage, const char *path)
 {
+	const char *root;
 	unsigned int len;
 
 	if (storage->alt_dir == NULL)
 		return NULL;
 
-	len = strlen(storage->alt_dir);
-	if (strncmp(path, storage->alt_dir, len) != 0)
-		return t_strconcat(storage->alt_dir, path + len, NULL);
-	else
+	root = mailbox_list_get_path(storage->storage.list, NULL,
+				     MAILBOX_LIST_PATH_TYPE_DIR);
+
+	len = strlen(root);
+	if (strncmp(path, root, len) != 0 && path[len] == '/') {
+		/* can't determine the alt path - shouldn't happen */
 		return NULL;
+	}
+	return t_strconcat(storage->alt_dir, path + len, NULL);
 }
 
 static struct mailbox *
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-storage.h
--- a/src/lib-storage/index/dbox/dbox-storage.h	Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.h	Tue Mar 04 04:07:32 2008 +0200
@@ -25,6 +25,9 @@
 #define DBOX_DEFAULT_ROTATE_MIN_SIZE (1024*16)
 #define DBOX_DEFAULT_ROTATE_DAYS 0
 #define DBOX_DEFAULT_MAX_OPEN_FILES 64
+
+/* Flag specifies if the message should be in primary or alternative storage */
+#define DBOX_INDEX_FLAG_ALT MAIL_INDEX_MAIL_FLAG_BACKEND
 
 struct dbox_index_header {
 	uint32_t last_dirty_flush_stamp;
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-sync-file.c
--- a/src/lib-storage/index/dbox/dbox-sync-file.c	Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-sync-file.c	Tue Mar 04 04:07:32 2008 +0200
@@ -324,9 +324,9 @@ dbox_sync_file_int(struct dbox_sync_cont
 		first_expunge_seq = (uint32_t)-1;
 	}
 
-	if (array_is_created(&entry->changes))
+	if (array_is_created(&entry->changes)) {
 		seqs = array_get(&entry->changes, &count);
-	else {
+	} else {
 		seqs = NULL;
 		count = 0;
 	}
@@ -344,6 +344,31 @@ dbox_sync_file_int(struct dbox_sync_cont
 	if (first_expunge_seq != (uint32_t)-1)
 		return dbox_sync_file_expunge(ctx, file, entry);
 	return 1;
+}
+
+static void
+dbox_sync_file_move_if_needed(struct dbox_sync_context *ctx,
+			      struct dbox_file *file,
+			      const struct dbox_sync_file_entry *entry)
+{
+	const struct seq_range *seq;
+	const struct mail_index_record *rec;
+	bool new_alt_path;
+
+	if (!array_is_created(&entry->changes))
+		return;
+
+	/* check if we want to move the file to alt path or back.
+	   FIXME: change this check somehow when a file may contain
+	   multiple messages. */
+	seq = array_idx(&entry->changes, 0);
+	rec = mail_index_lookup(ctx->sync_view, seq[0].seq1);
+	new_alt_path = (rec->flags & DBOX_INDEX_FLAG_ALT) != 0;
+	if (new_alt_path != file->alt_path) {
+		/* move the file. if it fails, nothing broke so
+		   don't worry about it. */
+		(void)dbox_file_move(file, new_alt_path);
+	}
 }
 
 static void
@@ -394,8 +419,10 @@ int dbox_sync_file(struct dbox_sync_cont
 		}
 	} else {
 		ret = dbox_file_open_or_create(file, TRUE, &deleted);
-		if (ret > 0 && !deleted)
+		if (ret > 0 && !deleted) {
+			dbox_sync_file_move_if_needed(ctx, file, entry);
 			ret = dbox_sync_file_int(ctx, file, entry, locked);
+		}
 	}
 	dbox_file_unref(&file);
 	return ret;
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-sync.c
--- a/src/lib-storage/index/dbox/dbox-sync.c	Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-sync.c	Tue Mar 04 04:07:32 2008 +0200
@@ -17,12 +17,13 @@
 #define DBOX_REBUILD_COUNT 3
 
 static int dbox_sync_add_seq(struct dbox_sync_context *ctx,
-			     enum mail_index_sync_type type, uint32_t seq)
+			     const struct mail_index_sync_rec *sync_rec,
+			     uint32_t seq)
 {
 	struct dbox_sync_file_entry *entry;
 	uint32_t file_id;
 	uoff_t offset;
-	bool uid_file;
+	bool uid_file, add;
 
 	if (!dbox_file_lookup(ctx->mbox, ctx->sync_view, seq,
 			      &file_id, &offset))
@@ -30,8 +31,22 @@ static int dbox_sync_add_seq(struct dbox
 
 	entry = hash_lookup(ctx->syncs, POINTER_CAST(file_id));


More information about the dovecot-cvs mailing list