]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Don't even try to override mbox dotlock if we can't get fcntl/flock.
authorTimo Sirainen <tss@iki.fi>
Fri, 14 Feb 2003 12:56:32 +0000 (14:56 +0200)
committerTimo Sirainen <tss@iki.fi>
Fri, 14 Feb 2003 12:56:32 +0000 (14:56 +0200)
--HG--
branch : HEAD

src/lib-index/mbox/mbox-lock.c
src/lib/file-dotlock.c
src/lib/file-dotlock.h

index 63382b74fb13974c523f89e338aad52ada55249f..3c53c5b49f58e6cd894b139a2e33772168afb449 100644 (file)
 /* 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 @@ static int mbox_lock_flock(struct mail_index *index,
                        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 @@ static int mbox_lock_fcntl(struct mail_index *index,
 {
        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 @@ static int mbox_lock_fcntl(struct mail_index *index,
                                              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;
 
-       index->lock_notify_cb(stale ? MAIL_LOCK_NOTIFY_MAILBOX_OVERRIDE :
-                             MAIL_LOCK_NOTIFY_MAILBOX_ABORT,
-                             secs_left, index->lock_notify_context);
+       return !failed;
+}
+
+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 @@ int mbox_lock(struct mail_index *index, enum mail_lock_type lock_type)
 
        /* 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 @@ int mbox_lock(struct mail_index *index, enum mail_lock_type lock_type)
                }
        }
 
-       /* 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 @@ int mbox_unlock(struct mail_index *index)
 
        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;
        }
 
index f8ddb939476badabaa037db47c1816b50db2e897..50370af74685fba1ddc2d9c1c14b18399d252c49 100644 (file)
@@ -143,7 +143,7 @@ static int try_create_lock(const char *lock_path, struct dotlock *dotlock_r)
        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 @@ static int try_create_lock(const char *lock_path, struct dotlock *dotlock_r)
 
 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 @@ int file_lock_dotlock(const char *path, int checkonly,
 
                                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);
                                }
                        }
 
index 1d88c1c1c04699d9239c7ca4efb358e254ed6ae4..17f9246c8cfb086dc777bc2482cffa8457f168ff 100644 (file)
@@ -17,11 +17,15 @@ struct dotlock {
    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