dbox-sync-expunge.c revision 5137d2d80255938a0f5fb8f3c1a21b34cf11ada3
/* Copyright (C) 2005 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "write-full.h"
#include "hex-dec.h"
#include "seq-range-array.h"
#include "dbox-storage.h"
#include "dbox-uidlist.h"
#include "dbox-file.h"
#include "dbox-sync.h"
#include <stddef.h>
static int
const struct dbox_sync_rec *sync_rec,
{
return -1;
}
return -1;
}
return 0;
}
static int
const struct dbox_sync_file_entry *sync_entry,
{
const struct dbox_sync_rec *sync_recs;
unsigned int count;
*sync_idx += 1;
continue;
return -1;
/* all of the UIDs uid1..uid2 should exist */
}
}
return 1;
}
return 0;
}
const struct dbox_sync_file_entry *sync_entry,
unsigned int sync_idx,
const struct dbox_uidlist_entry *orig_entry,
{
struct dbox_uidlist_entry dest_entry;
const struct dbox_sync_rec *sync_recs;
unsigned int sync_count;
/* there are some expunged mails in the file, go through all
of the mails. */
}
/* skip mails until we find the first we don't want expunged */
while (ret > 0) {
break;
}
if (ret <= 0) {
if (ret == 0) {
"%s: Expunging lost UID %u from file %u",
}
return ret;
}
if (sync_idx == sync_count)
else {
return -1;
}
for (;; file_seq++) {
&dotlock);
if (fd >= 0)
break;
"file_dotlock_open(%s) failed: %m", path);
return -1;
}
/* try again with another file name */
}
/* write file header */
ret = -1;
while (ret > 0) {
/* update mail's location in index */
ret = -1;
break;
}
if (seq == 0) {
"Expunged UID %u reappeared in file %s",
ret = -1;
break;
}
&hdr_offset, NULL);
/* copy the mail */
if (bytes < 0) {
"o_stream_send_istream(%s) failed: %m",
ret = -1;
break;
}
"o_stream_send_istream(%s) wrote only %"
ret = -1;
break;
}
/* seek to next non-expunged mail */
for (;;) {
if (ret <= 0)
break;
&sync_idx,
if (ret <= 0)
break;
}
if (ret <= 0) {
if (ret == 0) {
/* we want to keep copying */
ret = 1;
}
break;
}
break;
}
}
if (ret == 0) {
struct dbox_file_header hdr;
/* update append_offset in header */
sizeof(hdr.append_offset_hex),
offsetof(struct dbox_file_header,
append_offset_hex)) < 0) {
"pwrite_full(%s) failed: %m", lock_path);
ret = -1;
}
}
if (ret < 0) {
return -1;
} else {
if (file_dotlock_replace(&dotlock, 0) < 0)
return -1;
/* new file created successfully. append it to uidlist. */
return 0;
}
}
const struct dbox_sync_file_entry *sync_entry,
unsigned int sync_idx)
{
const struct dbox_sync_rec *sync_recs;
struct dbox_uidlist_entry *entry;
const char *path;
unsigned int i, count, sync_count;
int ret;
bool seen_expunges, skipped_expunges;
return -1;
/* file is already unlinked. just remove from index. */
return 0;
}
return -1;
/* find the first non-expunged mail */
for (i = 0; i < count; i++) {
if (!seen_expunges) {
if (uid < first_expunged_uid) {
/* range begins with non-expunged messages */
}
}
/* non-expunged mails exist in this file */
break;
}
/* fully used up this uid range */
break;
}
/* this sync_rec was fully used. look up the next.
range[] doesn't contain non-existing UIDs, so
exp_uid2+1 should exist in it. */
if (ret <= 0) {
if (ret < 0)
return -1;
/* end of sync records */
break;
}
}
/* non-expunged mails exist in this file */
break;
}
}
if (i != count) {
/* mails expunged from the middle. have to copy everything
after the first expunged mail to new file. after copying
return -1;
i++;
}
if (!skipped_expunges) {
/* all mails expunged from file, unlink it. */
"unlink(%s) failed: %m", path);
return -1;
}
return 0;
}
/* mails expunged from the end of file, ftruncate() it */
if (ret <= 0) {
if (ret < 0)
return -1;
/* unexpected EOF -> already truncated */
} else {
/* file can no longer be appended to */
offsetof(struct dbox_file_header,
append_offset_hex)) < 0) {
return -1;
}
return -1;
}
/* all mails in the file are expunged now */
offsetof(struct dbox_file_header,
have_expunged_mails)) < 0) {
"pwrite_full(%s) failed: %m",
return -1;
}
}
}
/* remove from uidlist entry */
for (; i > 0; i--) {
break;
}
/* file can no longer be written to */
return 0;
}
static int
const struct dbox_sync_file_entry *sync_entry)
{
struct dbox_uidlist_entry *entry;
const struct dbox_sync_rec *recs;
return 0;
for (i = 0; i < count; i++) {
continue;
return -1;
}
}
}
}
return 0;
}
const struct dbox_sync_file_entry *sync_entry,
unsigned int sync_idx)
{
const struct dbox_sync_rec *sync_rec;
const char *path;
int ret;
/* we need to have the file locked in case another process is
appending there already. */
&dotlock);
if (ret < 0) {
"file_dotlock_create(%s) failed: %m", path);
return -1;
}
if (ret > 0) {
/* locked - copy the non-expunged mails after the
expunged mail to new file */
}
/* remember that we failed, so we don't waste time trying to
lock the file multiple times within same sync. */
}
/* couldn't lock it, someone's appending. we have no other
choice but to just mark the mail expunged. otherwise we'd
deadlock (appending process waits for uidlist lock which
we have, we wait for file lock which append process has) */
return -1;
/* mark in the header that the file contains expunged messages */
offsetof(struct dbox_file_header,
have_expunged_mails)) < 0) {
return -1;
}
/* remove UIDs from the uidlist entry */
}