changeset 1550:e1b2614c9e16 HEAD

Dirty maildir flags support works now.
author Timo Sirainen <tss@iki.fi>
date Sun, 15 Jun 2003 05:20:52 +0300
parents 3620bfe9cb05
children 313779bde3ec
files src/lib-index/mail-index-open.c src/lib-index/mail-index.h src/lib-index/maildir/maildir-expunge.c src/lib-index/maildir/maildir-index.h src/lib-index/maildir/maildir-sync.c src/lib-index/maildir/maildir-update-flags.c src/lib-storage/index/maildir/maildir-storage.c
diffstat 7 files changed, 112 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-index-open.c	Sun Jun 15 05:20:12 2003 +0300
+++ b/src/lib-index/mail-index-open.c	Sun Jun 15 05:20:52 2003 +0300
@@ -30,6 +30,9 @@
 	index->maildir_have_new =
 		(hdr->flags & MAIL_INDEX_FLAG_MAILDIR_NEW) != 0;
 
+	if ((hdr->flags & MAIL_INDEX_FLAG_DIRTY_MESSAGES) != 0)
+		index->next_dirty_flush = ioloop_time;
+
 	/* update \Recent message counters */
 	if ((flags & MAIL_INDEX_OPEN_FLAG_UPDATE_RECENT) != 0 &&
 	    hdr->last_nonrecent_uid != hdr->next_uid-1) {
--- a/src/lib-index/mail-index.h	Sun Jun 15 05:20:12 2003 +0300
+++ b/src/lib-index/mail-index.h	Sun Jun 15 05:20:52 2003 +0300
@@ -404,7 +404,7 @@
 
 	/* last maildir sync: */
 	time_t last_new_mtime, last_uidlist_mtime;
-	time_t maildir_cur_dirty;
+	time_t maildir_cur_dirty, next_dirty_flush;
 	int maildir_lock_fd;
 	pool_t new_filename_pool;
 	struct hash_table *new_filenames;
@@ -458,7 +458,7 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
-	0, 0, 0, 0
+	0, 0, 0, 0, 0
 #endif
 
 /* defaults - same as above but prefixed with mail_index_. */
--- a/src/lib-index/maildir/maildir-expunge.c	Sun Jun 15 05:20:12 2003 +0300
+++ b/src/lib-index/maildir/maildir-expunge.c	Sun Jun 15 05:20:52 2003 +0300
@@ -17,6 +17,12 @@
 	if (*fname == NULL)
 		return -1;
 
+	/* if we're in out-of-space condition, reset it since we'll probably
+	   have enough space now. */
+	index->maildir_keep_new = FALSE;
+	if (index->next_dirty_flush != 0)
+		index->next_dirty_flush = ioloop_time;
+
 	if ((rec->index_flags & INDEX_MAIL_FLAG_MAILDIR_NEW) != 0) {
 		/* probably in new/ dir */
 		path = t_strconcat(index->mailbox_path, "/new/", *fname, NULL);
--- a/src/lib-index/maildir/maildir-index.h	Sun Jun 15 05:20:12 2003 +0300
+++ b/src/lib-index/maildir/maildir-index.h	Sun Jun 15 05:20:52 2003 +0300
@@ -8,6 +8,9 @@
 /* ":2,DFRST" - leave the 2 extra for other clients' additions */
 #define MAILDIR_LOCATION_EXTRA_SPACE 10
 
+/* How often to try to flush dirty flags. */
+#define MAILDIR_DIRTY_FLUSH_TIMEOUT (60*5)
+
 struct mail_index *
 maildir_index_alloc(const char *maildir, const char *index_dir,
 		    const char *control_dir);
@@ -35,6 +38,7 @@
 int maildir_index_update_flags(struct mail_index *index,
 			       struct mail_index_record *rec, unsigned int seq,
 			       enum mail_flags flags, int external_change);
+int maildir_try_flush_dirty_flags(struct mail_index *index, int force);
 
 struct istream *maildir_open_mail(struct mail_index *index,
 				  struct mail_index_record *rec,
--- a/src/lib-index/maildir/maildir-sync.c	Sun Jun 15 05:20:12 2003 +0300
+++ b/src/lib-index/maildir/maildir-sync.c	Sun Jun 15 05:20:52 2003 +0300
@@ -1098,6 +1098,9 @@
 	struct stat st;
 	time_t new_mtime, cur_mtime;
 
+	if (!maildir_try_flush_dirty_flags(ctx->index, FALSE))
+		return FALSE;
+
 	if (index->fd != -1) {
 		/* FIXME: file_sync_stamp should be in index file's headers.
 		   it should also contain maildir_cur_dirty. */
--- a/src/lib-index/maildir/maildir-update-flags.c	Sun Jun 15 05:20:12 2003 +0300
+++ b/src/lib-index/maildir/maildir-update-flags.c	Sun Jun 15 05:20:52 2003 +0300
@@ -7,6 +7,66 @@
 
 #include <stdio.h>
 
+int maildir_try_flush_dirty_flags(struct mail_index *index, int force)
+{
+	struct mail_index_record *rec;
+	const char *old_fname, *old_path, *new_fname, *new_path;
+	int flag, dirty = FALSE;
+
+	if (index->next_dirty_flush == 0 ||
+	    (ioloop_time < index->next_dirty_flush && !force))
+		return TRUE;
+
+	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
+		return FALSE;
+
+	rec = index->lookup(index, 1);
+	while (rec != NULL) {
+		if ((rec->index_flags & INDEX_MAIL_FLAG_DIRTY) != 0) {
+			old_fname = maildir_get_location(index, rec);
+			if (old_fname == NULL)
+				return FALSE;
+
+			flag = (rec->index_flags &
+				INDEX_MAIL_FLAG_MAILDIR_NEW) != 0;
+			old_path = t_strconcat(index->mailbox_path,
+					       flag ? "/new/" : "/cur/",
+					       old_fname, NULL);
+
+			new_fname = maildir_filename_set_flags(old_fname,
+							       rec->msg_flags);
+			new_path = t_strconcat(index->mailbox_path,
+					       "/cur/", new_fname, NULL);
+
+			if (strcmp(old_path, new_path) == 0 ||
+			    rename(old_path, new_path) == 0)
+                                rec->index_flags &= ~INDEX_MAIL_FLAG_DIRTY;
+			else {
+				dirty = TRUE;
+				if (errno != ENOENT && errno != EACCES &&
+				    !ENOSPACE(errno)) {
+					index_set_error(index,
+						"rename(%s, %s) failed: %m",
+						old_path, new_path);
+					return FALSE;
+				}
+			}
+		}
+
+		rec = index->next(index, rec);
+	}
+
+	if (!dirty) {
+		index->header->flags &= ~MAIL_INDEX_FLAG_DIRTY_MESSAGES;
+		index->next_dirty_flush = 0;
+	} else {
+		index->next_dirty_flush =
+			ioloop_time + MAILDIR_DIRTY_FLUSH_TIMEOUT;
+	}
+
+	return TRUE;
+}
+
 static int handle_error(struct mail_index *index,
 			const char *path, const char *new_path)
 {
@@ -76,6 +136,8 @@
 					       "/cur/", new_fname, NULL);
 		}
 
+		ret = 0; break;
+
 		if (strcmp(old_fname, new_fname) == 0)
 			ret = 1;
 		else {
@@ -117,6 +179,10 @@
 		/* we couldn't actually rename() the file now.
 		   leave it's flags dirty so they get changed later. */
 		rec->index_flags |= INDEX_MAIL_FLAG_DIRTY;
+		index->header->flags |= MAIL_INDEX_FLAG_DIRTY_MESSAGES;
+		index->next_dirty_flush =
+			ioloop_time + MAILDIR_DIRTY_FLUSH_TIMEOUT;
+		*new_fname_r = NULL;
 	}
 	return TRUE;
 }
@@ -127,7 +193,7 @@
 {
 	struct mail_index_update *update;
 	const char *new_fname;
-	int ret;
+	int failed = FALSE;
 
 	t_push();
 	if (!maildir_rename_mail(index, rec, flags, &new_fname)) {
@@ -135,18 +201,18 @@
 		return FALSE;
 	}
 
-	/* update the filename in index */
-	update = index->update_begin(index, rec);
-	index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0);
+	if (new_fname != NULL) {
+		/* update the filename in index */
+		update = index->update_begin(index, rec);
+		index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0);
+		if (!index->update_end(update))
+			failed = TRUE;
+	}
 
-	if (!index->update_end(update))
-		ret = FALSE;
-	else if (!mail_index_update_flags(index, rec, seq, flags,
-					  external_change))
-		ret = FALSE;
-	else
-		ret = TRUE;
+	if (!failed && !mail_index_update_flags(index, rec, seq, flags,
+						external_change))
+		failed = TRUE;
 	t_pop();
 
-	return ret;
+	return !failed;
 }
--- a/src/lib-storage/index/maildir/maildir-storage.c	Sun Jun 15 05:20:12 2003 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sun Jun 15 05:20:52 2003 +0300
@@ -635,6 +635,21 @@
 	}
 }
 
+static int maildir_storage_close(struct mailbox *box)
+{
+	struct index_mailbox *ibox = (struct index_mailbox *) box;
+	int failed = FALSE;
+
+        index_storage_init_lock_notify(ibox);
+	if (!maildir_try_flush_dirty_flags(ibox->index, TRUE)) {
+		mail_storage_set_index_error(ibox);
+		failed = TRUE;
+	}
+	ibox->index->set_lock_notify_callback(ibox->index, NULL, NULL);
+
+	return index_storage_close(box) && !failed;
+}
+
 static void maildir_storage_auto_sync(struct mailbox *box,
 				      enum mailbox_sync_type sync_type,
 				      unsigned int min_newmail_notify_interval)
@@ -688,7 +703,7 @@
 	NULL, /* name */
 	NULL, /* storage */
 
-	index_storage_close,
+	maildir_storage_close,
 	index_storage_get_status,
 	index_storage_sync,
 	maildir_storage_auto_sync,