From 9f99b5c3e607c41c16a6380203d401250d9e2603 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 25 Mar 2013 17:02:15 +0200 Subject: [PATCH] doveadm sync/backup: Added -g to sync only the specified mailbox (by GUID) Similar to -m . --- src/doveadm/dsync/doveadm-dsync.c | 23 ++++++--- src/doveadm/dsync/dsync-brain-mailbox-tree.c | 6 ++- src/doveadm/dsync/dsync-brain-private.h | 3 +- src/doveadm/dsync/dsync-brain.c | 6 +++ src/doveadm/dsync/dsync-brain.h | 3 ++ src/doveadm/dsync/dsync-ibc-pipe.c | 2 + src/doveadm/dsync/dsync-ibc-stream.c | 13 ++++- src/doveadm/dsync/dsync-ibc.h | 2 + src/doveadm/dsync/dsync-mailbox-tree-fill.c | 53 +++++++++++++------- src/doveadm/dsync/dsync-mailbox-tree.h | 7 +-- 10 files changed, 88 insertions(+), 30 deletions(-) diff --git a/src/doveadm/dsync/doveadm-dsync.c b/src/doveadm/dsync/doveadm-dsync.c index 97514522e7..6f1269f61e 100644 --- a/src/doveadm/dsync/doveadm-dsync.c +++ b/src/doveadm/dsync/doveadm-dsync.c @@ -36,7 +36,7 @@ #include #include -#define DSYNC_COMMON_GETOPT_ARGS "+dEfl:m:n:Nr:Rs:" +#define DSYNC_COMMON_GETOPT_ARGS "+dEfg:l:m:n:Nr:Rs:" #define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30 enum dsync_run_type { @@ -49,6 +49,7 @@ struct dsync_cmd_context { struct doveadm_mail_cmd_context ctx; enum dsync_brain_sync_type sync_type; const char *mailbox, *namespace_prefix; + guid_128_t mailbox_guid; const char *state_input, *rawlog_path; const char *remote_name; @@ -75,6 +76,7 @@ struct dsync_cmd_context { unsigned int backup:1; unsigned int reverse_backup:1; unsigned int remote_user_prefix:1; + unsigned int no_mail_sync:1; }; static bool legacy_dsync = FALSE; @@ -468,13 +470,12 @@ cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) else if (ctx->backup) brain_flags |= DSYNC_BRAIN_FLAG_BACKUP_SEND; + if (ctx->no_mail_sync) + brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC; if (doveadm_debug) brain_flags |= DSYNC_BRAIN_FLAG_DEBUG; - if (ctx->mailbox != NULL && *ctx->mailbox == '\0') { - brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC; - ctx->mailbox = NULL; - } brain = dsync_brain_master_init(user, ibc, sync_ns, ctx->mailbox, + ctx->mailbox_guid, ctx->sync_type, brain_flags, ctx->lock_timeout, ctx->state_input == NULL ? "" : @@ -766,13 +767,23 @@ cmd_mailbox_dsync_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) case 'f': ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_FULL; break; + case 'g': + if (optarg[0] == '\0') + ctx->no_mail_sync = TRUE; + else if (guid_128_from_string(optarg, ctx->mailbox_guid) < 0 || + guid_128_is_empty(ctx->mailbox_guid)) + i_error("Invalid -g parameter: %s", optarg); + break; case 'l': ctx->lock = TRUE; if (str_to_uint(optarg, &ctx->lock_timeout) < 0) i_error("Invalid -l parameter: %s", optarg); break; case 'm': - ctx->mailbox = optarg; + if (optarg[0] == '\0') + ctx->no_mail_sync = TRUE; + else + ctx->mailbox = optarg; break; case 'n': ctx->namespace_prefix = optarg; diff --git a/src/doveadm/dsync/dsync-brain-mailbox-tree.c b/src/doveadm/dsync/dsync-brain-mailbox-tree.c index a295c516c4..a049aee81b 100644 --- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c +++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c @@ -85,14 +85,16 @@ void dsync_brain_mailbox_trees_init(struct dsync_brain *brain) /* fill the local mailbox tree */ if (brain->sync_ns != NULL) { if (dsync_mailbox_tree_fill(brain->local_mailbox_tree, - brain->sync_ns, brain->sync_box) < 0) + brain->sync_ns, brain->sync_box, + brain->sync_box_guid) < 0) brain->failed = TRUE; } else { for (ns = brain->user->namespaces; ns != NULL; ns = ns->next) { if (!dsync_brain_want_namespace(brain, ns)) continue; if (dsync_mailbox_tree_fill(brain->local_mailbox_tree, - ns, brain->sync_box) < 0) + ns, brain->sync_box, + brain->sync_box_guid) < 0) brain->failed = TRUE; } } diff --git a/src/doveadm/dsync/dsync-brain-private.h b/src/doveadm/dsync/dsync-brain-private.h index 4fd319de92..0021a03462 100644 --- a/src/doveadm/dsync/dsync-brain-private.h +++ b/src/doveadm/dsync/dsync-brain-private.h @@ -50,7 +50,8 @@ struct dsync_brain { struct mail_user *user; struct dsync_ibc *ibc; struct mail_namespace *sync_ns; - char *sync_box; + const char *sync_box; + guid_128_t sync_box_guid; enum dsync_brain_sync_type sync_type; unsigned int lock_timeout; diff --git a/src/doveadm/dsync/dsync-brain.c b/src/doveadm/dsync/dsync-brain.c index 33fdce3a05..c01dd7649b 100644 --- a/src/doveadm/dsync/dsync-brain.c +++ b/src/doveadm/dsync/dsync-brain.c @@ -87,6 +87,7 @@ dsync_brain_set_flags(struct dsync_brain *brain, enum dsync_brain_flags flags) struct dsync_brain * dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, struct mail_namespace *sync_ns, const char *sync_box, + const guid_128_t sync_box_guid, enum dsync_brain_sync_type sync_type, enum dsync_brain_flags flags, unsigned int lock_timeout, const char *state) @@ -103,6 +104,7 @@ dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, if (sync_ns != NULL) brain->sync_ns = sync_ns; brain->sync_box = p_strdup(brain->pool, sync_box); + memcpy(brain->sync_box_guid, sync_box_guid, sizeof(brain->sync_box_guid)); brain->lock_timeout = lock_timeout; brain->master_brain = TRUE; dsync_brain_set_flags(brain, flags); @@ -121,6 +123,8 @@ dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, ibc_set.hostname = my_hostdomain(); ibc_set.sync_ns_prefix = sync_ns == NULL ? NULL : sync_ns->prefix; ibc_set.sync_box = sync_box; + memcpy(ibc_set.sync_box_guid, sync_box_guid, + sizeof(ibc_set.sync_box_guid)); ibc_set.sync_type = sync_type; ibc_set.lock_timeout = lock_timeout; /* reverse the backup direction for the slave */ @@ -302,6 +306,8 @@ static bool dsync_brain_slave_recv_handshake(struct dsync_brain *brain) ibc_set->sync_ns_prefix); } brain->sync_box = p_strdup(brain->pool, ibc_set->sync_box); + memcpy(brain->sync_box_guid, ibc_set->sync_box_guid, + sizeof(brain->sync_box_guid)); i_assert(brain->sync_type == DSYNC_BRAIN_SYNC_TYPE_UNKNOWN); brain->sync_type = ibc_set->sync_type; dsync_brain_set_flags(brain, ibc_set->brain_flags); diff --git a/src/doveadm/dsync/dsync-brain.h b/src/doveadm/dsync/dsync-brain.h index 383f0b9c81..1dc07b3e31 100644 --- a/src/doveadm/dsync/dsync-brain.h +++ b/src/doveadm/dsync/dsync-brain.h @@ -1,6 +1,8 @@ #ifndef DSYNC_BRAIN_H #define DSYNC_BRAIN_H +#include "guid.h" + struct mail_namespace; struct mail_user; struct dsync_ibc; @@ -31,6 +33,7 @@ enum dsync_brain_sync_type { struct dsync_brain * dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, struct mail_namespace *sync_ns, const char *sync_box, + const guid_128_t sync_box_guid, enum dsync_brain_sync_type sync_type, enum dsync_brain_flags flags, unsigned int lock_timeout, const char *state); diff --git a/src/doveadm/dsync/dsync-ibc-pipe.c b/src/doveadm/dsync/dsync-ibc-pipe.c index 0c6ba31d93..522724c0fe 100644 --- a/src/doveadm/dsync/dsync-ibc-pipe.c +++ b/src/doveadm/dsync/dsync-ibc-pipe.c @@ -161,6 +161,8 @@ dsync_ibc_pipe_send_handshake(struct dsync_ibc *ibc, item->u.set = *set; item->u.set.sync_ns_prefix = p_strdup(item->pool, set->sync_ns_prefix); item->u.set.sync_box = p_strdup(item->pool, set->sync_box); + memcpy(item->u.set.sync_box_guid, set->sync_box_guid, + sizeof(item->u.set.sync_box_guid)); } static enum dsync_ibc_recv_ret diff --git a/src/doveadm/dsync/dsync-ibc-stream.c b/src/doveadm/dsync/dsync-ibc-stream.c index a1969fea63..e6017497f7 100644 --- a/src/doveadm/dsync/dsync-ibc-stream.c +++ b/src/doveadm/dsync/dsync-ibc-stream.c @@ -70,7 +70,8 @@ static const struct { { .name = "handshake", .chr = 'H', .required_keys = "hostname", - .optional_keys = "sync_ns_prefix sync_box sync_type debug sync_visible_namespaces " + .optional_keys = "sync_ns_prefix sync_box sync_box_guid sync_type " + "debug sync_visible_namespaces " "send_mail_requests backup_send backup_recv lock_timeout" }, { .name = "mailbox_state", @@ -589,6 +590,10 @@ dsync_ibc_stream_send_handshake(struct dsync_ibc *_ibc, } if (set->sync_box != NULL) dsync_serializer_encode_add(encoder, "sync_box", set->sync_box); + if (!guid_128_is_empty(set->sync_box_guid)) { + dsync_serializer_encode_add(encoder, "sync_box_guid", + guid_128_to_string(set->sync_box_guid)); + } sync_type[0] = sync_type[1] = '\0'; switch (set->sync_type) { @@ -655,6 +660,12 @@ dsync_ibc_stream_recv_handshake(struct dsync_ibc *_ibc, set->sync_ns_prefix = p_strdup(pool, value); if (dsync_deserializer_decode_try(decoder, "sync_box", &value)) set->sync_box = p_strdup(pool, value); + if (dsync_deserializer_decode_try(decoder, "sync_box_guid", &value) && + guid_128_from_string(value, set->sync_box_guid) < 0) { + dsync_ibc_input_error(ibc, decoder, + "Invalid sync_box_guid: %s", value); + return DSYNC_IBC_RECV_RET_TRYAGAIN; + } if (dsync_deserializer_decode_try(decoder, "sync_type", &value)) { switch (value[0]) { case 'f': diff --git a/src/doveadm/dsync/dsync-ibc.h b/src/doveadm/dsync/dsync-ibc.h index bb7a726fe2..c046aaf256 100644 --- a/src/doveadm/dsync/dsync-ibc.h +++ b/src/doveadm/dsync/dsync-ibc.h @@ -37,6 +37,8 @@ struct dsync_ibc_settings { const char *sync_ns_prefix; /* if non-NULL, sync only this mailbox name */ const char *sync_box; + /* if non-empty, sync only this mailbox GUID */ + guid_128_t sync_box_guid; enum dsync_brain_sync_type sync_type; enum dsync_brain_flags brain_flags; diff --git a/src/doveadm/dsync/dsync-mailbox-tree-fill.c b/src/doveadm/dsync/dsync-mailbox-tree-fill.c index 2557a39c6b..ddf2ebb1f4 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c +++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c @@ -30,6 +30,17 @@ dsync_mailbox_tree_add_node(struct dsync_mailbox_tree *tree, return 0; } +static int +dsync_mailbox_tree_add_exists_node(struct dsync_mailbox_tree *tree, + const struct mailbox_info *info, + struct dsync_mailbox_node **node_r) +{ + if (dsync_mailbox_tree_add_node(tree, info, node_r) < 0) + return -1; + (*node_r)->existence = DSYNC_MAILBOX_NODE_EXISTS; + return 0; +} + static int dsync_mailbox_tree_get_selectable(struct mailbox *box, struct mailbox_metadata *metadata_r, @@ -55,7 +66,8 @@ dsync_mailbox_tree_get_selectable(struct mailbox *box, } static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree, - const struct mailbox_info *info) + const struct mailbox_info *info, + const guid_128_t box_guid) { struct dsync_mailbox_node *node; struct mailbox *box; @@ -63,16 +75,14 @@ static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree, struct mailbox_status status; const char *errstr; enum mail_error error; + int ret = 0; if ((info->flags & MAILBOX_NONEXISTENT) != 0) return 0; - - if (dsync_mailbox_tree_add_node(tree, info, &node) < 0) - return -1; - node->existence = DSYNC_MAILBOX_NODE_EXISTS; - - if ((info->flags & MAILBOX_NOSELECT) != 0) - return 0; + if ((info->flags & MAILBOX_NOSELECT) != 0) { + return !guid_128_is_empty(box_guid) ? 0 : + dsync_mailbox_tree_add_exists_node(tree, info, &node); + } /* get GUID and UIDVALIDITY for selectable mailbox */ box = mailbox_alloc(info->ns->list, info->vname, 0); @@ -88,16 +98,24 @@ static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree, default: i_error("Failed to access mailbox %s: %s", info->vname, errstr); - mailbox_free(&box); - return -1; + ret = -1; } - } else { - memcpy(node->mailbox_guid, metadata.guid, - sizeof(node->mailbox_guid)); - node->uid_validity = status.uidvalidity; - node->uid_next = status.uidnext; + mailbox_free(&box); + return ret; } mailbox_free(&box); + + if (!guid_128_is_empty(box_guid) && + !guid_128_equals(box_guid, metadata.guid)) { + /* unwanted mailbox */ + return 0; + } + if (dsync_mailbox_tree_add_exists_node(tree, info, &node) < 0) + return -1; + memcpy(node->mailbox_guid, metadata.guid, + sizeof(node->mailbox_guid)); + node->uid_validity = status.uidvalidity; + node->uid_next = status.uidnext; return 0; } @@ -235,7 +253,8 @@ dsync_mailbox_tree_fix_guid_duplicate(struct dsync_mailbox_tree *tree, } int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, - struct mail_namespace *ns, const char *box_name) + struct mail_namespace *ns, const char *box_name, + const guid_128_t box_guid) { const enum mailbox_list_iter_flags list_flags = /* FIXME: we'll skip symlinks, because we can't handle them @@ -267,7 +286,7 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, /* first add all of the existing mailboxes */ iter = mailbox_list_iter_init(ns->list, list_pattern, list_flags); while ((info = mailbox_list_iter_next(iter)) != NULL) { - if (dsync_mailbox_tree_add(tree, info) < 0) + if (dsync_mailbox_tree_add(tree, info, box_guid) < 0) ret = -1; } if (mailbox_list_iter_deinit(&iter) < 0) { diff --git a/src/doveadm/dsync/dsync-mailbox-tree.h b/src/doveadm/dsync/dsync-mailbox-tree.h index 0e35c99136..58e4531c1f 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree.h +++ b/src/doveadm/dsync/dsync-mailbox-tree.h @@ -121,10 +121,11 @@ const char *dsync_mailbox_node_get_full_name(const struct dsync_mailbox_tree *tr void dsync_mailbox_node_copy_data(struct dsync_mailbox_node *dest, const struct dsync_mailbox_node *src); -/* Add nodes to tree from the given namespace. If box_name is non-NULL, - add only that mailbox to the tree. */ +/* Add nodes to tree from the given namespace. If box_name or box_guid is + non-NULL, add only that mailbox to the tree. */ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, - struct mail_namespace *ns, const char *box_name); + struct mail_namespace *ns, const char *box_name, + const guid_128_t box_guid); /* Return all known deleted mailboxes and directories. */ const struct dsync_mailbox_delete * -- 2.47.3