[dovecot-cvs] dovecot/src/lib-storage/index/maildir maildir-copy.c,1.19,1.20 maildir-save.c,1.15,1.16 maildir-storage.c,1.23,1.24 maildir-storage.h,1.11,1.12

cras at procontrol.fi cras at procontrol.fi
Wed Jan 22 21:23:30 EET 2003


Update of /home/cvs/dovecot/src/lib-storage/index/maildir
In directory danu:/tmp/cvs-serv16040/src/lib-storage/index/maildir

Modified Files:
	maildir-copy.c maildir-save.c maildir-storage.c 
	maildir-storage.h 
Log Message:
Support for MULTIAPPEND extension. COPY now behaves like spec says - if it
fails, none of the messages are copied. maildir_copy_with_hardlinks didn't
actually work.



Index: maildir-copy.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-copy.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- maildir-copy.c	20 Jan 2003 14:52:51 -0000	1.19
+++ maildir-copy.c	22 Jan 2003 19:23:28 -0000	1.20
@@ -10,24 +10,38 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+struct rollback {
+	struct rollback *next;
+	const char *fname;
+};
+
 static int hardlink_messageset(struct messageset_context *ctx,
 			       struct index_mailbox *src,
 			       struct index_mailbox *dest)
 {
-        struct mail_index *index = src->index;
+	struct mail_index *index = src->index;
+	pool_t pool;
+        struct rollback *rollbacks, *rb;
         const struct messageset_mail *mail;
 	enum mail_flags flags;
 	const char **custom_flags;
-	const char *fname, *src_fname, *dest_fname;
+	const char *fname, *src_path, *dest_fname, *dest_path;
+	int ret;
+
+	pool = pool_alloconly_create("hard copy rollbacks", 2048);
+	rollbacks = NULL;
 
 	custom_flags = mail_custom_flags_list_get(index->custom_flags);
 
+	ret = 1;
 	while ((mail = index_messageset_next(ctx)) != NULL) {
 		flags = mail->rec->msg_flags;
 		if (!index_mailbox_fix_custom_flags(dest, &flags,
 						    custom_flags,
-						    MAIL_CUSTOM_FLAGS_COUNT))
-			return -1;
+						    MAIL_CUSTOM_FLAGS_COUNT)) {
+			ret = -1;
+			break;
+		}
 
 		/* link the file */
 		fname = index->lookup_field(index, mail->rec,
@@ -36,31 +50,50 @@
 			index_set_corrupted(index,
 				"Missing location field for record %u",
 				mail->rec->uid);
-			return -1;
+			ret = -1;
+			break;
 		}
 
 		t_push();
