dbox-index.c revision a4a07e3219b59e21a8fdb3841a71f1c644d8ac0a
/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "hex-dec.h"
#include "str.h"
#include "istream.h"
#include "ostream.h"
#include "write-full.h"
#include "nfs-workarounds.h"
#include "safe-mkstemp.h"
#include "mailbox-uidvalidity.h"
#include "dbox-storage.h"
#include "dbox-file.h"
#include "dbox-index.h"
#include <stdio.h>
#include <stdlib.h>
#define DBOX_INDEX_LOCK_RETRY_COUNT 10
struct dbox_index {
struct dbox_mailbox *mbox;
char *path;
int fd;
unsigned int next_file_id;
};
struct dbox_index_append_context {
struct dbox_index *index;
unsigned int new_record_idx;
unsigned int first_new_file_id;
unsigned int locked_header:1;
};
{
struct dbox_index *index;
return index;
}
{
}
}
{
}
struct dbox_index_record *rec)
{
char *p;
unsigned long uid;
if (*line++ != ' ')
return -1;
return -1;
else {
/* convert to new format */
}
return 0;
}
unsigned int offset)
{
struct dbox_index_record rec;
/* <file id> <status><expunges><dirty> [<status-specific data>] */
line++;
}
if (*line++ != ' ')
return -1;
/* UID files shouldn't be listed in dbox.index */
return -1;
}
return -1;
line += 3;
return -1;
}
return 0;
}
static int
{
"dbox index %s corrupted: %s",
return -1;
}
{
const char *fname;
const char *path;
return mailbox_uidvalidity_next(path);
}
struct dbox_index_file_header *hdr)
{
if (index->uid_validity == 0) {
const struct mail_index_header *idx_hdr;
}
sizeof(hdr->uid_validity_hex));
sizeof(hdr->next_file_id_hex));
}
{
struct dbox_index_file_header hdr;
if (index->uid_validity == 0)
return 0;
}
{
const char *line;
}
{
const char *line;
int ret;
return 0;
return -1;
}
ret = -1;
break;
}
}
return ret == 0 ? 1 :
}
{
unsigned int i;
int ret;
for (i = 0;; i++) {
return ret;
/* doesn't exist / corrupted */
if (i == DBOX_INDEX_LOCK_RETRY_COUNT)
break;
T_BEGIN {
} T_END;
if (ret < 0)
return -1;
}
return -1;
}
{
if (dbox_index_read_or_create(index) < 0)
return -1;
return 1;
}
return -1;
}
return -1;
}
if (dbox_index_read(index) < 0)
return -1;
return 1;
}
return 0;
}
{
if (dbox_index_refresh(index) < 0)
return -1;
}
return 0;
}
{
}
struct dbox_index_record *
{
struct dbox_index_record *records;
unsigned int count;
if ((file_id & DBOX_FILE_ID_FLAG_UID) != 0)
return NULL;
if (dbox_index_refresh(index) < 0)
return NULL;
}
}
static int
{
const char *errstr;
return 0;
"File is locked by another process (EACCES)";
return -1;
}
return 1;
}
{
}
static int
{
struct dbox_index_record *rec;
int ret;
return 0;
}
return 1;
}
/* we'll need to try to lock this record */
if (ret > 0) {
} else if (ret == 0)
return ret;
}
{
int i, ret;
if ((file_id & DBOX_FILE_ID_FLAG_UID) != 0) {
return 1;
}
if (dbox_index_refresh(index) < 0)
return 1;
}
for (i = 0; i < DBOX_INDEX_LOCK_RETRY_COUNT; i++) {
return ret;
/* if file was recreated, reopen it and try again */
}
return 0;
}
{
struct dbox_index_record *rec;
return;
}
{
int i, ret;
if (dbox_index_refresh(index) < 0)
return 1;
}
for (i = 0; i < DBOX_INDEX_LOCK_RETRY_COUNT; i++) {
/* lock the whole file */
if (ret <= 0)
return ret;
}
return 0;
}
{
int i, ret;
if (dbox_index_refresh(index) < 0)
return 1;
}
for (i = 0; i < DBOX_INDEX_LOCK_RETRY_COUNT; i++) {
sizeof(struct dbox_index_file_header));
if (ret <= 0)
return -1;
/* if file was recreated, reopen it and try again */
return ret < 0;
}
return -1;
}
{
sizeof(struct dbox_index_file_header));
}
static void
{
break;
i_unreached();
break;
break;
break;
}
}
bool locked)
{
int fd;
if (locked) {
}
if (fd == -1) {
"safe_mkstemp_hostpid(%s) failed: %m",
}
return fd;
}
{
struct dbox_index_record *records;
struct dbox_index_file_header hdr;
unsigned int i, count;
if (fd == -1)
return -1;
for (i = 0; i < count; ) {
} else {
str_truncate(str, 0);
i++;
}
}
if (o_stream_flush(output) < 0) {
ret = -1;
}
ret = -1;
}
}
ret = -1;
}
if (ret == 0) {
if (locked) {
"rename(%s, %s) failed: %m",
ret = -1;
}
} else {
TRUE) < 0 &&
"link(%s, %s) failed: %m",
ret = -1;
}
}
}
}
return ret;
}
struct dbox_index_append_context *
{
struct dbox_index_append_context *ctx;
const void *data;
bool expunged;
/* refresh the index now if there's a possibility of some appendable
files existing */
(void)dbox_index_refresh(index);
}
return ctx;
}
static bool
struct dbox_index_record *record,
{
unsigned int i, count;
return FALSE;
return FALSE;
/* if we already have it in our files list, we already checked that
we can't append to it. */
for (i = 0; i < count; i++) {
return FALSE;
}
&lock_status) <= 0)
return FALSE;
/* open the file to see if we can append */
return FALSE;
}
return TRUE;
}
{
struct dbox_index_record *records;
unsigned int i, count;
int ret;
/* first try to use files already used in this append */
for (i = 0; i < count; i++) {
output_r) > 0) {
return 0;
}
}
/* try to find an existing appendable file */
for (i = 0; i < count; i++) {
break;
}
/* create a new file */
output_r)) <= 0) {
return -1;
}
}
return 0;
}
{
}
{
unsigned int i, count;
else {
count = 0;
}
for (i = 0; i < count; i++) {
if (*changes[i] == DBOX_METADATA_POP3_UIDL) {
break;
}
}
} else {
}
}
{
struct dbox_index_record rec;
unsigned int file_id;
!dbox_file_can_append(file, 0)) {
/* single UID message file */
}
if (!ctx->locked_header) {
return -1;
return -1;
}
return -1;
}
}
return -1;
if (file->maildir_file) {
} else {
}
return 0;
}
static void
{
unsigned int i, count;
for (i = 0; i < count; i++) {
i_error("unlink(%s) failed: %m",
dbox_file_get_path(files[i]));
}
} else {
/* FIXME: we should delete the appended mails.. */
}
}
}
static int
{
int ret;
if (ret <= 0)
return -1;
ctx->output_offset) < 0) {
ret = -1;
}
return ret < 0 ? -1 : 0;
}
{
struct dbox_index_file_header hdr;
return -1;
}
return 0;
}
{
unsigned int i, count;
int ret = 0;
for (i = 0; i < count; i++) {
ret = -1;
} T_END;
}
/* write the new records to index */
}
/* we have to rollback changes we made */
}
return ret;
}
{
unsigned int i, count;
int ret = 0;
for (i = 0; i < count; i++) {
/* FIXME: update status */
}
dbox_file_unref(&files[i]);
}
if (ctx->locked_header) {
ret = -1;
}
return ret;
}
{
unsigned int i, count;
for (i = 0; i < count; i++) {
else {
i_error("unlink(%s) failed: %m",
}
}
}
}