maildir-util.c revision d4002fe1f64d25a792f76fb102ef7dc519cd4e24
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2004-2017 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen#include "mkdir-parents.h"
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen#include "mailbox-list-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-uidlist.h"
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen#include "maildir-keywords.h"
6fe91298731abf0b70dfd796ecc30d3be81fa5d1Timo Sirainen#include "maildir-filename-flags.h"
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen#include "maildir-sync.h"
436adac819e7cbeef04af08dcc6a4f3ecd4a1d9eMartti Rannanjärvi#include "mailbox-recent-flags.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen#include <stdio.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
73a552a9ed06cd6017ad4ee4b252a8b38c8ac42dTimo Sirainen#include <dirent.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <fcntl.h>
73a552a9ed06cd6017ad4ee4b252a8b38c8ac42dTimo Sirainen#include <utime.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7ccdf78cd45aea9d14e048a5b9f077515c71978fTimo Sirainen#define MAILDIR_RESYNC_RETRY_COUNT 10
7ccdf78cd45aea9d14e048a5b9f077515c71978fTimo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenstatic const char *
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainenmaildir_filename_guess(struct maildir_mailbox *mbox, uint32_t uid,
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen const char *fname,
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen enum maildir_uidlist_rec_flag *uidlist_flags,
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen bool *have_flags_r)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen{
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen struct mail_index_view *view = mbox->flags_view;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen struct maildir_keywords_sync_ctx *kw_ctx;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen enum mail_flags flags;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ARRAY_TYPE(keyword_indexes) keywords;
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen const char *p;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen uint32_t seq;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (view == NULL || !mail_index_lookup_seq(view, uid, &seq)) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen *have_flags_r = FALSE;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return fname;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen t_array_init(&keywords, 32);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen mail_index_lookup_view_flags(view, seq, &flags, &keywords);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (array_count(&keywords) == 0) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen *have_flags_r = (flags & MAIL_FLAGS_NONRECENT) != 0;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen fname = maildir_filename_flags_set(fname, flags);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen } else {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen *have_flags_r = TRUE;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen kw_ctx = maildir_keywords_sync_init_readonly(mbox->keywords,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mbox->box.index);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen fname = maildir_filename_flags_kw_set(kw_ctx, fname,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen flags, &keywords);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen maildir_keywords_sync_deinit(&kw_ctx);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen if (*have_flags_r) {
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 ||
817d027593510c3ba70ad542ce0011f5f6916d1eTimo Sirainen mailbox_recent_flags_have_uid(&mbox->box, uid))) {
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen /* probably in new/ dir, drop ":2," from fname */
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen *uidlist_flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen p = strrchr(fname, MAILDIR_INFO_SEP);
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen if (p != NULL)
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen fname = t_strdup_until(fname, p);
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen }
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return fname;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen}
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int maildir_file_do_try(struct maildir_mailbox *mbox, uint32_t uid,
00efa7d99981e18e286c02b18c1163dde18ee521Timo Sirainen maildir_file_do_func *callback, void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen const char *path, *fname;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen enum maildir_uidlist_rec_flag flags;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen bool have_flags;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6013fbad6638795a00e6c2a2dd2cdbee19612494Timo Sirainen ret = maildir_sync_lookup(mbox, uid, &flags, &fname);
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen if (ret <= 0)
7ede6554e451ec039a67beec7d6ee4aff61d386eTimo Sirainen return ret == 0 ? -2 : -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
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,
e0cc94d52184944c5da76b509da184e8449b3a5cTimo Sirainen &flags, &have_flags);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen }
1235bbd139a1ff97f641fa0e77205eb9adbb0400Timo Sirainen /* make a copy, just in case callback refreshes uidlist and
1235bbd139a1ff97f641fa0e77205eb9adbb0400Timo Sirainen the pointer becomes invalid. */
1235bbd139a1ff97f641fa0e77205eb9adbb0400Timo Sirainen fname = t_strdup(fname);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen ret = 0;
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 "/new/", fname, NULL);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = callback(mbox, path, context);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen if (ret == 0) {
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen path = t_strconcat(mailbox_get_path(&mbox->box), "/cur/",
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen fname, NULL);
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen ret = callback(mbox, path, context);
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen }
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen if (ret > 0 && (flags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen /* file was found. make sure we remember its latest name. */
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen maildir_uidlist_update_fname(mbox->uidlist, fname);
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen } else if (ret == 0 &&
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen (flags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) == 0) {
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen /* file wasn't found. mark this message nonsynced, so we can
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen retry the lookup by guessing the flags */
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen maildir_uidlist_add_flags(mbox->uidlist, fname,
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen MAILDIR_UIDLIST_REC_FLAG_NONSYNCED);
2bde8972f2dcec46d96543407cc5b56954054359Timo Sirainen }
2f2823ad8928654ed405467c6c1f4fd4c6f5cf7cTimo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainenstatic int do_racecheck(struct maildir_mailbox *mbox, const char *path,
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen void *context)
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen{
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen const uint32_t *uidp = context;
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen struct stat st;
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen int ret;
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen ret = lstat(path, &st);
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen if (ret == 0 && (st.st_mode & S_IFMT) == S_IFLNK) {
7fc0f80480063a9d4cb9e8c07b50db2a5627799eTimo Sirainen /* most likely a symlink pointing to a nonexistent file */
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&mbox->box,
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen "Maildir: Symlink destination doesn't exist for UID=%u: %s", *uidp, path);
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen return -2;
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen } else if (ret < 0 && errno != ENOENT) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&mbox->box, "lstat(%s) failed: %m", path);
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen return -1;
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen } else {
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen /* success or ENOENT, either way we're done */
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&mbox->box,
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen "maildir_file_do(%s): Filename keeps changing for UID=%u", path, *uidp);
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen return -1;
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen }
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen}
825f6569a5276488133796c2f529c65128a09ba0Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen#undef maildir_file_do
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint maildir_file_do(struct maildir_mailbox *mbox, uint32_t uid,
00efa7d99981e18e286c02b18c1163dde18ee521Timo Sirainen maildir_file_do_func *callback, void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int i, ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen T_BEGIN {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = maildir_file_do_try(mbox, uid, callback, context);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen } T_END;
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen if (ret == 0 && mbox->storage->set->maildir_very_dirty_syncs) T_BEGIN {
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen /* try guessing again with refreshed flags */
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen if (maildir_sync_refresh_flags_view(mbox) == 0)
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen ret = maildir_file_do_try(mbox, uid, callback, context);
a8c1d873ebe624cf65893d79e1a509203116cb9aTimo Sirainen } T_END;
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)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen T_BEGIN {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen ret = maildir_file_do_try(mbox, uid, callback, context);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen } T_END;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen if (i == MAILDIR_RESYNC_RETRY_COUNT) T_BEGIN {
b0ab23e6fd425bf864cdc9fdab0631573d4d1b5fTimo Sirainen ret = maildir_file_do_try(mbox, uid, do_racecheck, &uid);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen } T_END;
039e42997fe5e0d1c5ad9306dc0ae69bf0e1ca10Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret == -2 ? 0 : ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainenstatic int maildir_create_path(struct mailbox *box, const char *path,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mailbox_list_path_type type, bool retry)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen{
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const struct mailbox_permissions *perm = mailbox_get_permissions(box);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen const char *p, *parent;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (mkdir_chgrp(path, perm->dir_create_mode, perm->file_create_gid,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen perm->file_create_gid_origin) == 0)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return 0;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen switch (errno) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen case EEXIST:
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return 0;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen case ENOENT:
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen p = strrchr(path, '/');
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (type == MAILBOX_LIST_PATH_TYPE_MAILBOX ||
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen p == NULL || !retry) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* mailbox was being deleted just now */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen mailbox_set_deleted(box);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return -1;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen }
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* create index/control root directory */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen parent = t_strdup_until(path, p);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (mailbox_list_mkdir_root(box->list, parent, type) < 0) {
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen mail_storage_copy_list_error(box->storage, box->list);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen return -1;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen }
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* should work now, try again */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen return maildir_create_path(box, path, type, FALSE);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen default:
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "mkdir(%s) failed: %m", path);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return -1;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen }
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenstatic int maildir_create_subdirs(struct mailbox *box)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen{
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen static const char *subdirs[] = { "cur", "new", "tmp" };
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen const char *dirs[N_ELEMENTS(subdirs) + 2];
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen enum mailbox_list_path_type types[N_ELEMENTS(subdirs) + 2];
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen struct stat st;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen const char *path;
ce8244c05b9f89d7729a5abe6f4838c1dce46c64Timo Sirainen unsigned int i, count;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* @UNSAFE: get a list of directories we want to create */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen for (i = 0; i < N_ELEMENTS(subdirs); i++) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen types[i] = MAILBOX_LIST_PATH_TYPE_MAILBOX;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen dirs[i] = t_strconcat(mailbox_get_path(box),
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen "/", subdirs[i], NULL);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_CONTROL, &path) > 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen types[i] = MAILBOX_LIST_PATH_TYPE_CONTROL;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen dirs[i++] = path;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX, &path) > 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen types[i] = MAILBOX_LIST_PATH_TYPE_INDEX;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen dirs[i++] = path;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen }
ce8244c05b9f89d7729a5abe6f4838c1dce46c64Timo Sirainen count = i;
ce8244c05b9f89d7729a5abe6f4838c1dce46c64Timo Sirainen i_assert(count <= N_ELEMENTS(dirs));
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
ce8244c05b9f89d7729a5abe6f4838c1dce46c64Timo Sirainen for (i = 0; i < count; i++) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen path = dirs[i];
ce8244c05b9f89d7729a5abe6f4838c1dce46c64Timo Sirainen if (stat(path, &st) == 0)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen continue;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (errno != ENOENT) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "stat(%s) failed: %m", path);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (maildir_create_path(box, path, types[i], TRUE) < 0)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen break;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return i == N_ELEMENTS(dirs) ? 0 : -1;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen}
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenbool maildir_set_deleted(struct mailbox *box)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen{
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen struct stat st;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen int ret;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (stat(mailbox_get_path(box), &st) < 0) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (errno == ENOENT)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen mailbox_set_deleted(box);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen "stat(%s) failed: %m", mailbox_get_path(box));
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
6cfb1377b2c034cfc4bd37361cc1520f2d8acd6dTimo Sirainen return FALSE;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* maildir itself exists. create all of its subdirectories in case
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen they got lost. */
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen ret = maildir_create_subdirs(box);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
6cfb1377b2c034cfc4bd37361cc1520f2d8acd6dTimo Sirainen return ret < 0 ? FALSE : TRUE;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen}
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainenint maildir_lose_unexpected_dir(struct mail_storage *storage, const char *path)
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen{
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen const char *dest, *fname, *p;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen /* There's a directory in maildir, get rid of it.
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen
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 if (rmdir(path) == 0) {
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen mail_storage_set_critical(storage,
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: rmdir()ed unwanted empty directory: %s",
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen path);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen return 1;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen } else if (errno == ENOENT) {
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen /* someone else rmdired or renamed it */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen return 0;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen } else if (errno != ENOTEMPTY) {
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen mail_storage_set_critical(storage,
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: Found unwanted directory %s, "
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "but rmdir() failed: %m", path);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen return -1;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen }
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen
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 p = strrchr(path, '/');
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen i_assert(p != NULL);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen fname = p + 1;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen while (p != path && p[-1] != '/') p--;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen i_assert(p != NULL);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen dest = t_strconcat(t_strdup_until(path, p), "extra-", fname, NULL);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen if (rename(path, dest) == 0) {
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen mail_storage_set_critical(storage,
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: renamed unwanted directory %s to %s",
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen path, dest);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen return 1;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen } else if (errno == ENOENT) {
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen /* someone else renamed it (could have been flag change) */
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen return 0;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen } else {
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen mail_storage_set_critical(storage,
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "Maildir: Found unwanted directory, "
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen "but rename(%s, %s) failed: %m", path, dest);
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen return -1;
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen }
f6f021c133f680cf3d559187524fd9abcbaae9b9Timo Sirainen}