dovecot-1.1: MAIL_INDEX_MAIL_FLAG_BACKEND specifies if file shou...
dovecot at dovecot.org
dovecot at dovecot.org
Tue Mar 4 06:28:08 EET 2008
details: http://hg.dovecot.org/dovecot-1.1/rev/9ef06104648a
changeset: 7331:9ef06104648a
user: Timo Sirainen <tss at iki.fi>
date: Tue Mar 04 04:07:32 2008 +0200
description:
MAIL_INDEX_MAIL_FLAG_BACKEND specifies if file should be in alt dir or
primary dir. If the flag is changed, the file is moved.
diffstat:
6 files changed, 183 insertions(+), 15 deletions(-)
src/lib-storage/index/dbox/dbox-file.c | 118 ++++++++++++++++++++++++++-
src/lib-storage/index/dbox/dbox-file.h | 4
src/lib-storage/index/dbox/dbox-storage.c | 13 ++
src/lib-storage/index/dbox/dbox-storage.h | 3
src/lib-storage/index/dbox/dbox-sync-file.c | 33 ++++++-
src/lib-storage/index/dbox/dbox-sync.c | 27 ++++--
diffs (truncated from 340 to 300 lines):
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-file.c
--- a/src/lib-storage/index/dbox/dbox-file.c Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-file.c Tue Mar 04 04:07:32 2008 +0200
@@ -7,6 +7,8 @@
#include "hostpid.h"
#include "istream.h"
#include "ostream.h"
+#include "mkdir-parents.h"
+#include "fdatasync-path.h"
#include "write-full.h"
#include "str.h"
#include "dbox-storage.h"
@@ -375,6 +377,7 @@ static int dbox_file_open_fd(struct dbox
static int dbox_file_open_fd(struct dbox_file *file)
{
const char *path;
+ bool alt = FALSE;
int i;
/* try the primary path first */
@@ -398,7 +401,11 @@ static int dbox_file_open_fd(struct dbox
/* try the alternative path */
path = t_strdup_printf("%s/%s", file->mbox->alt_path,
file->fname);
- }
+ alt = TRUE;
+ }
+ i_free(file->current_path);
+ file->current_path = i_strdup(path);
+ file->alt_path = alt;
return 1;
}
@@ -1015,7 +1022,7 @@ static int dbox_file_grow_metadata(struc
} else {
i_error("%s: Metadata changed unexpectedly",
dbox_file_get_path(file));
- ret = 0;
+ ret = -1;
}
dbox_index_unlock_file(file->mbox->dbox_index, file->file_id);
@@ -1199,6 +1206,113 @@ bool dbox_file_lookup(struct dbox_mailbo
return TRUE;
}
+int dbox_file_move(struct dbox_file *file, bool alt_path)
+{
+ struct ostream *output;
+ const char *dest_dir, *temp_path, *dest_path;
+ struct stat st;
+ bool deleted;
+ int out_fd, ret = 0;
+
+ i_assert(file->input != NULL);
+
+ if (file->alt_path == alt_path)
+ return 0;
+
+ if (stat(file->current_path, &st) < 0 && errno == ENOENT) {
+ /* already expunged by another session */
+ return 0;
+ }
+
+ dest_dir = alt_path ? file->mbox->alt_path : file->mbox->path;
+ temp_path = t_strdup_printf("%s/%s", dest_dir,
+ dbox_generate_tmp_filename());
+
+ /* first copy the file. make sure to catch every possible error
+ since we really don't want to break the file. */
+ out_fd = open(temp_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (out_fd == -1 && errno == ENOENT) {
+ if (mkdir_parents(dest_dir, 0700) < 0) {
+ i_error("mkdir_parents(%s) failed: %m", dest_dir);
+ return -1;
+ }
+ out_fd = open(temp_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ }
+ if (out_fd == -1) {
+ i_error("open(%s, O_CREAT) failed: %m", temp_path);
+ return -1;
+ }
+ output = o_stream_create_fd_file(out_fd, 0, FALSE);
+ i_stream_seek(file->input, 0);
+ while ((ret = o_stream_send_istream(output, file->input)) > 0) ;
+ if (ret == 0)
+ ret = o_stream_flush(output);
+ if (output->stream_errno != 0) {
+ errno = output->stream_errno;
+ i_error("write(%s) failed: %m", temp_path);
+ ret = -1;
+ } else if (file->input->stream_errno != 0) {
+ errno = file->input->stream_errno;
+ i_error("read(%s) failed: %m", file->current_path);
+ ret = -1;
+ } else if (ret < 0) {
+ i_error("o_stream_send_istream(%s, %s) "
+ "failed with unknown error",
+ temp_path, file->current_path);
+ }
+ o_stream_unref(&output);
+
+ if (!file->mbox->ibox.fsync_disable && ret == 0) {
+ if (fsync(out_fd) < 0) {
+ i_error("fsync(%s) failed: %m", temp_path);
+ ret = -1;
+ }
+ }
+ if (close(out_fd) < 0) {
+ i_error("close(%s) failed: %m", temp_path);
+ ret = -1;
+ }
+ if (ret < 0) {
+ (void)unlink(temp_path);
+ return -1;
+ }
+
+ /* the temp file was successfully written. rename it now to the
+ destination file. the destination shouldn't exist, but if it does
+ its contents should be the same (except for maybe older metadata) */
+ dest_path = t_strdup_printf("%s/%s", dest_dir, file->fname);
+ if (rename(temp_path, dest_path) < 0) {
+ i_error("rename(%s, %s) failed: %m", temp_path, dest_path);
+ (void)unlink(temp_path);
+ return -1;
+ }
+ if (!file->mbox->ibox.fsync_disable) {
+ if (fdatasync_path(dest_dir) < 0) {
+ i_error("fdatasync(%s) failed: %m", dest_dir);
+ (void)unlink(dest_path);
+ return -1;
+ }
+ }
+ if (unlink(file->current_path) < 0) {
+ i_error("unlink(%s) failed: %m", file->current_path);
+ if (errno == EACCES) {
+ /* configuration problem? revert the write */
+ (void)unlink(dest_path);
+ }
+ /* who knows what happened to the file. keep both just to be
+ sure both won't get deleted. */
+ return -1;
+ }
+
+ /* file was successfully moved - reopen it */
+ dbox_file_close(file);
+ if (dbox_file_open(file, TRUE, &deleted) <= 0) {
+ i_error("dbox_file_move(%s): reopening file failed", dest_path);
+ return -1;
+ }
+ return 0;
+}
+
void dbox_mail_metadata_flags_append(string_t *str, enum mail_flags flags)
{
unsigned int i;
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-file.h
--- a/src/lib-storage/index/dbox/dbox-file.h Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-file.h Tue Mar 04 04:07:32 2008 +0200
@@ -128,6 +128,7 @@ struct dbox_file {
/* Includes the trailing LF that shouldn't be used */
unsigned int metadata_len;
+ unsigned int alt_path:1;
unsigned int maildir_file:1;
unsigned int nonappendable:1;
unsigned int deleted:1;
@@ -217,6 +218,9 @@ bool dbox_file_lookup(struct dbox_mailbo
bool dbox_file_lookup(struct dbox_mailbox *mbox, struct mail_index_view *view,
uint32_t seq, uint32_t *file_id_r, uoff_t *offset_r);
+/* Move the file to alt path or back. */
+int dbox_file_move(struct dbox_file *file, bool alt_path);
+
/* Append flags as metadata value to given string */
void dbox_mail_metadata_flags_append(string_t *str, enum mail_flags flags);
/* Append keywords as metadata value to given string */
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-storage.c
--- a/src/lib-storage/index/dbox/dbox-storage.c Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.c Tue Mar 04 04:07:32 2008 +0200
@@ -151,16 +151,21 @@ static const char *
static const char *
dbox_get_alt_path(struct dbox_storage *storage, const char *path)
{
+ const char *root;
unsigned int len;
if (storage->alt_dir == NULL)
return NULL;
- len = strlen(storage->alt_dir);
- if (strncmp(path, storage->alt_dir, len) != 0)
- return t_strconcat(storage->alt_dir, path + len, NULL);
- else
+ root = mailbox_list_get_path(storage->storage.list, NULL,
+ MAILBOX_LIST_PATH_TYPE_DIR);
+
+ len = strlen(root);
+ if (strncmp(path, root, len) != 0 && path[len] == '/') {
+ /* can't determine the alt path - shouldn't happen */
return NULL;
+ }
+ return t_strconcat(storage->alt_dir, path + len, NULL);
}
static struct mailbox *
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-storage.h
--- a/src/lib-storage/index/dbox/dbox-storage.h Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-storage.h Tue Mar 04 04:07:32 2008 +0200
@@ -25,6 +25,9 @@
#define DBOX_DEFAULT_ROTATE_MIN_SIZE (1024*16)
#define DBOX_DEFAULT_ROTATE_DAYS 0
#define DBOX_DEFAULT_MAX_OPEN_FILES 64
+
+/* Flag specifies if the message should be in primary or alternative storage */
+#define DBOX_INDEX_FLAG_ALT MAIL_INDEX_MAIL_FLAG_BACKEND
struct dbox_index_header {
uint32_t last_dirty_flush_stamp;
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-sync-file.c
--- a/src/lib-storage/index/dbox/dbox-sync-file.c Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-sync-file.c Tue Mar 04 04:07:32 2008 +0200
@@ -324,9 +324,9 @@ dbox_sync_file_int(struct dbox_sync_cont
first_expunge_seq = (uint32_t)-1;
}
- if (array_is_created(&entry->changes))
+ if (array_is_created(&entry->changes)) {
seqs = array_get(&entry->changes, &count);
- else {
+ } else {
seqs = NULL;
count = 0;
}
@@ -344,6 +344,31 @@ dbox_sync_file_int(struct dbox_sync_cont
if (first_expunge_seq != (uint32_t)-1)
return dbox_sync_file_expunge(ctx, file, entry);
return 1;
+}
+
+static void
+dbox_sync_file_move_if_needed(struct dbox_sync_context *ctx,
+ struct dbox_file *file,
+ const struct dbox_sync_file_entry *entry)
+{
+ const struct seq_range *seq;
+ const struct mail_index_record *rec;
+ bool new_alt_path;
+
+ if (!array_is_created(&entry->changes))
+ return;
+
+ /* check if we want to move the file to alt path or back.
+ FIXME: change this check somehow when a file may contain
+ multiple messages. */
+ seq = array_idx(&entry->changes, 0);
+ rec = mail_index_lookup(ctx->sync_view, seq[0].seq1);
+ new_alt_path = (rec->flags & DBOX_INDEX_FLAG_ALT) != 0;
+ if (new_alt_path != file->alt_path) {
+ /* move the file. if it fails, nothing broke so
+ don't worry about it. */
+ (void)dbox_file_move(file, new_alt_path);
+ }
}
static void
@@ -394,8 +419,10 @@ int dbox_sync_file(struct dbox_sync_cont
}
} else {
ret = dbox_file_open_or_create(file, TRUE, &deleted);
- if (ret > 0 && !deleted)
+ if (ret > 0 && !deleted) {
+ dbox_sync_file_move_if_needed(ctx, file, entry);
ret = dbox_sync_file_int(ctx, file, entry, locked);
+ }
}
dbox_file_unref(&file);
return ret;
diff -r 93f67b71476c -r 9ef06104648a src/lib-storage/index/dbox/dbox-sync.c
--- a/src/lib-storage/index/dbox/dbox-sync.c Tue Mar 04 04:05:35 2008 +0200
+++ b/src/lib-storage/index/dbox/dbox-sync.c Tue Mar 04 04:07:32 2008 +0200
@@ -17,12 +17,13 @@
#define DBOX_REBUILD_COUNT 3
static int dbox_sync_add_seq(struct dbox_sync_context *ctx,
- enum mail_index_sync_type type, uint32_t seq)
+ const struct mail_index_sync_rec *sync_rec,
+ uint32_t seq)
{
struct dbox_sync_file_entry *entry;
uint32_t file_id;
uoff_t offset;
- bool uid_file;
+ bool uid_file, add;
if (!dbox_file_lookup(ctx->mbox, ctx->sync_view, seq,
&file_id, &offset))
@@ -30,8 +31,22 @@ static int dbox_sync_add_seq(struct dbox
entry = hash_lookup(ctx->syncs, POINTER_CAST(file_id));
More information about the dovecot-cvs
mailing list