changeset 1176:625d4d2b35ee HEAD

Don't even try to override mbox dotlock if we can't get fcntl/flock.
author Timo Sirainen <tss@iki.fi>
date Fri, 14 Feb 2003 14:56:32 +0200
parents 5bf4efe73b2d
children dee729f18aa1
files src/lib-index/mbox/mbox-lock.c src/lib/file-dotlock.c src/lib/file-dotlock.h
diffstat 3 files changed, 94 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mbox/mbox-lock.c	Fri Feb 14 12:58:50 2003 +0200
+++ b/src/lib-index/mbox/mbox-lock.c	Fri Feb 14 14:56:32 2003 +0200
@@ -25,6 +25,12 @@
 /* assume stale dotlock if mbox file hasn't changed for n seconds */
 #define DEFAULT_DOTLOCK_CHANGE_TIMEOUT 30
 
+struct dotlock_context {
+	struct mail_index *index;
+        enum mail_lock_type lock_type;
+	int last_stale;
+};
+
 static int lock_settings_initialized = FALSE;
 static int use_dotlock, use_fcntl_lock, use_flock, fcntl_before_flock;
 static int use_read_dotlock, lock_timeout, dotlock_change_timeout;
@@ -82,8 +88,11 @@
 			return FALSE;
 		}
 
+		if (max_wait_time == 0)
+			return FALSE;
+
 		now = time(NULL);
