changeset 1454:80f82c6a3250 HEAD

We have to sync dovecot-uidlist before indexing mails in new/ dir or we'll get UID conflicts.
author Timo Sirainen <tss@iki.fi>
date Thu, 08 May 2003 21:59:38 +0300
parents 30e8a75d7842
children 4f7d146f6201
files src/lib-index/maildir/maildir-build.c src/lib-index/maildir/maildir-index.h src/lib-index/maildir/maildir-sync.c
diffstat 3 files changed, 80 insertions(+), 79 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/maildir/maildir-build.c	Thu May 08 18:53:07 2003 +0300
+++ b/src/lib-index/maildir/maildir-build.c	Thu May 08 21:59:38 2003 +0300
@@ -2,15 +2,11 @@
 
 #include "lib.h"
 #include "istream.h"
-#include "str.h"
 #include "maildir-index.h"
-#include "mail-index-data.h"
 #include "mail-index-util.h"
 
-#include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <dirent.h>
 #include <sys/stat.h>
 
 static int maildir_record_update(struct mail_index *index,
@@ -127,70 +123,3 @@
 		return index_file_set_syscall_error(index, path, "close()");
 	return ret;
 }
-
-int maildir_index_build_dir(struct mail_index *index,
-			    const char *source_dir, const char *dest_dir,
-			    DIR *dirp, struct dirent *d)
-{
-	const char *final_dir;
-	string_t *sourcepath, *destpath;
-	int failed;
-
-	i_assert(index->maildir_lock_fd != -1);
-	i_assert(index->lock_type != MAIL_LOCK_SHARED);
-
-	sourcepath = t_str_new(PATH_MAX);
-	destpath = t_str_new(PATH_MAX);
-
-	final_dir = dest_dir != NULL ? dest_dir : source_dir;
-
-	failed = FALSE;
-	for (; d != NULL && !failed; d = readdir(dirp)) {
-		if (d->d_name[0] == '.')
-			continue;
-
-		if (dest_dir != NULL) {
-			/* rename() has the problem that it might overwrite
-			   some mails, but that happens only with a broken
-			   client that has created non-unique base name.
-
-			   Alternative would be link() + unlink(), but that's
-			   racy when multiple clients try to move the mail from
-			   new/ to cur/:
-
-			   a) One of the clients uses slightly different
-			   filename (eg. sets flags)
-
-			   b) Third client changes mail's flag between
-			   client1's unlink() and client2's link() calls.
-
-			   Checking first if file exists with stat() is pretty
-			   useless as well. It requires that we also stat the
-			   file in new/, to make sure that the dest file isn't
-			   actually the same file which someone _just_ had
-			   rename()d. */
-			str_truncate(sourcepath, 0);
-			str_truncate(destpath, 0);
-
-			str_printfa(sourcepath, "%s/%s", source_dir, d->d_name);
-			str_printfa(destpath, "%s/%s", dest_dir, d->d_name);
-
-			if (rename(str_c(sourcepath), str_c(destpath)) < 0 &&
-			    errno != ENOENT) {
-				index_set_error(index, "maildir build: "
-						"rename(%s, %s) failed: %m",
-						str_c(sourcepath),
-						str_c(destpath));
-				failed = TRUE;
-				break;
-			}
-		}
-
-		t_push();
-		failed = !maildir_index_append_file(index, final_dir,
-						    d->d_name);
-		t_pop();
-	}
-
-	return !failed;
-}
--- a/src/lib-index/maildir/maildir-index.h	Thu May 08 18:53:07 2003 +0300
+++ b/src/lib-index/maildir/maildir-index.h	Thu May 08 21:59:38 2003 +0300
@@ -28,9 +28,6 @@
 
 int maildir_index_append_file(struct mail_index *index, const char *dir,
 			      const char *fname);
-int maildir_index_build_dir(struct mail_index *index,
-			    const char *source_dir, const char *dest_dir,
-			    DIR *dirp, struct dirent *d);
 
 struct istream *maildir_open_mail(struct mail_index *index,
 				  struct mail_index_record *rec,
--- a/src/lib-index/maildir/maildir-sync.c	Thu May 08 18:53:07 2003 +0300
+++ b/src/lib-index/maildir/maildir-sync.c	Thu May 08 21:59:38 2003 +0300
@@ -4,11 +4,13 @@
 #include "buffer.h"
 #include "hash.h"
 #include "ioloop.h"
+#include "str.h"
 #include "maildir-index.h"
 #include "maildir-uidlist.h"
 #include "mail-index-data.h"
 #include "mail-index-util.h"
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -437,6 +439,74 @@
 	return TRUE;
 }
 