-		src_fname = t_strconcat(index->mailbox_path, "cur/",
-					fname, NULL);
-		dest_fname = t_strconcat(dest->index->mailbox_path, "new/",
-                	maildir_filename_set_flags(
+		src_path = t_strconcat(index->mailbox_path, "/cur/",
+				       fname, NULL);
+		dest_fname = t_strconcat(maildir_filename_set_flags(
 				maildir_generate_tmp_filename(), flags), NULL);
+		dest_path = t_strconcat(dest->index->mailbox_path, "/new/",
+					dest_fname, NULL);
 
-		if (link(src_fname, dest_fname) < 0) {
+		if (link(src_path, dest_path) == 0) {
+			rb = p_new(pool, struct rollback, 1);
+			rb->fname = p_strdup(pool, dest_fname);
+			rb->next = rollbacks;
+			rollbacks = rb;
+		} else {
 			if (errno != EXDEV) {
 				mail_storage_set_critical(src->box.storage,
 					"link(%s, %s) failed: %m",
-					src_fname, dest_fname);
+					src_path, dest_path);
 				t_pop();
-				return -1;
+				ret = -1;
+				break;
 			}
 			t_pop();
-			return 0;
+			ret = 0;
+			break;
 		}
 		t_pop();
 	}
 
-	return 1;
+	if (ret <= 0) {
+		for (rb = rollbacks; rb != NULL; rb = rb->next) {
+			t_push();
+			(void)unlink(t_strconcat(dest->index->mailbox_path,
+						 "new/", rb->fname, NULL));
+			t_pop();
+		}
+	}
+
+	pool_unref(pool);
+	return ret;
 }
 
 static int copy_with_hardlinks(struct index_mailbox *src,
@@ -68,15 +101,21 @@
 			       const char *messageset, int uidset)
 {
         struct messageset_context *ctx;
-	int ret;
+	int ret, ret2;
 
 	if (!index_storage_sync_and_lock(src, TRUE, MAIL_LOCK_SHARED))
 		return -1;
 
-	ctx = index_messageset_init(src, messageset, uidset);
+	ctx = index_messageset_init(src, messageset, uidset, FALSE);
 	ret = hardlink_messageset(ctx, src, dest);
-	if (index_messageset_deinit(ctx) < 0)
+	ret2 = index_messageset_deinit(ctx);
+	if (ret2 < 0)
 		ret = -1;
+	else {
+		mail_storage_set_error(src->box.storage,
+			"Some of the requested messages no longer exist.");
+		ret = -1;
+	}
 
 	(void)index_storage_lock(src, MAIL_LOCK_UNLOCK);
 

Index: maildir-save.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-save.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- maildir-save.c	20 Jan 2003 14:52:51 -0000	1.15
+++ maildir-save.c	22 Jan 2003 19:23:28 -0000	1.16
@@ -12,6 +12,21 @@
 #include <fcntl.h>
 #include <utime.h>
 
+struct mail_filename {
+	struct mail_filename *next;
+	const char *src, *dest;
+};
+
+struct mail_save_context {
+	pool_t pool;
+
+	struct index_mailbox *ibox;
+	int transaction;
+
+	const char *tmpdir, *newdir;
+	struct mail_filename *files;
+};
+
 const char *maildir_generate_tmp_filename(void)
 {
 	static unsigned int create_count = 0;
@@ -49,7 +64,7 @@
 
 static const char *
 maildir_read_into_tmp(struct mail_storage *storage, const char *dir,
-		      struct istream *input, uoff_t data_size)
+		      struct istream *input)
 {
 	const char *fname, *path;
 	struct ostream *output;
@@ -65,7 +80,7 @@
 	o_stream_set_blocking(output, 60000, NULL, NULL);
 
 	path = t_strconcat(dir, "/", fname, NULL);
-	if (!index_storage_save(storage, path, input, output, data_size))
+	if (!index_storage_save(storage, path, input, output))
 		fname = NULL;
 
 	o_stream_unref(output);
@@ -78,25 +93,48 @@
 	return fname;
 }
 
-int maildir_storage_save(struct mailbox *box,
-			 const struct mail_full_flags *flags,
-			 time_t internal_date,
-			 int timezone_offset __attr_unused__,
-			 struct istream *data, uoff_t data_size)
+static int maildir_copy(struct mail_save_context *ctx,
+			const char *src, const char *dest)
+{
+	const char *tmp_path, *new_path;
+
+	t_push();
+
+	tmp_path = t_strconcat(ctx->tmpdir, "/", src, NULL);
+	new_path = t_strconcat(ctx->newdir, "/", dest, NULL);
+
+	if (rename(tmp_path, new_path) == 0) {
+		t_pop();
+		return TRUE;
+	}
+
+	if (errno == ENOSPC) {
+		mail_storage_set_error(ctx->ibox->box.storage,
+				       "Not enough disk space");
+	} else {
+		mail_storage_set_critical(ctx->ibox->box.storage,
+					  "rename(%s, %s) failed: %m",
+					  tmp_path, new_path);
+	}
+
+	(void)unlink(tmp_path);
+	t_pop();
+	return FALSE;
+}
+
+int maildir_storage_save_next(struct mail_save_context *ctx,
+			      const struct mail_full_flags *flags,
+			      time_t received_date,
+			      int timezone_offset __attr_unused__,
+			      struct istream *data)
 {
-        struct index_mailbox *ibox = (struct index_mailbox *) box;
 	enum mail_flags mail_flags;
         struct utimbuf buf;
-	const char *tmpdir, *fname, *tmp_path, *new_path;
+	const char *fname, *dest_fname, *tmp_path;
 	int failed;
 
-	if (box->readonly) {
-		mail_storage_set_error(box->storage, "Mailbox is read-only");
-		return FALSE;
-	}
-
 	mail_flags = flags->flags;
-	if (!index_mailbox_fix_custom_flags(ibox, &mail_flags,
+	if (!index_mailbox_fix_custom_flags(ctx->ibox, &mail_flags,
 					    flags->custom_flags,
 					    flags->custom_flags_count))
 		return FALSE;
@@ -104,44 +142,100 @@
 	t_push();
 
 	/* create the file into tmp/ directory */
-	tmpdir = t_strconcat(ibox->index->mailbox_path, "/tmp", NULL);
-	fname = maildir_read_into_tmp(box->storage, tmpdir, data, data_size);
+	fname = maildir_read_into_tmp(ctx->ibox->box.storage,
+				      ctx->tmpdir, data);
 	if (fname == NULL) {
 		t_pop();
 		return FALSE;
 	}
-	tmp_path = t_strconcat(tmpdir, "/", fname, NULL);
 
-	fname = maildir_filename_set_flags(fname, mail_flags);
-	new_path = t_strconcat(ibox->index->mailbox_path, "/new/", fname, NULL);
+	tmp_path = t_strconcat(ctx->tmpdir, "/", fname, NULL);
 
-	/* set the internal_date by modifying mtime */
+	/* set the received_date by modifying mtime */
 	buf.actime = ioloop_time;
-	buf.modtime = internal_date;
+	buf.modtime = received_date;
 	if (utime(tmp_path, &buf) < 0) {
-		/* just warn, don't bother actually failing */
-		mail_storage_set_critical(box->storage, "utime() failed for "
-					  "%s: %m", tmp_path);
+		mail_storage_set_critical(ctx->ibox->box.storage,
+					  "utime() failed for %s: %m",
+					  tmp_path);
+		t_pop();
+		return FALSE;
 	}
 
-	/* move the file into new/ directory - syncing will pick it
-	   up from there */
-	if (rename(tmp_path, new_path) == 0)
+	/* now, if we want to be able to rollback the whole append session,
+	   we'll just store the name of this temp file and move it later
+	   into new/ */
+	dest_fname = maildir_filename_set_flags(fname, mail_flags);
+	if (ctx->transaction) {
+		struct mail_filename *mf;
+
+		mf = p_new(ctx->pool, struct mail_filename, 1);
+		mf->next = ctx->files;
+		mf->src = p_strdup(ctx->pool, fname);
+		mf->dest = p_strdup(ctx->pool, dest_fname);
+		ctx->files = mf;
+
 		failed = FALSE;
-	else {
-		if (errno == ENOSPC) {
-			mail_storage_set_error(box->storage,
-					       "Not enough disk space");
-		} else {
-			mail_storage_set_critical(box->storage,
-						  "rename(%s, %s) failed: %m",
-						  tmp_path, new_path);
+	} else {
+		failed = !maildir_copy(ctx, fname, dest_fname);
+	}
+
+	t_pop();
+	return !failed;
+}
+
+struct mail_save_context *
+maildir_storage_save_init(struct mailbox *box, int transaction)
+{
+	struct index_mailbox *ibox = (struct index_mailbox *) box;
+	struct mail_save_context *ctx;
+	pool_t pool;
+
+	if (box->readonly) {
+		mail_storage_set_error(box->storage, "Mailbox is read-only");
+		return NULL;
+	}
+
+	pool = pool_alloconly_create("mail_save_context", 2048);
+	ctx = p_new(pool, struct mail_save_context, 1);
+	ctx->pool = pool;
+	ctx->ibox = ibox;
+	ctx->transaction = transaction;
+
+	ctx->tmpdir = p_strconcat(pool, ibox->index->mailbox_path,
+				  "/tmp", NULL);
+	ctx->newdir = p_strconcat(pool, ibox->index->mailbox_path,
+				  "/new", NULL);
+
+	return ctx;
+}
+
+int maildir_storage_save_deinit(struct mail_save_context *ctx, int rollback)
+{
+	struct mail_filename *mf, *mf2;
+	const char *new_path;
+	int failed = FALSE;
+
+	if (!rollback) {
+		for (mf = ctx->files; mf != NULL; mf = mf->next) {
+			if (!maildir_copy(ctx, mf->src, mf->dest)) {
+				failed = TRUE;
+				break;
+			}
 		}
 
-		(void)unlink(tmp_path);
-		failed = TRUE;
+		if (failed) {
+			/* failed, try to unlink the mails already moved */
+			for (mf2 = ctx->files; mf2 != mf; mf2 = mf2->next) {
+				t_push();
+				new_path = t_strconcat(ctx->newdir, "/",
+						       mf2->dest, NULL);
+				(void)unlink(new_path);
+				t_pop();
+			}
+		}
 	}
 
-	t_pop();
+	pool_unref(ctx->pool);
 	return !failed;
 }

Index: maildir-storage.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- maildir-storage.c	20 Jan 2003 14:52:51 -0000	1.23
+++ maildir-storage.c	22 Jan 2003 19:23:28 -0000	1.24
@@ -569,7 +569,9 @@
 	index_storage_search_init,
 	index_storage_search_deinit,
 	index_storage_search_next,
-	maildir_storage_save,
+	maildir_storage_save_init,
+	maildir_storage_save_deinit,
+	maildir_storage_save_next,
 	mail_storage_is_inconsistency_error,
 
 	FALSE,

Index: maildir-storage.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- maildir-storage.h	20 Jan 2003 14:52:51 -0000	1.11
+++ maildir-storage.h	22 Jan 2003 19:23:28 -0000	1.12
@@ -5,10 +5,14 @@
 
 int maildir_storage_copy(struct mailbox *box, struct mailbox *destbox,
 			 const char *messageset, int uidset);
-int maildir_storage_save(struct mailbox *box,
-			 const struct mail_full_flags *flags,
-			 time_t internal_date, int timezone_offset,
-			 struct istream *data, uoff_t data_size);
+
+struct mail_save_context *
+maildir_storage_save_init(struct mailbox *box, int transaction);
+int maildir_storage_save_deinit(struct mail_save_context *ctx, int rollback);
+int maildir_storage_save_next(struct mail_save_context *ctx,
+			      const struct mail_full_flags *flags,
+			      time_t received_date, int timezone_offset,
+			      struct istream *data);
 
 int maildir_find_mailboxes(struct mail_storage *storage, const char *mask,
 			   mailbox_list_callback_t callback, void *context);




More information about the dovecot-cvs mailing list