fts-expunge-log.c revision 2ee478390151150a62dfd4a9d4e7b3a3d3a6da06
/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "crc32.h"
#include "hash.h"
#include "istream.h"
#include "write-full.h"
#include "seq-range-array.h"
#include "mail-storage.h"
#include "fts-expunge-log.h"
#include <unistd.h>
#include <fcntl.h>
struct fts_expunge_log_record {
/* CRC32 of this entire record (except this checksum) */
/* Size of this entire record */
/* Mailbox GUID */
/* { uid1, uid2 } pairs */
/* uint32_t expunge_uid_ranges[]; */
/* Total number of messages expunged so far in this log */
/* uint32_t expunge_count; */
};
struct fts_expunge_log {
char *path;
int fd;
};
struct fts_expunge_log_mailbox {
unsigned uids_count;
};
struct fts_expunge_log_append_ctx {
struct fts_expunge_log *log;
struct hash_table *mailboxes;
struct fts_expunge_log_mailbox *prev_mailbox;
bool failed;
};
struct fts_expunge_log_read_ctx {
struct fts_expunge_log *log;
struct fts_expunge_log_read_record read_rec;
bool failed;
bool corrupted;
};
{
struct fts_expunge_log *log;
return log;
}
{
}
{
int fd;
/* FIXME: use proper permissions */
if (fd == -1) {
return 0;
return -1;
}
return -1;
}
return 1;
}
static int
{
/* same file */
return 0;
}
/* file changed */
/* recreate the file */
} else {
return -1;
}
}
static int
{
return -1;
}
*expunge_count_r = 0;
return 0;
}
/* we'll assume that write()s atomically grow the file size, as
O_APPEND almost guarantees. even if not, having a race condition
isn't the end of the world. the expunge count is simply read wrong
and fts optimize is performed earlier or later than intended. */
if (ret < 0) {
return -1;
}
if (ret != sizeof(*expunge_count_r)) {
(int)ret, (int)sizeof(*expunge_count_r));
return -1;
}
return 0;
}
struct fts_expunge_log_append_ctx *
{
struct fts_expunge_log_append_ctx *ctx;
return ctx;
}
static struct fts_expunge_log_mailbox *
const guid_128_t mailbox_guid)
{
struct fts_expunge_log_mailbox *mailbox;
return mailbox;
}
const guid_128_t mailbox_guid,
{
struct fts_expunge_log_mailbox *mailbox;
else {
}
mailbox->uids_count++;
}
static void
{
struct hash_iterate_context *iter;
struct fts_expunge_log_record *rec;
/* uint32_t expunge_uid_ranges[]; */
sizeof(struct seq_range));
/* uint32_t expunge_count; */
/* update the header now that we know the record contents */
rec->record_size -
}
}
static int
{
uint32_t expunge_count, *e;
int ret;
/* try to append to the latest file */
return -1;
return -1;
/* the file was opened with O_APPEND, so this write() should be
appended atomically without any need for locking. */
for (;;) {
}
break;
/* the log was unlinked, so we'll need to write again to
the new file. the expunge_count needs to be reset to zero
from here. */
sizeof(uint32_t));
i_assert(*e > expunge_count);
*e -= expunge_count;
expunge_count = 0;
}
buffer_free(&buf);
if (ret == 0) {
/* finish by closing the log. this forces NFS to flush the
changes to disk without our having to explicitly play with
fsync() */
/* FIXME: we should ftruncate() in case there
were partial writes.. */
ret = -1;
}
}
return ret;
}
{
if (ret == 0)
return ret;
}
unsigned int *expunges_r)
{
int ret;
*expunges_r = 0;
return ret;
}
}
struct fts_expunge_log_read_ctx *
{
struct fts_expunge_log_read_ctx *ctx;
return ctx;
}
static bool
unsigned int *uids_size_r)
{
return FALSE;
}
static void
unsigned int wanted_size)
{
} else {
i_error("Corrupted fts expunge log %s: "
}
}
const struct fts_expunge_log_read_record *
{
const unsigned char *data;
const struct fts_expunge_log_record *rec;
unsigned int uids_size;
return NULL;
/* initial read to try to get the record */
/* expected EOF - mark the file as read by unlinking it */
/* try reading again, in case something new was written */
}
/* expected EOF */
return NULL;
}
return NULL;
}
i_error("Corrupted fts expunge log %s: "
"Invalid record size: %u",
return NULL;
}
/* read the entire record */
return NULL;
}
}
/* verify that the record checksum is valid */
i_error("Corrupted fts expunge log %s: "
"Record checksum mismatch: %u != %u",
return NULL;
}
/* create the UIDs array by pointing it directly into input
stream's buffer */
sizeof(struct seq_range));
}
{
return ret;
}