dovecot: Leave uidlist fd open so we can check if uidlist has be...

dovecot at dovecot.org dovecot at dovecot.org
Wed Jul 4 05:07:55 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/db959f0d94e3
changeset: 5891:db959f0d94e3
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Jul 04 05:07:48 2007 +0300
description:
Leave uidlist fd open so we can check if uidlist has been rewritten from
inode instead of relying on mtime changes. Removed utime() call for
uidlist.

diffstat:

1 file changed, 44 insertions(+), 24 deletions(-)
src/lib-storage/index/maildir/maildir-uidlist.c |   68 ++++++++++++++---------

diffs (186 lines):

diff -r 989abd5017a4 -r db959f0d94e3 src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Wed Jul 04 04:47:28 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Wed Jul 04 05:07:48 2007 +0300
@@ -17,7 +17,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
-#include <utime.h>
 
 /* NFS: How many times to retry reading dovecot-uidlist file if ESTALE
    error occurs in the middle of reading it */
@@ -40,10 +39,12 @@ struct maildir_uidlist {
 	struct maildir_mailbox *mbox;
 	char *fname;
 
+	int fd;
+	dev_t fd_dev;
+	ino_t fd_ino;
+
 	int lock_fd;
 	unsigned int lock_count;
-
-	time_t last_mtime;
 
 	pool_t record_pool;
 	ARRAY_TYPE(maildir_uidlist_rec_p) records;
@@ -179,6 +180,7 @@ struct maildir_uidlist *maildir_uidlist_
 	struct maildir_uidlist *uidlist;
 
 	uidlist = i_new(struct maildir_uidlist, 1);
+	uidlist->fd = -1;
 	uidlist->mbox = mbox;
 	uidlist->fname =
 		i_strconcat(mbox->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
@@ -202,6 +204,11 @@ void maildir_uidlist_deinit(struct maild
 {
 	i_assert(!UIDLIST_IS_LOCKED(uidlist));
 
+	if (uidlist->fd != -1) {
+		if (close(uidlist->fd) < 0)
+			i_error("close(%s) failed: %m", uidlist->fname);
+	}
+
 	hash_destroy(uidlist->files);
 	if (uidlist->record_pool != NULL)
 		pool_unref(uidlist->record_pool);
@@ -293,7 +300,14 @@ maildir_uidlist_update_read(struct maild
 	struct stat st;
 	int fd, ret;
 
-        *retry_r = FALSE;
+	*retry_r = FALSE;
+
+	if (uidlist->fd != -1) {
+		if (close(uidlist->fd) < 0)
+			i_error("close(%s) failed: %m", uidlist->fname);
+		uidlist->fd = -1;
+		uidlist->fd_ino = 0;
+	}
 
 	fd = nfs_safe_open(uidlist->fname, O_RDONLY);
 	if (fd == -1) {
@@ -326,7 +340,7 @@ maildir_uidlist_update_read(struct maild
 
 	uidlist->version = 0;
 
-	input = i_stream_create_file(fd, default_pool, 4096, TRUE);
+	input = i_stream_create_file(fd, default_pool, 4096, FALSE);
 
 	/* get header */
 	line = i_stream_read_next_line(input);
@@ -371,10 +385,11 @@ maildir_uidlist_update_read(struct maild
         if (ret == 0) {
                 /* file is broken */
                 (void)unlink(uidlist->fname);
-                uidlist->last_mtime = 0;
         } else if (ret > 0) {
                 /* success */
-		uidlist->last_mtime = st.st_mtime;
+		uidlist->fd = fd;
+		uidlist->fd_dev = st.st_dev;
+		uidlist->fd_ino = st.st_ino;
         } else {
                 /* I/O error */
                 if (input->stream_errno == ESTALE && try_retry)
@@ -384,9 +399,13 @@ maildir_uidlist_update_read(struct maild
 			mail_storage_set_critical(storage,
 				"read(%s) failed: %m", uidlist->fname);
 		}
-        }
+	}
 
 	i_stream_destroy(&input);
+	if (ret <= 0) {
+		if (close(fd) < 0)
+			i_error("close(%s) failed: %m", uidlist->fname);
+	}
 	return ret;
 }
 
@@ -398,7 +417,7 @@ int maildir_uidlist_update(struct maildi
         bool retry;
         int ret;
 
-	if (uidlist->last_mtime != 0) {
+	if (uidlist->fd != -1) {
 		if (nfs_safe_stat(uidlist->fname, &st) < 0) {
 			if (errno != ENOENT) {
 				mail_storage_set_critical(storage,
@@ -408,7 +427,8 @@ int maildir_uidlist_update(struct maildi
 			return 0;
 		}
 
-		if (st.st_mtime == uidlist->last_mtime) {
+		if (st.st_ino == uidlist->fd_ino &&
+		    CMP_DEV_T(st.st_dev, uidlist->fd_dev)) {
 			/* unchanged */
 			return 1;
 		}
@@ -469,7 +489,7 @@ maildir_uidlist_lookup(struct maildir_ui
 
 	rec = maildir_uidlist_lookup_rec(uidlist, uid, &idx);
 	if (rec == NULL) {
-		if (uidlist->last_mtime != 0)
+		if (uidlist->fd != -1)
 			return NULL;
 
 		/* the uidlist doesn't exist. */
@@ -554,7 +574,6 @@ static int maildir_uidlist_rewrite_fd(st
 {
 	struct mail_storage *storage = &uidlist->mbox->storage->storage;
 	struct maildir_uidlist_iter_ctx *iter;
-	struct utimbuf ut;
 	string_t *str;
 	uint32_t uid;
         enum maildir_uidlist_rec_flag flags;
@@ -618,17 +637,6 @@ static int maildir_uidlist_rewrite_fd(st
 		return -1;
 	}
 
-	/* uidlist's mtime must grow every time */
-	uidlist->last_mtime = ioloop_time <= uidlist->last_mtime ?
-		uidlist->last_mtime + 1 : ioloop_time;
-	ut.actime = ioloop_time;
-	ut.modtime = uidlist->last_mtime;
-	if (utime(temp_path, &ut) < 0) {
-		mail_storage_set_critical(storage,
-			"utime(%s) failed: %m", temp_path);
-		return -1;
-	}
-
 	if (!uidlist->mbox->ibox.fsync_disable) {
 		if (fsync(uidlist->lock_fd) < 0) {
 			mail_storage_set_critical(storage,
@@ -644,6 +652,7 @@ static int maildir_uidlist_rewrite(struc
 {
 	struct maildir_mailbox *mbox = uidlist->mbox;
 	const char *temp_path, *db_path;
+	struct stat st;
 	int ret;
 
 	i_assert(uidlist->lock_count ==
@@ -657,11 +666,22 @@ static int maildir_uidlist_rewrite(struc
 		db_path = t_strconcat(mbox->control_dir,
 				      "/" MAILDIR_UIDLIST_NAME, NULL);
 
-		if (file_dotlock_replace(&uidlist->dotlock, 0) <= 0) {
+		if (file_dotlock_replace(&uidlist->dotlock,
+				DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) <= 0) {
 			mail_storage_set_critical(&mbox->storage->storage,
 				"file_dotlock_replace(%s) failed: %m", db_path);
 			(void)unlink(temp_path);
+			(void)close(uidlist->lock_fd);
 			ret = -1;
+		} else {
+			uidlist->fd = uidlist->lock_fd;
+			if (fstat(uidlist->fd, &st) < 0) {
+				i_error("fstat(%s) failed: %m", uidlist->fname);
+				uidlist->fd_ino = 0;
+			} else {
+				uidlist->fd_dev = st.st_dev;
+				uidlist->fd_ino = st.st_ino;
+			}
 		}
 
 		uidlist->lock_fd = -1;


More information about the dovecot-cvs mailing list