[dovecot-cvs] dovecot/src/lib-storage/index/maildir maildir-sync.c, 1.98, 1.99

tss at dovecot.org tss at dovecot.org
Wed Mar 28 11:08:10 EEST 2007


Update of /var/lib/cvs/dovecot/src/lib-storage/index/maildir
In directory talvi:/tmp/cvs-serv5525

Modified Files:
	maildir-sync.c 
Log Message:
If we find duplicate hard links which haven't changed for 30 secs, unlink()
one of the filenames.



Index: maildir-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-storage/index/maildir/maildir-sync.c,v
retrieving revision 1.98
retrieving revision 1.99
diff -u -d -r1.98 -r1.99
--- maildir-sync.c	24 Mar 2007 00:49:23 -0000	1.98
+++ maildir-sync.c	28 Mar 2007 08:08:08 -0000	1.99
@@ -208,6 +208,8 @@
    exists as the hard link of the file itself. */
 #define MAILDIR_SCAN_DIR_MAX_COUNT 5
 
+#define DUPE_LINKS_DELETE_SECS 30
+
 struct maildir_sync_context {
         struct maildir_mailbox *mbox;
 	const char *new_dir, *cur_dir;
@@ -715,16 +717,29 @@
 	if (ex_st.st_ino == old_st.st_ino &&
 	    CMP_DEV_T(ex_st.st_dev, old_st.st_dev)) {
 		/* Files are the same. this means either a race condition
-		   between stat() calls, or that the files were link()ed.
-
-		   There's really no easy way to handle this. If the files
-		   really are duplicate links, rename()ing one on top of
-		   another won't work. Then again if we unlink() one of them
-		   and this was actually a race condition, we just deleted
-		   a mail.
+		   between stat() calls, or that the files were link()ed. */
+		if (ex_st.st_nlink > 1 && old_st.st_nlink == ex_st.st_nlink &&
+		    ex_st.st_ctime == old_st.st_ctime &&
+		    ex_st.st_ctime < ioloop_time - DUPE_LINKS_DELETE_SECS) {
+			/* The file has hard links and it hasn't had any
+			   changes (such as renames) for a while, so this
+			   isn't a race condition.
 
-		   So for now, just do nothing. Lets hope there aren't any
-		   duplicate links in the maildir. */
+			   rename()ing one file on top of the other would fix
+			   this safely, except POSIX decided that rename()
+			   doesn't work that way. So we'll have unlink() one
+			   and hope that another process didn't just decide to
+			   unlink() the other (uidlist lock prevents this from
+			   happening) */
+			if (unlink(old_path) == 0) {
+				i_warning("Unlinked a duplicate: %s",
+					  old_fname);
+			} else {
+				mail_storage_set_critical(
+					STORAGE(mbox->storage),
+					"unlink(%s) failed: %m", old_path);
+			}
+		}
 		t_pop();
 		return 0;
 	}



More information about the dovecot-cvs mailing list