maildir-uidlist.c revision 6af9d209ee997d624aecbaf4a0bcd0ca7d60c31a
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde/* Copyright (c) 2003-2010 Dovecot authors, see the included COPYING file */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen Version 1 format has been used for most versions of Dovecot up to v1.0.x.
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde It's also compatible with Courier IMAP's courierimapuiddb file.
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde The format is:
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde header: 1 <uid validity> <next uid>
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde entry: <uid> <filename>
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde Version 2 format was written by a few development Dovecot versions, but
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde v1.0.x still parses the format. The format has <flags> field after <uid>.
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen Version 3 format is an extensible format used by Dovecot v1.1 and later.
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen It's also parsed by v1.0.2 (and later). The format is:
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde header: 3 [<key><value> ...]
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen entry: <uid> [<key><value> ...] :<filename>
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen See enum maildir_uidlist_*_ext_key for used keys.
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde/* NFS: How many times to retry reading dovecot-uidlist file if ESTALE
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen error occurs in the middle of reading it */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#define UIDLIST_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde (UIDLIST_IS_LOCKED(uidlist) || (uidlist)->mbox == NULL)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde unsigned char *extensions; /* <data>\0[<data>\0 ...]\0 */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo SirainenARRAY_DEFINE_TYPE(maildir_uidlist_rec_p, struct maildir_uidlist_rec *);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int version;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int uid_validity, next_uid, prev_read_uid, last_seen_uid;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int read_records_count, read_line_count;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int first_unwritten_pos, first_new_pos;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct maildir_uidlist_rec *const *next, *const *end;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic int maildir_uidlist_open_latest(struct maildir_uidlist *uidlist);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool maildir_uidlist_iter_next_rec(struct maildir_uidlist_iter_ctx *ctx,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic int maildir_uidlist_lock_timeout(struct maildir_uidlist *uidlist,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde const enum dotlock_create_flags dotlock_flags =
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (!uidlist->locked_refresh && refresh_when_locked) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde index_storage_lock_notify_reset(&uidlist->mbox->box);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde control_dir = mailbox_list_get_path(box->list, box->name,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen path = t_strconcat(control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde for (i = 0;; i++) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde old_mask = umask(0777 & ~box->file_create_mode);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde ret = file_dotlock_create(&uidlist->dotlock_settings, path,
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* failure */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT ||
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen eacces_error_get_creating("file_dotlock_create", path));
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen "file_dotlock_create(%s) failed: %m",
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* the control dir doesn't exist. create it unless the whole
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mailbox was just deleted. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (!maildir_set_deleted(&uidlist->mbox->box))
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* make sure we have the latest changes before
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen changing anything */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenint maildir_uidlist_lock(struct maildir_uidlist *uidlist)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return maildir_uidlist_lock_timeout(uidlist, FALSE, TRUE, FALSE);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wildeint maildir_uidlist_try_lock(struct maildir_uidlist *uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return maildir_uidlist_lock_timeout(uidlist, TRUE, TRUE, FALSE);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenint maildir_uidlist_lock_touch(struct maildir_uidlist *uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenbool maildir_uidlist_is_locked(struct maildir_uidlist *uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenbool maildir_uidlist_is_read(struct maildir_uidlist *uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenvoid maildir_uidlist_unlock(struct maildir_uidlist *uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstruct maildir_uidlist *maildir_uidlist_init(struct maildir_mailbox *mbox)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen control_dir = mailbox_list_get_path(mbox->box.list, mbox->box.name,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uidlist->path = i_strconcat(control_dir, "/"MAILDIR_UIDLIST_NAME, NULL);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uidlist->files = hash_table_create(default_pool, default_pool, 4096,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uidlist->hdr_extensions = str_new(default_pool, 128);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uidlist->dotlock_settings.use_io_notify = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen mail_storage_get_lock_timeout(&mbox->storage->storage,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uidlist->dotlock_settings.callback = dotlock_callback;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uidlist->dotlock_settings.context = &mbox->box;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen uidlist->dotlock_settings.temp_prefix = mbox->storage->temp_prefix;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic void maildir_uidlist_close(struct maildir_uidlist *uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct mail_storage *storage = uidlist->mbox->box.storage;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic void maildir_uidlist_reset(struct maildir_uidlist *uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenvoid maildir_uidlist_deinit(struct maildir_uidlist **_uidlist)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic int maildir_uid_cmp(struct maildir_uidlist_rec *const *rec1,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenmaildir_uidlist_set_corrupted(struct maildir_uidlist *uidlist,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *fmt, ...)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct mail_storage *storage = uidlist->mbox->box.storage;
return idx;
const char **line_p,
line++;
return FALSE;
return TRUE;
const char *line)
unsigned int count;
uid = 0;
line++;
line);
return FALSE;
return FALSE;
return FALSE;
return TRUE;
return FALSE;
bool ret;
T_BEGIN {
rec);
} T_END;
if (!ret) {
return FALSE;
return FALSE;
return TRUE;
return FALSE;
return TRUE;
const char *line,
unsigned int *uid_validity_r,
unsigned int *next_uid_r)
char key;
const char *value;
switch (key) {
const char *line;
int ret;
case UIDLIST_VERSION:
T_BEGIN {
&next_uid);
} T_END;
if (ret < 0)
const char *line;
last_read_offset = 0;
if (ret > 0) {
ret = 0;
orig_uid_validity != 0) {
if (ret == 0) {
} else if (ret > 0) {
} else if (!*retry_r) {
if (ret <= 0) {
return ret;
int ret;
bool recreated;
int ret;
if (ret <= 0) {
if (!recreated)
bool retry;
int ret;
if (!retry)
if (ret >= 0) {
return ret;
int ret;
return ret;
const char **fname_r)
int ret;
if (ret <= 0) {
if (ret < 0)
return ret;
const char **fname_r)
int ret;
return ret;
int ret;
return NULL;
if (*p == (unsigned char)key)
return NULL;
const char *value)
unsigned int len;
if (*p != (unsigned char)key)
p += len;
const char *value)
int ret;
if (ret <= 0) {
if (ret < 0)
T_BEGIN {
} T_END;
const char *strp;
unsigned int len;
int ret;
if (ret < 0) {
unsigned int i, count;
seq++;
seq++; i++;
for (; i < count; i++)
if (ret == 0) {
if (ret < 0) {
if (ret < 0)
return ret;
int ret;
return ret;
unsigned int min_rewrite_count;
return FALSE;
return TRUE;
return FALSE;
return TRUE;
return TRUE;
bool nonsynced)
unsigned int i, count;
if (nonsynced) {
for (i = 0; i < count; i++)
for (i = 0; i < count; i++)
bool *locked_r)
int ret;
if (ret <= 0) {
return ret;
bool locked;
int ret;
if (ret <= 0)
return ret;
unsigned int count;
if (uid != 0) {
unsigned char *ret;
return NULL;
T_BEGIN {
unsigned int len;
} T_END;
return ret;
const char *filename,
const char *p, *dir;
MAILDIR_UIDLIST_REC_FLAG_MOVED)) == 0) {
if (uid != 0) {
const char *filename)
unsigned int idx;
const char *value)
const char *filename)
return FALSE;
return TRUE;
const char *filename)
T_BEGIN {
} T_END;
bool success)
int ret;
if (!success)
return ret;
const char *filename,
struct maildir_uidlist_iter_ctx *
unsigned int count;
return ctx;
idx++;
idx--;
return FALSE;
return TRUE;
const char **filename_r)
return FALSE;
return TRUE;