mailbox-list-index-backend.c revision f5447068410d91377dad69e5393553015032ef6f
/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "hostpid.h"
#include "mail-index.h"
#include "subscription-file.h"
#include "mailbox-list-delete.h"
#include "mailbox-list-subscriptions.h"
#include "mailbox-list-index-storage.h"
#include "mailbox-list-index-sync.h"
#include <stdio.h>
#define GLOBAL_TEMP_PREFIX ".temp."
struct index_mailbox_list {
struct mailbox_list list;
const char *temp_prefix;
const char *create_mailbox_name;
};
extern struct mailbox_list index_mailbox_list;
static int
static struct mailbox_list *index_list_alloc(void)
{
struct index_mailbox_list *list;
}
{
const char *dir;
*error_r = "LAYOUT=index requires mailbox_list_index=yes";
return -1;
}
return -1;
}
return 0;
}
{
}
{
}
static int
struct mail_index_view *view,
const char *name,
struct mailbox_list_index_node **node_r,
{
unsigned int i;
*seq_r = 0;
for (i = 0; i < 2; i++) {
return 0;
return 1;
/* mailbox was just expunged. refreshing should notice it. */
return -1;
}
i_panic("mailbox list index: refreshing doesn't lose expunged uid=%u",
return -1;
}
static const char *
const guid_128_t mailbox_guid)
{
}
static int
{
struct mail_index_view *view;
struct mailbox_list_index_node *node;
struct mailbox_status status;
const char *root_dir;
int ret;
/* return root directories */
path_r) ? 1 : 0;
}
/* consistently use mailbox_dir_name as part of all mailbox
switch (type) {
break;
break;
i_unreached();
default:
break;
}
return 0;
return 1;
}
/* we could get here during sync from
index_list_mailbox_create_selectable() */
seq = 0;
ret = 0;
ret = 1;
} else {
}
} else {
return -1;
if (ret < 0) {
return -1;
}
}
if (ret == 0) {
ret = -1;
ret = -1;
} else {
ret = 1;
}
return ret;
}
static const char *
{
}
{
const char *path;
"Subscriptions not supported");
return -1;
}
}
static int
enum mailbox_existence *existence_r)
{
struct mailbox_list_index_node *node;
return -1;
return 0;
MAILBOX_LIST_INDEX_FLAG_NOSELECT)) == 0) {
/* selectable */
} else {
/* non-selectable */
}
return 0;
}
static int
{
struct mailbox_list_index_sync_context *sync_ctx;
struct mailbox_list_index_node *node;
bool created;
int ret;
return -1;
/* didn't already exist */
ret = 1;
} else {
/* already existed */
ret = 0;
}
ret = -1;
return ret;
}
static int
const guid_128_t mailbox_guid)
{
struct index_mailbox_list *list =
struct mailbox_list_index_sync_context *sync_ctx;
struct mailbox_list_index_record rec;
struct mailbox_list_index_node *node;
const void *data;
return -1;
if (box->corrupted_mailbox_name) {
/* an existing mailbox is being created with a "unknown" name.
opening the mailbox will hopefully find its real name and
rename it. */
}
if (!created &&
MAILBOX_LIST_INDEX_FLAG_NOSELECT)) == 0) {
/* already selectable */
return 0;
}
/* make it selectable */
/* set UIDVALIDITY if was set by the storage */
struct mail_index_view *view;
}
/* set GUID */
/* make sure we forget any changes done internally */
return -1;
}
return 1;
}
static int
{
struct index_mailbox_list *list =
struct mailbox_update new_update;
enum mailbox_existence existence;
int ret;
/* first do a quick check that it doesn't exist */
return -1;
}
/* now add the directory to index locked */
return -1;
}
/* if no GUID is requested, generate it ourself. set
UIDVALIDITY to index sometimes later. */
i_zero(&new_update);
else
new_update = *update;
/* create the backend mailbox first before it exists in the
list. the mailbox creation wants to use get_path() though,
so use a bit kludgy create_mailbox_* variables during the
creation to return the path. we'll also support recursively
creating more mailboxes in here. */
const char *old_name;
if (ret == 0) {
/* backend mailbox was successfully created. now add it
to the list. */
if (ret < 0)
if (ret <= 0) {
/* failed to add to list. rollback the backend
mailbox creation */
bool create_error = ret < 0;
if (create_error)
if (mailbox_delete(box) < 0)
ret = -1;
if (create_error)
}
}
if (ret < 0)
return ret;
} else {
ret = 0;
}
if (ret == 0) {
"Mailbox already exists");
return -1;
}
return 0;
}
static int
const struct mailbox_update *update)
{
&old_path) <= 0)
return -1;
/* rename the directory */
&root_dir)) {
;
;
return -1;
} else {
return -1;
}
}
return 0;
}
static int
enum mailbox_existence *existence_r)
{
struct index_mailbox_list *list =
return -1;
}
return 0;
}
{
struct mailbox_list_index_node *node;
if (box->corrupted_mailbox_name)
return TRUE;
}
{
return;
/* mailbox already exists. don't give up yet, just use the newname
as prefix and add the "lost-xx" as suffix. */
/* oldname should be at the root level, but check for hierarchies
anyway to be safe. */
if (p != NULL)
oldname = p+1;
}
{
const void *data;
const unsigned char *name_hdr;
return -1;
/* FIXME: dsync-merge is performing a delete in obox - remove
this check once dsync-merging is no longer used. */
return 0;
}
/* if mailbox name has changed, update it to the header. Use \0
as the hierarchy separator in the header. This is to make sure
we don't keep rewriting the name just in case some backend switches
between separators when accessed different ways. */
/* Get the current mailbox name with \0 separators. */
for (size_t i = 0; i < box_name_len; i++) {
if (box_zerosep_name[i] == sep)
box_zerosep_name[i] = '\0';
}
/* Does it match what's in the header now? */
&data, &name_hdr_size);
/* Remove trailing \0 - header doesn't shrink always */
}
if (name_hdr_size == box_name_len &&
/* Same mailbox name */
} else if (!mailbox_has_corrupted_name(box)) {
/* Mailbox name changed - update */
struct mail_index_transaction *trans =
(void)mail_index_transaction_commit(&trans);
} else if (name_hdr_size > 0) {
/* Mailbox name is corrupted. Rename it to the previous name. */
for (size_t i = 0; i < name_hdr_size; i++) {
if (newname[i] == '\0')
}
}
return 0;
}
enum mailbox_sync_flags flags)
{
if ((flags & MAILBOX_SYNC_FLAG_FORCE_RESYNC) != 0 &&
!ilist->force_resynced) {
/* try to rebuild list index only once - even if it failed */
}
}
{
if (ilist->force_resync_failed) {
/* fail this only once */
return -1;
}
return 0;
}
static void
enum mailbox_list_path_type type)
{
&mailbox_path) <= 0 ||
return;
/* this directory may contain also child mailboxes' data.
we don't want to delete that. */
rmdir_path) < 0)
return;
} else {
}
}
/* avoid leaving empty directories lying around */
}
static void
{
}
static int
bool delete_selectable)
{
struct mailbox_list_index_sync_context *sync_ctx;
int ret;
/* we're rolling back a failed create. if the name exists in the
list, it was done by somebody else so we don't want to
remove it. */
return 0;
}
return -1;
return -1;
return ret;
}
static int
{
const char *path;
int ret;
/* first delete the mailbox files */
&path);
if (ret <= 0)
return ret;
MAILBOX_LIST_FLAG_NO_DELETES)) != 0) {
ret = 0;
} else {
}
if (ret == 0) {
return -1;
}
return ret;
}
static int
{
int ret;
return -1;
if (ret == 0) {
"Mailbox has children, delete them first");
return -1;
}
return 0;
}
static int
const char *name ATTR_UNUSED)
{
"Symlinks not supported");
return -1;
}
static int
{
struct mailbox_list_index_sync_context *sync_ctx;
const void *data;
"Renaming not supported across namespaces.");
return -1;
}
"Can't rename mailbox under itself.");
return -1;
}
return -1;
return -1;
}
if (!created) {
"Target mailbox already exists");
return -1;
}
/* copy all the data from old node to new node */
/* remove the old node from existence */
/* update the old index record to contain the new name_id/parent_uid,
then expunge the added index record */
/* mailbox is renamed - clear away the corruption flag so the
new name will be written to the mailbox index header. */
}
}
static struct mailbox_list_iterate_context *
const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
struct mailbox_list_iterate_context *ctx;
if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
flags);
}
return ctx;
}
static const struct mailbox_info *
{
return mailbox_list_subscriptions_iter_next(ctx);
return NULL;
}
{
return 0;
}
struct mailbox_list index_mailbox_list = {
.v = {
.init = index_list_init,
}
};
struct mailbox_vfuncs *v)
{
return TRUE;
/* NOTE: this is using the same v as
mailbox_list_index_status_init_mailbox(), so don't have them
accidentally override each others. */
v->open = index_list_mailbox_open;
return FALSE;
}