maildir-sync.c revision ea9fd7f876643e985946a2563140359064819b8e
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen Here's a description of how we handle Maildir synchronization and
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it's problems:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen We want to be as efficient as we can. The most efficient way to
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen check if changes have occurred is to stat() the new/ and cur/
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen directories and uidlist file - if their mtimes haven't changed,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen there's no changes and we don't need to do anything.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Problem 1: Multiple changes can happen within a single second -
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen nothing guarantees that once we synced it, someone else didn't just
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen then make a modification. Such modifications wouldn't get noticed
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen until a new modification occurred later.
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen Problem 2: Syncing cur/ directory is much more costly than syncing
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen new/. Moving mails from new/ to cur/ will always change mtime of
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cur/ causing us to sync it as well.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Problem 3: We may not be able to move mail from new/ to cur/
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen because we're out of quota, or simply because we're accessing a
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen read-only mailbox.
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen MAILDIR_SYNC_SECS
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen -----------------
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen Several checks below use MAILDIR_SYNC_SECS, which should be maximum
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen clock drift between all computers accessing the maildir (eg. via
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen NFS), rounded up to next second. Our default is 1 second, since
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainen everyone should be using NTP.
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen Note that setting it to 0 works only if there's only one computer
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen accessing the maildir. It's practically impossible to make two
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen clocks _exactly_ synchronized.
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen It might be possible to only use file server's clock by looking at
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen the atime field, but I don't know how well that would actually work.
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen cur directory
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen -------------
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen We have dirty_cur_time variable which is set to cur/ directory's
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen mtime when it's >= time() - MAILDIR_SYNC_SECS and we _think_ we have
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen synchronized the directory.
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen When dirty_cur_time is non-zero, we don't synchronize the cur/
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen directory until
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen a) cur/'s mtime changes
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen b) opening a mail fails with ENOENT
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen c) time() > dirty_cur_time + MAILDIR_SYNC_SECS
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen This allows us to modify the maildir multiple times without having
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen to sync it at every change. The sync will eventually be done to
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen make sure we didn't miss any external changes.
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen The dirty_cur_time is set when:
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen - we change message flags
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen - we expunge messages
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen - we move mail from new/ to cur/
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen - we sync cur/ directory and it's mtime is >= time() - MAILDIR_SYNC_SECS
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen It's unset when we do the final syncing, ie. when mtime is
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen older than time() - MAILDIR_SYNC_SECS.
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen new directory
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen -------------
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen If new/'s mtime is >= time() - MAILDIR_SYNC_SECS, always synchronize
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen it. dirty_cur_time-like feature might save us a few syncs, but
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen that might break a client which saves a mail in one connection and
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen tries to fetch it in another one. new/ directory is almost always
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen empty, so syncing it should be very fast anyway. Actually this can
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen still happen if we sync only new/ dir while another client is also
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen moving mails from it to cur/ - it takes us a while to see them.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen That's pretty unlikely to happen however, and only way to fix it
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen would be to always synchronize cur/ after new/.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen Normally we move all mails from new/ to cur/ whenever we sync it. If
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen it's not possible for some reason, we mark the mail with "probably
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen exists in new/ directory" flag.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen If rename() still fails because of ENOSPC or EDQUOT, we still save
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen the flag changes in index with dirty-flag on. When moving the mail
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen to cur/ directory, or when we notice it's already moved there, we
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen apply the flag changes to the filename, rename it and remove the
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen dirty flag. If there's dirty flags, this should be tried every time
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen after expunge or when closing the mailbox.
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen This file contains UID <-> filename mappings. It's updated only when
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen new mail arrives, so it may contain filenames that have already been
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen deleted. Updating is done by getting uidlist.lock file, writing the
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen whole uidlist into it and rename()ing it over the old uidlist. This
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen means there's no need to lock the file for reading.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen Whenever uidlist is rewritten, it's mtime must be larger than the old
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen one's. Use utime() before rename() if needed. Note that inode checking
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen wouldn't have been sufficient as inode numbers can be reused.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen This file is usually read the first time you need to know filename for
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen given UID. After that it's not re-read unless new mails come that we
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen don't know about.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen broken clients
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen --------------
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen Originally the middle identifier in Maildir filename was specified
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen only as <process id>_<delivery counter>. That however created a
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen problem with randomized PIDs which made it possible that the same
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen PID was reused within one second.
7f773564b94e6054a40d3785cb63c29f1e4d4deeTimo Sirainen So if within one second a mail was delivered, MUA moved it to cur/
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen and another mail was delivered by a new process using same PID as
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen the first one, we likely ended up overwriting the first mail when
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen the second mail was moved over it.
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen Nowadays everyone should be giving a bit more specific identifier,
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen for example include microseconds in it which Dovecot does.
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen There's a simple way to prevent this from happening in some cases:
dda2c506c8fc8ac2f88272de4523ded42baa0aa0Timo Sirainen Don't move the mail from new/ to cur/ if it's mtime is >= time() -
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen MAILDIR_SYNC_SECS. The second delivery's link() call then fails
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen because the file is already in new/, and it will then use a
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen different filename. There's a few problems with this however:
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen - it requires extra stat() call which is unneeded extra I/O
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen - another MUA might still move the mail to cur/
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen - if first file's flags are modified by either Dovecot or another
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MUA, it's moved to cur/ (you _could_ just do the dirty-flagging
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen but that'd be ugly)
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen Because this is useful only for very few people and it requires
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen extra I/O, I decided not to implement this. It should be however
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen quite easy to do since we need to be able to deal with files in new/
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen It's also possible to never accidentally overwrite a mail by using
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen link() + unlink() rather than rename(). This however isn't very
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen good idea as it introduces potential race conditions when multiple
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen clients are accessing the mailbox:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Trying to move the same mail from new/ to cur/ at the same time:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen a) Client 1 uses slightly different filename than client 2,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for example one sets read-flag on but the other doesn't.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen You have the same mail duplicated now.
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen b) Client 3 sees the mail between Client 1's and 2's link() calls
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen and changes it's flag. You have the same mail duplicated now.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen And it gets worse when they're unlink()ing in cur/ directory:
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen c) Client 1 changes mails's flag and client 2 changes it back
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen between 1's link() and unlink(). The mail is now expunged.
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen d) If you try to deal with the duplicates by unlink()ing another
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen one of them, you might end up unlinking both of them.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen So, what should we do then if we notice a duplicate? First of all,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it might not be a duplicate at all, readdir() might have just
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen returned it twice because it was just renamed. What we should do is
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen create a completely new base name for it and rename() it to that.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen If the call fails with ENOENT, it only means that it wasn't a
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen duplicate after all.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen/* When rename()ing many files from new/ to cur/, it's possible that next
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen readdir() skips some files. we don't of course wish to lose them, so we
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen go and rescan the new/ directory again from beginning until no files are
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen left. This value is just an optimization to avoid checking the directory
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen twice unneededly. usually only NFS is the problem case. 1 is the safest
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bet here, but I guess 5 will do just fine too. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen/* This is mostly to avoid infinite looping when rename() destination already
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen exists as the hard link of the file itself. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen struct maildir_index_sync_context *index_sync_ctx;
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenvoid maildir_sync_notify(struct maildir_sync_context *ctx)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen /* we got here from maildir-save.c. it has no
325f4573edfa5b751832ac01023f3e81be992bf0Timo Sirainen maildir_sync_context, */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (now - ctx->last_touch > MAILDIR_LOCK_TOUCH_SECS && ctx->locked) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen (void)maildir_uidlist_lock_touch(ctx->mbox->uidlist);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (now - ctx->last_notify > MAIL_STORAGE_STAYALIVE_SECS) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (box->storage->callbacks.notify_ok != NULL) {
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainenmaildir_sync_context_new(struct maildir_mailbox *mbox,
a60c1c1fca85402e6fccbf3ae0784b7179ae186cTimo Sirainen ctx->new_dir = t_strconcat(mbox->ibox.box.path, "/new", NULL);
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen ctx->cur_dir = t_strconcat(mbox->ibox.box.path, "/cur", NULL);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainenstatic void maildir_sync_deinit(struct maildir_sync_context *ctx)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (void)maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_sync_index_rollback(&ctx->index_sync_ctx);
39775ad03c459efe64cce924658da5094ba417e1Timo Sirainenstatic int maildir_fix_duplicate(struct maildir_sync_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fname1 = maildir_uidlist_sync_get_full_filename(ctx->uidlist_sync_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (stat(path1, &st1) < 0 || stat(path2, &st2) < 0) {
08fa343b3aace9343da3195686c65c5326eda207Timo Sirainen /* most likely the files just don't exist anymore.
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen don't really care about other errors much. */
dc049c5e83d947aaf1b97c26ae819cc9577e0475Timo Sirainen /* Files are the same. this means either a race condition
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen between stat() calls, or that the files were link()ed. */
6843896c40bee4f9b6680ca7ced598c446e9f999Timo Sirainen if (st1.st_nlink > 1 && st2.st_nlink == st1.st_nlink &&
33ae95df45c9b5ec51332a6b39eb5322038686b9Timo Sirainen st1.st_ctime < ioloop_time - DUPE_LINKS_DELETE_SECS) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* The file has hard links and it hasn't had any
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen changes (such as renames) for a while, so this
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen isn't a race condition.
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen rename()ing one file on top of the other would fix
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen this safely, except POSIX decided that rename()
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen doesn't work that way. So we'll have unlink() one
d0d7fcf3ce44f26fdf34c1542a25cec644c5c4c7Timo Sirainen and hope that another process didn't just decide to
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen unlink() the other (uidlist lock prevents this from
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen happening) */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen new_path = t_strconcat(ctx->mbox->ibox.box.path, "/new/",
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen i_warning("Fixed a duplicate: %s -> %s", path2, new_fname);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen mail_storage_set_critical(&ctx->mbox->storage->storage,
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen "Couldn't fix a duplicate: rename(%s, %s) failed: %m",
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)
#ifdef __APPLE__
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)
} else if (*new_changed_r) {
const char *fname;
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)
if (ret == 0)
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;