[dovecot-cvs] dovecot/src/lib-storage/index/maildir maildir-sync.c, 1.77.2.14, 1.77.2.15

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


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

Modified Files:
      Tag: branch_1_0
	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.77.2.14
retrieving revision 1.77.2.15
diff -u -d -r1.77.2.14 -r1.77.2.15
--- maildir-sync.c	24 Mar 2007 00:49:21 -0000	1.77.2.14
+++ maildir-sync.c	28 Mar 2007 08:08:06 -0000	1.77.2.15
@@ -209,6 +209,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;
@@ -720,16 +722,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