]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added mailbox_list_get_guid() to get/create directory GUID.
authorTimo Sirainen <tss@iki.fi>
Thu, 6 Aug 2009 00:23:46 +0000 (20:23 -0400)
committerTimo Sirainen <tss@iki.fi>
Thu, 6 Aug 2009 00:23:46 +0000 (20:23 -0400)
Directory GUIDs are mainly useful for dsync to identify \Noselect mailboxes.

--HG--
branch : HEAD

src/lib-storage/index/cydir/cydir-storage.c
src/lib-storage/index/cydir/cydir-storage.h
src/lib-storage/index/dbox/dbox-storage.c
src/lib-storage/index/dbox/dbox-storage.h
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/maildir/maildir-storage.h
src/lib-storage/mailbox-list.c
src/lib-storage/mailbox-list.h

index c9abc8923d7c0d207cb84f80a12cdd516a9a54de..64ff217195d75f6f356c4efadd40e2b3c26598f2 100644 (file)
@@ -46,6 +46,8 @@ cydir_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
                set->layout = MAILBOX_LIST_NAME_FS;
        if (set->subscription_fname == NULL)
                set->subscription_fname = CYDIR_SUBSCRIPTION_FILE_NAME;
+       if (set->dir_guid_fname == NULL)
+               set->dir_guid_fname = CYDIR_DIR_GUID_FILE_NAME;
 }
 
 static int create_cydir(struct mail_storage *storage, struct mailbox_list *list,
index 47e649105bda6924b265e2053703e6080542e4d4..3d1f657bf986838350f481972f84db4c5627ac9b 100644 (file)
@@ -7,6 +7,7 @@
 #define CYDIR_STORAGE_NAME "cydir"
 #define CYDIR_SUBSCRIPTION_FILE_NAME "subscriptions."
 #define CYDIR_INDEX_PREFIX "dovecot.index"
+#define CYDIR_DIR_GUID_FILE_NAME "dovecot.dir.guid."
 
 struct cydir_storage {
        struct mail_storage storage;
index 25457650e1e863c43786c99fb4eb282debf83553..3733917d5e3de1f5599221911694f4f56246a9c7 100644 (file)
@@ -109,6 +109,8 @@ dbox_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
                set->layout = MAILBOX_LIST_NAME_FS;
        if (set->subscription_fname == NULL)
                set->subscription_fname = DBOX_SUBSCRIPTION_FILE_NAME;
+       if (set->dir_guid_fname == NULL)
+               set->dir_guid_fname = DBOX_DIR_GUID_FILE_NAME;
        if (set->maildir_name == NULL)
                set->maildir_name = DBOX_MAILDIR_NAME;
        if (set->mailbox_dir_name == NULL)
index 2a85a8f62a3fae3cf6e205d192fdd943a66ed8df..9da8ee2a8d75e2b0405ae164d69f7dae63e644c8 100644 (file)
@@ -9,6 +9,7 @@
 #define DBOX_SUBSCRIPTION_FILE_NAME "subscriptions"
 #define DBOX_UIDVALIDITY_FILE_NAME "dovecot-uidvalidity"
 #define DBOX_INDEX_PREFIX "dovecot.index"
+#define DBOX_DIR_GUID_FILE_NAME "dbox-GUID"
 
 #define DBOX_MAILBOX_DIR_NAME "mailboxes"
 #define DBOX_TRASH_DIR_NAME "trash"
index ecab2ebd13402905b9773e2389806e1e276d30ec..d79a9963cde482bfb711b197bc189ff3f5f587cf 100644 (file)
@@ -140,6 +140,8 @@ static void maildir_storage_get_list_settings(const struct mail_namespace *ns,
                set->layout = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS;
        if (set->subscription_fname == NULL)
                set->subscription_fname = MAILDIR_SUBSCRIPTION_FILE_NAME;
+       if (set->dir_guid_fname == NULL)
+               set->dir_guid_fname = MAILDIR_DIR_GUID_FILE_NAME;
 
        if (set->inbox_path == NULL &&
            (strcmp(set->layout, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0 ||
index 92ce5c1d871277a16bcaf8f95ade1b2028577cfb..cb170bb0797dcceff3835e7f42507a50006a22ae 100644 (file)
@@ -8,6 +8,7 @@
 #define MAILDIR_INDEX_PREFIX "dovecot.index"
 #define MAILDIR_UNLINK_DIRNAME "DOVECOT-TRASHED"
 #define MAILDIR_UIDVALIDITY_FNAME "dovecot-uidvalidity"
+#define MAILDIR_DIR_GUID_FILE_NAME "dovecot-dir-guid"
 
 /* "base,S=123:2," means:
    <base> [<extra sep> <extra data> [..]] <info sep> 2 <flags sep> */
index 98733c0093c26b5be45ce973dab37495538153b2..e625255fe668219c49be32cff3cfe3878f7dd22e 100644 (file)
@@ -131,6 +131,8 @@ int mailbox_list_create(const char *driver, struct mail_namespace *ns,
        list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
        list->set.subscription_fname =
                p_strdup(list->pool, set->subscription_fname);
+       list->set.dir_guid_fname =
+               p_strdup(list->pool, set->dir_guid_fname);
        list->set.maildir_name = set->maildir_name == NULL ||
                (list->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 ? "" :
                p_strdup(list->pool, set->maildir_name);
@@ -731,6 +733,109 @@ int mailbox_list_rename_mailbox(struct mailbox_list *oldlist,
                                         rename_children);
 }
 
+static int mailbox_list_read_guid(struct mailbox_list *list, const char *path,
+                                 uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
+{
+       int fd, ret;
+
+       fd = open(path, O_RDONLY);
+       if (fd != -1) {
+               ret = read_full(fd, mailbox_guid, MAIL_GUID_128_SIZE);
+               close_keep_errno(fd);
+               if (ret > 0)
+                       return 1;
+               if (ret < 0) {
+                       mailbox_list_set_critical(list, "read(%s) failed: %m",
+                                                 path);
+                       return -1;
+               }
+               /* recreate it */
+               mailbox_list_set_critical(list, "Corrupted mailbox GUID in %s",
+                                         path);
+               (void)unlink(path);
+               return 0;
+       } else if (errno == ENOENT) {
+               return 0;
+       } else if (errno == EACCES) {
+               mailbox_list_set_critical(list, "%s",
+                                         eacces_error_get("open", path));
+               return -1;
+       } else {
+               mailbox_list_set_critical(list, "open(%s) failed: %m", path);
+               return -1;
+       }
+}
+
+static int
+mailbox_list_get_guid_real(struct mailbox_list *list, const char *name,
+                          uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
+{
+       string_t *temp_path;
+       const char *dir, *path;
+       int fd, ret;
+
+       memset(mailbox_guid, 0, MAIL_GUID_128_SIZE);
+       if (list->set.dir_guid_fname == NULL) {
+               mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
+                       "Storage doesn't support mailbox GUIDs");
+               return -1;
+       }
+
+       dir = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
+       path = t_strconcat(dir, "/", list->set.dir_guid_fname, NULL);
+
+       /* try reading the GUID from the file */
+       if ((ret = mailbox_list_read_guid(list, path, mailbox_guid)) < 0)
+               return -1;
+
+       /* create temp file containing a new GUID. the file must never be
+          modified and it doesn't contain anything sensitive, so just make
+          it world-readable. */
+       temp_path = t_str_new(256);
+       str_append(temp_path, path);
+       fd = safe_mkstemp_hostpid_group(temp_path, 0644, (gid_t)-1, NULL);
+       if (fd == -1) {
+               mailbox_list_set_critical(list,
+                       "safe_mkstemp(%s) failed: %m", str_c(temp_path));
+               return -1;
+       }
+
+       mail_generate_guid_128(mailbox_guid);
+       ret = write_full(fd, mailbox_guid, MAIL_GUID_128_SIZE);
+       close_keep_errno(fd);
+       if (ret < 0) {
+               mailbox_list_set_critical(list,
+                       "write(%s) failed: %m", str_c(temp_path));
+       } else if (link(str_c(temp_path), path) == 0) {
+               /* success */
+       } else if (errno == EEXIST) {
+               /* someone else just created the GUID, read it. */
+               ret = mailbox_list_read_guid(list, path, mailbox_guid);
+               if (ret == 0) {
+                       /* broken? shouldn't really happen. we anyway deleted
+                          it already, so try again. */
+                       return mailbox_list_get_guid(list, name, mailbox_guid);
+               }
+       } else {
+               mailbox_list_set_critical(list, "link(%s, %s) failed: %m",
+                                         str_c(temp_path), path);
+               ret = -1;
+       }
+       (void)unlink(str_c(temp_path));
+       return ret < 0 ? -1 : 0;
+}
+
+int mailbox_list_get_guid(struct mailbox_list *list, const char *name,
+                         uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
+{
+       int ret;
+
+       T_BEGIN {
+               ret = mailbox_list_get_guid_real(list, name, mailbox_guid);
+       } T_END;
+       return ret;
+}
+
 static int mailbox_list_try_delete(struct mailbox_list *list, const char *dir)
 {
        if (unlink_directory(dir, TRUE) == 0 || errno == ENOENT)
index 0956c482762b460f457d7897d1fc2d145135c5a1..6cf2fff22c1fa256db348eb0eba96d71647de03e 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MAILBOX_LIST_H
 #define MAILBOX_LIST_H
 
+#include "mail-types.h"
 #include "mail-error.h"
 
 struct mail_namespace;
@@ -94,6 +95,7 @@ struct mailbox_list_settings {
 
        const char *inbox_path;
        const char *subscription_fname;
+       const char *dir_guid_fname;
        /* If non-empty, it means that mails exist in a maildir_name
           subdirectory. eg. if you have a directory containing directories:
 
@@ -181,6 +183,9 @@ const char *mailbox_list_get_path(struct mailbox_list *list, const char *name,
 int mailbox_list_get_mailbox_name_status(struct mailbox_list *list,
                                         const char *name,
                                         enum mailbox_name_status *status);
+/* Get 128bit mailbox directory GUID, creating it if necessary. */
+int mailbox_list_get_guid(struct mailbox_list *list, const char *name,
+                         uint8_t mailbox_guid[MAIL_GUID_128_SIZE]);
 
 /* Returns a prefix that temporary files should use without conflicting
    with the namespace. */