]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Fix invalid parents in LAYOUT=index
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 15 Nov 2016 23:03:20 +0000 (01:03 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 18 Nov 2016 11:45:30 +0000 (13:45 +0200)
Previously it just kept complaining without fixing the errors.

src/lib-storage/list/mailbox-list-index-sync.c
src/lib-storage/list/mailbox-list-index.c
src/lib-storage/list/mailbox-list-index.h

index 13d3f6331e18f992f2c718552279d769bdd2087b..8db5667df0002f45b32f53f3eb87e0088d0daea7 100644 (file)
@@ -353,6 +353,52 @@ mailbox_list_index_sync_update_hdr(struct mailbox_list_index_sync_context *sync_
        }
 }
 
+static void
+mailbox_list_index_sync_update_corrupted_node(struct mailbox_list_index_sync_context *sync_ctx,
+                                             struct mailbox_list_index_node *node)
+{
+       struct mailbox_list_index_record irec;
+       uint32_t seq;
+       const void *data;
+       bool expunged;
+
+       if (!mail_index_lookup_seq(sync_ctx->view, node->uid, &seq))
+               return;
+
+       if (node->corrupted_parent) {
+               mail_index_lookup_ext(sync_ctx->view, seq,
+                                     sync_ctx->ilist->ext_id,
+                                     &data, &expunged);
+               i_assert(data != NULL);
+
+               memcpy(&irec, data, sizeof(irec));
+               irec.parent_uid = node->parent == NULL ? 0 : node->parent->uid;
+               mail_index_update_ext(sync_ctx->trans, seq,
+                                     sync_ctx->ilist->ext_id, &irec, NULL);
+               node->corrupted_parent = FALSE;
+       }
+}
+
+static void
+mailbox_list_index_sync_update_corrupted_nodes(struct mailbox_list_index_sync_context *sync_ctx,
+                                              struct mailbox_list_index_node *node)
+{
+       for (; node != NULL; node = node->next) {
+               mailbox_list_index_sync_update_corrupted_node(sync_ctx, node);
+               mailbox_list_index_sync_update_corrupted_nodes(sync_ctx, node->children);
+       }
+}
+
+static void
+mailbox_list_index_sync_update_corrupted(struct mailbox_list_index_sync_context *sync_ctx)
+{
+       if (!sync_ctx->ilist->corrupted)
+               return;
+
+       mailbox_list_index_sync_update_corrupted_nodes(sync_ctx,
+               sync_ctx->ilist->mailbox_tree);
+}
+
 int mailbox_list_index_sync_end(struct mailbox_list_index_sync_context **_sync_ctx,
                                bool success)
 {
@@ -361,8 +407,10 @@ int mailbox_list_index_sync_end(struct mailbox_list_index_sync_context **_sync_c
 
        *_sync_ctx = NULL;
 
-       if (success)
+       if (success) {
+               mailbox_list_index_sync_update_corrupted(sync_ctx);
                mailbox_list_index_sync_update_hdr(sync_ctx);
+       }
        mail_index_view_close(&sync_ctx->view);
 
        if (success) {
index f36e9ae7a2cde4b77677cb1f2a7598dd0b261481..fcf2cd13f0890b470e9b50a5a7bb8e190108b333 100644 (file)
@@ -258,7 +258,7 @@ static int mailbox_list_index_parse_records(struct mailbox_list_index *ilist,
                                            struct mail_index_view *view,
                                            const char **error_r)
 {
-       struct mailbox_list_index_node *node;
+       struct mailbox_list_index_node *node, *parent;
        HASH_TABLE(struct mailbox_list_index_node *,
                   struct mailbox_list_index_node *) duplicate_hash;
        const struct mail_index_record *rec;
@@ -319,19 +319,22 @@ static int mailbox_list_index_parse_records(struct mailbox_list_index *ilist,
 
                if (irec->parent_uid != 0) {
                        /* node should have a parent */
-                       node->parent = mailbox_list_index_lookup_uid(ilist,
-                                                       irec->parent_uid);
-                       if (node->parent != NULL) {
-                               node->next = node->parent->children;
-                               node->parent->children = node;
+                       parent = mailbox_list_index_lookup_uid(ilist,
+                                                              irec->parent_uid);
+                       if (parent == NULL) {
+                               *error_r = t_strdup_printf(
+                                       "parent_uid=%u points to nonexistent record",
+                                       irec->parent_uid);
+                               if (ilist->has_backing_store)
+                                       break;
+                               /* just place it under the root */
+                               node->corrupted_parent = TRUE;
+                       } else {
+                               node->parent = parent;
+                               node->next = parent->children;
+                               parent->children = node;
                                continue;
                        }
-                       *error_r = t_strdup_printf(
-                               "parent_uid=%u points to nonexistent record",
-                               irec->parent_uid);
-                       if (ilist->has_backing_store)
-                               break;
-                       /* just place it under the root */
                }
                if (hash_table_lookup(duplicate_hash, node) == NULL)
                        hash_table_insert(duplicate_hash, node, node);
index ba274c472dc903ba253a567b26ad348d4e2de6c3..cf85bf103258b501119f63c11dedf1b3b00fdbf2 100644 (file)
@@ -80,6 +80,8 @@ struct mailbox_list_index_node {
 
        uint32_t name_id, uid;
        enum mailbox_list_index_flags flags;
+       /* parent_uid is corrupted on disk - need to update it */
+       bool corrupted_parent;
        const char *name;
 };