bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
dfa2201c6ac8ddb2d2798dee15662cfe774e644eMartti Rannanjärvi#include "path-util.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ioloop.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "fs-api.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mkdir-parents.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "unlink-old-files.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-uidvalidity.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-list-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "index-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "dbox-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdio.h>
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen#include <dirent.h>
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen#include <unistd.h>
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen#include <utime.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid dbox_storage_get_list_settings(const struct mail_namespace *ns ATTR_UNUSED,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_list_settings *set)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (set->layout == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set->layout = MAILBOX_LIST_NAME_FS;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (set->subscription_fname == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set->subscription_fname = DBOX_SUBSCRIPTION_FILE_NAME;
63e207529879438e9f4412d97cdc34bdc82a3702Timo Sirainen if (*set->maildir_name == '\0')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set->maildir_name = DBOX_MAILDIR_NAME;
63e207529879438e9f4412d97cdc34bdc82a3702Timo Sirainen if (*set->mailbox_dir_name == '\0')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen set->mailbox_dir_name = DBOX_MAILBOX_DIR_NAME;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainenstatic bool
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainendbox_alt_path_has_changed(const char *root_dir, const char *alt_path,
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen const char *alt_path2, const char *alt_symlink_path)
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen{
dd645357a6b851a3a9527d16e2bced731e46dcaaMartti Rannanjärvi const char *linkpath, *error;
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen
dd645357a6b851a3a9527d16e2bced731e46dcaaMartti Rannanjärvi if (t_readlink(alt_symlink_path, &linkpath, &error) < 0) {
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen if (errno == ENOENT)
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen return alt_path != NULL;
dd645357a6b851a3a9527d16e2bced731e46dcaaMartti Rannanjärvi i_error("t_readlink(%s) failed: %s", alt_symlink_path, error);
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen return FALSE;
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen }
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen if (alt_path == NULL) {
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen i_warning("dbox %s: Original ALT=%s, "
afc8d11e88b1e5f4b6833fabaf8e4259e8297314Timo Sirainen "but currently no ALT path set", root_dir, linkpath);
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen return TRUE;
afc8d11e88b1e5f4b6833fabaf8e4259e8297314Timo Sirainen } else if (strcmp(linkpath, alt_path) != 0) {
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen if (strcmp(linkpath, alt_path2) == 0) {
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen /* FIXME: for backwards compatibility. old versions
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen created the symlink to mailboxes/ directory, which
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen was fine with sdbox, but didn't even exist with
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen mdbox. we'll silently replace the symlink. */
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen return TRUE;
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen }
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen i_warning("dbox %s: Original ALT=%s, "
afc8d11e88b1e5f4b6833fabaf8e4259e8297314Timo Sirainen "but currently ALT=%s", root_dir, linkpath, alt_path);
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen return TRUE;
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen }
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen return FALSE;
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen}
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainenstatic void dbox_verify_alt_path(struct mailbox_list *list)
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen{
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen const char *root_dir, *alt_symlink_path, *alt_path, *alt_path2;
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen root_dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_DIR);
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen alt_symlink_path =
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen t_strconcat(root_dir, "/"DBOX_ALT_SYMLINK_NAME, NULL);
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen (void)mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_ALT_DIR,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &alt_path);
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen (void)mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX,
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen &alt_path2);
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen if (!dbox_alt_path_has_changed(root_dir, alt_path, alt_path2,
9345a14605e87c749048d37965d5c92caaab2ee9Timo Sirainen alt_symlink_path))
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen return;
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen /* unlink/create the current alt path symlink */
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen i_unlink_if_exists(alt_symlink_path);
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen if (alt_path != NULL) {
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen int ret = symlink(alt_path, alt_symlink_path);
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen if (ret < 0 && errno == ENOENT) {
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen /* root_dir doesn't exist yet - create it */
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen if (mailbox_list_mkdir_root(list, root_dir,
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen MAILBOX_LIST_PATH_TYPE_DIR) < 0)
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen return;
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen ret = symlink(alt_path, alt_symlink_path);
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen }
11d4b189a3d98628828228e605fea1f91c689b05Timo Sirainen if (ret < 0 && errno != EEXIST) {
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen i_error("symlink(%s, %s) failed: %m",
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen alt_path, alt_symlink_path);
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen }
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen }
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen}
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint dbox_storage_create(struct mail_storage *_storage,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mail_namespace *ns,
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const char **error_r)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek struct dbox_storage *storage = DBOX_STORAGE(_storage);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const struct mail_storage_settings *set = _storage->set;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const char *error;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
84af637240881b8c1cc4df472832f49de952e4c6Timo Sirainen if (*set->mail_attachment_fs != '\0' &&
84af637240881b8c1cc4df472832f49de952e4c6Timo Sirainen *set->mail_attachment_dir != '\0') {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *name, *args, *dir;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
f504be57bf0a77b1ad055322c4aa936606fc6e4dTimo Sirainen args = strpbrk(set->mail_attachment_fs, ": ");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (args == NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen name = set->mail_attachment_fs;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen args = "";
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen name = t_strdup_until(set->mail_attachment_fs, args++);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen if (strcmp(name, "sis-queue") == 0 &&
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen (_storage->class_flags & MAIL_STORAGE_CLASS_FLAG_FILE_PER_MSG) != 0) {
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen /* FIXME: the deduplication part doesn't work, because
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen sdbox renames the files.. */
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen *error_r = "mail_attachment_fs: "
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen "sis-queue not currently supported by sdbox";
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen return -1;
abceedfdab26c07b48b7156298187a204e24fafaTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dir = mail_user_home_expand(_storage->user,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen set->mail_attachment_dir);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen storage->attachment_dir = p_strdup(_storage->pool, dir);
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen if (mailbox_list_init_fs(ns->list, name, args,
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen storage->attachment_dir,
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen &storage->attachment_fs, &error) < 0) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen *error_r = t_strdup_printf("mail_attachment_fs: %s",
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen error);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
1fb81cb0b622cef1690c96bcc6a3e183e0b1e6ffTimo Sirainen
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen if (!ns->list->set.alt_dir_nocheck)
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen dbox_verify_alt_path(ns->list);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return 0;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid dbox_storage_destroy(struct mail_storage *_storage)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek struct dbox_storage *storage = DBOX_STORAGE(_storage);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (storage->attachment_fs != NULL)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen fs_deinit(&storage->attachment_fs);
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainen index_storage_destroy(_storage);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenuint32_t dbox_get_uidvalidity_next(struct mailbox_list *list)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen path = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_CONTROL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen path = t_strconcat(path, "/"DBOX_UIDVALIDITY_FILE_NAME, NULL);
a920bbb8580be2446af28a77dac9ecf548f3c6f4Timo Sirainen return mailbox_uidvalidity_next(list, path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid dbox_notify_changes(struct mailbox *box)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
f35e836d33ee83899caded9dffb9c68bfed9c843Timo Sirainen const char *dir, *path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (box->notify_callback == NULL)
7e2671b295927b461adc8b6c4ed6a1c4761fb323Timo Sirainen mailbox_watch_remove_all(box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &dir) <= 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return;
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen path = t_strdup_printf("%s/"MAIL_INDEX_PREFIX".log", dir);
7e2671b295927b461adc8b6c4ed6a1c4761fb323Timo Sirainen mailbox_watch_add(box, path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainenstatic bool
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainendbox_cleanup_temp_files(struct mailbox_list *list, const char *path,
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen time_t last_scan_time, time_t last_change_time)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
68b5e132f1f8bb2528482310daffcc06c2f019d3Timo Sirainen unsigned int interval = list->mail_set->mail_temp_scan_interval;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* check once in a while if there are temp files to clean up */
68b5e132f1f8bb2528482310daffcc06c2f019d3Timo Sirainen if (interval == 0) {
68b5e132f1f8bb2528482310daffcc06c2f019d3Timo Sirainen /* disabled */
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen return FALSE;
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen } else if (last_scan_time >= ioloop_time - (time_t)interval) {
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen /* not the time to scan it yet */
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen return FALSE;
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen } else {
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen bool stated = FALSE;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (last_change_time == (time_t)-1) {
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen /* Don't know the ctime yet - look it up. */
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen struct stat st;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (stat(path, &st) < 0) {
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (errno == ENOENT)
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen i_error("stat(%s) failed: %m", path);
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen return FALSE;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen }
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen last_change_time = st.st_ctime;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen stated = TRUE;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen }
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen if (last_scan_time > last_change_time + DBOX_TMP_DELETE_SECS) {
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen /* there haven't been any changes to this directory
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen since we last checked it. If we did an extra stat(),
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen we need to update the last_scan_time to avoid
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen stat()ing the next time. */
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen return stated;
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *prefix =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_list_get_global_temp_prefix(list);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)unlink_old_files(path, prefix,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ioloop_time - DBOX_TMP_DELETE_SECS);
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainenint dbox_mailbox_check_existence(struct mailbox *box, time_t *path_ctime_r)
888ab4e17f7441b4dcca4a01886d055b57f4586dTimo Sirainen{
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen const char *index_path, *box_path = mailbox_get_path(box);
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen struct stat st;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen int ret = -1;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen *path_ctime_r = (time_t)-1;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (box->list->set.iter_from_index_dir) {
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen /* Just because the index directory exists, it doesn't mean
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen that the mailbox is selectable. Check that by seeing if
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen dovecot.index.log exists. If it doesn't, fallback to
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen checking for the dbox-Mails in the mail root directory.
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen So this also means that if a mailbox is \NoSelect, listing
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen it will always do a stat() for dbox-Mails in the mail root
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen directory. That's not ideal, but this makes the behavior
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen safer and \NoSelect mailboxes are somewhat rare. */
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX,
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen &index_path) < 0)
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen return -1;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen i_assert(index_path != NULL);
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen index_path = t_strconcat(index_path, "/", box->index_prefix,
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen ".log", NULL);
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen ret = stat(index_path, &st);
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen }
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (ret < 0) {
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen ret = stat(box_path, &st);
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (ret == 0)
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen *path_ctime_r = st.st_ctime;
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
265ca08926833c86de4311164ed031e5f5b42fcdTimo Sirainen if (ret == 0) {
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen return 0;
c5e2aa3148bc73f766c4a3a435c9dac2b45133e7Timo Sirainen } else if (errno == ENOENT || errno == ENAMETOOLONG) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainen T_MAIL_ERR_MAILBOX_NOT_FOUND(box->vname));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (errno == EACCES) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "%s",
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen mail_error_eacces_msg("stat", box_path));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "stat(%s) failed: %m", box_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
50bf6cfe2aa6111fb38af37970f9551b2286638cTimo Sirainen}
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainenint dbox_mailbox_open(struct mailbox *box, time_t path_ctime)
50bf6cfe2aa6111fb38af37970f9551b2286638cTimo Sirainen{
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen const char *box_path = mailbox_get_path(box);
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen if (index_storage_mailbox_open(box, FALSE) < 0)
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen return -1;
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen mail_index_set_fsync_mode(box->index,
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen box->storage->set->parsed_fsync_mode,
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen MAIL_INDEX_FSYNC_MASK_APPENDS |
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen MAIL_INDEX_FSYNC_MASK_EXPUNGES);
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen const struct mail_index_header *hdr = mail_index_get_header(box->view);
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen if (dbox_cleanup_temp_files(box->list, box_path,
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen hdr->last_temp_file_scan, path_ctime)) {
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen /* temp files were scanned. update the last scan timestamp. */
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen index_mailbox_update_last_temp_file_scan(box);
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen }
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainenstatic int dir_is_empty(struct mail_storage *storage, const char *path)
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen{
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen DIR *dir;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen struct dirent *d;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen int ret = 1;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen dir = opendir(path);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen if (dir == NULL) {
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen if (errno == ENOENT) {
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen /* race condition with DELETE/RENAME? */
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen return 1;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen }
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen mail_storage_set_critical(storage, "opendir(%s) failed: %m",
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen path);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen return -1;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen }
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen while ((d = readdir(dir)) != NULL) {
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen if (*d->d_name == '.')
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen continue;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen ret = 0;
7bb3cf9215277fb997cbdce9e39056a4ac2b9536Timo Sirainen break;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen }
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen if (closedir(dir) < 0) {
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen mail_storage_set_critical(storage, "closedir(%s) failed: %m",
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen path);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen ret = -1;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen }
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen return ret;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen}
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint dbox_mailbox_create(struct mailbox *box,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mailbox_update *update, bool directory)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek struct dbox_storage *storage = DBOX_STORAGE(box->storage);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen const char *alt_path;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen struct stat st;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen int ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
3d6fdafca17c073606b63745ca8638e035e871f4Timo Sirainen if ((ret = index_storage_mailbox_create(box, directory)) <= 0)
3d6fdafca17c073606b63745ca8638e035e871f4Timo Sirainen return ret;
84e49ad7d7a840d600a961daeca60802e3d69cd0Timo Sirainen if (mailbox_open(box) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen
f3ef965d5c79680b63ceb172af60a82013c9a8d6Timo Sirainen if (mail_index_get_header(box->view)->uid_validity != 0) {
f3ef965d5c79680b63ceb172af60a82013c9a8d6Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
f3ef965d5c79680b63ceb172af60a82013c9a8d6Timo Sirainen "Mailbox already exists");
f3ef965d5c79680b63ceb172af60a82013c9a8d6Timo Sirainen return -1;
f3ef965d5c79680b63ceb172af60a82013c9a8d6Timo Sirainen }
f3ef965d5c79680b63ceb172af60a82013c9a8d6Timo Sirainen
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen /* if alt path already exists and contains files, rebuild storage so
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen that we don't start overwriting files. */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX, &alt_path);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (ret > 0 && stat(alt_path, &st) == 0) {
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen ret = dir_is_empty(box->storage, alt_path);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen if (ret < 0)
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen return -1;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen if (ret == 0) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box,
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi "Existing files in alt path, "
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi "rebuilding storage to avoid losing messages");
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen storage->v.set_mailbox_corrupted(box);
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen return -1;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen }
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen /* dir is empty, ignore it */
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen }
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen return dbox_mailbox_create_indexes(box, update);
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen}
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainenint dbox_mailbox_create_indexes(struct mailbox *box,
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen const struct mailbox_update *update)
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen{
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek struct dbox_storage *storage = DBOX_STORAGE(box->storage);
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen struct mail_index_sync_ctx *sync_ctx;
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen struct mail_index_view *view;
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen struct mail_index_transaction *trans;
48d8312488089dc1a8360991f0881d91095c21eaTimo Sirainen int ret;
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainen
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen /* use syncing as a lock */
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen ret = mail_index_sync_begin(box->index, &sync_ctx, &view, &trans, 0);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen if (ret <= 0) {
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen i_assert(ret != 0);
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen mailbox_set_index_error(box);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen }
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen if (mail_index_get_header(view)->uid_validity == 0) {
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen if (storage->v.mailbox_create_indexes(box, update, trans) < 0) {
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen mail_index_sync_rollback(&sync_ctx);
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return -1;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen }
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen }
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen return mail_index_sync_commit(&sync_ctx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainenint dbox_verify_alt_storage(struct mailbox_list *list)
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen{
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen const char *alt_path;
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen struct stat st;
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_ALT_DIR,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &alt_path))
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen return 0;
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen /* make sure alt storage is mounted. if it's not, abort the rebuild. */
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen if (stat(alt_path, &st) == 0)
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen return 0;
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen if (errno != ENOENT) {
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen i_error("stat(%s) failed: %m", alt_path);
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen return -1;
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen }
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen /* try to create the alt directory. if it fails, it means alt
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen storage isn't mounted. */
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen if (mailbox_list_mkdir_root(list, alt_path,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen MAILBOX_LIST_PATH_TYPE_ALT_DIR) < 0)
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen return -1;
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen return 0;
755abfa2bc6c5f072519b545faa1487357046b27Timo Sirainen}
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainenbool dbox_header_have_flag(struct mailbox *box, uint32_t ext_id,
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen unsigned int flags_offset, uint8_t flag)
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen{
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen const void *data;
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen size_t data_size;
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen uint8_t flags = 0;
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen mail_index_get_header_ext(box->view, ext_id, &data, &data_size);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen if (flags_offset < data_size)
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen flags = *((const uint8_t *)data + flags_offset);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen return (flags & flag) != 0;
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen}