maildir-util.c revision e0cc94d52184944c5da76b509da184e8449b3a5c
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2004-2011 Dovecot authors, see the included COPYING file */
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenstatic const char *
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenmaildir_filename_guess(struct maildir_mailbox *mbox, uint32_t uid,
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen struct mail_index_view *view = mbox->flags_view;
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen const char *p;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (view == NULL || !mail_index_lookup_seq(view, uid, &seq)) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen mail_index_lookup_view_flags(view, seq, &flags, &keywords);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen *have_flags_r = (flags & MAIL_FLAGS_NONRECENT) != 0;
6fe91298731abf0b70dfd796ecc30d3be81fa5d1Timo Sirainen fname = maildir_filename_flags_set(NULL, fname, flags, NULL);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen kw_ctx = maildir_keywords_sync_init_readonly(mbox->keywords,
6fe91298731abf0b70dfd796ecc30d3be81fa5d1Timo Sirainen fname = maildir_filename_flags_set(kw_ctx, fname,
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen /* don't even bother looking into new/ dir */
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen *uidlist_flags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen } else if ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_MOVED) == 0 &&
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen ((*uidlist_flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 ||
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen /* probably in new/ dir, drop ":2," from fname */
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen *uidlist_flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int maildir_file_do_try(struct maildir_mailbox *mbox, uint32_t uid,
00efa7d99981e18e286c02b18c1163dde18ee521Timo Sirainen maildir_file_do_func *callback, void *context)
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen ret = maildir_sync_lookup(mbox, uid, &flags, &fname);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if ((flags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen /* let's see if we can guess the filename based on index */
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen fname = maildir_filename_guess(mbox, uid, fname,
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if ((flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* probably in new/ dir */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen path = t_strconcat(mailbox_get_path(&mbox->box),
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen path = t_strconcat(mailbox_get_path(&mbox->box), "/cur/", fname, NULL);
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainenstatic int do_racecheck(struct maildir_mailbox *mbox, const char *path,
42eaa08044fbb134cdc7b342355d8f6772f647fbTimo Sirainen if (lstat(path, &st) == 0 && (st.st_mode & S_IFMT) == S_IFLNK) {
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen /* most likely a symlink pointing to a nonexistent file */
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen "Maildir: Symlink destination doesn't exist: %s", path);
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen "maildir_file_do(%s): Filename keeps changing", path);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint maildir_file_do(struct maildir_mailbox *mbox, uint32_t uid,
00efa7d99981e18e286c02b18c1163dde18ee521Timo Sirainen maildir_file_do_func *callback, void *context)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = maildir_file_do_try(mbox, uid, callback, context);
7ccdf78cd45aea9d14e048a5b9f077515c71978fTimo Sirainen for (i = 0; i < MAILDIR_RESYNC_RETRY_COUNT && ret == 0; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* file is either renamed or deleted. sync the maildir and
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen see which one. if file appears to be renamed constantly,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen don't try to open it more than 10 times. */
f7ad1162969feff6b08f0e640a928db1783daae9Timo Sirainen if (maildir_storage_sync_force(mbox, uid) < 0)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = maildir_file_do_try(mbox, uid, callback, context);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (i == MAILDIR_RESYNC_RETRY_COUNT) T_BEGIN {
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen ret = maildir_file_do_try(mbox, uid, do_racecheck, context);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainenstatic int maildir_create_path(struct mailbox *box, const char *path,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const struct mailbox_permissions *perm = mailbox_get_permissions(box);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *p, *parent;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (mkdir_chgrp(path, perm->dir_create_mode, perm->file_create_gid,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* mailbox was being deleted just now */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* create index/control root directory */
be110f0a3888a24282f06820ec0b5068d2b8f906Timo Sirainen if (mailbox_list_mkdir_root(box->list, parent, type) == 0) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* should work now, try again */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return maildir_create_path(box, path, type, FALSE);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* fall through */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic int maildir_create_subdirs(struct mailbox *box)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen static const char *subdirs[] = { "cur", "new", "tmp" };
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mailbox_list_path_type types[N_ELEMENTS(subdirs) + 2];
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen unsigned int i;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* @UNSAFE: get a list of directories we want to create */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dirs[i++] = mailbox_list_get_path(box->list, box->name,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen dirs[i++] = mailbox_list_get_path(box->list, box->name,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (maildir_create_path(box, path, types[i], TRUE) < 0)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen "stat(%s) failed: %m", mailbox_get_path(box));
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* maildir itself exists. create all of its subdirectories in case
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen they got lost. */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainenint maildir_lose_unexpected_dir(struct mail_storage *storage, const char *path)
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen /* There's a directory in maildir, get rid of it.
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen In some installations this was caused by a messed up configuration
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen where e.g. mails was initially delivered to new/new/ directory.
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen Also Dovecot v2.0.0 - v2.0.4 sometimes may have renamed tmp/
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen directory under new/ or cur/. */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: rmdir()ed unwanted empty directory: %s",
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen /* someone else rmdired or renamed it */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: Found unwanted directory %s, "
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen /* It's not safe to delete this directory since it has some files in it,
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen but it's also not helpful to log this message over and over again.
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen Get rid of this error by renaming the directory elsewhere */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen dest = t_strconcat(t_strdup_until(path, p), "extra-", fname, NULL);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: renamed unwanted directory %s to %s",
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen /* someone else renamed it (could have been flag change) */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: Found unwanted directory, "