-		if (max_wait_time != 0 && now >= max_wait_time) {
+		if (now >= max_wait_time) {
 			index->mailbox_lock_timeout = TRUE;
 			index_set_error(index, "Timeout while waiting for "
 					"release of flock() lock for mbox file "
@@ -110,15 +119,18 @@
 {
 	struct flock fl;
 	time_t now;
+	int wait_type;
 
 	fl.l_type = MAIL_LOCK_TO_FLOCK(lock_type);
 	fl.l_whence = SEEK_SET;
 	fl.l_start = 0;
 	fl.l_len = 0;
 
-	while (fcntl(index->mbox_fd, F_SETLKW, &fl) == -1) {
+        wait_type = max_wait_time == 0 ? F_SETLK : F_SETLKW;
+	while (fcntl(index->mbox_fd, wait_type, &fl) < 0) {
 		if (errno != EINTR) {
-			mbox_set_syscall_error(index, "fcntl()");
+			if (errno != EAGAIN && errno != EACCES)
+				mbox_set_syscall_error(index, "fcntl()");
 			return FALSE;
 		}
 
@@ -137,44 +149,82 @@
 					      index->lock_notify_context);
 		}
 	}
-
 	return TRUE;
 }
 
-static int mbox_file_locks(struct mail_index *index, time_t max_wait_time)
+static int mbox_file_locks(struct mail_index *index,
+			   enum mail_lock_type lock_type, time_t max_wait_time)
 {
+	struct stat st;
+
+	/* now we need to have the file itself locked. open it if needed. */
+	if (stat(index->mailbox_path, &st) < 0)
+		return mbox_set_syscall_error(index, "stat()");
+
+	if (st.st_dev != index->mbox_dev || st.st_ino != index->mbox_ino)
+		mbox_file_close_fd(index);
+
+	if (index->mbox_fd == -1) {
+		if (!mbox_file_open(index)) {
+			(void)mbox_unlock(index);
+			return FALSE;
+		}
+	}
+
 	if (use_fcntl_lock && fcntl_before_flock) {
-		if (!mbox_lock_fcntl(index, index->mbox_lock_type,
-				     max_wait_time))
+		if (!mbox_lock_fcntl(index, lock_type, max_wait_time))
 			return FALSE;
 	}
 #ifdef HAVE_FLOCK
 	if (use_flock) {
-		if (!mbox_lock_flock(index, index->mbox_lock_type,
-				     max_wait_time))
+		if (!mbox_lock_flock(index, lock_type, max_wait_time))
 			return FALSE;
 	}
 #endif
 	if (use_fcntl_lock && !fcntl_before_flock) {
-		if (!mbox_lock_fcntl(index, index->mbox_lock_type,
-				     max_wait_time))
+		if (!mbox_lock_fcntl(index, lock_type, max_wait_time))
 			return FALSE;
 	}
 	return TRUE;
 }
 
-static void dotlock_callback(unsigned int secs_left, int stale, void *context)
+static int mbox_file_unlock(struct mail_index *index)
 {
-	struct mail_index *index = context;
+	int failed = FALSE;
+
+#ifdef HAVE_FLOCK
+	if (use_flock && !mbox_lock_flock(index, MAIL_LOCK_UNLOCK, 0))
+		failed = TRUE;
+#endif
+	if (use_fcntl_lock &&
+	    !mbox_lock_fcntl(index, MAIL_LOCK_UNLOCK, 0))
+		failed = TRUE;
+
+	return !failed;
+}
 
-	index->lock_notify_cb(stale ? MAIL_LOCK_NOTIFY_MAILBOX_OVERRIDE :
-			      MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
-			      secs_left, index->lock_notify_context);
+static int dotlock_callback(unsigned int secs_left, int stale, void *context)
+{
+	struct dotlock_context *ctx = context;
+
+	if (stale && !ctx->last_stale) {
+		if (!mbox_file_locks(ctx->index, ctx->lock_type, 0)) {
+			/* we couldn't get fcntl/flock - it's really locked */
+			ctx->last_stale = TRUE;
+			return FALSE;
+		}
+		(void)mbox_file_unlock(ctx->index);
+	}
+	ctx->last_stale = stale;
+
+	ctx->index->lock_notify_cb(stale ? MAIL_LOCK_NOTIFY_MAILBOX_OVERRIDE :
+				   MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
+				   secs_left, ctx->index->lock_notify_context);
+	return TRUE;
 }
 
 int mbox_lock(struct mail_index *index, enum mail_lock_type lock_type)
 {
-	struct stat st;
 	time_t max_wait_time;
 	int ret;
 
@@ -197,11 +247,17 @@
 
 	/* make .lock file first to protect overwriting the file */
 	if (use_dotlock && index->mbox_dotlock.ino == 0) {
+		struct dotlock_context ctx;
+
+		ctx.index = index;
+		ctx.lock_type = lock_type;
+		ctx.last_stale = -1;
+
 		ret = file_lock_dotlock(index->mailbox_path,
 					lock_type == MAIL_LOCK_SHARED &&
 					!use_read_dotlock, lock_timeout,
 					dotlock_change_timeout,
-					dotlock_callback, index,
+					dotlock_callback, &ctx,
 					&index->mbox_dotlock);
 
 		if (ret < 0) {
@@ -217,22 +273,8 @@
 		}
 	}
 
-	/* now we need to have the file itself locked. open it if needed. */
-	if (stat(index->mailbox_path, &st) < 0)
-		return mbox_set_syscall_error(index, "stat()");
-
-	if (st.st_dev != index->mbox_dev || st.st_ino != index->mbox_ino)
-		mbox_file_close_fd(index);
-
-	if (index->mbox_fd == -1) {
-		if (!mbox_file_open(index)) {
-			(void)mbox_unlock(index);
-			return FALSE;
-		}
-	}
-
 	index->mbox_lock_type = lock_type;
-	if (!mbox_file_locks(index, max_wait_time)) {
+	if (!mbox_file_locks(index, index->mbox_lock_type, max_wait_time)) {
 		(void)mbox_unlock(index);
 		return FALSE;
 	}
@@ -251,12 +293,7 @@
 
 	failed = FALSE;
 	if (index->mbox_fd != -1) {
-#ifdef HAVE_FLOCK
-		if (use_flock && !mbox_lock_flock(index, MAIL_LOCK_UNLOCK, 0))
-			failed = TRUE;
-#endif
-		if (use_fcntl_lock &&
-		    !mbox_lock_fcntl(index, MAIL_LOCK_UNLOCK, 0))
+		if (!mbox_file_unlock(index))
 			failed = TRUE;
 	}
 
--- a/src/lib/file-dotlock.c	Fri Feb 14 12:58:50 2003 +0200
+++ b/src/lib/file-dotlock.c	Fri Feb 14 14:56:32 2003 +0200
@@ -143,7 +143,7 @@
 	struct stat st;
 	int fd;
 
-	fd = open(lock_path, O_WRONLY | O_EXCL | O_CREAT, 0);
+	fd = open(lock_path, O_WRONLY | O_EXCL | O_CREAT, 0644);
 	if (fd == -1)
 		return -1;
 
@@ -180,8 +180,8 @@
 
 int file_lock_dotlock(const char *path, int checkonly,
 		      unsigned int timeout, unsigned int stale_timeout,
-		      void (*callback)(unsigned int secs_left, int stale,
-				       void *context),
+		      int (*callback)(unsigned int secs_left, int stale,
+				      void *context),
 		      void *context, struct dotlock *dotlock_r)
 {
 	const char *lock_path;
@@ -230,10 +230,15 @@
 
 				if (change_secs >= stale_notify_threshold &&
 				    change_secs <= wait_left) {
-					callback(stale_timeout - change_secs,
-						 TRUE, context);
+					if (!callback(stale_timeout -
+						      change_secs,
+						      TRUE, context)) {
+						/* we don't want to override */
+						lock_info.last_change = now;
+					}
 				} else {
-					callback(wait_left, FALSE, context);
+					(void)callback(wait_left, FALSE,
+						       context);
 				}
 			}
 
--- a/src/lib/file-dotlock.h	Fri Feb 14 12:58:50 2003 +0200
+++ b/src/lib/file-dotlock.h	Fri Feb 14 14:56:32 2003 +0200
@@ -17,11 +17,15 @@
    still locked, override the lock file.
 
    If checkonly is TRUE, we don't actually create the lock file, only make
-   sure that it doesn't exist. This is racy, so you shouldn't rely on it. */
+   sure that it doesn't exist. This is racy, so you shouldn't rely on it.
+
+   callback is called once in a while. stale is set to TRUE if stale lock is
+   detected and will be overridden in secs_left. If callback returns FALSE
+   then, the lock will not be overridden. */
 int file_lock_dotlock(const char *path, int checkonly,
 		      unsigned int timeout, unsigned int stale_timeout,
-		      void (*callback)(unsigned int secs_left, int stale,
-				       void *context),
+		      int (*callback)(unsigned int secs_left, int stale,
+				      void *context),
 		      void *context, struct dotlock *dotlock_r);
 
 /* Delete the dotlock file. Returns 1 if successful, 0 if the file was already