+static int maildir_sync_new(struct mail_index *index,
+			    const char *source_dir, const char *dest_dir,
+			    DIR *dirp, struct dirent *d, int append_index)
+{
+	const char *final_dir;
+	string_t *sourcepath, *destpath;
+	int failed;
+
+	i_assert(index->maildir_lock_fd != -1);
+	i_assert(index->lock_type != MAIL_LOCK_SHARED);
+
+	sourcepath = t_str_new(PATH_MAX);
+	destpath = t_str_new(PATH_MAX);
+
+	final_dir = dest_dir != NULL ? dest_dir : source_dir;
+
+	failed = FALSE;
+	for (; d != NULL && !failed; d = readdir(dirp)) {
+		if (d->d_name[0] == '.')
+			continue;
+
+		if (dest_dir != NULL) {
+			/* rename() has the problem that it might overwrite
+			   some mails, but that happens only with a broken
+			   client that has created non-unique base name.
+
+			   Alternative would be link() + unlink(), but that's
+			   racy when multiple clients try to move the mail from
+			   new/ to cur/:
+
+			   a) One of the clients uses slightly different
+			   filename (eg. sets flags)
+
+			   b) Third client changes mail's flag between
+			   client1's unlink() and client2's link() calls.
+
+			   Checking first if file exists with stat() is pretty
+			   useless as well. It requires that we also stat the
+			   file in new/, to make sure that the dest file isn't
+			   actually the same file which someone _just_ had
+			   rename()d. */
+			str_truncate(sourcepath, 0);
+			str_truncate(destpath, 0);
+
+			str_printfa(sourcepath, "%s/%s", source_dir, d->d_name);
+			str_printfa(destpath, "%s/%s", dest_dir, d->d_name);
+
+			if (rename(str_c(sourcepath), str_c(destpath)) < 0 &&
+			    errno != ENOENT) {
+				index_set_error(index, "maildir build: "
+						"rename(%s, %s) failed: %m",
+						str_c(sourcepath),
+						str_c(destpath));
+				failed = TRUE;
+				break;
+			}
+		}
+
+		if (append_index) {
+			t_push();
+			failed = !maildir_index_append_file(index, final_dir,
+							    d->d_name);
+			t_pop();
+		}
+	}
+
+	return !failed;
+}
 static int maildir_index_lock_and_sync(struct mail_index *index, int *changes,
 				       DIR *new_dirp, struct dirent *new_dent,
 				       struct maildir_uidlist **uidlist_r)
@@ -533,15 +603,18 @@
 	/* move mail from new/ to cur/ */
 	if (new_dirp != NULL && INDEX_IS_UIDLIST_LOCKED(index)) {
 		new_dir = t_strconcat(index->mailbox_path, "/new", NULL);
-		if (!maildir_index_build_dir(index, new_dir, cur_dir,
-					     new_dirp, new_dent))
+		if (!maildir_sync_new(index, new_dir, cur_dir,
+				      new_dirp, new_dent, FALSE))
 			return FALSE;
 
 		if (uidlist != NULL)
 			uidlist->rewrite = TRUE;
 
 		/* set cur/ directory's timestamp into past to make sure we
-		   notice if new mail is moved there */
+		   notice if new mail is moved there. FIXME: is this such a
+		   good idea? Works fine only as long as others don't try
+		   the same thing.. But alternative is to wait a second or
+		   potentially lose some mails. */
 		ut.actime = ut.modtime = ioloop_time-60;
 		if (utime(cur_dir, &ut) < 0) {
 			index_file_set_syscall_error(index, cur_dir, "utime()");
@@ -550,8 +623,10 @@
 
 		/* We have to always scan the cur/ directory to make
 		   sure we don't miss any mails some other non-Dovecot
-		   client may have moved there. FIXME: make it
-		   optional, it's unnecessary with Dovecot-only setup */
+		   client may have moved there. FIXME: in Dovecot-only setup
+		   we could just skip checking cur/ changes. In that case the
+		   new/ dir has to be be synced after uidlist is first synced
+		   or there could be some problems with conflicting UIDs */
 		cur_changed = TRUE;
 
 		/* set the cur/ directory's timestamp */