dovecot-2.1: mdbox: Make sure m.* files aren't overwritten when ...

dovecot at dovecot.org dovecot at dovecot.org
Fri Dec 9 16:26:49 EET 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/31825aab83f6
changeset: 13831:31825aab83f6
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Dec 09 16:26:39 2011 +0200
description:
mdbox: Make sure m.* files aren't overwritten when storage index isn't found.
This mainly helps to avoid situations where m.1 is replaced by mail delivery
when index directory has been (wrongly) changed.

diffstat:

 src/lib-storage/index/dbox-multi/mdbox-map-private.h |   2 +
 src/lib-storage/index/dbox-multi/mdbox-map.c         |  66 +++++++++++++++++--
 2 files changed, 61 insertions(+), 7 deletions(-)

diffs (138 lines):

diff -r ec3714f01ef2 -r 31825aab83f6 src/lib-storage/index/dbox-multi/mdbox-map-private.h
--- a/src/lib-storage/index/dbox-multi/mdbox-map-private.h	Thu Dec 08 18:56:48 2011 +0200
+++ b/src/lib-storage/index/dbox-multi/mdbox-map-private.h	Fri Dec 09 16:26:39 2011 +0200
@@ -23,6 +23,8 @@
 	mode_t create_mode;
 	gid_t create_gid;
 	const char *create_gid_origin;
+
+	unsigned int verify_existing_file_ids:1;
 };
 
 struct mdbox_map_append {
diff -r ec3714f01ef2 -r 31825aab83f6 src/lib-storage/index/dbox-multi/mdbox-map.c
--- a/src/lib-storage/index/dbox-multi/mdbox-map.c	Thu Dec 08 18:56:48 2011 +0200
+++ b/src/lib-storage/index/dbox-multi/mdbox-map.c	Fri Dec 09 16:26:39 2011 +0200
@@ -108,7 +108,7 @@
 	struct stat st;
 
 	if (stat(path, &st) == 0)
-		return 0;
+		return 1;
 
 	if (mailbox_list_mkdir(map->root_list, NULL, path) < 0) {
 		mail_storage_copy_list_error(MAP_STORAGE(map), map->root_list);
@@ -119,14 +119,16 @@
 
 static int mdbox_map_mkdir_storage(struct mdbox_map *map)
 {
-	if (mdbox_map_mkdir_storage_path(map, map->path) < 0)
+	int ret;
+
+	if ((ret = mdbox_map_mkdir_storage_path(map, map->path)) < 0)
 		return -1;
 
 	if (strcmp(map->path, map->index_path) != 0) {
 		if (mdbox_map_mkdir_storage_path(map, map->index_path) < 0)
 			return -1;
 	}
-	return 0;
+	return ret;
 }
 
 static void mdbox_map_cleanup(struct mdbox_map *map)
@@ -150,7 +152,7 @@
 static int mdbox_map_open_internal(struct mdbox_map *map, bool create_missing)
 {
 	enum mail_index_open_flags open_flags;
-	int ret;
+	int ret = 0;
 
 	if (map->view != NULL) {
 		/* already opened */
@@ -160,11 +162,24 @@
 	open_flags = MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY |
 		mail_storage_settings_to_index_flags(MAP_STORAGE(map)->set);
 	if (create_missing) {
-		open_flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
-		if (mdbox_map_mkdir_storage(map) < 0)
+		if ((ret = mdbox_map_mkdir_storage(map)) < 0)
 			return -1;
+		if (ret > 0) {
+			/* storage/ directory already existed.
+			   the index should exist also. */
+		} else {
+			open_flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
+		}
 	}
 	ret = mail_index_open(map->index, open_flags);
+	if (ret == 0 && create_missing) {
+		/* storage/ already existed, but indexes didn't. we'll need to
+		   take extra steps to make sure we won't overwrite any m.*
+		   files that may already exist. */
+		map->verify_existing_file_ids = TRUE;
+		open_flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
+		ret = mail_index_open(map->index, open_flags);
+	}
 	if (ret < 0) {
 		mail_storage_set_internal_error(MAP_STORAGE(map));
 		mail_index_reset_error(map->index);
@@ -1147,13 +1162,39 @@
 	array_delete(&ctx->appends, count-1, 1);
 }
 
+static int
+mdbox_find_highest_file_id(struct mdbox_map *map, uint32_t *file_id_r)
+{
+	const unsigned int prefix_len = strlen(MDBOX_MAIL_FILE_PREFIX);
+	DIR *dir;
+	struct dirent *d;
+	unsigned int id, highest_id = 0;
+
+	dir = opendir(map->path);
+	if (dir == NULL) {
+		i_error("opendir(%s) failed: %m", map->path);
+		return -1;
+	}
+	while ((d = readdir(dir)) != NULL) {
+		if (strncmp(d->d_name, MDBOX_MAIL_FILE_PREFIX, prefix_len) == 0 &&
+		    str_to_uint(d->d_name + prefix_len, &id) == 0) {
+			if (highest_id < id)
+				highest_id = id;
+		}
+	}
+	(void)closedir(dir);
+
+	*file_id_r = highest_id;
+	return 0;
+}
+
 static int mdbox_map_assign_file_ids(struct mdbox_map_append_context *ctx,
 				     bool separate_transaction)
 {
 	struct dbox_file_append_context *const *file_appends;
 	unsigned int i, count;
 	struct mdbox_map_mail_index_header hdr;
-	uint32_t first_file_id, file_id;
+	uint32_t first_file_id, file_id, existing_id;
 
 	/* start the syncing. we'll need it even if there are no file ids to
 	   be assigned. */
@@ -1163,6 +1204,17 @@
 	mdbox_map_get_ext_hdr(ctx->map, ctx->atomic->sync_view, &hdr);
 	file_id = hdr.highest_file_id + 1;
 
+	if (ctx->map->verify_existing_file_ids) {
+		/* storage/ directory had been already created but
+		   without indexes. scan to see if there exists a higher
+		   m.* file id than what is in header, so we won't
+		   accidentally overwrite any existing files. */
+		if (mdbox_find_highest_file_id(ctx->map, &existing_id) < 0)
+			return -1;
+		if (file_id < existing_id+1)
+			file_id = existing_id+1;
+	}
+
 	/* assign file_ids for newly created files */
 	first_file_id = file_id;
 	file_appends = array_get(&ctx->file_appends, &count);


More information about the dovecot-cvs mailing list