mail-index-sync-ext.c revision 41c4f318bf58ca0b7edb613d344ca208414eb1c9
/* Copyright (c) 2004-2010 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "buffer.h"
#include "mail-index-view-private.h"
#include "mail-index-sync-private.h"
#include "mail-index-modseq.h"
#include "mail-transaction-log.h"
#include <stdlib.h>
{
const struct mail_index_ext *ext;
const struct mail_index_registered_ext *rext;
void **contexts;
struct mail_index_expunge_handler eh;
unsigned int ext_count, id_map_count;
unsigned int rext_count, context_count;
return;
else
continue;
}
}
void
{
const struct mail_index_expunge_handler *eh;
return;
}
}
}
{
unsigned int count;
return;
/* set space for extra contexts */
/* make sure the extra_contexts contains everything */
/* we need to update the expunge handler list in case they had
already been called */
}
{
const struct mail_index_registered_ext *rext;
void **extra_contexts;
unsigned int i, rext_count, context_count;
return;
for (i = 0; i < context_count; i++) {
if (extra_contexts[i] != NULL) {
&extra_contexts[i]);
}
}
}
static struct mail_index_ext_header *
{
struct mail_index_ext_header *ext_hdr;
void *hdr_base;
/* do some kludgy jumping to get to it. */
return ext_hdr;
}
{
}
{
struct mail_index_ext_header *ext_hdr;
unsigned int i, count;
const void *src;
/* @UNSAFE */
for (i = 0; i < count; i++) {
ext[i].record_offset = 0;
}
/* we are growing the extension record. remember this
so we don't write extra data while copying the record */
}
/* we simply try to use the extensions with largest alignment
requirement first. FIXME: if the extension sizes don't match
alignment, this may not give the minimal layout. */
offset = sizeof(struct mail_index_record);
for (;;) {
for (i = 0; i < count; i++) {
if (sorted[i]->record_offset == 0 &&
sorted[i]->record_size > 0) {
break;
}
}
if (i == count) {
/* all done */
break;
}
/* we have to leave space here */
} else {
}
}
/* keep record size divisible with maximum alignment */
}
/* copy the records to new buffer */
offset = 0;
/* write the base record */
sizeof(struct mail_index_record));
/* write extensions */
for (i = 0; i < count; i++) {
copy_sizes[i]);
}
}
/* we didn't fully write the last record */
}
/* update record offsets in headers */
for (i = 0; i < count; i++) {
}
}
static void
sync_ext_resize(const struct mail_transaction_ext_intro *u,
bool no_shrink)
{
struct mail_index_ext *ext;
struct mail_index_ext_header *ext_hdr;
/* header shrank */
if (no_shrink)
else {
}
/* header grown */
}
}
}
if (modified) {
}
/* move all hdr_offset of all extensions after this one */
}
}
if (reorder) {
} else if (modified) {
/* header size changed. recreate index file. */
(void)mail_index_sync_get_atomic_map(ctx);
}
}
static bool
{
unsigned char *p;
if (ext_map_idx >= 1024) {
/* don't try to track too high values */
return TRUE;
}
}
if (*p != 0) {
/* we've already complained once */
return FALSE;
}
*p = 1;
return TRUE;
}
static void
const char *name,
const struct mail_index_ext_header *ext_hdr,
{
struct mail_index_map *map;
const struct mail_index_ext *ext;
/* be sure to get a unique mapping before we modify the extensions,
otherwise other map users will see the new extension but not the
data records that sync_ext_reorder() adds. */
/* we need to add padding between base header and extensions */
}
/* register record offset initially using zero,
sync_ext_reorder() will fix it. */
ext_hdr);
/* <ext_hdr> <name> [padding] [header data] */
/* header must begin and end in correct alignment */
}
{
const struct mail_index_registered_ext *rext;
struct mail_index_ext_header ext_hdr;
struct mail_transaction_ext_intro u;
i_unreached();
if (!fix_size)
return;
/* make sure it's the expected size */
memset(&u, 0, sizeof(u));
} else {
}
}
const struct mail_transaction_ext_intro *u)
{
struct mail_index_ext_header ext_hdr;
const struct mail_index_ext *ext;
bool no_shrink;
/* default to ignoring the following extension updates in case this
intro is corrupted */
return -1;
"Extension introduction for unknown id %u", u->ext_id);
return -1;
}
"Extension introduction without id or name");
return -1;
}
ext_map_idx = u->ext_id;
} else {
}
else {
}
if (!ctx->internal_update &&
/* Keyword extension is handled internally by the keyword
code. Any attempt to modify them directly could cause
assert-crashes later, so prevent them immediately. */
"Extension introduction for keywords");
return -1;
}
/* make sure the header looks valid before doing anything with it */
"Broken extension introduction: %s", error);
return -1;
}
/* exists already */
/* check if we need to resize anything */
} else {
/* extension was reset and this transaction hadn't
yet seen it. ignore this update (except for
resets). */
}
return 1;
}
return 1;
}
struct mail_index_map *map,
struct mail_index_ext *ext)
{
struct mail_index_record *rec;
uint32_t i;
ext->record_size);
}
}
const struct mail_transaction_ext_reset *u)
{
struct mail_index_map *map;
struct mail_index_ext_header *ext_hdr;
struct mail_index_ext *ext;
"Extension reset without intro prefix");
return -1;
}
/* previous extension intro was broken */
return -1;
}
/* since we're resetting the extension, don't check cur_ext_ignore */
/* a new index file will be created, so the old data won't be
accidentally used by other processes. */
if (!u->preserve_data)
return 1;
}
const void *data)
{
const struct mail_index_ext *ext;
"Extension header update without intro prefix");
return -1;
}
if (ctx->cur_ext_ignore)
return 1;
"Extension header update points outside header size");
return -1;
}
return 1;
}
int
const struct mail_transaction_ext_rec_update *u)
{
struct mail_index_record *rec;
const struct mail_index_ext *ext;
const struct mail_index_registered_ext *rext;
void *old_data;
int ret;
"Extension record update for invalid uid=%u", u->uid);
return -1;
}
return 1;
/* call sync handlers only when its registered type matches with
void **extra_context =
if (ret <= 0)
return ret;
}
/* @UNSAFE */
return 1;
}
int
const struct mail_transaction_ext_atomic_inc *u)
{
struct mail_index_record *rec;
const struct mail_index_ext *ext;
void *data;
"Extension record inc for invalid uid=%u", u->uid);
return -1;
}
return 1;
switch (ext->record_size) {
case 1: {
break;
}
case 2: {
break;
}
case 4: {
break;
}
case 8: {
break;
}
default:
"Extension record inc with invalid size=%u",
ext->record_size);
return -1;
}
"Extension record inc drops number below zero "
"(uid=%u, diff=%d, orig=%llu)",
return -1;
}
return 1;
}