From: Timo Sirainen Date: Thu, 6 Aug 2009 00:23:46 +0000 (-0400) Subject: Added mailbox_list_get_guid() to get/create directory GUID. X-Git-Tag: 2.0.alpha1~322 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6bc5fed79741503437c6d46d9f282b66bd029c6b;p=thirdparty%2Fdovecot%2Fcore.git Added mailbox_list_get_guid() to get/create directory GUID. Directory GUIDs are mainly useful for dsync to identify \Noselect mailboxes. --HG-- branch : HEAD --- diff --git a/src/lib-storage/index/cydir/cydir-storage.c b/src/lib-storage/index/cydir/cydir-storage.c index c9abc8923d..64ff217195 100644 --- a/src/lib-storage/index/cydir/cydir-storage.c +++ b/src/lib-storage/index/cydir/cydir-storage.c @@ -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, diff --git a/src/lib-storage/index/cydir/cydir-storage.h b/src/lib-storage/index/cydir/cydir-storage.h index 47e649105b..3d1f657bf9 100644 --- a/src/lib-storage/index/cydir/cydir-storage.h +++ b/src/lib-storage/index/cydir/cydir-storage.h @@ -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; diff --git a/src/lib-storage/index/dbox/dbox-storage.c b/src/lib-storage/index/dbox/dbox-storage.c index 25457650e1..3733917d5e 100644 --- a/src/lib-storage/index/dbox/dbox-storage.c +++ b/src/lib-storage/index/dbox/dbox-storage.c @@ -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) diff --git a/src/lib-storage/index/dbox/dbox-storage.h b/src/lib-storage/index/dbox/dbox-storage.h index 2a85a8f62a..9da8ee2a8d 100644 --- a/src/lib-storage/index/dbox/dbox-storage.h +++ b/src/lib-storage/index/dbox/dbox-storage.h @@ -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" diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index ecab2ebd13..d79a9963cd 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -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 || diff --git a/src/lib-storage/index/maildir/maildir-storage.h b/src/lib-storage/index/maildir/maildir-storage.h index 92ce5c1d87..cb170bb079 100644 --- a/src/lib-storage/index/maildir/maildir-storage.h +++ b/src/lib-storage/index/maildir/maildir-storage.h @@ -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: [ [..]] 2 */ diff --git a/src/lib-storage/mailbox-list.c b/src/lib-storage/mailbox-list.c index 98733c0093..e625255fe6 100644 --- a/src/lib-storage/mailbox-list.c +++ b/src/lib-storage/mailbox-list.c @@ -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) diff --git a/src/lib-storage/mailbox-list.h b/src/lib-storage/mailbox-list.h index 0956c48276..6cf2fff22c 100644 --- a/src/lib-storage/mailbox-list.h +++ b/src/lib-storage/mailbox-list.h @@ -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. */