squat-uidlist.c revision 5af1117325be8181393905218eb18e77f885e103
/* Copyright (C) 2006 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "ostream.h"
#include "file-cache.h"
#include "mmap-util.h"
#include "read-full.h"
#include "write-full.h"
#include "squat-trie.h"
#include "squat-uidlist.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define UIDLIST_COMPRESS_PERCENTAGE 30
#define UIDLIST_UID_COMPRESS_PERCENTAGE 20
#define UID_NODE_PREV_FLAG_OLD 0x00000001
#define UID_LIST_IDX_FLAG_SINGLE 0x80000000
struct squat_uidlist_header {
};
struct uid_node {
};
struct squat_uidlist_get_context {
struct squat_uidlist *uidlist;
};
struct squat_uidlist {
struct squat_trie *trie;
char *filepath;
int fd;
void *mmap_base;
const uint8_t *const_mmap_base;
struct file_cache *file_cache;
struct squat_uidlist_header hdr;
unsigned int check_expunges:1;
unsigned int write_failed:1;
unsigned int mmap_disable:1;
};
struct squat_uidlist_compress_ctx {
struct squat_uidlist *uidlist;
char *tmp_path;
struct squat_uidlist_header hdr;
unsigned int seen_expunged:1;
unsigned int failed:1;
};
static void
const char *function)
{
i_error("%s failed with index search uidlist file %s: %m",
}
const struct squat_uidlist_header *hdr,
{
"uidlist: uidvalidity changed");
return -1;
}
"uidlist: used_file_size too large");
return -1;
}
return 0;
}
{
int ret;
if (ret < 0)
return ret;
}
{
int ret;
if (!uidlist->mmap_disable) {
/* everything is already mapped */
return 1;
}
} else {
return -1;
if (ret == 0)
return 0;
}
return -1;
}
return 0;
}
if (!uidlist->mmap_disable) {
return -1;
}
} else {
/* the header is always read separately. everything between it
and the used_file_size doesn't change */
}
return 0;
return 1;
}
{
int ret;
return 0;
return -1;
}
if (uidlist->mmap_disable)
/* broken */
}
return ret;
}
{
/* we should get here only if normal file opening failed */
return -1;
}
if (uidlist->mmap_disable)
return 0;
}
{
}
}
}
struct squat_uidlist *
{
struct squat_uidlist *uidlist;
return uidlist;
}
{
}
{
int ret;
return 0;
return -1;
}
/* no need to reopen, just remap */
return ret < 0 ? -1 : 0;
/* broken file */
}
}
if (squat_uidlist_open(uidlist) < 0)
return -1;
return 0;
}
{
return 0;
}
{
if (uid_list_idx == 0) {
return 0;
}
}
/* continue an existing list in the uidlist file */
} else if ((uid_list_idx & UID_LIST_IDX_FLAG_SINGLE) != 0) {
/* trying to add the same uid again */
return 0;
}
/* convert single UID to a list */
} else {
/* update an in-memory list */
/* broken */
"corrupted uidlist index (adding)");
return -1;
}
/* trying to add the same uid again */
return 0;
}
}
return 0;
}
static int
{
return 0;
if (ret < 0) {
return -1;
}
return 0;
}
static int
{
return -1;
return -1;
return -1;
return -1;
return 0;
}
static int
{
return -1;
data_start = data;
p = data;
if ((num & 1) != 0) {
/* prev_uid..next_uid */
/* try to increase this range */
break;
}
p = data;
}
p = data;
}
*prev_uid_r = next_uid;
return 0;
}
static int
int level)
{
/* first UID */
} else {
if ((prev_idx & UID_NODE_PREV_FLAG_OLD) != 0) {
prev_idx >>= 1;
&prev_uid,
&written_uid) < 0 ||
"corrupted continued uidlist index");
return -1;
}
} else {
&prev_uid, &written_uid,
level+1) < 0)
return -1;
}
/* prev_uid contains the previous node's UID.
written_uid contains the last written UID. */
if (level != 0) {
/* this node continue the range */
return 0;
} else {
/* finishing range */
return 0;
}
}
if (written_uid != prev_uid) {
/* range ends at prev_uid */
} else {
/* no range */
}
}
return 0;
}
{
if (squat_uidlist_create(uidlist) < 0)
return -1;
}
0, FALSE);
/* creating a new file, write a dummy header */
} else {
}
return 0;
}
{
/* write size + buffer */
return -1;
}
return 0;
}
{
if ((uid_list_idx & UID_LIST_IDX_FLAG_SINGLE) != 0) {
/* this is a single UID "list" */
return 0;
}
/* the list hasn't changed */
return 0;
}
/* broken */
"corrupted uidlist index (finishing)");
return -1;
}
/* write the uidlist into a buffer */
&prev_uid, &written_uid, 0) < 0) {
return -1;
}
if (squat_uidlist_write_init(uidlist) < 0) {
return -1;
}
}
/* new uidlist index is the offset in uidlist file */
return 0;
}
{
}
{
if (ret == 0) {
}
}
uidlist->node_pool_used = 0;
uidlist->current_uid = 0;
if (squat_uidlist_map(uidlist) <= 0)
ret = -1;
return ret;
}
unsigned int current_message_count)
{
/* see if we've reached the max. deleted space in file */
return TRUE;
}
if (current_message_count == 0)
return TRUE;
return TRUE;
}
return FALSE;
}
bool update_disk)
{
if (update_disk) {
/* NOTE: we're writing this flag without locking */
"pwrite_full()");
return -1;
}
}
return 0;
}
struct squat_uidlist_compress_ctx *
{
struct squat_uidlist_compress_ctx *ctx;
int fd;
if (existing_uids != NULL) {
1024);
}
if (fd == -1) {
} else {
}
if (squat_uidlist_refresh(uidlist) < 0)
return ctx;
}
static bool
{
return FALSE;
}
static void
{
return;
}
}
}
static int
bool *all_expunged_r)
{
if ((num & 1) != 0) {
break;
}
}
if (!ctx->seen_expunged) {
/* no changes */
return 0;
}
/* everything expunged */
*all_expunged_r = TRUE;
return 1;
}
/* recreate the list and write it */
&prev_uid, &written_uid, 0) < 0)
return -1;
return -1;
*all_expunged_r = FALSE;
return 1;
}
{
int ret;
if ((*uid_list_idx & UID_LIST_IDX_FLAG_SINGLE) != 0) {
return 0;
}
return 1;
}
return -1;
"corrupted uidlist index (compressing)");
return -1;
}
ret = 0;
else {
bool all_expunged;
&all_expunged);
if (ret < 0) {
return -1;
}
if (ret > 0 && all_expunged)
return 0;
}
if (ret == 0) {
return -1;
}
}
return 1;
}
{
}
}
{
int ret = 0;
return -1;
}
/* write the header */
}
ret = -1;
if (ret == 0) {
i_error("rename(%s, %s) failed: %m",
ret = -1;
} else {
/* reopen */
}
}
if (ret < 0)
return ret;
}
static void
{
if (ctx->filter_pos == 0) {
return;
}
ctx->filter_pos++;
}
static int
{
return -1;
if ((num & 1) != 0) {
break;
}
}
return 0;
}
static int
{
if ((uid_list_idx & UID_LIST_IDX_FLAG_SINGLE) != 0) {
return 0;
}
}
{
struct squat_uidlist_get_context ctx;
}
{
struct squat_uidlist_get_context ctx;
unsigned int count;
if (count > 0) {
}
}
{
}
unsigned int *count_r)
{
}