maildir-sync.c revision 305465bb1a4c5d90c4b4e2c2790eb05fa4ebc41e
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch Here's a description of how we handle Maildir synchronization and
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch it's problems:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch We want to be as efficient as we can. The most efficient way to
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch check if changes have occurred is to stat() the new/ and cur/
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch directories and uidlist file - if their mtimes haven't changed,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch there's no changes and we don't need to do anything.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch Problem 1: Multiple changes can happen within a single second -
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch nothing guarantees that once we synced it, someone else didn't just
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch then make a modification. Such modifications wouldn't get noticed
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch until a new modification occurred later.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch Problem 2: Syncing cur/ directory is much more costly than syncing
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch new/. Moving mails from new/ to cur/ will always change mtime of
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cur/ causing us to sync it as well.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch Problem 3: We may not be able to move mail from new/ to cur/
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch because we're out of quota, or simply because we're accessing a
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch read-only mailbox.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch MAILDIR_SYNC_SECS
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch -----------------
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch Several checks below use MAILDIR_SYNC_SECS, which should be maximum
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch clock drift between all computers accessing the maildir (eg. via
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch NFS), rounded up to next second. Our default is 1 second, since
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch everyone should be using NTP.
96fbbe9c6fd04bca25770020bf94eec50888bc9bStephan Bosch Note that setting it to 0 works only if there's only one computer
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch accessing the maildir. It's practically impossible to make two
659f431cb56f26ec07e308db4d6c563c0eaa5300Stephan Bosch clocks _exactly_ synchronized.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch It might be possible to only use file server's clock by looking at
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch the atime field, but I don't know how well that would actually work.
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cur directory
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch -------------
659f431cb56f26ec07e308db4d6c563c0eaa5300Stephan Bosch We have dirty_cur_time variable which is set to cur/ directory's
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch mtime when it's >= time() - MAILDIR_SYNC_SECS and we _think_ we have
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch synchronized the directory.
620b60321d04006b32a116824d49b88b61be7131Stephan Bosch When dirty_cur_time is non-zero, we don't synchronize the cur/
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch directory until
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch a) cur/'s mtime changes
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch b) opening a mail fails with ENOENT
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "buffer.h"
#include "hash.h"
#include "str.h"
#include "eacces-error.h"
#include "nfs-workarounds.h"
#include "maildir-storage.h"
#include "maildir-uidlist.h"
#include "maildir-filename.h"
#include "maildir-sync.h"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
struct maildir_sync_context {
/* we got here from maildir-save.c. it has no
static struct maildir_sync_context *
return ctx;
fname2);
const char *path;
unsigned int i = 0, move_count = 0;
#ifdef HAVE_DIRFD
if (new_dir) {
errno = 0;
flags = 0;
if (move_new) {
move_count++;
move_count++;
} else if (new_dir) {
if ((i % MAILDIR_SLOW_CHECK_COUNT) == 0)
if (ret <= 0) {
if (ret < 0)
T_BEGIN {
} T_END;
if (ret < 0)
if (errno != 0) {
if (dir_changed) {
const void *data;
if (data_size == 0) {
(undirty || \
if (!*new_changed_r) {
if (!*cur_changed_r) {
if (check_new)
if (check_cur)
return FALSE;
int ret;
if (forced)
if (ret <= 0)
return ret;
if (!cur_changed) {
sync_flags = 0;
if (forced)
if (ret <= 0) {
if (ret == 0) {
if (forced) {
if (ret <= 0) {
unsigned int count = 0;
if (ret < 0)
if (cur_changed) {
if (ret < 0)
if (ret == 0)
*find_uid = 0;
*find_uid = 0;
bool lost_files;
int ret;
T_BEGIN {
} T_END;
if (uid != 0) {
T_BEGIN {
&lost_files);
} T_END;
return ret;
struct mailbox_sync_context *
int ret = 0;
T_BEGIN {
&lost_files);
} T_END;
if (lost_files) {
int ret;
T_BEGIN {
} T_END;