index-storage.c revision 619828b3991026dd315e5e67098ba80d4856d35e
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "ioloop.h"
#include "str.h"
#include "mkdir-parents.h"
#include "mail-index-alloc-cache.h"
#include "mail-index-private.h"
#include "mail-index-modseq.h"
#include "mailbox-log.h"
#include "mailbox-list-private.h"
#include "mail-search-build.h"
#include "index-storage.h"
#include "index-mail.h"
#include "index-attachment.h"
#include "index-thread-private.h"
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#define LOCK_NOTIFY_INTERVAL 30
struct index_storage_module index_storage_module =
enum mail_cache_decision_type dec)
{
const char *const *arr;
int i;
return;
for (i = 0; i < MAIL_INDEX_CACHE_FIELD_COUNT; i++) {
*arr) == 0) {
break;
}
}
if (i == MAIL_INDEX_CACHE_FIELD_COUNT) {
i_error("%s: Invalid cache field name '%s', ignoring ",
}
}
}
{
static bool initialized = FALSE;
if (!initialized) {
initialized = TRUE;
set_cache_decisions("mail_cache_fields",
set_cache_decisions("mail_never_cache_fields",
}
sizeof(global_cache_fields));
}
unsigned int secs_left)
{
const char *str;
/* if notify type changes, print the message immediately */
/* first override notification, show it */
} else {
return;
}
}
switch (notify_type) {
case MAILBOX_LOCK_NOTIFY_NONE:
break;
break;
"%u seconds", secs_left);
break;
break;
"will override in %u seconds", secs_left);
break;
}
}
{
}
static struct mail_index *
{
const char *index_dir, *mailbox_path;
if (*index_dir == '\0')
box->index_prefix);
}
bool auto_boxes ATTR_UNUSED,
enum mailbox_existence *existence_r)
{
}
enum mailbox_existence *existence_r)
{
/* see if it's selectable */
return 0;
}
"stat(%s) failed: %m", path);
return -1;
}
/* see if it's non-selectable */
return 0;
}
return 0;
}
{
return 0;
return -1;
}
return 0;
}
{
int ret;
if (move_to_memory)
if (index_storage_mailbox_alloc_index(box) < 0)
return -1;
/* make sure mail_index_set_permissions() has been called */
(void)mailbox_get_permissions(box);
if (ret <= 0 || move_to_memory) {
if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
return -1;
}
/* try opening once more. it should be created
directly into memory now. */
index_flags) < 0)
i_panic("in-memory index creation failed");
}
}
if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
"Couldn't create index file");
return -1;
}
}
return -1;
}
}
sizeof(struct index_vsize_header), 0,
sizeof(uint64_t));
return 0;
}
enum mailbox_flags flags,
const char *index_prefix)
{
static unsigned int mailbox_generation_sequence = 0;
struct index_mailbox_context *ibox;
}
enum mailbox_feature feature)
{
if ((feature & MAILBOX_FEATURE_CONDSTORE) != 0) {
}
return 0;
}
{
ibox->recent_flags_prev_uid = 0;
ibox->recent_flags_count = 0;
ibox->sync_last_check = 0;
}
{
}
const struct mailbox_update *update)
{
const struct mail_cache_field *old_fields;
struct mail_cache_field field;
unsigned int i, j, old_count;
&old_count);
/* There shouldn't be many fields, so don't worry about O(n^2). */
/* see if it's an existing field */
for (j = 0; j < old_count; j++) {
break;
}
if (j != old_count) {
field = old_fields[j];
/* new header */
} else {
/* new unknown field. we can't do anything about
this since we don't know its type */
continue;
}
}
if (array_count(&new_fields) > 0) {
}
}
const struct mailbox_update *update)
{
const struct mail_index_header *hdr;
struct mail_index_view *view;
struct mail_index_transaction *trans;
int ret;
if (mailbox_open(box) < 0)
return -1;
/* make sure we get the latest index info */
if (update->uid_validity != 0 &&
if (hdr->uid_validity != 0) {
/* UIDVALIDITY change requires index to be reset */
}
}
if (update->min_next_uid != 0 &&
}
if (update->min_first_recent_uid != 0 &&
}
if (update->min_highest_modseq != 0 &&
}
return ret;
}
{
enum mail_error error;
return 0;
return -1;
}
/* failed directory deletion, but mailbox deletion succeeded.
this was probably maildir++, which internally deleted the
directory as well. add changelog record about that too. */
return 0;
}
{
struct mail_search_context *ctx;
struct mailbox_transaction_context *t;
struct mail_search_args *search_args;
t = mailbox_transaction_begin(box, 0);
if (mailbox_search_deinit(&ctx) < 0) {
return -1;
}
return mailbox_transaction_commit(&t);
}
{
struct mailbox_metadata metadata;
struct mailbox_status status;
enum mail_error error;
int ret_guid;
/* \noselect mailbox, try deleting only the directory */
}
/* specifically support symlinked shared mailboxes. a deletion
will simply remove the symlink, not actually expunge any
mails */
return 0;
}
/* we can't easily atomically delete all mails and the mailbox. so:
1) expunge all mails
2) mark the mailbox deleted (modifications after this will fail)
3) check if a race condition between 1) and 2) added any mails:
yes) abort and undelete mailbox
no) finish deleting the mailbox
*/
if (!box->deleting_must_be_empty) {
if (mailbox_expunge_all_mails(box) < 0)
return -1;
}
return -1;
return -1;
"New mails were added to mailbox during deletion");
return -1;
}
/* Make sure the indexes are closed before trying to delete the
directory that contains them. It can still fail with some NFS
implementations if indexes are opened by another session, but
that can't really be helped. */
return -1;
}
if (ret_guid == 0) {
}
if (error != MAIL_ERROR_EXISTS)
return -1;
/* we deleted the mailbox, but couldn't delete the directory
because it has children. that's not an error. */
}
return 0;
}
bool rename_children)
{
rename_children) < 0) {
return -1;
}
/* we'll track mailbox names, instead of GUIDs. We may be renaming a
non-selectable mailbox (directory), which doesn't even have a GUID */
return 0;
}
{
}
{
}
{
ctx->min_modseq = 0;
ctx->received_tz_offset = 0;
ctx->pop3_order = 0;
}
static void
{
const struct mail_cache_field *dest_field;
unsigned int src_field_idx, dest_field_idx;
uint32_t t;
if (dest_field_idx == -1U) {
/* unknown field */
return;
}
if ((dest_field->decision &
/* field not wanted in destination mailbox */
return;
}
buffer_set_used_size(buf, 0);
/* save date must update when mail is copied */
t = ioloop_time;
buffer_append(buf, &t, sizeof(t));
} else {
buffer_set_used_size(buf, 0);
}
}
}
{
T_BEGIN {
struct mailbox_metadata src_metadata;
const struct mailbox_cache_field *field;
&src_metadata) < 0)
i_unreached();
}
} T_END;
}
{
struct mail_namespace *ns;
const char *subs_name;
else {
/* subscriptions=no namespace, find another one where we can
add the subscription to */
"This namespace has no subscriptions");
return -1;
}
/* use <orig ns prefix><orig storage name> as the
subscription name */
/* drop the common prefix (typically there isn't one) */
}
return -1;
}
return 0;
}