/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "hash.h"
#include "str.h"
#include "mail-index-view-private.h"
#include "mail-storage-hooks.h"
#include "mail-storage-private.h"
#include "mailbox-list-index-storage.h"
#include "mailbox-list-index-sync.h"
/* dovecot.list.index.log doesn't have to be kept for that long. */
{
}
{
}
{
ilist->highest_name_id = 0;
ilist->sync_log_file_seq = 0;
ilist->sync_log_file_offset = 0;
}
{
unsigned int lock_timeout;
return 0;
return -1;
/* LAYOUT=index. this is the only location for the mailbox
data, so we must never move it into memory. */
}
}
.log = {
},
};
/* try opening once more. it should be created
directly into memory now, except if it fails with
LAYOUT=index backend. */
index_flags) < 0) {
return -1;
}
}
}
return 0;
}
struct mailbox_list_index_node *
const char *name)
{
return node;
}
return NULL;
}
static struct mailbox_list_index_node *
{
const char *const *path;
unsigned int i;
if (*name == '\0')
for (i = 0;; i++) {
break;
}
return node;
}
struct mailbox_list_index_node *
{
T_BEGIN {
} T_END;
return node;
}
struct mailbox_list_index_node *
{
}
{
}
}
struct mailbox_list_index_node *node)
{
}
struct mail_index_view *view)
{
char *name;
int ret = 0;
if (size == 0)
return 0;
for (i = sizeof(struct mailbox_list_index_header); i < size; ) {
/* get id */
return -1;
i += sizeof(id);
/* allow extra space in the end as long as last id=0 */
return id == 0 ? 0 : -1;
}
/* get name */
if (p == NULL)
return -1;
len = (const char *)p - (const char *)name_start;
} else {
/* corrupted index. fix the name. */
str_truncate(str, 0);
ret = -1;
}
i += len + 1;
/* add id => name to hash table */
}
return ret;
}
static void
struct mailbox_list_index_node *node,
const char *prefix)
{
char *name;
}
const struct mailbox_list_index_node *n2)
{
}
static unsigned int
{
}
const struct mailbox_list_index_node *node)
{
const struct mailbox_list_index_node *n;
if (n == node)
return TRUE;
}
return FALSE;
}
struct mail_index_view *view,
const char **error_r)
{
HASH_TABLE(struct mailbox_list_index_node *,
struct mailbox_list_index_node *) duplicate_hash;
const void *data;
bool expunged;
struct mailbox_list_index_node, 1);
*error_r = "Missing list extension data";
/* list index is missing, no point trying
to do second scan either */
count = 0;
break;
}
MAILBOX_LIST_INDEX_FLAG_NOSELECT)) == 0) {
/* no backing store and mailbox has no GUID.
it can't be selectable, but the flag is missing. */
*error_r = "mailbox is missing guid - "
"setting it non-selectable";
}
/* invalid name_id - assign a new one */
}
if (ilist->has_backing_store)
break;
/* generate a new name and use it */
}
}
/* do a second scan to create the actual mailbox tree hierarchy.
this is needed because the parent_uid may be smaller or higher than
the current node's uid */
count = 0;
if (irec->parent_uid != 0) {
/* node should have a parent */
irec->parent_uid);
"parent_uid=%u points to nonexistent record",
irec->parent_uid);
if (ilist->has_backing_store)
break;
/* just place it under the root */
"parent_uid=%u loops to node itself (%s)",
if (ilist->has_backing_store)
break;
/* just place it under the root */
} else {
continue;
}
}
else {
if (ilist->has_backing_store) {
"Duplicate mailbox '%s' in index",
break;
}
/* we have only the mailbox list index and this node
may have a different GUID, so rename it. */
"Duplicate mailbox '%s' in index, renaming to %s",
}
}
}
{
const char *error;
if (!force &&
/* nothing changed */
return 0;
}
}
if (ilist->has_backing_store) {
return -1;
}
}
"Corrupted mailbox list index %s: %s",
if (ilist->has_backing_store) {
return -1;
}
}
return 0;
}
struct mail_index_view *view)
{
const void *data;
if (!ilist->has_backing_store)
return FALSE;
}
{
return 0;
/* we haven't been to ioloop since last refresh, skip checking
it. when we're accessing many mailboxes at once (e.g.
index every single time. */
return 0;
}
return mailbox_list_index_refresh_force(list);
}
{
int ret;
bool refresh;
if (mailbox_list_index_index_open(list) < 0)
return -1;
return -1;
}
/* refresh list of mailboxes */
} else {
}
if (mailbox_list_index_handle_corruption(list) < 0)
ret = -1;
return ret;
}
{
(void)mailbox_list_index_refresh(list);
}
{
sizeof(ilist->last_refresh_timeval));
if (!ilist->has_backing_store)
return;
(void)mailbox_list_index_index_open(list);
if (mail_index_transaction_commit(&trans) < 0)
}
ilist->to_refresh =
}
}
static int
{
return -1;
else {
/* FIXME: implement a generic handler that
just lists mailbox directories in filesystem
and adds the missing ones to the index. */
}
}
}
return mailbox_list_index_set_uncorrupted(list);
}
{
int ret;
else if (ilist->rebuild_on_missing_inbox)
else
return 0;
/* make sure we don't recurse */
if (ilist->handling_corruption)
return 0;
/* Perform the rebuilding locked. Note that if we're here because
INBOX wasn't found, this may be because another process is in the
middle of creating it. Waiting for the lock here makes sure that
we don't start rebuilding before it's finished. In that case the
rebuild is a bit unnecessary, but harmless (and avoiding the rebuild
just adds extra code complexity). */
if (mailbox_list_lock(list) < 0)
ret = -1;
else {
}
return ret;
}
{
return -1;
}
{
}
}
static void
const char *name, bool selectable)
{
return;
(void)mailbox_list_index_refresh_force(list);
(!selectable ||
MAILBOX_LIST_INDEX_FLAG_NOSELECT)) == 0)) {
/* index is out of sync - refresh */
}
}
const char *name)
{
return;
(void)mailbox_list_index_refresh_force(list);
/* index is out of sync - refresh */
}
}
{
return -1;
}
return 0;
}
static int
const struct mailbox_update *update,
bool directory)
{
return -1;
}
return 0;
}
static int
const struct mailbox_update *update)
{
return -1;
}
return 0;
}
static int
{
return -1;
}
return 0;
}
static int
{
return -1;
}
return 0;
}
static int
const char *oldname,
struct mailbox_list *newlist,
const char *newname)
{
return -1;
}
return 0;
}
static int
{
const void *data;
return -1;
is to trigger NOTIFY watcher to handle SubscriptionChange events */
if (mailbox_list_index_index_open(_list) < 0)
return -1;
else {
}
(void)mail_index_transaction_commit(&trans);
return 0;
}
{
return FALSE;
return FALSE;
return TRUE;
}
{
bool has_backing_store;
/* layout=index doesn't have any backing store */
if (!mailbox_list_index_is_enabled(list)) {
/* reserve the module context anyway, so syncing code knows
that the index is disabled */
return;
}
/* secondary lists aren't accessible via namespaces, so we
need to finish them now. */
}
}
{
const char *dir;
return;
/* we've delayed this part of the initialization so that mbox format
can override the index root directory path */
&dir)) {
/* in-memory indexes */
}
sizeof(struct mailbox_list_index_header),
sizeof(struct mailbox_list_index_record),
sizeof(uint32_t));
sizeof(uint32_t), 0,
sizeof(uint32_t));
}
static void
{
}
static struct mailbox_sync_context *
enum mailbox_sync_flags flags)
{
if (ibox->have_backend)
}
static int
struct mailbox_sync_status *status_r)
{
return -1;
if (ibox->have_backend)
else
return 0;
}
{
return;
/* for layout=index these get overridden */
/* These are used by both status and backend code, but they can't both
be overriding the same function pointer since they share the
super pointer. */
}
};
void mailbox_list_index_init(void); /* called in mailbox-list-register.c */
void mailbox_list_index_init(void)
{
}