maildir-uidlist.c revision 894fa3dbc0a4874b2700088bd30fbc161f4f4ce6
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
abc834c020080fe44a1ea4e34278327e99e3e12eEugen Kuksa Version 1 format has been used for most versions of Dovecot up to v1.0.x.
abc834c020080fe44a1ea4e34278327e99e3e12eEugen Kuksa It's also compatible with Courier IMAP's courierimapuiddb file.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa The format is:
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa header: 1 <uid validity> <next uid>
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa entry: <uid> <filename>
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa Version 2 format was written by a few development Dovecot versions, but
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa v1.0.x still parses the format. The format has <flags> field after <uid>.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa Version 3 format is an extensible format used by Dovecot v1.1 and later.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa It's also parsed by v1.0.2 (and later). The format is:
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa header: 3 [<key><value> ...]
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa entry: <uid> [<key><value> ...] :<filename>
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa See enum maildir_uidlist_*_ext_key for used keys.
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa/* NFS: How many times to retry reading dovecot-uidlist file if ESTALE
b1fe9054ad7c7192fe4c474363247dad15963e99Eugen Kuksa error occurs in the middle of reading it */
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa#define UIDLIST_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT
d89f470f7da0b9f8295d0ac0defff09884894b8bEugen Kuksa/* how many seconds to wait before overriding uidlist.lock */
67daeb8066e4460cb820db60c45138dd48309bb9Eugen Kuksa unsigned char *extensions; /* <data>\0[<data>\0 ...]\0 */
daf3e28fff47a65b53d6fb65155301763b9f166eEugen KuksaARRAY_DEFINE_TYPE(maildir_uidlist_rec_p, struct maildir_uidlist_rec *);
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa unsigned int version;
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa unsigned int uid_validity, next_uid, prev_read_uid, last_seen_uid;
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa unsigned int read_records_count, read_line_count;
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa unsigned int first_unwritten_pos, first_nouid_pos;
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa struct maildir_uidlist_rec *const *next, *const *end;
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksastatic bool maildir_uidlist_iter_next_rec(struct maildir_uidlist_iter_ctx *ctx,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksastatic int maildir_uidlist_lock_timeout(struct maildir_uidlist *uidlist,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa control_dir = mailbox_list_get_path(box->storage->list, box->name,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa path = t_strconcat(control_dir, "/" MAILDIR_UIDLIST_NAME, NULL);
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa for (i = 0;; i++) {
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa old_mask = umask(0777 & ~box->file_create_mode);
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa ret = file_dotlock_create(&uidlist->dotlock_settings, path,
f9e467b8fe6fef705eec2989b20e92eaa9d917e1Eugen Kuksa /* failure */
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT ||
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa /* the control dir doesn't exist. create it unless the whole
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa mailbox was just deleted. */
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa /* make sure we have the latest changes before changing anything */
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksaint maildir_uidlist_lock(struct maildir_uidlist *uidlist)
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa return maildir_uidlist_lock_timeout(uidlist, FALSE);
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksaint maildir_uidlist_try_lock(struct maildir_uidlist *uidlist)
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa return maildir_uidlist_lock_timeout(uidlist, TRUE);
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksaint maildir_uidlist_lock_touch(struct maildir_uidlist *uidlist)
284432981d641cf3d679841f75acbcf039d83062Eugen Kuksabool maildir_uidlist_is_locked(struct maildir_uidlist *uidlist)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksavoid maildir_uidlist_unlock(struct maildir_uidlist *uidlist)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksamaildir_uidlist_init_readonly(struct index_mailbox *ibox)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa control_dir = mailbox_list_get_path(box->storage->list, box->name,
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa uidlist->path = i_strconcat(control_dir, "/"MAILDIR_UIDLIST_NAME, NULL);
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa uidlist->files = hash_create(default_pool, default_pool, 4096,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa uidlist->hdr_extensions = str_new(default_pool, 128);
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa (box->storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa uidlist->dotlock_settings.timeout = UIDLIST_LOCK_STALE_TIMEOUT + 2;
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa uidlist->dotlock_settings.stale_timeout = UIDLIST_LOCK_STALE_TIMEOUT;
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksastruct maildir_uidlist *maildir_uidlist_init(struct maildir_mailbox *mbox)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa uidlist = maildir_uidlist_init_readonly(&mbox->ibox);
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa uidlist->dotlock_settings.temp_prefix = mbox->storage->temp_prefix;
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksastatic void maildir_uidlist_close(struct maildir_uidlist *uidlist)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksavoid maildir_uidlist_deinit(struct maildir_uidlist **_uidlist)
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksastatic int maildir_uid_cmp(const void *p1, const void *p2)
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa const struct maildir_uidlist_rec *const *rec1 = p1, *const *rec2 = p2;
0b99be5ced371cca00283694e1bd53a8ac0d7b5dEugen Kuksamaildir_uidlist_records_array_delete(struct maildir_uidlist *uidlist,
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa struct maildir_uidlist_rec *const *recs, *const *pos;
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa unsigned int count;
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa pos = bsearch(&rec, recs, count, sizeof(*recs), maildir_uid_cmp);
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksamaildir_uidlist_read_extended(struct maildir_uidlist *uidlist,
b1fe9054ad7c7192fe4c474363247dad15963e99Eugen Kuksa const char **line_p,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa buf = buffer_create_dynamic(pool_datastack_create(), 128);
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa /* skip over an extension field */
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa /* save the extensions */
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa rec->extensions = p_malloc(uidlist->record_pool, buf->used);
line++;
return FALSE;
return TRUE;
const char *fmt, ...)
const char *line)
uid = 0;
line++;
line);
bool ret;
T_BEGIN {
rec);
} T_END;
if (!ret) {
const char *line;
char key;
const char *value;
switch (key) {
} T_END;
const char *line;
unsigned int orig_next_uid;
last_read_offset = 0;
if (ret > 0) {
ret = 0;
if (ret == 0) {
} else if (ret > 0) {
if (ret <= 0) {
return ret;
int ret;
if (ret <= 0)
return ret;
if (recreated)
if (!retry)
if (ret >= 0)
return ret;
static struct maildir_uidlist_rec *
unsigned int *idx_r)
return NULL;
return NULL;
const char *fname;
return NULL;
return NULL;
return fname;
unsigned int idx;
return NULL;
unsigned int idx;
const char *value;
return NULL;
if (*p == (char)key)
return NULL;
const char *value)
unsigned int idx;
unsigned int len;
if (*p != (char)key)
p += len;
const char *value)
T_BEGIN {
} T_END;
unsigned int len;
int ret;
if (ret < 0) {
if (ret == 0) {
if (ret < 0) {
return ret;
int ret;
return ret;
bool nonsynced)
unsigned int i, count;
if (nonsynced) {
for (i = 0; i < count; i++)
for (i = 0; i < count; i++)
bool locked;
int ret;
return ret;
if (ret == 0) {
if (!locked) {
const char *filename,
unsigned char *ret;
return NULL;
T_BEGIN {
unsigned int len;
} T_END;
return ret;
const char *filename,
MAILDIR_UIDLIST_REC_FLAG_MOVED)) == 0) {
const char *filename)
const char *filename)
return FALSE;
return TRUE;
const char *filename)
unsigned int count;
T_BEGIN {
} T_END;
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;