]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Add mailbox_list_[un]lock()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 9 Jan 2018 20:36:58 +0000 (15:36 -0500)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Fri, 9 Feb 2018 14:09:41 +0000 (16:09 +0200)
src/lib-storage/mailbox-list-private.h
src/lib-storage/mailbox-list.c

index 7de90d389ebcfa9fa183b312ab9683b285c98ab0..2c5e55ee76a4221b279cf5bed52d096c6d0bf365 100644 (file)
@@ -124,6 +124,9 @@ struct mailbox_list {
        struct mailbox_log *changelog;
        time_t changelog_timestamp;
 
+       struct file_lock *lock;
+       int lock_refcount;
+
        pool_t guid_cache_pool;
        HASH_TABLE(uint8_t *, struct mailbox_guid_cache_rec *) guid_cache;
        bool guid_cache_errors;
@@ -243,5 +246,7 @@ const struct mailbox_info *
 mailbox_list_iter_autocreate_filter(struct mailbox_list_iterate_context *ctx,
                                    const struct mailbox_info *_info);
 
+int mailbox_list_lock(struct mailbox_list *list);
+void mailbox_list_unlock(struct mailbox_list *list);
 
 #endif
index 26410ab3099045e9de156da02b37794956996d61..0bf8f8438cdbbf4280000c26584d71361534c43c 100644 (file)
@@ -6,6 +6,7 @@
 #include "ioloop.h"
 #include "file-create-locked.h"
 #include "mkdir-parents.h"
+#include "hex-binary.h"
 #include "str.h"
 #include "sha1.h"
 #include "hash.h"
@@ -28,6 +29,9 @@
 #include <dirent.h>
 #include <sys/stat.h>
 
+#define MAILBOX_LIST_LOCK_FNAME "mailboxes.lock"
+#define MAILBOX_LIST_LOCK_SECS 60
+
 #define MAILBOX_LIST_FS_CONTEXT(obj) \
        MODULE_CONTEXT(obj, mailbox_list_fs_module)
 
@@ -2049,3 +2053,75 @@ struct mailbox_list *mailbox_list_fs_get_list(struct fs *fs)
        ctx = MAILBOX_LIST_FS_CONTEXT(fs);
        return ctx == NULL ? NULL : ctx->list;
 }
+
+int mailbox_list_lock(struct mailbox_list *list)
+{
+       struct mailbox_permissions perm;
+       struct file_create_settings set;
+       const char *lock_dir, *lock_fname, *lock_path, *error;
+
+       if (list->lock_refcount > 0) {
+               list->lock_refcount++;
+               return 0;
+       }
+
+       mailbox_list_get_root_permissions(list, &perm);
+       i_zero(&set);
+       set.lock_timeout_secs = list->mail_set->mail_max_lock_timeout == 0 ?
+               MAILBOX_LIST_LOCK_SECS :
+               I_MIN(MAILBOX_LIST_LOCK_SECS, list->mail_set->mail_max_lock_timeout);
+       set.lock_method = list->mail_set->parsed_lock_method;
+       set.mode = perm.file_create_mode;
+       set.gid = perm.file_create_gid;
+       set.gid_origin = perm.file_create_gid_origin;
+
+       lock_fname = MAILBOX_LIST_LOCK_FNAME;
+       if (list->set.volatile_dir != NULL) {
+               /* Use VOLATILEDIR. It's shared with all mailbox_lists, so use
+                  hash of the namespace prefix as a way to make this lock name
+                  unique across the namespaces. */
+               unsigned char ns_prefix_hash[SHA1_RESULTLEN];
+               sha1_get_digest(list->ns->prefix, list->ns->prefix_len,
+                               ns_prefix_hash);
+               lock_fname = t_strconcat(MAILBOX_LIST_LOCK_FNAME,
+                       binary_to_hex(ns_prefix_hash, sizeof(ns_prefix_hash)), NULL);
+               lock_dir = list->set.volatile_dir;
+               set.mkdir_mode = 0700;
+       } else if (mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_INDEX,
+                                             &lock_dir)) {
+               /* use index root directory */
+               if (mailbox_list_mkdir_missing_index_root(list) < 0)
+                       return -1;
+       } else if (mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_DIR,
+                                             &lock_dir)) {
+               /* use mailbox root directory */
+               if (mailbox_list_mkdir_root(list, lock_dir,
+                                           MAILBOX_LIST_PATH_TYPE_DIR) < 0)
+                       return -1;
+       } else {
+               /* No filesystem used by mailbox list (e.g. imapc).
+                  Just assume it's locked */
+               list->lock_refcount = 1;
+               return 0;
+       }
+       lock_path = t_strdup_printf("%s/%s", lock_dir, lock_fname);
+       if (mail_storage_lock_create(lock_path, &set, list->mail_set,
+                                    &list->lock, &error) <= 0) {
+               mailbox_list_set_critical(list,
+                       "Couldn't create mailbox list lock %s: %s",
+                       lock_path, error);
+               return -1;
+       }
+
+       list->lock_refcount = 1;
+       return 0;
+}
+
+void mailbox_list_unlock(struct mailbox_list *list)
+{
+       i_assert(list->lock_refcount > 0);
+       if (--list->lock_refcount > 0)
+               return;
+
+       file_lock_free(&list->lock);
+}